summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty')
-rw-r--r--3rdparty/libuv/LICENSE46
-rw-r--r--3rdparty/libuv/MAINTAINERS.md36
-rw-r--r--3rdparty/libuv/Makefile.am344
-rw-r--r--3rdparty/libuv/Makefile.mingw84
-rw-r--r--3rdparty/libuv/README.md245
-rw-r--r--3rdparty/libuv/docs/src/async.rst57
-rw-r--r--3rdparty/libuv/docs/src/check.rst46
-rw-r--r--3rdparty/libuv/docs/src/conf.py348
-rw-r--r--3rdparty/libuv/docs/src/design.rst137
-rw-r--r--3rdparty/libuv/docs/src/dll.rst44
-rw-r--r--3rdparty/libuv/docs/src/dns.rst108
-rw-r--r--3rdparty/libuv/docs/src/errors.rst331
-rw-r--r--3rdparty/libuv/docs/src/fs.rst300
-rw-r--r--3rdparty/libuv/docs/src/fs_event.rst108
-rw-r--r--3rdparty/libuv/docs/src/fs_poll.rst72
-rw-r--r--3rdparty/libuv/docs/src/handle.rst181
-rw-r--r--3rdparty/libuv/docs/src/idle.rst54
-rw-r--r--3rdparty/libuv/docs/src/index.rst95
-rw-r--r--3rdparty/libuv/docs/src/loop.rst166
-rw-r--r--3rdparty/libuv/docs/src/migration_010_100.rst244
-rw-r--r--3rdparty/libuv/docs/src/misc.rst328
-rw-r--r--3rdparty/libuv/docs/src/pipe.rst104
-rw-r--r--3rdparty/libuv/docs/src/poll.rst103
-rw-r--r--3rdparty/libuv/docs/src/prepare.rst46
-rw-r--r--3rdparty/libuv/docs/src/process.rst225
-rw-r--r--3rdparty/libuv/docs/src/request.rst82
-rw-r--r--3rdparty/libuv/docs/src/signal.rst77
-rw-r--r--3rdparty/libuv/docs/src/sphinx-plugins/manpage.py46
-rw-r--r--3rdparty/libuv/docs/src/static/architecture.pngbin0 -> 206767 bytes
-rw-r--r--3rdparty/libuv/docs/src/static/diagrams.key/Data/st0-311.jpgbin0 -> 19328 bytes
-rw-r--r--3rdparty/libuv/docs/src/static/diagrams.key/Data/st1-475.jpgbin0 -> 12655 bytes
-rw-r--r--3rdparty/libuv/docs/src/static/diagrams.key/Index.zipbin0 -> 71160 bytes
-rw-r--r--3rdparty/libuv/docs/src/static/diagrams.key/Metadata/BuildVersionHistory.plist8
-rw-r--r--3rdparty/libuv/docs/src/static/diagrams.key/Metadata/DocumentIdentifier1
-rw-r--r--3rdparty/libuv/docs/src/static/diagrams.key/Metadata/Properties.plistbin0 -> 340 bytes
-rw-r--r--3rdparty/libuv/docs/src/static/diagrams.key/preview-micro.jpgbin0 -> 1425 bytes
-rw-r--r--3rdparty/libuv/docs/src/static/diagrams.key/preview-web.jpgbin0 -> 8106 bytes
-rw-r--r--3rdparty/libuv/docs/src/static/diagrams.key/preview.jpgbin0 -> 107456 bytes
-rw-r--r--3rdparty/libuv/docs/src/static/favicon.icobin0 -> 15086 bytes
-rw-r--r--3rdparty/libuv/docs/src/static/logo.pngbin0 -> 33545 bytes
-rw-r--r--3rdparty/libuv/docs/src/static/loop_iteration.pngbin0 -> 80528 bytes
-rw-r--r--3rdparty/libuv/docs/src/stream.rst219
-rw-r--r--3rdparty/libuv/docs/src/tcp.rst108
-rw-r--r--3rdparty/libuv/docs/src/threading.rst160
-rw-r--r--3rdparty/libuv/docs/src/threadpool.rst67
-rw-r--r--3rdparty/libuv/docs/src/timer.rst76
-rw-r--r--3rdparty/libuv/docs/src/tty.rst93
-rw-r--r--3rdparty/libuv/docs/src/udp.rst295
-rw-r--r--3rdparty/libuv/docs/src/version.rst60
-rw-r--r--3rdparty/libuv/gyp_uv.py93
-rw-r--r--3rdparty/libuv/img/banner.pngbin0 -> 44102 bytes
-rw-r--r--3rdparty/libuv/img/logos.svg152
-rw-r--r--3rdparty/libuv/include/android-ifaddrs.h54
-rw-r--r--3rdparty/libuv/include/pthread-fixes.h72
-rw-r--r--3rdparty/libuv/include/stdint-msvc2008.h247
-rw-r--r--3rdparty/libuv/include/tree.h768
-rw-r--r--3rdparty/libuv/include/uv-aix.h32
-rw-r--r--3rdparty/libuv/include/uv-bsd.h34
-rw-r--r--3rdparty/libuv/include/uv-darwin.h61
-rw-r--r--3rdparty/libuv/include/uv-errno.h418
-rw-r--r--3rdparty/libuv/include/uv-linux.h34
-rw-r--r--3rdparty/libuv/include/uv-sunos.h44
-rw-r--r--3rdparty/libuv/include/uv-threadpool.h37
-rw-r--r--3rdparty/libuv/include/uv-unix.h383
-rw-r--r--3rdparty/libuv/include/uv-version.h43
-rw-r--r--3rdparty/libuv/include/uv-win.h653
-rw-r--r--3rdparty/libuv/include/uv.h1482
-rw-r--r--3rdparty/libuv/libuv.nsi86
-rw-r--r--3rdparty/libuv/libuv.pc.in11
-rw-r--r--3rdparty/libuv/m4/.gitignore4
-rw-r--r--3rdparty/libuv/m4/as_case.m421
-rw-r--r--3rdparty/libuv/m4/libuv-check-flags.m4319
-rw-r--r--3rdparty/libuv/samples/.gitignore22
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/.gitignore21
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/LICENSE53
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/build.gyp46
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/client.c737
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/defs.h139
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/getopt.c131
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/main.c99
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/s5.c271
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/s5.h94
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/server.c241
-rw-r--r--3rdparty/libuv/samples/socks5-proxy/util.c72
-rw-r--r--3rdparty/libuv/src/fs-poll.c255
-rw-r--r--3rdparty/libuv/src/heap-inl.h245
-rw-r--r--3rdparty/libuv/src/inet.c309
-rw-r--r--3rdparty/libuv/src/queue.h108
-rw-r--r--3rdparty/libuv/src/threadpool.c303
-rw-r--r--3rdparty/libuv/src/unix/aix.c1158
-rw-r--r--3rdparty/libuv/src/unix/android-ifaddrs.c703
-rw-r--r--3rdparty/libuv/src/unix/async.c290
-rw-r--r--3rdparty/libuv/src/unix/atomic-ops.h77
-rw-r--r--3rdparty/libuv/src/unix/core.c1104
-rw-r--r--3rdparty/libuv/src/unix/darwin-proctitle.c206
-rw-r--r--3rdparty/libuv/src/unix/darwin.c335
-rw-r--r--3rdparty/libuv/src/unix/dl.c80
-rw-r--r--3rdparty/libuv/src/unix/freebsd.c450
-rw-r--r--3rdparty/libuv/src/unix/fs.c1310
-rw-r--r--3rdparty/libuv/src/unix/fsevents.c904
-rw-r--r--3rdparty/libuv/src/unix/getaddrinfo.c202
-rw-r--r--3rdparty/libuv/src/unix/getnameinfo.c120
-rw-r--r--3rdparty/libuv/src/unix/internal.h316
-rw-r--r--3rdparty/libuv/src/unix/kqueue.c426
-rw-r--r--3rdparty/libuv/src/unix/linux-core.c899
-rw-r--r--3rdparty/libuv/src/unix/linux-inotify.c285
-rw-r--r--3rdparty/libuv/src/unix/linux-syscalls.c471
-rw-r--r--3rdparty/libuv/src/unix/linux-syscalls.h158
-rw-r--r--3rdparty/libuv/src/unix/loop-watcher.c68
-rw-r--r--3rdparty/libuv/src/unix/loop.c155
-rw-r--r--3rdparty/libuv/src/unix/netbsd.c370
-rw-r--r--3rdparty/libuv/src/unix/openbsd.c386
-rw-r--r--3rdparty/libuv/src/unix/pipe.c288
-rw-r--r--3rdparty/libuv/src/unix/poll.c113
-rw-r--r--3rdparty/libuv/src/unix/process.c563
-rw-r--r--3rdparty/libuv/src/unix/proctitle.c102
-rw-r--r--3rdparty/libuv/src/unix/pthread-fixes.c104
-rw-r--r--3rdparty/libuv/src/unix/signal.c467
-rw-r--r--3rdparty/libuv/src/unix/spinlock.h53
-rw-r--r--3rdparty/libuv/src/unix/stream.c1615
-rw-r--r--3rdparty/libuv/src/unix/sunos.c765
-rw-r--r--3rdparty/libuv/src/unix/tcp.c362
-rw-r--r--3rdparty/libuv/src/unix/thread.c525
-rw-r--r--3rdparty/libuv/src/unix/timer.c172
-rw-r--r--3rdparty/libuv/src/unix/tty.c279
-rw-r--r--3rdparty/libuv/src/unix/udp.c873
-rw-r--r--3rdparty/libuv/src/uv-common.c627
-rw-r--r--3rdparty/libuv/src/uv-common.h227
-rw-r--r--3rdparty/libuv/src/version.c45
-rw-r--r--3rdparty/libuv/src/win/async.c99
-rw-r--r--3rdparty/libuv/src/win/atomicops-inl.h56
-rw-r--r--3rdparty/libuv/src/win/core.c457
-rw-r--r--3rdparty/libuv/src/win/dl.c113
-rw-r--r--3rdparty/libuv/src/win/error.c170
-rw-r--r--3rdparty/libuv/src/win/fs-event.c552
-rw-r--r--3rdparty/libuv/src/win/fs.c2468
-rw-r--r--3rdparty/libuv/src/win/getaddrinfo.c358
-rw-r--r--3rdparty/libuv/src/win/getnameinfo.c150
-rw-r--r--3rdparty/libuv/src/win/handle-inl.h179
-rw-r--r--3rdparty/libuv/src/win/handle.c154
-rw-r--r--3rdparty/libuv/src/win/internal.h382
-rw-r--r--3rdparty/libuv/src/win/loop-watcher.c122
-rw-r--r--3rdparty/libuv/src/win/pipe.c2118
-rw-r--r--3rdparty/libuv/src/win/poll.c635
-rw-r--r--3rdparty/libuv/src/win/process-stdio.c510
-rw-r--r--3rdparty/libuv/src/win/process.c1247
-rw-r--r--3rdparty/libuv/src/win/req-inl.h224
-rw-r--r--3rdparty/libuv/src/win/req.c25
-rw-r--r--3rdparty/libuv/src/win/signal.c356
-rw-r--r--3rdparty/libuv/src/win/snprintf.c42
-rw-r--r--3rdparty/libuv/src/win/stream-inl.h56
-rw-r--r--3rdparty/libuv/src/win/stream.c249
-rw-r--r--3rdparty/libuv/src/win/tcp.c1507
-rw-r--r--3rdparty/libuv/src/win/thread.c697
-rw-r--r--3rdparty/libuv/src/win/timer.c200
-rw-r--r--3rdparty/libuv/src/win/tty.c2084
-rw-r--r--3rdparty/libuv/src/win/udp.c926
-rw-r--r--3rdparty/libuv/src/win/util.c1232
-rw-r--r--3rdparty/libuv/src/win/winapi.c146
-rw-r--r--3rdparty/libuv/src/win/winapi.h4710
-rw-r--r--3rdparty/libuv/src/win/winsock.c561
-rw-r--r--3rdparty/libuv/src/win/winsock.h190
-rw-r--r--3rdparty/libuv/test/benchmark-async-pummel.c119
-rw-r--r--3rdparty/libuv/test/benchmark-async.c141
-rw-r--r--3rdparty/libuv/test/benchmark-fs-stat.c136
-rw-r--r--3rdparty/libuv/test/benchmark-getaddrinfo.c92
-rw-r--r--3rdparty/libuv/test/benchmark-list.h163
-rw-r--r--3rdparty/libuv/test/benchmark-loop-count.c92
-rw-r--r--3rdparty/libuv/test/benchmark-million-async.c112
-rw-r--r--3rdparty/libuv/test/benchmark-million-timers.c86
-rw-r--r--3rdparty/libuv/test/benchmark-multi-accept.c447
-rw-r--r--3rdparty/libuv/test/benchmark-ping-pongs.c221
-rw-r--r--3rdparty/libuv/test/benchmark-pound.c351
-rw-r--r--3rdparty/libuv/test/benchmark-pump.c476
-rw-r--r--3rdparty/libuv/test/benchmark-sizes.c46
-rw-r--r--3rdparty/libuv/test/benchmark-spawn.c164
-rw-r--r--3rdparty/libuv/test/benchmark-tcp-write-batch.c144
-rw-r--r--3rdparty/libuv/test/benchmark-thread.c64
-rw-r--r--3rdparty/libuv/test/benchmark-udp-pummel.c243
-rw-r--r--3rdparty/libuv/test/blackhole-server.c121
-rw-r--r--3rdparty/libuv/test/dns-server.c340
-rw-r--r--3rdparty/libuv/test/echo-server.c378
-rw-r--r--3rdparty/libuv/test/fixtures/empty_file0
-rw-r--r--3rdparty/libuv/test/fixtures/load_error.node1
-rw-r--r--3rdparty/libuv/test/run-benchmarks.c65
-rw-r--r--3rdparty/libuv/test/run-tests.c181
-rw-r--r--3rdparty/libuv/test/runner-unix.c400
-rw-r--r--3rdparty/libuv/test/runner-unix.h36
-rw-r--r--3rdparty/libuv/test/runner-win.c371
-rw-r--r--3rdparty/libuv/test/runner-win.h39
-rw-r--r--3rdparty/libuv/test/runner.c466
-rw-r--r--3rdparty/libuv/test/runner.h178
-rw-r--r--3rdparty/libuv/test/task.h220
-rw-r--r--3rdparty/libuv/test/test-active.c84
-rw-r--r--3rdparty/libuv/test/test-async-null-cb.c55
-rw-r--r--3rdparty/libuv/test/test-async.c134
-rw-r--r--3rdparty/libuv/test/test-barrier.c106
-rw-r--r--3rdparty/libuv/test/test-callback-order.c77
-rw-r--r--3rdparty/libuv/test/test-callback-stack.c205
-rw-r--r--3rdparty/libuv/test/test-close-fd.c76
-rw-r--r--3rdparty/libuv/test/test-close-order.c80
-rw-r--r--3rdparty/libuv/test/test-condvar.c173
-rw-r--r--3rdparty/libuv/test/test-connection-fail.c151
-rw-r--r--3rdparty/libuv/test/test-cwd-and-chdir.c51
-rw-r--r--3rdparty/libuv/test/test-default-loop-close.c59
-rw-r--r--3rdparty/libuv/test/test-delayed-accept.c189
-rw-r--r--3rdparty/libuv/test/test-dlerror.c55
-rw-r--r--3rdparty/libuv/test/test-embed.c138
-rw-r--r--3rdparty/libuv/test/test-emfile.c110
-rw-r--r--3rdparty/libuv/test/test-error.c50
-rw-r--r--3rdparty/libuv/test/test-fail-always.c29
-rw-r--r--3rdparty/libuv/test/test-fs-event.c907
-rw-r--r--3rdparty/libuv/test/test-fs-poll.c186
-rw-r--r--3rdparty/libuv/test/test-fs.c2664
-rw-r--r--3rdparty/libuv/test/test-get-currentexe.c86
-rw-r--r--3rdparty/libuv/test/test-get-loadavg.c35
-rw-r--r--3rdparty/libuv/test/test-get-memory.c38
-rw-r--r--3rdparty/libuv/test/test-getaddrinfo.c184
-rw-r--r--3rdparty/libuv/test/test-getnameinfo.c101
-rw-r--r--3rdparty/libuv/test/test-getsockname.c361
-rw-r--r--3rdparty/libuv/test/test-handle-fileno.c121
-rw-r--r--3rdparty/libuv/test/test-homedir.c49
-rw-r--r--3rdparty/libuv/test/test-hrtime.c54
-rw-r--r--3rdparty/libuv/test/test-idle.c99
-rw-r--r--3rdparty/libuv/test/test-ip4-addr.c46
-rw-r--r--3rdparty/libuv/test/test-ip6-addr.c141
-rw-r--r--3rdparty/libuv/test/test-ipc-send-recv.c411
-rw-r--r--3rdparty/libuv/test/test-ipc.c779
-rw-r--r--3rdparty/libuv/test/test-list.h732
-rw-r--r--3rdparty/libuv/test/test-loop-alive.c67
-rw-r--r--3rdparty/libuv/test/test-loop-close.c53
-rw-r--r--3rdparty/libuv/test/test-loop-configure.c38
-rw-r--r--3rdparty/libuv/test/test-loop-handles.c337
-rw-r--r--3rdparty/libuv/test/test-loop-stop.c71
-rw-r--r--3rdparty/libuv/test/test-loop-time.c63
-rw-r--r--3rdparty/libuv/test/test-multiple-listen.c109
-rw-r--r--3rdparty/libuv/test/test-mutexes.c162
-rw-r--r--3rdparty/libuv/test/test-osx-select.c140
-rw-r--r--3rdparty/libuv/test/test-pass-always.c28
-rw-r--r--3rdparty/libuv/test/test-ping-pong.c270
-rw-r--r--3rdparty/libuv/test/test-pipe-bind-error.c136
-rw-r--r--3rdparty/libuv/test/test-pipe-close-stdout-read-stdin.c104
-rw-r--r--3rdparty/libuv/test/test-pipe-connect-error.c95
-rw-r--r--3rdparty/libuv/test/test-pipe-connect-multiple.c104
-rw-r--r--3rdparty/libuv/test/test-pipe-connect-prepare.c83
-rw-r--r--3rdparty/libuv/test/test-pipe-getsockname.c263
-rw-r--r--3rdparty/libuv/test/test-pipe-pending-instances.c59
-rw-r--r--3rdparty/libuv/test/test-pipe-sendmsg.c169
-rw-r--r--3rdparty/libuv/test/test-pipe-server-close.c91
-rw-r--r--3rdparty/libuv/test/test-pipe-set-non-blocking.c99
-rw-r--r--3rdparty/libuv/test/test-platform-output.c126
-rw-r--r--3rdparty/libuv/test/test-poll-close-doesnt-corrupt-stack.c114
-rw-r--r--3rdparty/libuv/test/test-poll-close.c73
-rw-r--r--3rdparty/libuv/test/test-poll-closesocket.c89
-rw-r--r--3rdparty/libuv/test/test-poll.c560
-rw-r--r--3rdparty/libuv/test/test-process-title.c53
-rw-r--r--3rdparty/libuv/test/test-queue-foreach-delete.c200
-rw-r--r--3rdparty/libuv/test/test-ref.c442
-rw-r--r--3rdparty/libuv/test/test-run-nowait.c45
-rw-r--r--3rdparty/libuv/test/test-run-once.c48
-rw-r--r--3rdparty/libuv/test/test-semaphore.c111
-rw-r--r--3rdparty/libuv/test/test-shutdown-close.c108
-rw-r--r--3rdparty/libuv/test/test-shutdown-eof.c182
-rw-r--r--3rdparty/libuv/test/test-shutdown-twice.c84
-rw-r--r--3rdparty/libuv/test/test-signal-multiple-loops.c290
-rw-r--r--3rdparty/libuv/test/test-signal.c152
-rw-r--r--3rdparty/libuv/test/test-socket-buffer-size.c77
-rw-r--r--3rdparty/libuv/test/test-spawn.c1706
-rw-r--r--3rdparty/libuv/test/test-stdio-over-pipes.c255
-rw-r--r--3rdparty/libuv/test/test-tcp-bind-error.c216
-rw-r--r--3rdparty/libuv/test/test-tcp-bind6-error.c176
-rw-r--r--3rdparty/libuv/test/test-tcp-close-accept.c188
-rw-r--r--3rdparty/libuv/test/test-tcp-close-while-connecting.c86
-rw-r--r--3rdparty/libuv/test/test-tcp-close.c136
-rw-r--r--3rdparty/libuv/test/test-tcp-connect-error-after-write.c98
-rw-r--r--3rdparty/libuv/test/test-tcp-connect-error.c73
-rw-r--r--3rdparty/libuv/test/test-tcp-connect-timeout.c91
-rw-r--r--3rdparty/libuv/test/test-tcp-connect6-error.c71
-rw-r--r--3rdparty/libuv/test/test-tcp-create-socket-early.c206
-rw-r--r--3rdparty/libuv/test/test-tcp-flags.c52
-rw-r--r--3rdparty/libuv/test/test-tcp-oob.c128
-rw-r--r--3rdparty/libuv/test/test-tcp-open.c220
-rw-r--r--3rdparty/libuv/test/test-tcp-read-stop.c76
-rw-r--r--3rdparty/libuv/test/test-tcp-shutdown-after-write.c138
-rw-r--r--3rdparty/libuv/test/test-tcp-try-write.c135
-rw-r--r--3rdparty/libuv/test/test-tcp-unexpected-read.c117
-rw-r--r--3rdparty/libuv/test/test-tcp-write-after-connect.c68
-rw-r--r--3rdparty/libuv/test/test-tcp-write-fail.c115
-rw-r--r--3rdparty/libuv/test/test-tcp-write-queue-order.c137
-rw-r--r--3rdparty/libuv/test/test-tcp-write-to-half-open-connection.c141
-rw-r--r--3rdparty/libuv/test/test-tcp-writealot.c176
-rw-r--r--3rdparty/libuv/test/test-thread-equal.c45
-rw-r--r--3rdparty/libuv/test/test-thread.c211
-rw-r--r--3rdparty/libuv/test/test-threadpool-cancel.c362
-rw-r--r--3rdparty/libuv/test/test-threadpool.c76
-rw-r--r--3rdparty/libuv/test/test-timer-again.c141
-rw-r--r--3rdparty/libuv/test/test-timer-from-check.c80
-rw-r--r--3rdparty/libuv/test/test-timer.c303
-rw-r--r--3rdparty/libuv/test/test-tty.c184
-rw-r--r--3rdparty/libuv/test/test-udp-bind.c93
-rw-r--r--3rdparty/libuv/test/test-udp-create-socket-early.c132
-rw-r--r--3rdparty/libuv/test/test-udp-dgram-too-big.c91
-rw-r--r--3rdparty/libuv/test/test-udp-ipv6.c193
-rw-r--r--3rdparty/libuv/test/test-udp-multicast-interface.c99
-rw-r--r--3rdparty/libuv/test/test-udp-multicast-interface6.c103
-rw-r--r--3rdparty/libuv/test/test-udp-multicast-join.c150
-rw-r--r--3rdparty/libuv/test/test-udp-multicast-join6.c161
-rw-r--r--3rdparty/libuv/test/test-udp-multicast-ttl.c94
-rw-r--r--3rdparty/libuv/test/test-udp-open.c204
-rw-r--r--3rdparty/libuv/test/test-udp-options.c126
-rw-r--r--3rdparty/libuv/test/test-udp-send-and-recv.c214
-rw-r--r--3rdparty/libuv/test/test-udp-send-immediate.c148
-rw-r--r--3rdparty/libuv/test/test-udp-send-unreachable.c150
-rw-r--r--3rdparty/libuv/test/test-udp-try-send.c133
-rw-r--r--3rdparty/libuv/test/test-walk-handles.c77
-rw-r--r--3rdparty/libuv/test/test-watcher-cross-stop.c103
-rw-r--r--3rdparty/libuv/uv.gyp508
-rw-r--r--3rdparty/libuv/vcbuild.bat153
-rw-r--r--3rdparty/lua-zlib/.gitattributes1
-rw-r--r--3rdparty/lua-zlib/CMakeLists.txt62
-rw-r--r--3rdparty/lua-zlib/Makefile62
-rw-r--r--3rdparty/lua-zlib/README151
-rw-r--r--3rdparty/lua-zlib/amnon_david.gzbin0 -> 65 bytes
-rw-r--r--3rdparty/lua-zlib/cmake/Modules/FindLuaJIT.cmake63
-rw-r--r--3rdparty/lua-zlib/lua_zlib.c401
-rw-r--r--3rdparty/lua-zlib/rockspec35
-rw-r--r--3rdparty/lua-zlib/tap.lua24
-rw-r--r--3rdparty/lua-zlib/test.lua198
-rw-r--r--3rdparty/lua-zlib/tom_macwright.gz4
-rw-r--r--3rdparty/lua-zlib/tom_macwright.outbin0 -> 245 bytes
-rw-r--r--3rdparty/lua-zlib/zlib.def2
-rw-r--r--3rdparty/luafilesystem/.travis.yml33
-rw-r--r--3rdparty/luafilesystem/.travis/platform.sh15
-rw-r--r--3rdparty/luafilesystem/.travis/setup_lua.sh101
-rw-r--r--3rdparty/luafilesystem/LICENSE21
-rw-r--r--3rdparty/luafilesystem/Makefile25
-rw-r--r--3rdparty/luafilesystem/Makefile.win25
-rw-r--r--3rdparty/luafilesystem/README23
-rw-r--r--3rdparty/luafilesystem/config24
-rw-r--r--3rdparty/luafilesystem/config.win19
-rw-r--r--3rdparty/luafilesystem/doc/us/doc.css212
-rw-r--r--3rdparty/luafilesystem/doc/us/examples.html103
-rw-r--r--3rdparty/luafilesystem/doc/us/index.html218
-rw-r--r--3rdparty/luafilesystem/doc/us/license.html122
-rw-r--r--3rdparty/luafilesystem/doc/us/luafilesystem.pngbin0 -> 8535 bytes
-rw-r--r--3rdparty/luafilesystem/doc/us/manual.html280
-rw-r--r--3rdparty/luafilesystem/rockspecs/luafilesystem-1.3.0-1.rockspec27
-rw-r--r--3rdparty/luafilesystem/rockspecs/luafilesystem-1.4.0-1.rockspec27
-rw-r--r--3rdparty/luafilesystem/rockspecs/luafilesystem-1.4.0-2.rockspec43
-rw-r--r--3rdparty/luafilesystem/rockspecs/luafilesystem-1.4.1-1.rockspec43
-rw-r--r--3rdparty/luafilesystem/rockspecs/luafilesystem-1.4.1rc1-1.rockspec43
-rw-r--r--3rdparty/luafilesystem/rockspecs/luafilesystem-1.4.2-1.rockspec26
-rw-r--r--3rdparty/luafilesystem/rockspecs/luafilesystem-1.5.0-1.rockspec27
-rw-r--r--3rdparty/luafilesystem/rockspecs/luafilesystem-1.6.0-1.rockspec27
-rw-r--r--3rdparty/luafilesystem/rockspecs/luafilesystem-1.6.1-1.rockspec27
-rw-r--r--3rdparty/luafilesystem/rockspecs/luafilesystem-1.6.2-1.rockspec27
-rw-r--r--3rdparty/luafilesystem/rockspecs/luafilesystem-1.6.3-1.rockspec28
-rw-r--r--3rdparty/luafilesystem/rockspecs/luafilesystem-cvs-1.rockspec44
-rw-r--r--3rdparty/luafilesystem/rockspecs/luafilesystem-cvs-2.rockspec26
-rw-r--r--3rdparty/luafilesystem/rockspecs/luafilesystem-cvs-3.rockspec27
-rw-r--r--3rdparty/luafilesystem/src/.gitignore2
-rw-r--r--3rdparty/luafilesystem/src/lfs.c906
-rw-r--r--3rdparty/luafilesystem/src/lfs.def4
-rw-r--r--3rdparty/luafilesystem/src/lfs.h34
-rw-r--r--3rdparty/luafilesystem/tests/test.lua175
-rw-r--r--3rdparty/luafilesystem/vc6/lfs.def5
-rw-r--r--3rdparty/luafilesystem/vc6/luafilesystem.dsw33
-rw-r--r--3rdparty/luafilesystem/vc6/luafilesystem_dll.dsp127
-rw-r--r--3rdparty/luv/.ci/install.bat270
-rw-r--r--3rdparty/luv/.ci/platform.sh15
-rw-r--r--3rdparty/luv/.ci/set_compiler_env.bat40
-rw-r--r--3rdparty/luv/.ci/setenv_lua.sh3
-rw-r--r--3rdparty/luv/.ci/setup_lua.sh122
-rw-r--r--3rdparty/luv/.ci/winmake.bat457
-rw-r--r--3rdparty/luv/.gitignore10
-rw-r--r--3rdparty/luv/.travis.yml36
-rw-r--r--3rdparty/luv/CMakeLists.txt191
-rw-r--r--3rdparty/luv/LICENSE.txt202
-rw-r--r--3rdparty/luv/Makefile61
-rw-r--r--3rdparty/luv/README.md213
-rw-r--r--3rdparty/luv/appveyor.yml42
-rw-r--r--3rdparty/luv/cmake/Modules/FindLibuv.cmake11
-rw-r--r--3rdparty/luv/cmake/Modules/FindLuaJIT.cmake55
-rw-r--r--3rdparty/luv/deps/lua.cmake128
-rw-r--r--3rdparty/luv/deps/lua_one.c97
-rw-r--r--3rdparty/luv/deps/luajit.cmake407
-rw-r--r--3rdparty/luv/deps/uv.cmake224
-rw-r--r--3rdparty/luv/docs.md1309
-rw-r--r--3rdparty/luv/examples/cqueues-main.lua31
-rw-r--r--3rdparty/luv/examples/cqueues-slave.lua55
-rw-r--r--3rdparty/luv/examples/echo-server-client.lua68
-rw-r--r--3rdparty/luv/examples/killing-children.lua24
-rw-r--r--3rdparty/luv/examples/lots-o-dns.lua49
-rw-r--r--3rdparty/luv/examples/repl.lua89
-rw-r--r--3rdparty/luv/examples/talking-to-children.lua47
-rw-r--r--3rdparty/luv/examples/tcp-cluster.lua84
-rw-r--r--3rdparty/luv/examples/timers.lua68
-rw-r--r--3rdparty/luv/examples/uvbook/helloworld.lua5
-rw-r--r--3rdparty/luv/examples/uvbook/idle-basic.lua14
-rw-r--r--3rdparty/luv/examples/uvbook/onchange.lua30
-rw-r--r--3rdparty/luv/examples/uvbook/queue-work.lua19
-rw-r--r--3rdparty/luv/examples/uvbook/tcp-echo-client.lua21
-rw-r--r--3rdparty/luv/examples/uvbook/tcp-echo-server.lua22
-rw-r--r--3rdparty/luv/examples/uvbook/thread-create.lua38
-rw-r--r--3rdparty/luv/examples/uvbook/uvcat.lua37
-rw-r--r--3rdparty/luv/examples/uvbook/uvtee.lua35
-rw-r--r--3rdparty/luv/lib/tap.lua165
-rw-r--r--3rdparty/luv/lib/utils.lua165
-rw-r--r--3rdparty/luv/luv-1.8.0-4.rockspec34
-rw-r--r--3rdparty/luv/msvcbuild.bat13
-rw-r--r--3rdparty/luv/src/async.c63
-rw-r--r--3rdparty/luv/src/check.c59
-rw-r--r--3rdparty/luv/src/constants.c649
-rw-r--r--3rdparty/luv/src/dns.c296
-rw-r--r--3rdparty/luv/src/fs.c614
-rw-r--r--3rdparty/luv/src/fs_event.c97
-rw-r--r--3rdparty/luv/src/fs_poll.c90
-rw-r--r--3rdparty/luv/src/handle.c173
-rw-r--r--3rdparty/luv/src/idle.c59
-rw-r--r--3rdparty/luv/src/lhandle.c116
-rw-r--r--3rdparty/luv/src/lhandle.h67
-rw-r--r--3rdparty/luv/src/loop.c92
-rw-r--r--3rdparty/luv/src/lreq.c71
-rw-r--r--3rdparty/luv/src/lreq.h43
-rw-r--r--3rdparty/luv/src/lthreadpool.h48
-rw-r--r--3rdparty/luv/src/luv.c519
-rw-r--r--3rdparty/luv/src/luv.h109
-rw-r--r--3rdparty/luv/src/misc.c316
-rw-r--r--3rdparty/luv/src/pipe.c114
-rw-r--r--3rdparty/luv/src/poll.c100
-rw-r--r--3rdparty/luv/src/prepare.c59
-rw-r--r--3rdparty/luv/src/process.c266
-rw-r--r--3rdparty/luv/src/req.c52
-rw-r--r--3rdparty/luv/src/schema.c16
-rw-r--r--3rdparty/luv/src/signal.c72
-rw-r--r--3rdparty/luv/src/stream.c263
-rw-r--r--3rdparty/luv/src/tcp.c182
-rw-r--r--3rdparty/luv/src/thread.c353
-rw-r--r--3rdparty/luv/src/timer.c84
-rw-r--r--3rdparty/luv/src/tty.c65
-rw-r--r--3rdparty/luv/src/udp.c260
-rw-r--r--3rdparty/luv/src/util.c56
-rw-r--r--3rdparty/luv/src/util.h26
-rw-r--r--3rdparty/luv/src/work.c224
-rw-r--r--3rdparty/luv/tests/manual-test-cluster.lua213
-rw-r--r--3rdparty/luv/tests/run.lua33
-rw-r--r--3rdparty/luv/tests/test-async.lua32
-rw-r--r--3rdparty/luv/tests/test-conversions.lua6
-rw-r--r--3rdparty/luv/tests/test-dns.lua125
-rw-r--r--3rdparty/luv/tests/test-fs.lua90
-rw-r--r--3rdparty/luv/tests/test-leaks.lua186
-rw-r--r--3rdparty/luv/tests/test-misc.lua85
-rw-r--r--3rdparty/luv/tests/test-prepare-check-idle-async.lua49
-rw-r--r--3rdparty/luv/tests/test-process.lua101
-rw-r--r--3rdparty/luv/tests/test-sigchld-after-lua_close.sh45
-rw-r--r--3rdparty/luv/tests/test-signal.lua40
-rw-r--r--3rdparty/luv/tests/test-tcp.lua114
-rw-r--r--3rdparty/luv/tests/test-thread.lua47
-rw-r--r--3rdparty/luv/tests/test-timer.lua87
-rw-r--r--3rdparty/luv/tests/test-work.lua48
-rw-r--r--3rdparty/rapidjson/.gitignore24
-rw-r--r--3rdparty/rapidjson/.gitmodules3
-rw-r--r--3rdparty/rapidjson/.travis.yml54
-rw-r--r--3rdparty/rapidjson/CHANGELOG.md79
-rw-r--r--3rdparty/rapidjson/CMakeLists.txt128
-rw-r--r--3rdparty/rapidjson/CMakeModules/FindGTestSrc.cmake30
-rw-r--r--3rdparty/rapidjson/RapidJSON.pc.in7
-rw-r--r--3rdparty/rapidjson/RapidJSONConfig.cmake.in3
-rw-r--r--3rdparty/rapidjson/RapidJSONConfigVersion.cmake.in10
-rw-r--r--3rdparty/rapidjson/appveyor.yml28
-rw-r--r--3rdparty/rapidjson/bin/data/glossary.json22
-rw-r--r--3rdparty/rapidjson/bin/data/menu.json27
-rw-r--r--3rdparty/rapidjson/bin/data/readme.txt1
-rw-r--r--3rdparty/rapidjson/bin/data/sample.json3315
-rw-r--r--3rdparty/rapidjson/bin/data/webapp.json88
-rw-r--r--3rdparty/rapidjson/bin/data/widget.json26
-rw-r--r--3rdparty/rapidjson/bin/encodings/utf16be.jsonbin0 -> 368 bytes
-rw-r--r--3rdparty/rapidjson/bin/encodings/utf16bebom.jsonbin0 -> 370 bytes
-rw-r--r--3rdparty/rapidjson/bin/encodings/utf16le.jsonbin0 -> 368 bytes
-rw-r--r--3rdparty/rapidjson/bin/encodings/utf16lebom.jsonbin0 -> 370 bytes
-rw-r--r--3rdparty/rapidjson/bin/encodings/utf32be.jsonbin0 -> 736 bytes
-rw-r--r--3rdparty/rapidjson/bin/encodings/utf32bebom.jsonbin0 -> 740 bytes
-rw-r--r--3rdparty/rapidjson/bin/encodings/utf32le.jsonbin0 -> 736 bytes
-rw-r--r--3rdparty/rapidjson/bin/encodings/utf32lebom.jsonbin0 -> 740 bytes
-rw-r--r--3rdparty/rapidjson/bin/encodings/utf8.json7
-rw-r--r--3rdparty/rapidjson/bin/encodings/utf8bom.json7
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail1.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail10.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail11.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail12.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail13.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail14.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail15.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail16.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail17.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail18.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail19.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail2.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail20.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail21.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail22.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail23.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail24.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail25.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail26.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail27.json2
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail28.json2
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail29.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail3.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail30.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail31.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail32.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail33.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail4.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail5.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail6.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail7.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail8.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/fail9.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/pass1.json58
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/pass2.json1
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/pass3.json6
-rw-r--r--3rdparty/rapidjson/bin/jsonchecker/readme.txt3
-rw-r--r--3rdparty/rapidjson/bin/types/booleans.json102
-rw-r--r--3rdparty/rapidjson/bin/types/floats.json102
-rw-r--r--3rdparty/rapidjson/bin/types/guids.json102
-rw-r--r--3rdparty/rapidjson/bin/types/integers.json102
-rw-r--r--3rdparty/rapidjson/bin/types/mixed.json592
-rw-r--r--3rdparty/rapidjson/bin/types/nulls.json102
-rw-r--r--3rdparty/rapidjson/bin/types/paragraphs.json102
-rw-r--r--3rdparty/rapidjson/bin/types/readme.txt1
-rw-r--r--3rdparty/rapidjson/doc/CMakeLists.txt25
-rw-r--r--3rdparty/rapidjson/doc/Doxyfile.in2368
-rw-r--r--3rdparty/rapidjson/doc/Doxyfile.zh-cn.in2368
-rw-r--r--3rdparty/rapidjson/doc/diagram/architecture.dot50
-rw-r--r--3rdparty/rapidjson/doc/diagram/architecture.pngbin0 -> 16569 bytes
-rw-r--r--3rdparty/rapidjson/doc/diagram/insituparsing.dot65
-rw-r--r--3rdparty/rapidjson/doc/diagram/insituparsing.pngbin0 -> 37281 bytes
-rw-r--r--3rdparty/rapidjson/doc/diagram/iterative-parser-states-diagram.dot62
-rw-r--r--3rdparty/rapidjson/doc/diagram/iterative-parser-states-diagram.pngbin0 -> 92378 bytes
-rw-r--r--3rdparty/rapidjson/doc/diagram/move1.dot47
-rw-r--r--3rdparty/rapidjson/doc/diagram/move1.pngbin0 -> 16081 bytes
-rw-r--r--3rdparty/rapidjson/doc/diagram/move2.dot62
-rw-r--r--3rdparty/rapidjson/doc/diagram/move2.pngbin0 -> 41517 bytes
-rw-r--r--3rdparty/rapidjson/doc/diagram/move3.dot60
-rw-r--r--3rdparty/rapidjson/doc/diagram/move3.pngbin0 -> 36371 bytes
-rw-r--r--3rdparty/rapidjson/doc/diagram/normalparsing.dot56
-rw-r--r--3rdparty/rapidjson/doc/diagram/normalparsing.pngbin0 -> 32887 bytes
-rw-r--r--3rdparty/rapidjson/doc/diagram/simpledom.dot54
-rw-r--r--3rdparty/rapidjson/doc/diagram/simpledom.pngbin0 -> 43670 bytes
-rw-r--r--3rdparty/rapidjson/doc/diagram/tutorial.dot58
-rw-r--r--3rdparty/rapidjson/doc/diagram/tutorial.pngbin0 -> 44634 bytes
-rw-r--r--3rdparty/rapidjson/doc/diagram/utilityclass.dot73
-rw-r--r--3rdparty/rapidjson/doc/diagram/utilityclass.pngbin0 -> 99993 bytes
-rw-r--r--3rdparty/rapidjson/doc/dom.md277
-rw-r--r--3rdparty/rapidjson/doc/dom.zh-cn.md281
-rw-r--r--3rdparty/rapidjson/doc/encoding.md146
-rw-r--r--3rdparty/rapidjson/doc/encoding.zh-cn.md152
-rw-r--r--3rdparty/rapidjson/doc/faq.md289
-rw-r--r--3rdparty/rapidjson/doc/faq.zh-cn.md290
-rw-r--r--3rdparty/rapidjson/doc/features.md98
-rw-r--r--3rdparty/rapidjson/doc/features.zh-cn.md97
-rw-r--r--3rdparty/rapidjson/doc/internals.md365
-rw-r--r--3rdparty/rapidjson/doc/logo/rapidjson.pngbin0 -> 5259 bytes
-rw-r--r--3rdparty/rapidjson/doc/logo/rapidjson.svg119
-rw-r--r--3rdparty/rapidjson/doc/misc/DoxygenLayout.xml194
-rw-r--r--3rdparty/rapidjson/doc/misc/doxygenextra.css274
-rw-r--r--3rdparty/rapidjson/doc/misc/footer.html27
-rw-r--r--3rdparty/rapidjson/doc/misc/header.html33
-rw-r--r--3rdparty/rapidjson/doc/performance.md26
-rw-r--r--3rdparty/rapidjson/doc/performance.zh-cn.md26
-rw-r--r--3rdparty/rapidjson/doc/pointer.md234
-rw-r--r--3rdparty/rapidjson/doc/pointer.zh-cn.md234
-rw-r--r--3rdparty/rapidjson/doc/sax.md475
-rw-r--r--3rdparty/rapidjson/doc/sax.zh-cn.md476
-rw-r--r--3rdparty/rapidjson/doc/schema.md237
-rw-r--r--3rdparty/rapidjson/doc/schema.zh-cn.md237
-rw-r--r--3rdparty/rapidjson/doc/stream.md426
-rw-r--r--3rdparty/rapidjson/doc/stream.zh-cn.md426
-rw-r--r--3rdparty/rapidjson/doc/tutorial.md517
-rw-r--r--3rdparty/rapidjson/doc/tutorial.zh-cn.md515
-rw-r--r--3rdparty/rapidjson/example/CMakeLists.txt36
-rw-r--r--3rdparty/rapidjson/example/capitalize/capitalize.cpp66
-rw-r--r--3rdparty/rapidjson/example/condense/condense.cpp32
-rw-r--r--3rdparty/rapidjson/example/jsonx/jsonx.cpp200
-rw-r--r--3rdparty/rapidjson/example/messagereader/messagereader.cpp105
-rw-r--r--3rdparty/rapidjson/example/pretty/pretty.cpp30
-rw-r--r--3rdparty/rapidjson/example/prettyauto/prettyauto.cpp56
-rw-r--r--3rdparty/rapidjson/example/schemavalidator/schemavalidator.cpp72
-rw-r--r--3rdparty/rapidjson/example/serialize/serialize.cpp173
-rw-r--r--3rdparty/rapidjson/example/simpledom/simpledom.cpp29
-rw-r--r--3rdparty/rapidjson/example/simplereader/simplereader.cpp38
-rw-r--r--3rdparty/rapidjson/example/simplewriter/simplewriter.cpp35
-rw-r--r--3rdparty/rapidjson/example/tutorial/tutorial.cpp151
-rw-r--r--3rdparty/rapidjson/include/rapidjson/allocators.h263
-rw-r--r--3rdparty/rapidjson/include/rapidjson/document.h2189
-rw-r--r--3rdparty/rapidjson/include/rapidjson/encodedstream.h270
-rw-r--r--3rdparty/rapidjson/include/rapidjson/encodings.h712
-rw-r--r--3rdparty/rapidjson/include/rapidjson/error/en.h74
-rw-r--r--3rdparty/rapidjson/include/rapidjson/error/error.h155
-rw-r--r--3rdparty/rapidjson/include/rapidjson/filereadstream.h99
-rw-r--r--3rdparty/rapidjson/include/rapidjson/filewritestream.h104
-rw-r--r--3rdparty/rapidjson/include/rapidjson/fwd.h151
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/biginteger.h290
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/diyfp.h258
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/dtoa.h243
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/ieee754.h78
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/itoa.h304
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/meta.h181
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/pow10.h55
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/regex.h696
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/stack.h230
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/strfunc.h55
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/strtod.h269
-rw-r--r--3rdparty/rapidjson/include/rapidjson/internal/swap.h46
-rw-r--r--3rdparty/rapidjson/include/rapidjson/istreamwrapper.h105
-rw-r--r--3rdparty/rapidjson/include/rapidjson/memorybuffer.h70
-rw-r--r--3rdparty/rapidjson/include/rapidjson/memorystream.h71
-rw-r--r--3rdparty/rapidjson/include/rapidjson/msinttypes/inttypes.h316
-rw-r--r--3rdparty/rapidjson/include/rapidjson/msinttypes/stdint.h300
-rw-r--r--3rdparty/rapidjson/include/rapidjson/ostreamwrapper.h76
-rw-r--r--3rdparty/rapidjson/include/rapidjson/pointer.h1345
-rw-r--r--3rdparty/rapidjson/include/rapidjson/prettywriter.h223
-rw-r--r--3rdparty/rapidjson/include/rapidjson/rapidjson.h569
-rw-r--r--3rdparty/rapidjson/include/rapidjson/reader.h1696
-rw-r--r--3rdparty/rapidjson/include/rapidjson/schema.h1979
-rw-r--r--3rdparty/rapidjson/include/rapidjson/stream.h179
-rw-r--r--3rdparty/rapidjson/include/rapidjson/stringbuffer.h117
-rw-r--r--3rdparty/rapidjson/include/rapidjson/writer.h558
-rw-r--r--3rdparty/rapidjson/library.json12
-rw-r--r--3rdparty/rapidjson/license.txt57
-rw-r--r--3rdparty/rapidjson/rapidjson.autopkg75
-rw-r--r--3rdparty/rapidjson/readme.md129
-rw-r--r--3rdparty/rapidjson/readme.zh-cn.md121
-rw-r--r--3rdparty/rapidjson/test/CMakeLists.txt20
-rw-r--r--3rdparty/rapidjson/test/perftest/CMakeLists.txt17
-rw-r--r--3rdparty/rapidjson/test/perftest/misctest.cpp974
-rw-r--r--3rdparty/rapidjson/test/perftest/perftest.cpp24
-rw-r--r--3rdparty/rapidjson/test/perftest/perftest.h180
-rw-r--r--3rdparty/rapidjson/test/perftest/platformtest.cpp166
-rw-r--r--3rdparty/rapidjson/test/perftest/rapidjsontest.cpp422
-rw-r--r--3rdparty/rapidjson/test/perftest/schematest.cpp216
-rw-r--r--3rdparty/rapidjson/test/unittest/CMakeLists.txt61
-rw-r--r--3rdparty/rapidjson/test/unittest/allocatorstest.cpp102
-rw-r--r--3rdparty/rapidjson/test/unittest/bigintegertest.cpp133
-rw-r--r--3rdparty/rapidjson/test/unittest/documenttest.cpp589
-rw-r--r--3rdparty/rapidjson/test/unittest/dtoatest.cpp91
-rw-r--r--3rdparty/rapidjson/test/unittest/encodedstreamtest.cpp313
-rw-r--r--3rdparty/rapidjson/test/unittest/encodingstest.cpp425
-rw-r--r--3rdparty/rapidjson/test/unittest/filestreamtest.cpp112
-rw-r--r--3rdparty/rapidjson/test/unittest/fwdtest.cpp227
-rw-r--r--3rdparty/rapidjson/test/unittest/istreamwrappertest.cpp171
-rw-r--r--3rdparty/rapidjson/test/unittest/itoatest.cpp158
-rw-r--r--3rdparty/rapidjson/test/unittest/jsoncheckertest.cpp99
-rw-r--r--3rdparty/rapidjson/test/unittest/namespacetest.cpp70
-rw-r--r--3rdparty/rapidjson/test/unittest/ostreamwrappertest.cpp91
-rw-r--r--3rdparty/rapidjson/test/unittest/pointertest.cpp1524
-rw-r--r--3rdparty/rapidjson/test/unittest/prettywritertest.cpp180
-rw-r--r--3rdparty/rapidjson/test/unittest/readertest.cpp1517
-rw-r--r--3rdparty/rapidjson/test/unittest/regextest.cpp576
-rw-r--r--3rdparty/rapidjson/test/unittest/schematest.cpp1157
-rw-r--r--3rdparty/rapidjson/test/unittest/simdtest.cpp159
-rw-r--r--3rdparty/rapidjson/test/unittest/strfunctest.cpp30
-rw-r--r--3rdparty/rapidjson/test/unittest/stringbuffertest.cpp163
-rw-r--r--3rdparty/rapidjson/test/unittest/strtodtest.cpp132
-rw-r--r--3rdparty/rapidjson/test/unittest/unittest.cpp50
-rw-r--r--3rdparty/rapidjson/test/unittest/unittest.h135
-rw-r--r--3rdparty/rapidjson/test/unittest/valuetest.cpp1498
-rw-r--r--3rdparty/rapidjson/test/unittest/writertest.cpp441
-rw-r--r--3rdparty/rapidjson/travis-doxygen.sh122
670 files changed, 144115 insertions, 0 deletions
diff --git a/3rdparty/libuv/LICENSE b/3rdparty/libuv/LICENSE
new file mode 100644
index 00000000000..4d411670e3f
--- /dev/null
+++ b/3rdparty/libuv/LICENSE
@@ -0,0 +1,46 @@
+libuv is part of the Node project: http://nodejs.org/
+libuv may be distributed alone under Node's license:
+
+====
+
+Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+
+====
+
+This license applies to all parts of libuv that are not externally
+maintained libraries.
+
+The externally maintained libraries used by libuv are:
+
+ - tree.h (from FreeBSD), copyright Niels Provos. Two clause BSD license.
+
+ - inet_pton and inet_ntop implementations, contained in src/inet.c, are
+ copyright the Internet Systems Consortium, Inc., and licensed under the ISC
+ license.
+
+ - stdint-msvc2008.h (from msinttypes), copyright Alexander Chemeris. Three
+ clause BSD license.
+
+ - pthread-fixes.h, pthread-fixes.c, copyright Google Inc. and Sony Mobile
+ Communications AB. Three clause BSD license.
+
+ - android-ifaddrs.h, android-ifaddrs.c, copyright Berkeley Software Design
+ Inc, Kenneth MacKay and Emergya (Cloud4all, FP7/2007-2013, grant agreement
+ n° 289016). Three clause BSD license.
diff --git a/3rdparty/libuv/MAINTAINERS.md b/3rdparty/libuv/MAINTAINERS.md
new file mode 100644
index 00000000000..4db2f5130c0
--- /dev/null
+++ b/3rdparty/libuv/MAINTAINERS.md
@@ -0,0 +1,36 @@
+
+# Project Maintainers
+
+libuv is currently managed by the following individuals:
+
+* **Ben Noordhuis** ([@bnoordhuis](https://github.com/bnoordhuis))
+ - GPG key: D77B 1E34 243F BAF0 5F8E 9CC3 4F55 C8C8 46AB 89B9 (pubkey-bnoordhuis)
+* **Bert Belder** ([@piscisaureus](https://github.com/piscisaureus))
+* **Fedor Indutny** ([@indutny](https://github.com/indutny))
+ - GPG key: AF2E EA41 EC34 47BF DD86 FED9 D706 3CCE 19B7 E890 (pubkey-indutny)
+* **Saúl Ibarra Corretgé** ([@saghul](https://github.com/saghul))
+ - GPG key: FDF5 1936 4458 319F A823 3DC9 410E 5553 AE9B C059 (pubkey-saghul)
+
+## Storing a maintainer key in Git
+
+It's quite handy to store a maintainer's signature as a git blob, and have
+that object tagged and signed with such key.
+
+Export your public key:
+
+ $ gpg --armor --export saghul@gmail.com > saghul.asc
+
+Store it as a blob on the repo:
+
+ $ git hash-object -w saghul.asc
+
+The previous command returns a hash, copy it. For the sake of this explanation,
+we'll assume it's 'abcd1234'. Storing the blob in git is not enough, it could
+be garbage collected since nothing references it, so we'll create a tag for it:
+
+ $ git tag -s pubkey-saghul abcd1234
+
+Commit the changes and push:
+
+ $ git push origin pubkey-saghul
+
diff --git a/3rdparty/libuv/Makefile.am b/3rdparty/libuv/Makefile.am
new file mode 100644
index 00000000000..0ef781ff198
--- /dev/null
+++ b/3rdparty/libuv/Makefile.am
@@ -0,0 +1,344 @@
+# Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ACLOCAL_AMFLAGS = -I m4
+
+AM_CPPFLAGS = -I$(top_srcdir)/include \
+ -I$(top_srcdir)/src
+
+include_HEADERS=include/uv.h include/uv-errno.h include/uv-threadpool.h include/uv-version.h
+
+CLEANFILES =
+
+lib_LTLIBRARIES = libuv.la
+libuv_la_CFLAGS = @CFLAGS@
+libuv_la_LDFLAGS = -no-undefined -version-info 1:0:0
+libuv_la_SOURCES = src/fs-poll.c \
+ src/heap-inl.h \
+ src/inet.c \
+ src/queue.h \
+ src/threadpool.c \
+ src/uv-common.c \
+ src/uv-common.h \
+ src/version.c
+
+if SUNOS
+# Can't be turned into a CC_CHECK_CFLAGS in configure.ac, it makes compilers
+# on other platforms complain that the argument is unused during compilation.
+libuv_la_CFLAGS += -pthread
+endif
+
+if WINNT
+
+include_HEADERS += include/uv-win.h include/tree.h
+AM_CPPFLAGS += -I$(top_srcdir)/src/win \
+ -DWIN32_LEAN_AND_MEAN \
+ -D_WIN32_WINNT=0x0600
+LIBS += -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv
+libuv_la_SOURCES += src/win/async.c \
+ src/win/atomicops-inl.h \
+ src/win/core.c \
+ src/win/dl.c \
+ src/win/error.c \
+ src/win/fs-event.c \
+ src/win/fs.c \
+ src/win/getaddrinfo.c \
+ src/win/getnameinfo.c \
+ src/win/handle.c \
+ src/win/handle-inl.h \
+ src/win/internal.h \
+ src/win/loop-watcher.c \
+ src/win/pipe.c \
+ src/win/poll.c \
+ src/win/process-stdio.c \
+ src/win/process.c \
+ src/win/req.c \
+ src/win/req-inl.h \
+ src/win/signal.c \
+ src/win/stream.c \
+ src/win/stream-inl.h \
+ src/win/tcp.c \
+ src/win/thread.c \
+ src/win/timer.c \
+ src/win/tty.c \
+ src/win/udp.c \
+ src/win/util.c \
+ src/win/winapi.c \
+ src/win/winapi.h \
+ src/win/winsock.c \
+ src/win/winsock.h
+
+else # WINNT
+
+include_HEADERS += include/uv-unix.h
+AM_CPPFLAGS += -I$(top_srcdir)/src/unix
+libuv_la_SOURCES += src/unix/async.c \
+ src/unix/atomic-ops.h \
+ src/unix/core.c \
+ src/unix/dl.c \
+ src/unix/fs.c \
+ src/unix/getaddrinfo.c \
+ src/unix/getnameinfo.c \
+ src/unix/internal.h \
+ src/unix/loop-watcher.c \
+ src/unix/loop.c \
+ src/unix/pipe.c \
+ src/unix/poll.c \
+ src/unix/process.c \
+ src/unix/signal.c \
+ src/unix/spinlock.h \
+ src/unix/stream.c \
+ src/unix/tcp.c \
+ src/unix/thread.c \
+ src/unix/timer.c \
+ src/unix/tty.c \
+ src/unix/udp.c
+
+endif # WINNT
+
+EXTRA_DIST = test/fixtures/empty_file \
+ test/fixtures/load_error.node \
+ include \
+ test \
+ docs \
+ img \
+ samples \
+ android-configure \
+ CONTRIBUTING.md \
+ LICENSE \
+ README.md \
+ checksparse.sh \
+ vcbuild.bat \
+ Makefile.mingw \
+ common.gypi \
+ gyp_uv.py \
+ uv.gyp
+
+
+
+TESTS = test/run-tests
+check_PROGRAMS = test/run-tests
+test_run_tests_CFLAGS =
+test_run_tests_SOURCES = test/blackhole-server.c \
+ test/dns-server.c \
+ test/echo-server.c \
+ test/run-tests.c \
+ test/runner.c \
+ test/runner.h \
+ test/task.h \
+ test/test-active.c \
+ test/test-async.c \
+ test/test-async-null-cb.c \
+ test/test-barrier.c \
+ test/test-callback-order.c \
+ test/test-callback-stack.c \
+ test/test-close-fd.c \
+ test/test-close-order.c \
+ test/test-condvar.c \
+ test/test-connection-fail.c \
+ test/test-cwd-and-chdir.c \
+ test/test-default-loop-close.c \
+ test/test-delayed-accept.c \
+ test/test-dlerror.c \
+ test/test-embed.c \
+ test/test-emfile.c \
+ test/test-error.c \
+ test/test-fail-always.c \
+ test/test-fs-event.c \
+ test/test-fs-poll.c \
+ test/test-fs.c \
+ test/test-get-currentexe.c \
+ test/test-get-loadavg.c \
+ test/test-get-memory.c \
+ test/test-getaddrinfo.c \
+ test/test-getnameinfo.c \
+ test/test-getsockname.c \
+ test/test-handle-fileno.c \
+ test/test-homedir.c \
+ test/test-hrtime.c \
+ test/test-idle.c \
+ test/test-ip4-addr.c \
+ test/test-ip6-addr.c \
+ test/test-ipc-send-recv.c \
+ test/test-ipc.c \
+ test/test-list.h \
+ test/test-loop-handles.c \
+ test/test-loop-alive.c \
+ test/test-loop-close.c \
+ test/test-loop-stop.c \
+ test/test-loop-time.c \
+ test/test-loop-configure.c \
+ test/test-multiple-listen.c \
+ test/test-mutexes.c \
+ test/test-osx-select.c \
+ test/test-pass-always.c \
+ test/test-ping-pong.c \
+ test/test-pipe-bind-error.c \
+ test/test-pipe-connect-error.c \
+ test/test-pipe-connect-multiple.c \
+ test/test-pipe-connect-prepare.c \
+ test/test-pipe-getsockname.c \
+ test/test-pipe-pending-instances.c \
+ test/test-pipe-sendmsg.c \
+ test/test-pipe-server-close.c \
+ test/test-pipe-close-stdout-read-stdin.c \
+ test/test-pipe-set-non-blocking.c \
+ test/test-platform-output.c \
+ test/test-poll-close.c \
+ test/test-poll-close-doesnt-corrupt-stack.c \
+ test/test-poll-closesocket.c \
+ test/test-poll.c \
+ test/test-process-title.c \
+ test/test-queue-foreach-delete.c \
+ test/test-ref.c \
+ test/test-run-nowait.c \
+ test/test-run-once.c \
+ test/test-semaphore.c \
+ test/test-shutdown-close.c \
+ test/test-shutdown-eof.c \
+ test/test-shutdown-twice.c \
+ test/test-signal-multiple-loops.c \
+ test/test-signal.c \
+ test/test-socket-buffer-size.c \
+ test/test-spawn.c \
+ test/test-stdio-over-pipes.c \
+ test/test-tcp-bind-error.c \
+ test/test-tcp-bind6-error.c \
+ test/test-tcp-close-accept.c \
+ test/test-tcp-close-while-connecting.c \
+ test/test-tcp-close.c \
+ test/test-tcp-create-socket-early.c \
+ test/test-tcp-connect-error-after-write.c \
+ test/test-tcp-connect-error.c \
+ test/test-tcp-connect-timeout.c \
+ test/test-tcp-connect6-error.c \
+ test/test-tcp-flags.c \
+ test/test-tcp-open.c \
+ test/test-tcp-read-stop.c \
+ test/test-tcp-shutdown-after-write.c \
+ test/test-tcp-unexpected-read.c \
+ test/test-tcp-oob.c \
+ test/test-tcp-write-to-half-open-connection.c \
+ test/test-tcp-write-after-connect.c \
+ test/test-tcp-writealot.c \
+ test/test-tcp-write-fail.c \
+ test/test-tcp-try-write.c \
+ test/test-tcp-write-queue-order.c \
+ test/test-thread-equal.c \
+ test/test-thread.c \
+ test/test-threadpool-cancel.c \
+ test/test-threadpool.c \
+ test/test-timer-again.c \
+ test/test-timer-from-check.c \
+ test/test-timer.c \
+ test/test-tty.c \
+ test/test-udp-bind.c \
+ test/test-udp-create-socket-early.c \
+ test/test-udp-dgram-too-big.c \
+ test/test-udp-ipv6.c \
+ test/test-udp-multicast-interface.c \
+ test/test-udp-multicast-interface6.c \
+ test/test-udp-multicast-join.c \
+ test/test-udp-multicast-join6.c \
+ test/test-udp-multicast-ttl.c \
+ test/test-udp-open.c \
+ test/test-udp-options.c \
+ test/test-udp-send-and-recv.c \
+ test/test-udp-send-immediate.c \
+ test/test-udp-send-unreachable.c \
+ test/test-udp-try-send.c \
+ test/test-walk-handles.c \
+ test/test-watcher-cross-stop.c
+test_run_tests_LDADD = libuv.la
+
+if WINNT
+test_run_tests_SOURCES += test/runner-win.c \
+ test/runner-win.h
+else
+test_run_tests_SOURCES += test/runner-unix.c \
+ test/runner-unix.h
+endif
+
+if AIX
+test_run_tests_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT
+endif
+
+if SUNOS
+test_run_tests_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500
+endif
+
+
+if AIX
+libuv_la_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT
+include_HEADERS += include/uv-aix.h
+libuv_la_SOURCES += src/unix/aix.c
+endif
+
+if ANDROID
+include_HEADERS += include/android-ifaddrs.h \
+ include/pthread-fixes.h
+libuv_la_SOURCES += src/unix/android-ifaddrs.c \
+ src/unix/pthread-fixes.c
+endif
+
+if DARWIN
+include_HEADERS += include/uv-darwin.h
+libuv_la_CFLAGS += -D_DARWIN_USE_64_BIT_INODE=1
+libuv_la_CFLAGS += -D_DARWIN_UNLIMITED_SELECT=1
+libuv_la_SOURCES += src/unix/darwin.c \
+ src/unix/darwin-proctitle.c \
+ src/unix/fsevents.c \
+ src/unix/kqueue.c \
+ src/unix/proctitle.c
+endif
+
+if DRAGONFLY
+include_HEADERS += include/uv-bsd.h
+endif
+
+if FREEBSD
+include_HEADERS += include/uv-bsd.h
+libuv_la_SOURCES += src/unix/freebsd.c src/unix/kqueue.c
+endif
+
+if LINUX
+include_HEADERS += include/uv-linux.h
+libuv_la_CFLAGS += -D_GNU_SOURCE
+libuv_la_SOURCES += src/unix/linux-core.c \
+ src/unix/linux-inotify.c \
+ src/unix/linux-syscalls.c \
+ src/unix/linux-syscalls.h \
+ src/unix/proctitle.c
+endif
+
+if NETBSD
+include_HEADERS += include/uv-bsd.h
+libuv_la_SOURCES += src/unix/kqueue.c src/unix/netbsd.c
+endif
+
+if OPENBSD
+include_HEADERS += include/uv-bsd.h
+libuv_la_SOURCES += src/unix/kqueue.c src/unix/openbsd.c
+endif
+
+if SUNOS
+include_HEADERS += include/uv-sunos.h
+libuv_la_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500
+libuv_la_SOURCES += src/unix/sunos.c
+endif
+
+if HAVE_PKG_CONFIG
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = @PACKAGE_NAME@.pc
+endif
diff --git a/3rdparty/libuv/Makefile.mingw b/3rdparty/libuv/Makefile.mingw
new file mode 100644
index 00000000000..156f15dab15
--- /dev/null
+++ b/3rdparty/libuv/Makefile.mingw
@@ -0,0 +1,84 @@
+# Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+CC ?= gcc
+
+CFLAGS += -Wall \
+ -Wextra \
+ -Wno-unused-parameter \
+ -Iinclude \
+ -Isrc \
+ -Isrc/win \
+ -DWIN32_LEAN_AND_MEAN \
+ -D_WIN32_WINNT=0x0600
+
+INCLUDES = include/stdint-msvc2008.h \
+ include/tree.h \
+ include/uv-errno.h \
+ include/uv-threadpool.h \
+ include/uv-version.h \
+ include/uv-win.h \
+ include/uv.h \
+ src/heap-inl.h \
+ src/queue.h \
+ src/uv-common.h \
+ src/win/atomicops-inl.h \
+ src/win/handle-inl.h \
+ src/win/internal.h \
+ src/win/req-inl.h \
+ src/win/stream-inl.h \
+ src/win/winapi.h \
+ src/win/winsock.h
+
+OBJS = src/fs-poll.o \
+ src/inet.o \
+ src/threadpool.o \
+ src/uv-common.o \
+ src/version.o \
+ src/win/async.o \
+ src/win/core.o \
+ src/win/dl.o \
+ src/win/error.o \
+ src/win/fs-event.o \
+ src/win/fs.o \
+ src/win/getaddrinfo.o \
+ src/win/getnameinfo.o \
+ src/win/handle.o \
+ src/win/loop-watcher.o \
+ src/win/pipe.o \
+ src/win/poll.o \
+ src/win/process-stdio.o \
+ src/win/process.o \
+ src/win/req.o \
+ src/win/signal.o \
+ src/win/stream.o \
+ src/win/tcp.o \
+ src/win/thread.o \
+ src/win/timer.o \
+ src/win/tty.o \
+ src/win/udp.o \
+ src/win/util.o \
+ src/win/winapi.o \
+ src/win/winsock.o
+
+all: libuv.a
+
+clean:
+ -$(RM) $(OBJS) libuv.a
+
+libuv.a: $(OBJS)
+ $(AR) crs $@ $^
+
+$(OBJS): %.o : %.c $(INCLUDES)
+ $(CC) $(CFLAGS) -c -o $@ $<
diff --git a/3rdparty/libuv/README.md b/3rdparty/libuv/README.md
new file mode 100644
index 00000000000..dfd24ba79d1
--- /dev/null
+++ b/3rdparty/libuv/README.md
@@ -0,0 +1,245 @@
+![libuv][libuv_banner]
+
+## Overview
+
+libuv is a multi-platform support library with a focus on asynchronous I/O. It
+was primarily developed for use by [Node.js](http://nodejs.org), but it's also
+used by [Luvit](http://luvit.io/), [Julia](http://julialang.org/),
+[pyuv](https://github.com/saghul/pyuv), and [others](https://github.com/libuv/libuv/wiki/Projects-that-use-libuv).
+
+## Feature highlights
+
+ * Full-featured event loop backed by epoll, kqueue, IOCP, event ports.
+
+ * Asynchronous TCP and UDP sockets
+
+ * Asynchronous DNS resolution
+
+ * Asynchronous file and file system operations
+
+ * File system events
+
+ * ANSI escape code controlled TTY
+
+ * IPC with socket sharing, using Unix domain sockets or named pipes (Windows)
+
+ * Child processes
+
+ * Thread pool
+
+ * Signal handling
+
+ * High resolution clock
+
+ * Threading and synchronization primitives
+
+## Versioning
+
+Starting with version 1.0.0 libuv follows the [semantic versioning](http://semver.org/)
+scheme. The API change and backwards compatibility rules are those indicated by
+SemVer. libuv will keep a stable ABI across major releases.
+
+## Community
+
+ * [Mailing list](http://groups.google.com/group/libuv)
+ * [IRC chatroom (#libuv@irc.freenode.org)](http://webchat.freenode.net?channels=libuv&uio=d4)
+
+## Documentation
+
+### Official API documentation
+
+Located in the docs/ subdirectory. It uses the [Sphinx](http://sphinx-doc.org/)
+framework, which makes it possible to build the documentation in multiple
+formats.
+
+Show different supported building options:
+
+ $ make help
+
+Build documentation as HTML:
+
+ $ make html
+
+Build documentation as man pages:
+
+ $ make man
+
+Build documentation as ePub:
+
+ $ make epub
+
+NOTE: Windows users need to use make.bat instead of plain 'make'.
+
+Documentation can be browsed online [here](http://docs.libuv.org).
+
+The [tests and benchmarks](https://github.com/libuv/libuv/tree/master/test)
+also serve as API specification and usage examples.
+
+### Other resources
+
+ * [An Introduction to libuv](http://nikhilm.github.com/uvbook/)
+ &mdash; An overview of libuv with tutorials.
+ * [LXJS 2012 talk](http://www.youtube.com/watch?v=nGn60vDSxQ4)
+ &mdash; High-level introductory talk about libuv.
+ * [libuv-dox](https://github.com/thlorenz/libuv-dox)
+ &mdash; Documenting types and methods of libuv, mostly by reading uv.h.
+ * [learnuv](https://github.com/thlorenz/learnuv)
+ &mdash; Learn uv for fun and profit, a self guided workshop to libuv.
+
+These resources are not handled by libuv maintainers and might be out of
+date. Please verify it before opening new issues.
+
+## Downloading
+
+libuv can be downloaded either from the
+[GitHub repository](https://github.com/libuv/libuv)
+or from the [downloads site](http://dist.libuv.org/dist/).
+
+Starting with libuv 1.7.0, binaries for Windows are also provided. This is to
+be considered EXPERIMENTAL.
+
+Before verifying the git tags or signature files, importing the relevant keys
+is necessary. Key IDs are listed in the
+[MAINTAINERS](https://github.com/libuv/libuv/blob/master/MAINTAINERS.md)
+file, but are also available as git blob objects for easier use.
+
+Importing a key the usual way:
+
+ $ gpg --keyserver pool.sks-keyservers.net \
+ --recv-keys AE9BC059
+
+Importing a key from a git blob object:
+
+ $ git show pubkey-saghul | gpg --import
+
+### Verifying releases
+
+Git tags are signed with the developer's key, they can be verified as follows:
+
+ $ git verify-tag v1.6.1
+
+Starting with libuv 1.7.0, the tarballs stored in the
+[downloads site](http://dist.libuv.org/dist/) are signed and an accompanying
+signature file sit alongside each. Once both the release tarball and the
+signature file are downloaded, the file can be verified as follows:
+
+ $ gpg --verify libuv-1.7.0.tar.gz.sign
+
+## Build Instructions
+
+For GCC there are two build methods: via autotools or via [GYP][].
+GYP is a meta-build system which can generate MSVS, Makefile, and XCode
+backends. It is best used for integration into other projects.
+
+To build with autotools:
+
+ $ sh autogen.sh
+ $ ./configure
+ $ make
+ $ make check
+ $ make install
+
+### Windows
+
+First, [Python][] 2.6 or 2.7 must be installed as it is required by [GYP][].
+If python is not in your path, set the environment variable `PYTHON` to its
+location. For example: `set PYTHON=C:\Python27\python.exe`
+
+To build with Visual Studio, launch a git shell (e.g. Cmd or PowerShell)
+and run vcbuild.bat which will checkout the GYP code into build/gyp and
+generate uv.sln as well as related project files.
+
+To have GYP generate build script for another system, checkout GYP into the
+project tree manually:
+
+ $ git clone https://chromium.googlesource.com/external/gyp.git build/gyp
+
+### Unix
+
+Run:
+
+ $ ./gyp_uv.py -f make
+ $ make -C out
+
+Run `./gyp_uv.py -f make -Dtarget_arch=x32` to build [x32][] binaries.
+
+### OS X
+
+Run:
+
+ $ ./gyp_uv.py -f xcode
+ $ xcodebuild -ARCHS="x86_64" -project uv.xcodeproj \
+ -configuration Release -target All
+
+Using Homebrew:
+
+ $ brew install --HEAD libuv
+
+Note to OS X users:
+
+Make sure that you specify the architecture you wish to build for in the
+"ARCHS" flag. You can specify more than one by delimiting with a space
+(e.g. "x86_64 i386").
+
+### Android
+
+Run:
+
+ $ source ./android-configure NDK_PATH gyp
+ $ make -C out
+
+Note for UNIX users: compile your project with `-D_LARGEFILE_SOURCE` and
+`-D_FILE_OFFSET_BITS=64`. GYP builds take care of that automatically.
+
+### Using Ninja
+
+To use ninja for build on ninja supported platforms, run:
+
+ $ ./gyp_uv.py -f ninja
+ $ ninja -C out/Debug #for debug build OR
+ $ ninja -C out/Release
+
+
+### Running tests
+
+Run:
+
+ $ ./gyp_uv.py -f make
+ $ make -C out
+ $ ./out/Debug/run-tests
+
+## Supported Platforms
+
+Microsoft Windows operating systems since Windows XP SP2. It can be built
+with either Visual Studio or MinGW. Consider using
+[Visual Studio Express 2010][] or later if you do not have a full Visual
+Studio license.
+
+Linux using the GCC toolchain.
+
+OS X using the GCC or XCode toolchain.
+
+Solaris 121 and later using GCC toolchain.
+
+AIX 6 and later using GCC toolchain (see notes).
+
+### AIX Notes
+
+AIX support for filesystem events requires the non-default IBM `bos.ahafs`
+package to be installed. This package provides the AIX Event Infrastructure
+that is detected by `autoconf`.
+[IBM documentation](http://www.ibm.com/developerworks/aix/library/au-aix_event_infrastructure/)
+describes the package in more detail.
+
+AIX support for filesystem events is not compiled when building with `gyp`.
+
+## Patches
+
+See the [guidelines for contributing][].
+
+[node.js]: http://nodejs.org/
+[GYP]: http://code.google.com/p/gyp/
+[Python]: https://www.python.org/downloads/
+[Visual Studio Express 2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express
+[guidelines for contributing]: https://github.com/libuv/libuv/blob/master/CONTRIBUTING.md
+[libuv_banner]: https://raw.githubusercontent.com/libuv/libuv/master/img/banner.png
diff --git a/3rdparty/libuv/docs/src/async.rst b/3rdparty/libuv/docs/src/async.rst
new file mode 100644
index 00000000000..5c400458244
--- /dev/null
+++ b/3rdparty/libuv/docs/src/async.rst
@@ -0,0 +1,57 @@
+
+.. _async:
+
+:c:type:`uv_async_t` --- Async handle
+=====================================
+
+Async handles allow the user to "wakeup" the event loop and get a callback
+called from another thread.
+
+
+Data types
+----------
+
+.. c:type:: uv_async_t
+
+ Async handle type.
+
+.. c:type:: void (*uv_async_cb)(uv_async_t* handle)
+
+ Type definition for callback passed to :c:func:`uv_async_init`.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_async_init(uv_loop_t* loop, uv_async_t* async, uv_async_cb async_cb)
+
+ Initialize the handle. A NULL callback is allowed.
+
+ .. note::
+ Unlike other handle initialization functions, it immediately starts the handle.
+
+.. c:function:: int uv_async_send(uv_async_t* async)
+
+ Wakeup the event loop and call the async handle's callback.
+
+ .. note::
+ It's safe to call this function from any thread. The callback will be called on the
+ loop thread.
+
+ .. warning::
+ libuv will coalesce calls to :c:func:`uv_async_send`, that is, not every call to it will
+ yield an execution of the callback. For example: if :c:func:`uv_async_send` is called 5
+ times in a row before the callback is called, the callback will only be called once. If
+ :c:func:`uv_async_send` is called again after the callback was called, it will be called
+ again.
+
+.. seealso::
+ The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/check.rst b/3rdparty/libuv/docs/src/check.rst
new file mode 100644
index 00000000000..36c93cf03d9
--- /dev/null
+++ b/3rdparty/libuv/docs/src/check.rst
@@ -0,0 +1,46 @@
+
+.. _check:
+
+:c:type:`uv_check_t` --- Check handle
+=====================================
+
+Check handles will run the given callback once per loop iteration, right
+after polling for i/o.
+
+
+Data types
+----------
+
+.. c:type:: uv_check_t
+
+ Check handle type.
+
+.. c:type:: void (*uv_check_cb)(uv_check_t* handle)
+
+ Type definition for callback passed to :c:func:`uv_check_start`.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_check_init(uv_loop_t* loop, uv_check_t* check)
+
+ Initialize the handle.
+
+.. c:function:: int uv_check_start(uv_check_t* check, uv_check_cb cb)
+
+ Start the handle with the given callback.
+
+.. c:function:: int uv_check_stop(uv_check_t* check)
+
+ Stop the handle, the callback will no longer be called.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/conf.py b/3rdparty/libuv/docs/src/conf.py
new file mode 100644
index 00000000000..b9eaa137432
--- /dev/null
+++ b/3rdparty/libuv/docs/src/conf.py
@@ -0,0 +1,348 @@
+# -*- coding: utf-8 -*-
+#
+# libuv API documentation documentation build configuration file, created by
+# sphinx-quickstart on Sun Jul 27 11:47:51 2014.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import os
+import re
+import sys
+
+
+def get_libuv_version():
+ with open('../../include/uv-version.h') as f:
+ data = f.read()
+ try:
+ m = re.search(r"""^#define UV_VERSION_MAJOR (\d)$""", data, re.MULTILINE)
+ major = int(m.group(1))
+ m = re.search(r"""^#define UV_VERSION_MINOR (\d)$""", data, re.MULTILINE)
+ minor = int(m.group(1))
+ m = re.search(r"""^#define UV_VERSION_PATCH (\d)$""", data, re.MULTILINE)
+ patch = int(m.group(1))
+ m = re.search(r"""^#define UV_VERSION_IS_RELEASE (\d)$""", data, re.MULTILINE)
+ is_release = int(m.group(1))
+ m = re.search(r"""^#define UV_VERSION_SUFFIX \"(\w*)\"$""", data, re.MULTILINE)
+ suffix = m.group(1)
+ return '%d.%d.%d%s' % (major, minor, patch, '-%s' % suffix if not is_release else '')
+ except Exception:
+ return 'unknown'
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+sys.path.insert(0, os.path.abspath('sphinx-plugins'))
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = ['manpage']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'libuv API documentation'
+copyright = u'libuv contributors'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = get_libuv_version()
+# The full version, including alpha/beta/rc tags.
+release = version
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = []
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+#keep_warnings = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'nature'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+html_title = 'libuv API documentation'
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+html_short_title = 'libuv %s API documentation' % version
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+html_logo = 'static/logo.png'
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+html_favicon = 'static/favicon.ico'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#html_extra_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'libuv'
+
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+# author, documentclass [howto, manual, or own class]).
+latex_documents = [
+ ('index', 'libuv.tex', u'libuv API documentation',
+ u'libuv contributors', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'libuv', u'libuv API documentation',
+ [u'libuv contributors'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ ('index', 'libuv', u'libuv API documentation',
+ u'libuv contributors', 'libuv', 'Cross-platform asynchronous I/O',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#texinfo_no_detailmenu = False
+
+
+# -- Options for Epub output ----------------------------------------------
+
+# Bibliographic Dublin Core info.
+epub_title = u'libuv API documentation'
+epub_author = u'libuv contributors'
+epub_publisher = u'libuv contributors'
+epub_copyright = u'2014, libuv contributors'
+
+# The basename for the epub file. It defaults to the project name.
+epub_basename = u'libuv'
+
+# The HTML theme for the epub output. Since the default themes are not optimized
+# for small screen space, using the same theme for HTML and epub output is
+# usually not wise. This defaults to 'epub', a theme designed to save visual
+# space.
+#epub_theme = 'epub'
+
+# The language of the text. It defaults to the language option
+# or en if the language is not set.
+#epub_language = ''
+
+# The scheme of the identifier. Typical schemes are ISBN or URL.
+#epub_scheme = ''
+
+# The unique identifier of the text. This can be a ISBN number
+# or the project homepage.
+#epub_identifier = ''
+
+# A unique identification for the text.
+#epub_uid = ''
+
+# A tuple containing the cover image and cover page html template filenames.
+#epub_cover = ()
+
+# A sequence of (type, uri, title) tuples for the guide element of content.opf.
+#epub_guide = ()
+
+# HTML files that should be inserted before the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_pre_files = []
+
+# HTML files shat should be inserted after the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+#epub_post_files = []
+
+# A list of files that should not be packed into the epub file.
+epub_exclude_files = ['search.html']
+
+# The depth of the table of contents in toc.ncx.
+#epub_tocdepth = 3
+
+# Allow duplicate toc entries.
+#epub_tocdup = True
+
+# Choose between 'default' and 'includehidden'.
+#epub_tocscope = 'default'
+
+# Fix unsupported image types using the PIL.
+#epub_fix_images = False
+
+# Scale large images.
+#epub_max_image_width = 0
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#epub_show_urls = 'inline'
+
+# If false, no index is generated.
+#epub_use_index = True
diff --git a/3rdparty/libuv/docs/src/design.rst b/3rdparty/libuv/docs/src/design.rst
new file mode 100644
index 00000000000..34c3cff68e5
--- /dev/null
+++ b/3rdparty/libuv/docs/src/design.rst
@@ -0,0 +1,137 @@
+
+.. _design:
+
+Design overview
+===============
+
+libuv is cross-platform support library which was originally written for NodeJS. It's designed
+around the event-driven asynchronous I/O model.
+
+The library provides much more than simply abstraction over different I/O polling mechanisms:
+'handles' and 'streams' provide a high level abstraction for sockets and other entities;
+cross-platform file I/O and threading functionality is also provided, amongst other things.
+
+Here is a diagram illustrating the different parts that compose libuv and what subsystem they
+relate to:
+
+.. image:: static/architecture.png
+ :scale: 75%
+ :align: center
+
+
+Handles and requests
+^^^^^^^^^^^^^^^^^^^^
+
+libuv provides users with 2 abstractions to work with, in combination with the event loop:
+handles and requests.
+
+Handles represent long-lived objects capable of performing certain operations while active. Some
+examples: a prepare handle gets its callback called once every loop iteration when active, and
+a TCP server handle get its connection callback called every time there is a new connection.
+
+Requests represent (typically) short-lived operations. These operations can be performed over a
+handle: write requests are used to write data on a handle; or standalone: getaddrinfo requests
+don't need a handle they run directly on the loop.
+
+
+The I/O loop
+^^^^^^^^^^^^
+
+The I/O (or event) loop is the central part of libuv. It establishes the content for all I/O
+operations, and it's meant to be tied to a single thread. One can run multiple event loops
+as long as each runs in a different thread. The libuv event loop (or any other API involving
+the loop or handles, for that matter) **is not thread-safe** except where stated otherwise.
+
+The event loop follows the rather usual single threaded asynchronous I/O approach: all (network)
+I/O is performed on non-blocking sockets which are polled using the best mechanism available
+on the given platform: epoll on Linux, kqueue on OSX and other BSDs, event ports on SunOS and IOCP
+on Windows. As part of a loop iteration the loop will block waiting for I/O activity on sockets
+which have been added to the poller and callbacks will be fired indicating socket conditions
+(readable, writable hangup) so handles can read, write or perform the desired I/O operation.
+
+In order to better understand how the event loop operates, the following diagram illustrates all
+stages of a loop iteration:
+
+.. image:: static/loop_iteration.png
+ :scale: 75%
+ :align: center
+
+
+#. The loop concept of 'now' is updated. The event loop caches the current time at the start of
+ the event loop tick in order to reduce the number of time-related system calls.
+
+#. If the loop is *alive* an iteration is started, otherwise the loop will exit immediately. So,
+ when is a loop considered to be *alive*? If a loop has active and ref'd handles, active
+ requests or closing handles it's considered to be *alive*.
+
+#. Due timers are run. All active timers scheduled for a time before the loop's concept of *now*
+ get their callbacks called.
+
+#. Pending callbacks are called. All I/O callbacks are called right after polling for I/O, for the
+ most part. There are cases, however, in which calling such a callback is deferred for the next
+ loop iteration. If the previous iteration deferred any I/O callback it will be run at this point.
+
+#. Idle handle callbacks are called. Despite the unfortunate name, idle handles are run on every
+ loop iteration, if they are active.
+
+#. Prepare handle callbacks are called. Prepare handles get their callbacks called right before
+ the loop will block for I/O.
+
+#. Poll timeout is calculated. Before blocking for I/O the loop calculates for how long it should
+ block. These are the rules when calculating the timeout:
+
+ * If the loop was run with the ``UV_RUN_NOWAIT`` flag, the timeout is 0.
+ * If the loop is going to be stopped (:c:func:`uv_stop` was called), the timeout is 0.
+ * If there are no active handles or requests, the timeout is 0.
+ * If there are any idle handles active, the timeout is 0.
+ * If there are any handles pending to be closed, the timeout is 0.
+ * If none of the above cases was matched, the timeout of the closest timer is taken, or
+ if there are no active timers, infinity.
+
+#. The loop blocks for I/O. At this point the loop will block for I/O for the timeout calculated
+ on the previous step. All I/O related handles that were monitoring a given file descriptor
+ for a read or write operation get their callbacks called at this point.
+
+#. Check handle callbacks are called. Check handles get their callbacks called right after the
+ loop has blocked for I/O. Check handles are essentially the counterpart of prepare handles.
+
+#. Close callbacks are called. If a handle was closed by calling :c:func:`uv_close` it will
+ get the close callback called.
+
+#. Special case in case the loop was run with ``UV_RUN_ONCE``, as it implies forward progress.
+ It's possible that no I/O callbacks were fired after blocking for I/O, but some time has passed
+ so there might be timers which are due, those timers get their callbacks called.
+
+#. Iteration ends. If the loop was run with ``UV_RUN_NOWAIT`` or ``UV_RUN_ONCE`` modes the
+ iteration is ended and :c:func:`uv_run` will return. If the loop was run with ``UV_RUN_DEFAULT``
+ it will continue from the start if it's still *alive*, otherwise it will also end.
+
+
+.. important::
+ libuv uses a thread pool to make asynchronous file I/O operations possible, but
+ network I/O is **always** performed in a single thread, each loop's thread.
+
+.. note::
+ While the polling mechanism is different, libuv makes the execution model consistent
+ across Unix systems and Windows.
+
+
+File I/O
+^^^^^^^^
+
+Unlike network I/O, there are no platform-specific file I/O primitives libuv could rely on,
+so the current approach is to run blocking file I/O operations in a thread pool.
+
+For a thorough explanation of the cross-platform file I/O landscape, checkout
+`this post <http://blog.libtorrent.org/2012/10/asynchronous-disk-io/>`_.
+
+libuv currently uses a global thread pool on which all loops can queue work on. 3 types of
+operations are currently run on this pool:
+
+ * Filesystem operations
+ * DNS functions (getaddrinfo and getnameinfo)
+ * User specified code via :c:func:`uv_queue_work`
+
+.. warning::
+ See the :c:ref:`threadpool` section for more details, but keep in mind the thread pool size
+ is quite limited.
diff --git a/3rdparty/libuv/docs/src/dll.rst b/3rdparty/libuv/docs/src/dll.rst
new file mode 100644
index 00000000000..fb13f908159
--- /dev/null
+++ b/3rdparty/libuv/docs/src/dll.rst
@@ -0,0 +1,44 @@
+
+.. _dll:
+
+Shared library handling
+=======================
+
+libuv provides cross platform utilities for loading shared libraries and
+retrieving symbols from them, using the following API.
+
+
+Data types
+----------
+
+.. c:type:: uv_lib_t
+
+ Shared library data type.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+
+API
+---
+
+.. c:function:: int uv_dlopen(const char* filename, uv_lib_t* lib)
+
+ Opens a shared library. The filename is in utf-8. Returns 0 on success and
+ -1 on error. Call :c:func:`uv_dlerror` to get the error message.
+
+.. c:function:: void uv_dlclose(uv_lib_t* lib)
+
+ Close the shared library.
+
+.. c:function:: int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr)
+
+ Retrieves a data pointer from a dynamic library. It is legal for a symbol
+ to map to NULL. Returns 0 on success and -1 if the symbol was not found.
+
+.. c:function:: const char* uv_dlerror(const uv_lib_t* lib)
+
+ Returns the last uv_dlopen() or uv_dlsym() error message.
diff --git a/3rdparty/libuv/docs/src/dns.rst b/3rdparty/libuv/docs/src/dns.rst
new file mode 100644
index 00000000000..1d881580966
--- /dev/null
+++ b/3rdparty/libuv/docs/src/dns.rst
@@ -0,0 +1,108 @@
+
+.. _dns:
+
+DNS utility functions
+=====================
+
+libuv provides asynchronous variants of `getaddrinfo` and `getnameinfo`.
+
+
+Data types
+----------
+
+.. c:type:: uv_getaddrinfo_t
+
+ `getaddrinfo` request type.
+
+.. c:type:: void (*uv_getaddrinfo_cb)(uv_getaddrinfo_t* req, int status, struct addrinfo* res)
+
+ Callback which will be called with the getaddrinfo request result once
+ complete. In case it was cancelled, `status` will have a value of
+ ``UV_ECANCELED``.
+
+.. c:type:: uv_getnameinfo_t
+
+ `getnameinfo` request type.
+
+.. c:type:: void (*uv_getnameinfo_cb)(uv_getnameinfo_t* req, int status, const char* hostname, const char* service)
+
+ Callback which will be called with the getnameinfo request result once
+ complete. In case it was cancelled, `status` will have a value of
+ ``UV_ECANCELED``.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+.. c:member:: uv_loop_t* uv_getaddrinfo_t.loop
+
+ Loop that started this getaddrinfo request and where completion will be
+ reported. Readonly.
+
+.. c:member:: struct addrinfo* uv_getaddrinfo_t.addrinfo
+
+ Pointer to a `struct addrinfo` containing the result. Must be freed by the user
+ with :c:func:`uv_freeaddrinfo`.
+
+ .. versionchanged:: 1.3.0 the field is declared as public.
+
+.. c:member:: uv_loop_t* uv_getnameinfo_t.loop
+
+ Loop that started this getnameinfo request and where completion will be
+ reported. Readonly.
+
+.. c:member:: char[NI_MAXHOST] uv_getnameinfo_t.host
+
+ Char array containing the resulting host. It's null terminated.
+
+ .. versionchanged:: 1.3.0 the field is declared as public.
+
+.. c:member:: char[NI_MAXSERV] uv_getnameinfo_t.service
+
+ Char array containing the resulting service. It's null terminated.
+
+ .. versionchanged:: 1.3.0 the field is declared as public.
+
+.. seealso:: The :c:type:`uv_req_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_getaddrinfo(uv_loop_t* loop, uv_getaddrinfo_t* req, uv_getaddrinfo_cb getaddrinfo_cb, const char* node, const char* service, const struct addrinfo* hints)
+
+ Asynchronous :man:`getaddrinfo(3)`.
+
+ Either node or service may be NULL but not both.
+
+ `hints` is a pointer to a struct addrinfo with additional address type
+ constraints, or NULL. Consult `man -s 3 getaddrinfo` for more details.
+
+ Returns 0 on success or an error code < 0 on failure. If successful, the
+ callback will get called sometime in the future with the lookup result,
+ which is either:
+
+ * status == 0, the res argument points to a valid `struct addrinfo`, or
+ * status < 0, the res argument is NULL. See the UV_EAI_* constants.
+
+ Call :c:func:`uv_freeaddrinfo` to free the addrinfo structure.
+
+ .. versionchanged:: 1.3.0 the callback parameter is now allowed to be NULL,
+ in which case the request will run **synchronously**.
+
+.. c:function:: void uv_freeaddrinfo(struct addrinfo* ai)
+
+ Free the struct addrinfo. Passing NULL is allowed and is a no-op.
+
+.. c:function:: int uv_getnameinfo(uv_loop_t* loop, uv_getnameinfo_t* req, uv_getnameinfo_cb getnameinfo_cb, const struct sockaddr* addr, int flags)
+
+ Asynchronous :man:`getnameinfo(3)`.
+
+ Returns 0 on success or an error code < 0 on failure. If successful, the
+ callback will get called sometime in the future with the lookup result.
+ Consult `man -s 3 getnameinfo` for more details.
+
+ .. versionchanged:: 1.3.0 the callback parameter is now allowed to be NULL,
+ in which case the request will run **synchronously**.
+
+.. seealso:: The :c:type:`uv_req_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/errors.rst b/3rdparty/libuv/docs/src/errors.rst
new file mode 100644
index 00000000000..cec25f5187e
--- /dev/null
+++ b/3rdparty/libuv/docs/src/errors.rst
@@ -0,0 +1,331 @@
+
+.. _errors:
+
+Error handling
+==============
+
+In libuv errors are negative numbered constants. As a rule of thumb, whenever
+there is a status parameter, or an API functions returns an integer, a negative
+number will imply an error.
+
+.. note::
+ Implementation detail: on Unix error codes are the negated `errno` (or `-errno`), while on
+ Windows they are defined by libuv to arbitrary negative numbers.
+
+
+Error constants
+---------------
+
+.. c:macro:: UV_E2BIG
+
+ argument list too long
+
+.. c:macro:: UV_EACCES
+
+ permission denied
+
+.. c:macro:: UV_EADDRINUSE
+
+ address already in use
+
+.. c:macro:: UV_EADDRNOTAVAIL
+
+ address not available
+
+.. c:macro:: UV_EAFNOSUPPORT
+
+ address family not supported
+
+.. c:macro:: UV_EAGAIN
+
+ resource temporarily unavailable
+
+.. c:macro:: UV_EAI_ADDRFAMILY
+
+ address family not supported
+
+.. c:macro:: UV_EAI_AGAIN
+
+ temporary failure
+
+.. c:macro:: UV_EAI_BADFLAGS
+
+ bad ai_flags value
+
+.. c:macro:: UV_EAI_BADHINTS
+
+ invalid value for hints
+
+.. c:macro:: UV_EAI_CANCELED
+
+ request canceled
+
+.. c:macro:: UV_EAI_FAIL
+
+ permanent failure
+
+.. c:macro:: UV_EAI_FAMILY
+
+ ai_family not supported
+
+.. c:macro:: UV_EAI_MEMORY
+
+ out of memory
+
+.. c:macro:: UV_EAI_NODATA
+
+ no address
+
+.. c:macro:: UV_EAI_NONAME
+
+ unknown node or service
+
+.. c:macro:: UV_EAI_OVERFLOW
+
+ argument buffer overflow
+
+.. c:macro:: UV_EAI_PROTOCOL
+
+ resolved protocol is unknown
+
+.. c:macro:: UV_EAI_SERVICE
+
+ service not available for socket type
+
+.. c:macro:: UV_EAI_SOCKTYPE
+
+ socket type not supported
+
+.. c:macro:: UV_EALREADY
+
+ connection already in progress
+
+.. c:macro:: UV_EBADF
+
+ bad file descriptor
+
+.. c:macro:: UV_EBUSY
+
+ resource busy or locked
+
+.. c:macro:: UV_ECANCELED
+
+ operation canceled
+
+.. c:macro:: UV_ECHARSET
+
+ invalid Unicode character
+
+.. c:macro:: UV_ECONNABORTED
+
+ software caused connection abort
+
+.. c:macro:: UV_ECONNREFUSED
+
+ connection refused
+
+.. c:macro:: UV_ECONNRESET
+
+ connection reset by peer
+
+.. c:macro:: UV_EDESTADDRREQ
+
+ destination address required
+
+.. c:macro:: UV_EEXIST
+
+ file already exists
+
+.. c:macro:: UV_EFAULT
+
+ bad address in system call argument
+
+.. c:macro:: UV_EFBIG
+
+ file too large
+
+.. c:macro:: UV_EHOSTUNREACH
+
+ host is unreachable
+
+.. c:macro:: UV_EINTR
+
+ interrupted system call
+
+.. c:macro:: UV_EINVAL
+
+ invalid argument
+
+.. c:macro:: UV_EIO
+
+ i/o error
+
+.. c:macro:: UV_EISCONN
+
+ socket is already connected
+
+.. c:macro:: UV_EISDIR
+
+ illegal operation on a directory
+
+.. c:macro:: UV_ELOOP
+
+ too many symbolic links encountered
+
+.. c:macro:: UV_EMFILE
+
+ too many open files
+
+.. c:macro:: UV_EMSGSIZE
+
+ message too long
+
+.. c:macro:: UV_ENAMETOOLONG
+
+ name too long
+
+.. c:macro:: UV_ENETDOWN
+
+ network is down
+
+.. c:macro:: UV_ENETUNREACH
+
+ network is unreachable
+
+.. c:macro:: UV_ENFILE
+
+ file table overflow
+
+.. c:macro:: UV_ENOBUFS
+
+ no buffer space available
+
+.. c:macro:: UV_ENODEV
+
+ no such device
+
+.. c:macro:: UV_ENOENT
+
+ no such file or directory
+
+.. c:macro:: UV_ENOMEM
+
+ not enough memory
+
+.. c:macro:: UV_ENONET
+
+ machine is not on the network
+
+.. c:macro:: UV_ENOPROTOOPT
+
+ protocol not available
+
+.. c:macro:: UV_ENOSPC
+
+ no space left on device
+
+.. c:macro:: UV_ENOSYS
+
+ function not implemented
+
+.. c:macro:: UV_ENOTCONN
+
+ socket is not connected
+
+.. c:macro:: UV_ENOTDIR
+
+ not a directory
+
+.. c:macro:: UV_ENOTEMPTY
+
+ directory not empty
+
+.. c:macro:: UV_ENOTSOCK
+
+ socket operation on non-socket
+
+.. c:macro:: UV_ENOTSUP
+
+ operation not supported on socket
+
+.. c:macro:: UV_EPERM
+
+ operation not permitted
+
+.. c:macro:: UV_EPIPE
+
+ broken pipe
+
+.. c:macro:: UV_EPROTO
+
+ protocol error
+
+.. c:macro:: UV_EPROTONOSUPPORT
+
+ protocol not supported
+
+.. c:macro:: UV_EPROTOTYPE
+
+ protocol wrong type for socket
+
+.. c:macro:: UV_ERANGE
+
+ result too large
+
+.. c:macro:: UV_EROFS
+
+ read-only file system
+
+.. c:macro:: UV_ESHUTDOWN
+
+ cannot send after transport endpoint shutdown
+
+.. c:macro:: UV_ESPIPE
+
+ invalid seek
+
+.. c:macro:: UV_ESRCH
+
+ no such process
+
+.. c:macro:: UV_ETIMEDOUT
+
+ connection timed out
+
+.. c:macro:: UV_ETXTBSY
+
+ text file is busy
+
+.. c:macro:: UV_EXDEV
+
+ cross-device link not permitted
+
+.. c:macro:: UV_UNKNOWN
+
+ unknown error
+
+.. c:macro:: UV_EOF
+
+ end of file
+
+.. c:macro:: UV_ENXIO
+
+ no such device or address
+
+.. c:macro:: UV_EMLINK
+
+ too many links
+
+
+API
+---
+
+.. c:function:: const char* uv_strerror(int err)
+
+ Returns the error message for the given error code. Leaks a few bytes
+ of memory when you call it with an unknown error code.
+
+.. c:function:: const char* uv_err_name(int err)
+
+ Returns the error name for the given error code. Leaks a few bytes
+ of memory when you call it with an unknown error code.
diff --git a/3rdparty/libuv/docs/src/fs.rst b/3rdparty/libuv/docs/src/fs.rst
new file mode 100644
index 00000000000..69e283f4c67
--- /dev/null
+++ b/3rdparty/libuv/docs/src/fs.rst
@@ -0,0 +1,300 @@
+
+.. _fs:
+
+Filesystem operations
+=====================
+
+libuv provides a wide variety of cross-platform sync and async filesystem
+operations. All functions defined in this document take a callback, which is
+allowed to be NULL. If the callback is NULL the request is completed synchronously,
+otherwise it will be performed asynchronously.
+
+All file operations are run on the threadpool, see :ref:`threadpool` for information
+on the threadpool size.
+
+
+Data types
+----------
+
+.. c:type:: uv_fs_t
+
+ Filesystem request type.
+
+.. c:type:: uv_timespec_t
+
+ Portable equivalent of ``struct timespec``.
+
+ ::
+
+ typedef struct {
+ long tv_sec;
+ long tv_nsec;
+ } uv_timespec_t;
+
+.. c:type:: uv_stat_t
+
+ Portable equivalent of ``struct stat``.
+
+ ::
+
+ typedef struct {
+ uint64_t st_dev;
+ uint64_t st_mode;
+ uint64_t st_nlink;
+ uint64_t st_uid;
+ uint64_t st_gid;
+ uint64_t st_rdev;
+ uint64_t st_ino;
+ uint64_t st_size;
+ uint64_t st_blksize;
+ uint64_t st_blocks;
+ uint64_t st_flags;
+ uint64_t st_gen;
+ uv_timespec_t st_atim;
+ uv_timespec_t st_mtim;
+ uv_timespec_t st_ctim;
+ uv_timespec_t st_birthtim;
+ } uv_stat_t;
+
+.. c:type:: uv_fs_type
+
+ Filesystem request type.
+
+ ::
+
+ typedef enum {
+ UV_FS_UNKNOWN = -1,
+ UV_FS_CUSTOM,
+ UV_FS_OPEN,
+ UV_FS_CLOSE,
+ UV_FS_READ,
+ UV_FS_WRITE,
+ UV_FS_SENDFILE,
+ UV_FS_STAT,
+ UV_FS_LSTAT,
+ UV_FS_FSTAT,
+ UV_FS_FTRUNCATE,
+ UV_FS_UTIME,
+ UV_FS_FUTIME,
+ UV_FS_ACCESS,
+ UV_FS_CHMOD,
+ UV_FS_FCHMOD,
+ UV_FS_FSYNC,
+ UV_FS_FDATASYNC,
+ UV_FS_UNLINK,
+ UV_FS_RMDIR,
+ UV_FS_MKDIR,
+ UV_FS_MKDTEMP,
+ UV_FS_RENAME,
+ UV_FS_SCANDIR,
+ UV_FS_LINK,
+ UV_FS_SYMLINK,
+ UV_FS_READLINK,
+ UV_FS_CHOWN,
+ UV_FS_FCHOWN
+ } uv_fs_type;
+
+.. c:type:: uv_dirent_t
+
+ Cross platform (reduced) equivalent of ``struct dirent``.
+ Used in :c:func:`uv_fs_scandir_next`.
+
+ ::
+
+ typedef enum {
+ UV_DIRENT_UNKNOWN,
+ UV_DIRENT_FILE,
+ UV_DIRENT_DIR,
+ UV_DIRENT_LINK,
+ UV_DIRENT_FIFO,
+ UV_DIRENT_SOCKET,
+ UV_DIRENT_CHAR,
+ UV_DIRENT_BLOCK
+ } uv_dirent_type_t;
+
+ typedef struct uv_dirent_s {
+ const char* name;
+ uv_dirent_type_t type;
+ } uv_dirent_t;
+
+
+Public members
+^^^^^^^^^^^^^^
+
+.. c:member:: uv_loop_t* uv_fs_t.loop
+
+ Loop that started this request and where completion will be reported.
+ Readonly.
+
+.. c:member:: uv_fs_type uv_fs_t.fs_type
+
+ FS request type.
+
+.. c:member:: const char* uv_fs_t.path
+
+ Path affecting the request.
+
+.. c:member:: ssize_t uv_fs_t.result
+
+ Result of the request. < 0 means error, success otherwise. On requests such
+ as :c:func:`uv_fs_read` or :c:func:`uv_fs_write` it indicates the amount of
+ data that was read or written, respectively.
+
+.. c:member:: uv_stat_t uv_fs_t.statbuf
+
+ Stores the result of :c:func:`uv_fs_stat` and other stat requests.
+
+.. c:member:: void* uv_fs_t.ptr
+
+ Stores the result of :c:func:`uv_fs_readlink` and serves as an alias to
+ `statbuf`.
+
+.. seealso:: The :c:type:`uv_req_t` members also apply.
+
+
+API
+---
+
+.. c:function:: void uv_fs_req_cleanup(uv_fs_t* req)
+
+ Cleanup request. Must be called after a request is finished to deallocate
+ any memory libuv might have allocated.
+
+.. c:function:: int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb)
+
+ Equivalent to :man:`close(2)`.
+
+.. c:function:: int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, int mode, uv_fs_cb cb)
+
+ Equivalent to :man:`open(2)`.
+
+ .. note::
+ On Windows libuv uses `CreateFileW` and thus the file is always opened
+ in binary mode. Because of this the O_BINARY and O_TEXT flags are not
+ supported.
+
+.. c:function:: int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file file, const uv_buf_t bufs[], unsigned int nbufs, int64_t offset, uv_fs_cb cb)
+
+ Equivalent to :man:`preadv(2)`.
+
+.. c:function:: int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
+
+ Equivalent to :man:`unlink(2)`.
+
+.. c:function:: int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, const uv_buf_t bufs[], unsigned int nbufs, int64_t offset, uv_fs_cb cb)
+
+ Equivalent to :man:`pwritev(2)`.
+
+.. c:function:: int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb)
+
+ Equivalent to :man:`mkdir(2)`.
+
+ .. note::
+ `mode` is currently not implemented on Windows.
+
+.. c:function:: int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl, uv_fs_cb cb)
+
+ Equivalent to :man:`mkdtemp(3)`.
+
+ .. note::
+ The result can be found as a null terminated string at `req->path`.
+
+.. c:function:: int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
+
+ Equivalent to :man:`rmdir(2)`.
+
+.. c:function:: int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, uv_fs_cb cb)
+.. c:function:: int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent)
+
+ Equivalent to :man:`scandir(3)`, with a slightly different API. Once the callback
+ for the request is called, the user can use :c:func:`uv_fs_scandir_next` to
+ get `ent` populated with the next directory entry data. When there are no
+ more entries ``UV_EOF`` will be returned.
+
+ .. note::
+ Unlike `scandir(3)`, this function does not return the "." and ".." entries.
+
+ .. note::
+ On Linux, getting the type of an entry is only supported by some filesystems (btrfs, ext2,
+ ext3 and ext4 at the time of this writing), check the :man:`getdents(2)` man page.
+
+.. c:function:: int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
+.. c:function:: int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb)
+.. c:function:: int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
+
+ Equivalent to :man:`stat(2)`, :man:`fstat(2)` and :man:`fstat(2)` respectively.
+
+.. c:function:: int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb)
+
+ Equivalent to :man:`rename(2)`.
+
+.. c:function:: int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb)
+
+ Equivalent to :man:`fsync(2)`.
+
+.. c:function:: int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb)
+
+ Equivalent to :man:`fdatasync(2)`.
+
+.. c:function:: int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file file, int64_t offset, uv_fs_cb cb)
+
+ Equivalent to :man:`ftruncate(2)`.
+
+.. c:function:: int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd, uv_file in_fd, int64_t in_offset, size_t length, uv_fs_cb cb)
+
+ Limited equivalent to :man:`sendfile(2)`.
+
+.. c:function:: int uv_fs_access(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb)
+
+ Equivalent to :man:`access(2)` on Unix. Windows uses ``GetFileAttributesW()``.
+
+.. c:function:: int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb)
+.. c:function:: int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, int mode, uv_fs_cb cb)
+
+ Equivalent to :man:`chmod(2)` and :man:`fchmod(2)` respectively.
+
+.. c:function:: int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, double mtime, uv_fs_cb cb)
+.. c:function:: int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime, double mtime, uv_fs_cb cb)
+
+ Equivalent to :man:`utime(2)` and :man:`futime(2)` respectively.
+
+.. c:function:: int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb)
+
+ Equivalent to :man:`link(2)`.
+
+.. c:function:: int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, int flags, uv_fs_cb cb)
+
+ Equivalent to :man:`symlink(2)`.
+
+ .. note::
+ On Windows the `flags` parameter can be specified to control how the symlink will
+ be created:
+
+ * ``UV_FS_SYMLINK_DIR``: indicates that `path` points to a directory.
+
+ * ``UV_FS_SYMLINK_JUNCTION``: request that the symlink is created
+ using junction points.
+
+.. c:function:: int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
+
+ Equivalent to :man:`readlink(2)`.
+
+.. c:function:: int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
+
+ Equivalent to :man:`realpath(3)` on Unix. Windows uses ``GetFinalPathNameByHandle()``.
+
+ .. note::
+ This function is not implemented on Windows XP and Windows Server 2003.
+ On these systems, UV_ENOSYS is returned.
+
+ .. versionadded:: 1.8.0
+
+.. c:function:: int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb)
+.. c:function:: int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb)
+
+ Equivalent to :man:`chown(2)` and :man:`fchown(2)` respectively.
+
+ .. note::
+ These functions are not implemented on Windows.
+
+.. seealso:: The :c:type:`uv_req_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/fs_event.rst b/3rdparty/libuv/docs/src/fs_event.rst
new file mode 100644
index 00000000000..c2d7f520236
--- /dev/null
+++ b/3rdparty/libuv/docs/src/fs_event.rst
@@ -0,0 +1,108 @@
+
+.. _fs_event:
+
+:c:type:`uv_fs_event_t` --- FS Event handle
+===========================================
+
+FS Event handles allow the user to monitor a given path for changes, for example,
+if the file was renamed or there was a generic change in it. This handle uses
+the best backend for the job on each platform.
+
+
+Data types
+----------
+
+.. c:type:: uv_fs_event_t
+
+ FS Event handle type.
+
+.. c:type:: void (*uv_fs_event_cb)(uv_fs_event_t* handle, const char* filename, int events, int status)
+
+ Callback passed to :c:func:`uv_fs_event_start` which will be called repeatedly
+ after the handle is started. If the handle was started with a directory the
+ `filename` parameter will be a relative path to a file contained in the directory.
+ The `events` parameter is an ORed mask of :c:type:`uv_fs_event` elements.
+
+.. c:type:: uv_fs_event
+
+ Event types that :c:type:`uv_fs_event_t` handles monitor.
+
+ ::
+
+ enum uv_fs_event {
+ UV_RENAME = 1,
+ UV_CHANGE = 2
+ };
+
+.. c:type:: uv_fs_event_flags
+
+ Flags that can be passed to :c:func:`uv_fs_event_start` to control its
+ behavior.
+
+ ::
+
+ enum uv_fs_event_flags {
+ /*
+ * By default, if the fs event watcher is given a directory name, we will
+ * watch for all events in that directory. This flags overrides this behavior
+ * and makes fs_event report only changes to the directory entry itself. This
+ * flag does not affect individual files watched.
+ * This flag is currently not implemented yet on any backend.
+ */
+ UV_FS_EVENT_WATCH_ENTRY = 1,
+ /*
+ * By default uv_fs_event will try to use a kernel interface such as inotify
+ * or kqueue to detect events. This may not work on remote filesystems such
+ * as NFS mounts. This flag makes fs_event fall back to calling stat() on a
+ * regular interval.
+ * This flag is currently not implemented yet on any backend.
+ */
+ UV_FS_EVENT_STAT = 2,
+ /*
+ * By default, event watcher, when watching directory, is not registering
+ * (is ignoring) changes in it's subdirectories.
+ * This flag will override this behaviour on platforms that support it.
+ */
+ UV_FS_EVENT_RECURSIVE = 4
+ };
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle)
+
+ Initialize the handle.
+
+.. c:function:: int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* path, unsigned int flags)
+
+ Start the handle with the given callback, which will watch the specified
+ `path` for changes. `flags` can be an ORed mask of :c:type:`uv_fs_event_flags`.
+
+ .. note:: Currently the only supported flag is ``UV_FS_EVENT_RECURSIVE`` and
+ only on OSX and Windows.
+
+.. c:function:: int uv_fs_event_stop(uv_fs_event_t* handle)
+
+ Stop the handle, the callback will no longer be called.
+
+.. c:function:: int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size)
+
+ Get the path being monitored by the handle. The buffer must be preallocated
+ by the user. Returns 0 on success or an error code < 0 in case of failure.
+ On success, `buffer` will contain the path and `size` its length. If the buffer
+ is not big enough UV_ENOBUFS will be returned and len will be set to the
+ required size.
+
+ .. versionchanged:: 1.3.0 the returned length no longer includes the terminating null byte,
+ and the buffer is not null terminated.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/fs_poll.rst b/3rdparty/libuv/docs/src/fs_poll.rst
new file mode 100644
index 00000000000..4efb2440e0b
--- /dev/null
+++ b/3rdparty/libuv/docs/src/fs_poll.rst
@@ -0,0 +1,72 @@
+
+.. _fs_poll:
+
+:c:type:`uv_fs_poll_t` --- FS Poll handle
+=========================================
+
+FS Poll handles allow the user to monitor a given path for changes. Unlike
+:c:type:`uv_fs_event_t`, fs poll handles use `stat` to detect when a file has
+changed so they can work on file systems where fs event handles can't.
+
+
+Data types
+----------
+
+.. c:type:: uv_fs_poll_t
+
+ FS Poll handle type.
+
+.. c:type:: void (*uv_fs_poll_cb)(uv_fs_poll_t* handle, int status, const uv_stat_t* prev, const uv_stat_t* curr)
+
+ Callback passed to :c:func:`uv_fs_poll_start` which will be called repeatedly
+ after the handle is started, when any change happens to the monitored path.
+
+ The callback is invoked with `status < 0` if `path` does not exist
+ or is inaccessible. The watcher is *not* stopped but your callback is
+ not called again until something changes (e.g. when the file is created
+ or the error reason changes).
+
+ When `status == 0`, the callback receives pointers to the old and new
+ :c:type:`uv_stat_t` structs. They are valid for the duration of the
+ callback only.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle)
+
+ Initialize the handle.
+
+.. c:function:: int uv_fs_poll_start(uv_fs_poll_t* handle, uv_fs_poll_cb poll_cb, const char* path, unsigned int interval)
+
+ Check the file at `path` for changes every `interval` milliseconds.
+
+ .. note::
+ For maximum portability, use multi-second intervals. Sub-second intervals will not detect
+ all changes on many file systems.
+
+.. c:function:: int uv_fs_poll_stop(uv_fs_poll_t* handle)
+
+ Stop the handle, the callback will no longer be called.
+
+.. c:function:: int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size)
+
+ Get the path being monitored by the handle. The buffer must be preallocated
+ by the user. Returns 0 on success or an error code < 0 in case of failure.
+ On success, `buffer` will contain the path and `size` its length. If the buffer
+ is not big enough UV_ENOBUFS will be returned and len will be set to the
+ required size.
+
+ .. versionchanged:: 1.3.0 the returned length no longer includes the terminating null byte,
+ and the buffer is not null terminated.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/handle.rst b/3rdparty/libuv/docs/src/handle.rst
new file mode 100644
index 00000000000..6ba597a21ab
--- /dev/null
+++ b/3rdparty/libuv/docs/src/handle.rst
@@ -0,0 +1,181 @@
+
+.. _handle:
+
+:c:type:`uv_handle_t` --- Base handle
+=====================================
+
+`uv_handle_t` is the base type for all libuv handle types.
+
+Structures are aligned so that any libuv handle can be cast to `uv_handle_t`.
+All API functions defined here work with any handle type.
+
+
+Data types
+----------
+
+.. c:type:: uv_handle_t
+
+ The base libuv handle type.
+
+.. c:type:: uv_any_handle
+
+ Union of all handle types.
+
+.. c:type:: void (*uv_alloc_cb)(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
+
+ Type definition for callback passed to :c:func:`uv_read_start` and
+ :c:func:`uv_udp_recv_start`. The user must fill the supplied :c:type:`uv_buf_t`
+ structure with whatever size, as long as it's > 0. A suggested size (65536 at the moment)
+ is provided, but it doesn't need to be honored. Setting the buffer's length to 0
+ will trigger a ``UV_ENOBUFS`` error in the :c:type:`uv_udp_recv_cb` or
+ :c:type:`uv_read_cb` callback.
+
+.. c:type:: void (*uv_close_cb)(uv_handle_t* handle)
+
+ Type definition for callback passed to :c:func:`uv_close`.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+.. c:member:: uv_loop_t* uv_handle_t.loop
+
+ Pointer to the :c:type:`uv_loop_t` where the handle is running on. Readonly.
+
+.. c:member:: void* uv_handle_t.data
+
+ Space for user-defined arbitrary data. libuv does not use this field.
+
+
+API
+---
+
+.. c:function:: int uv_is_active(const uv_handle_t* handle)
+
+ Returns non-zero if the handle is active, zero if it's inactive. What
+ "active" means depends on the type of handle:
+
+ - A uv_async_t handle is always active and cannot be deactivated, except
+ by closing it with uv_close().
+
+ - A uv_pipe_t, uv_tcp_t, uv_udp_t, etc. handle - basically any handle that
+ deals with i/o - is active when it is doing something that involves i/o,
+ like reading, writing, connecting, accepting new connections, etc.
+
+ - A uv_check_t, uv_idle_t, uv_timer_t, etc. handle is active when it has
+ been started with a call to uv_check_start(), uv_idle_start(), etc.
+
+ Rule of thumb: if a handle of type `uv_foo_t` has a `uv_foo_start()`
+ function, then it's active from the moment that function is called.
+ Likewise, `uv_foo_stop()` deactivates the handle again.
+
+.. c:function:: int uv_is_closing(const uv_handle_t* handle)
+
+ Returns non-zero if the handle is closing or closed, zero otherwise.
+
+ .. note::
+ This function should only be used between the initialization of the handle and the
+ arrival of the close callback.
+
+.. c:function:: void uv_close(uv_handle_t* handle, uv_close_cb close_cb)
+
+ Request handle to be closed. `close_cb` will be called asynchronously after
+ this call. This MUST be called on each handle before memory is released.
+
+ Handles that wrap file descriptors are closed immediately but
+ `close_cb` will still be deferred to the next iteration of the event loop.
+ It gives you a chance to free up any resources associated with the handle.
+
+ In-progress requests, like uv_connect_t or uv_write_t, are cancelled and
+ have their callbacks called asynchronously with status=UV_ECANCELED.
+
+.. c:function:: void uv_ref(uv_handle_t* handle)
+
+ Reference the given handle. References are idempotent, that is, if a handle
+ is already referenced calling this function again will have no effect.
+
+ See :ref:`refcount`.
+
+.. c:function:: void uv_unref(uv_handle_t* handle)
+
+ Un-reference the given handle. References are idempotent, that is, if a handle
+ is not referenced calling this function again will have no effect.
+
+ See :ref:`refcount`.
+
+.. c:function:: int uv_has_ref(const uv_handle_t* handle)
+
+ Returns non-zero if the handle referenced, zero otherwise.
+
+ See :ref:`refcount`.
+
+.. c:function:: size_t uv_handle_size(uv_handle_type type)
+
+ Returns the size of the given handle type. Useful for FFI binding writers
+ who don't want to know the structure layout.
+
+
+Miscellaneous API functions
+---------------------------
+
+The following API functions take a :c:type:`uv_handle_t` argument but they work
+just for some handle types.
+
+.. c:function:: int uv_send_buffer_size(uv_handle_t* handle, int* value)
+
+ Gets or sets the size of the send buffer that the operating
+ system uses for the socket.
+
+ If `*value` == 0, it will return the current send buffer size,
+ otherwise it will use `*value` to set the new send buffer size.
+
+ This function works for TCP, pipe and UDP handles on Unix and for TCP and
+ UDP handles on Windows.
+
+ .. note::
+ Linux will set double the size and return double the size of the original set value.
+
+.. c:function:: int uv_recv_buffer_size(uv_handle_t* handle, int* value)
+
+ Gets or sets the size of the receive buffer that the operating
+ system uses for the socket.
+
+ If `*value` == 0, it will return the current receive buffer size,
+ otherwise it will use `*value` to set the new receive buffer size.
+
+ This function works for TCP, pipe and UDP handles on Unix and for TCP and
+ UDP handles on Windows.
+
+ .. note::
+ Linux will set double the size and return double the size of the original set value.
+
+.. c:function:: int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd)
+
+ Gets the platform dependent file descriptor equivalent.
+
+ The following handles are supported: TCP, pipes, TTY, UDP and poll. Passing
+ any other handle type will fail with `UV_EINVAL`.
+
+ If a handle doesn't have an attached file descriptor yet or the handle
+ itself has been closed, this function will return `UV_EBADF`.
+
+ .. warning::
+ Be very careful when using this function. libuv assumes it's in control of the file
+ descriptor so any change to it may lead to malfunction.
+
+
+.. _refcount:
+
+Reference counting
+------------------
+
+The libuv event loop (if run in the default mode) will run until there are no
+active `and` referenced handles left. The user can force the loop to exit early
+by unreferencing handles which are active, for example by calling :c:func:`uv_unref`
+after calling :c:func:`uv_timer_start`.
+
+A handle can be referenced or unreferenced, the refcounting scheme doesn't use
+a counter, so both operations are idempotent.
+
+All handles are referenced when active by default, see :c:func:`uv_is_active`
+for a more detailed explanation on what being `active` involves.
diff --git a/3rdparty/libuv/docs/src/idle.rst b/3rdparty/libuv/docs/src/idle.rst
new file mode 100644
index 00000000000..1f51c4a19e4
--- /dev/null
+++ b/3rdparty/libuv/docs/src/idle.rst
@@ -0,0 +1,54 @@
+
+.. _idle:
+
+:c:type:`uv_idle_t` --- Idle handle
+===================================
+
+Idle handles will run the given callback once per loop iteration, right
+before the :c:type:`uv_prepare_t` handles.
+
+.. note::
+ The notable difference with prepare handles is that when there are active idle handles,
+ the loop will perform a zero timeout poll instead of blocking for i/o.
+
+.. warning::
+ Despite the name, idle handles will get their callbacks called on every loop iteration,
+ not when the loop is actually "idle".
+
+
+Data types
+----------
+
+.. c:type:: uv_idle_t
+
+ Idle handle type.
+
+.. c:type:: void (*uv_idle_cb)(uv_idle_t* handle)
+
+ Type definition for callback passed to :c:func:`uv_idle_start`.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_idle_init(uv_loop_t* loop, uv_idle_t* idle)
+
+ Initialize the handle.
+
+.. c:function:: int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb)
+
+ Start the handle with the given callback.
+
+.. c:function:: int uv_idle_stop(uv_idle_t* idle)
+
+ Stop the handle, the callback will no longer be called.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/index.rst b/3rdparty/libuv/docs/src/index.rst
new file mode 100644
index 00000000000..fa89c4bffe5
--- /dev/null
+++ b/3rdparty/libuv/docs/src/index.rst
@@ -0,0 +1,95 @@
+
+Welcome to the libuv API documentation
+======================================
+
+Overview
+--------
+
+libuv is a multi-platform support library with a focus on asynchronous I/O. It
+was primarily developed for use by `Node.js`_, but it's also used by `Luvit`_,
+`Julia`_, `pyuv`_, and `others`_.
+
+.. note::
+ In case you find errors in this documentation you can help by sending
+ `pull requests <https://github.com/libuv/libuv>`_!
+
+.. _Node.js: http://nodejs.org
+.. _Luvit: http://luvit.io
+.. _Julia: http://julialang.org
+.. _pyuv: https://github.com/saghul/pyuv
+.. _others: https://github.com/libuv/libuv/wiki/Projects-that-use-libuv
+
+
+Features
+--------
+
+* Full-featured event loop backed by epoll, kqueue, IOCP, event ports.
+* Asynchronous TCP and UDP sockets
+* Asynchronous DNS resolution
+* Asynchronous file and file system operations
+* File system events
+* ANSI escape code controlled TTY
+* IPC with socket sharing, using Unix domain sockets or named pipes (Windows)
+* Child processes
+* Thread pool
+* Signal handling
+* High resolution clock
+* Threading and synchronization primitives
+
+
+Downloads
+---------
+
+libuv can be downloaded from `here <http://dist.libuv.org/dist/>`_.
+
+
+Installation
+------------
+
+Installation instructions can be found on `the README <https://github.com/libuv/libuv/blob/master/README.md>`_.
+
+
+Upgrading
+---------
+
+Migration guides for different libuv versions, starting with 1.0.
+
+.. toctree::
+ :maxdepth: 1
+
+ migration_010_100
+
+
+Documentation
+-------------
+
+.. toctree::
+ :maxdepth: 1
+
+ design
+ errors
+ version
+ loop
+ handle
+ request
+ timer
+ prepare
+ check
+ idle
+ async
+ poll
+ signal
+ process
+ stream
+ tcp
+ pipe
+ tty
+ udp
+ fs_event
+ fs_poll
+ fs
+ threadpool
+ dns
+ dll
+ threading
+ misc
diff --git a/3rdparty/libuv/docs/src/loop.rst b/3rdparty/libuv/docs/src/loop.rst
new file mode 100644
index 00000000000..2a01d796375
--- /dev/null
+++ b/3rdparty/libuv/docs/src/loop.rst
@@ -0,0 +1,166 @@
+
+.. _loop:
+
+:c:type:`uv_loop_t` --- Event loop
+==================================
+
+The event loop is the central part of libuv's functionality. It takes care
+of polling for i/o and scheduling callbacks to be run based on different sources
+of events.
+
+
+Data types
+----------
+
+.. c:type:: uv_loop_t
+
+ Loop data type.
+
+.. c:type:: uv_run_mode
+
+ Mode used to run the loop with :c:func:`uv_run`.
+
+ ::
+
+ typedef enum {
+ UV_RUN_DEFAULT = 0,
+ UV_RUN_ONCE,
+ UV_RUN_NOWAIT
+ } uv_run_mode;
+
+.. c:type:: void (*uv_walk_cb)(uv_handle_t* handle, void* arg)
+
+ Type definition for callback passed to :c:func:`uv_walk`.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+.. c:member:: void* uv_loop_t.data
+
+ Space for user-defined arbitrary data. libuv does not use this field. libuv does, however,
+ initialize it to NULL in :c:func:`uv_loop_init`, and it poisons the value (on debug builds)
+ on :c:func:`uv_loop_close`.
+
+
+API
+---
+
+.. c:function:: int uv_loop_init(uv_loop_t* loop)
+
+ Initializes the given `uv_loop_t` structure.
+
+.. c:function:: int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...)
+
+ .. versionadded:: 1.0.2
+
+ Set additional loop options. You should normally call this before the
+ first call to :c:func:`uv_run` unless mentioned otherwise.
+
+ Returns 0 on success or a UV_E* error code on failure. Be prepared to
+ handle UV_ENOSYS; it means the loop option is not supported by the platform.
+
+ Supported options:
+
+ - UV_LOOP_BLOCK_SIGNAL: Block a signal when polling for new events. The
+ second argument to :c:func:`uv_loop_configure` is the signal number.
+
+ This operation is currently only implemented for SIGPROF signals,
+ to suppress unnecessary wakeups when using a sampling profiler.
+ Requesting other signals will fail with UV_EINVAL.
+
+.. c:function:: int uv_loop_close(uv_loop_t* loop)
+
+ Closes all internal loop resources. This function must only be called once
+ the loop has finished its execution or it will return UV_EBUSY. After this
+ function returns the user shall free the memory allocated for the loop.
+
+.. c:function:: uv_loop_t* uv_default_loop(void)
+
+ Returns the initialized default loop. It may return NULL in case of
+ allocation failure.
+
+ This function is just a convenient way for having a global loop throughout
+ an application, the default loop is in no way different than the ones
+ initialized with :c:func:`uv_loop_init`. As such, the default loop can (and
+ should) be closed with :c:func:`uv_loop_close` so the resources associated
+ with it are freed.
+
+.. c:function:: int uv_run(uv_loop_t* loop, uv_run_mode mode)
+
+ This function runs the event loop. It will act differently depending on the
+ specified mode:
+
+ - UV_RUN_DEFAULT: Runs the event loop until there are no more active and
+ referenced handles or requests. Returns non-zero if :c:func:`uv_stop`
+ was called and there are still active handles or requests. Returns
+ zero in all other cases.
+ - UV_RUN_ONCE: Poll for i/o once. Note that this function blocks if
+ there are no pending callbacks. Returns zero when done (no active handles
+ or requests left), or non-zero if more callbacks are expected (meaning
+ you should run the event loop again sometime in the future).
+ - UV_RUN_NOWAIT: Poll for i/o once but don't block if there are no
+ pending callbacks. Returns zero if done (no active handles
+ or requests left), or non-zero if more callbacks are expected (meaning
+ you should run the event loop again sometime in the future).
+
+.. c:function:: int uv_loop_alive(const uv_loop_t* loop)
+
+ Returns non-zero if there are active handles or request in the loop.
+
+.. c:function:: void uv_stop(uv_loop_t* loop)
+
+ Stop the event loop, causing :c:func:`uv_run` to end as soon as
+ possible. This will happen not sooner than the next loop iteration.
+ If this function was called before blocking for i/o, the loop won't block
+ for i/o on this iteration.
+
+.. c:function:: size_t uv_loop_size(void)
+
+ Returns the size of the `uv_loop_t` structure. Useful for FFI binding
+ writers who don't want to know the structure layout.
+
+.. c:function:: int uv_backend_fd(const uv_loop_t* loop)
+
+ Get backend file descriptor. Only kqueue, epoll and event ports are
+ supported.
+
+ This can be used in conjunction with `uv_run(loop, UV_RUN_NOWAIT)` to
+ poll in one thread and run the event loop's callbacks in another see
+ test/test-embed.c for an example.
+
+ .. note::
+ Embedding a kqueue fd in another kqueue pollset doesn't work on all platforms. It's not
+ an error to add the fd but it never generates events.
+
+.. c:function:: int uv_backend_timeout(const uv_loop_t* loop)
+
+ Get the poll timeout. The return value is in milliseconds, or -1 for no
+ timeout.
+
+.. c:function:: uint64_t uv_now(const uv_loop_t* loop)
+
+ Return the current timestamp in milliseconds. The timestamp is cached at
+ the start of the event loop tick, see :c:func:`uv_update_time` for details
+ and rationale.
+
+ The timestamp increases monotonically from some arbitrary point in time.
+ Don't make assumptions about the starting point, you will only get
+ disappointed.
+
+ .. note::
+ Use :c:func:`uv_hrtime` if you need sub-millisecond granularity.
+
+.. c:function:: void uv_update_time(uv_loop_t* loop)
+
+ Update the event loop's concept of "now". Libuv caches the current time
+ at the start of the event loop tick in order to reduce the number of
+ time-related system calls.
+
+ You won't normally need to call this function unless you have callbacks
+ that block the event loop for longer periods of time, where "longer" is
+ somewhat subjective but probably on the order of a millisecond or more.
+
+.. c:function:: void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg)
+
+ Walk the list of handles: `walk_cb` will be executed with the given `arg`.
diff --git a/3rdparty/libuv/docs/src/migration_010_100.rst b/3rdparty/libuv/docs/src/migration_010_100.rst
new file mode 100644
index 00000000000..bb6ac1a8092
--- /dev/null
+++ b/3rdparty/libuv/docs/src/migration_010_100.rst
@@ -0,0 +1,244 @@
+
+.. _migration_010_100:
+
+libuv 0.10 -> 1.0.0 migration guide
+===================================
+
+Some APIs changed quite a bit throughout the 1.0.0 development process. Here
+is a migration guide for the most significant changes that happened after 0.10
+was released.
+
+
+Loop initialization and closing
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In libuv 0.10 (and previous versions), loops were created with `uv_loop_new`, which
+allocated memory for a new loop and initialized it; and destroyed with `uv_loop_delete`,
+which destroyed the loop and freed the memory. Starting with 1.0, those are deprecated
+and the user is responsible for allocating the memory and then initializing the loop.
+
+libuv 0.10
+
+::
+
+ uv_loop_t* loop = uv_loop_new();
+ ...
+ uv_loop_delete(loop);
+
+libuv 1.0
+
+::
+
+ uv_loop_t* loop = malloc(sizeof *loop);
+ uv_loop_init(loop);
+ ...
+ uv_loop_close(loop);
+ free(loop);
+
+.. note::
+ Error handling was omitted for brevity. Check the documentation for :c:func:`uv_loop_init`
+ and :c:func:`uv_loop_close`.
+
+
+Error handling
+~~~~~~~~~~~~~~
+
+Error handling had a major overhaul in libuv 1.0. In general, functions and status parameters
+would get 0 for success and -1 for failure on libuv 0.10, and the user had to use `uv_last_error`
+to fetch the error code, which was a positive number.
+
+In 1.0, functions and status parameters contain the actual error code, which is 0 for success, or
+a negative number in case of error.
+
+libuv 0.10
+
+::
+
+ ... assume 'server' is a TCP server which is already listening
+ r = uv_listen((uv_stream_t*) server, 511, NULL);
+ if (r == -1) {
+ uv_err_t err = uv_last_error(uv_default_loop());
+ /* err.code contains UV_EADDRINUSE */
+ }
+
+libuv 1.0
+
+::
+
+ ... assume 'server' is a TCP server which is already listening
+ r = uv_listen((uv_stream_t*) server, 511, NULL);
+ if (r < 0) {
+ /* r contains UV_EADDRINUSE */
+ }
+
+
+Threadpool changes
+~~~~~~~~~~~~~~~~~~
+
+In libuv 0.10 Unix used a threadpool which defaulted to 4 threads, while Windows used the
+`QueueUserWorkItem` API, which uses a Windows internal threadpool, which defaults to 512
+threads per process.
+
+In 1.0, we unified both implementations, so Windows now uses the same implementation Unix
+does. The threadpool size can be set by exporting the ``UV_THREADPOOL_SIZE`` environment
+variable. See :c:ref:`threadpool`.
+
+
+Allocation callback API change
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In libuv 0.10 the callback had to return a filled :c:type:`uv_buf_t` by value:
+
+::
+
+ uv_buf_t alloc_cb(uv_handle_t* handle, size_t size) {
+ return uv_buf_init(malloc(size), size);
+ }
+
+In libuv 1.0 a pointer to a buffer is passed to the callback, which the user
+needs to fill:
+
+::
+
+ void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ buf->base = malloc(size);
+ buf->len = size;
+ }
+
+
+Unification of IPv4 / IPv6 APIs
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+libuv 1.0 unified the IPv4 and IPv6 APIS. There is no longer a `uv_tcp_bind` and `uv_tcp_bind6`
+duality, there is only :c:func:`uv_tcp_bind` now.
+
+IPv4 functions took ``struct sockaddr_in`` structures by value, and IPv6 functions took
+``struct sockaddr_in6``. Now functions take a ``struct sockaddr*`` (note it's a pointer).
+It can be stack allocated.
+
+libuv 0.10
+
+::
+
+ struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", 1234);
+ ...
+ uv_tcp_bind(&server, addr)
+
+libuv 1.0
+
+::
+
+ struct sockaddr_in addr;
+ uv_ip4_addr("0.0.0.0", 1234, &addr)
+ ...
+ uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+
+The IPv4 and IPv6 struct creating functions (:c:func:`uv_ip4_addr` and :c:func:`uv_ip6_addr`)
+have also changed, make sure you check the documentation.
+
+..note::
+ This change applies to all functions that made a distinction between IPv4 and IPv6
+ addresses.
+
+
+Streams / UDP data receive callback API change
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The streams and UDP data receive callbacks now get a pointer to a :c:type:`uv_buf_t` buffer,
+not a structure by value.
+
+libuv 0.10
+
+::
+
+ void on_read(uv_stream_t* handle,
+ ssize_t nread,
+ uv_buf_t buf) {
+ ...
+ }
+
+ void recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ uv_buf_t buf,
+ struct sockaddr* addr,
+ unsigned flags) {
+ ...
+ }
+
+libuv 1.0
+
+::
+
+ void on_read(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ ...
+ }
+
+ void recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ ...
+ }
+
+
+Receiving handles over pipes API change
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In libuv 0.10 (and earlier versions) the `uv_read2_start` function was used to start reading
+data on a pipe, which could also result in the reception of handles over it. The callback
+for such function looked like this:
+
+::
+
+ void on_read(uv_pipe_t* pipe,
+ ssize_t nread,
+ uv_buf_t buf,
+ uv_handle_type pending) {
+ ...
+ }
+
+In libuv 1.0, `uv_read2_start` was removed, and the user needs to check if there are pending
+handles using :c:func:`uv_pipe_pending_count` and :c:func:`uv_pipe_pending_type` while in
+the read callback:
+
+::
+
+ void on_read(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ ...
+ while (uv_pipe_pending_count((uv_pipe_t*) handle) != 0) {
+ pending = uv_pipe_pending_type((uv_pipe_t*) handle);
+ ...
+ }
+ ...
+ }
+
+
+Extracting the file descriptor out of a handle
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+While it wasn't supported by the API, users often accessed the libuv internals in
+order to get access to the file descriptor of a TCP handle, for example.
+
+::
+
+ fd = handle->io_watcher.fd;
+
+This is now properly exposed through the :c:func:`uv_fileno` function.
+
+
+uv_fs_readdir rename and API change
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`uv_fs_readdir` returned a list of strings in the `req->ptr` field upon completion in
+libuv 0.10. In 1.0, this function got renamed to :c:func:`uv_fs_scandir`, since it's
+actually implemented using ``scandir(3)``.
+
+In addition, instead of allocating a full list strings, the user is able to get one
+result at a time by using the :c:func:`uv_fs_scandir_next` function. This function
+does not need to make a roundtrip to the threadpool, because libuv will keep the
+list of *dents* returned by ``scandir(3)`` around.
diff --git a/3rdparty/libuv/docs/src/misc.rst b/3rdparty/libuv/docs/src/misc.rst
new file mode 100644
index 00000000000..2ce0887db0c
--- /dev/null
+++ b/3rdparty/libuv/docs/src/misc.rst
@@ -0,0 +1,328 @@
+
+.. _misc:
+
+Miscellaneous utilities
+=======================
+
+This section contains miscellaneous functions that don't really belong in any
+other section.
+
+
+Data types
+----------
+
+.. c:type:: uv_buf_t
+
+ Buffer data type.
+
+ .. c:member:: char* uv_buf_t.base
+
+ Pointer to the base of the buffer. Readonly.
+
+ .. c:member:: size_t uv_buf_t.len
+
+ Total bytes in the buffer. Readonly.
+
+ .. note::
+ On Windows this field is ULONG.
+
+.. c:type:: void* (*uv_malloc_func)(size_t size)
+
+ Replacement function for :man:`malloc(3)`.
+ See :c:func:`uv_replace_allocator`.
+
+.. c:type:: void* (*uv_realloc_func)(void* ptr, size_t size)
+
+ Replacement function for :man:`realloc(3)`.
+ See :c:func:`uv_replace_allocator`.
+
+.. c:type:: void* (*uv_calloc_func)(size_t count, size_t size)
+
+ Replacement function for :man:`calloc(3)`.
+ See :c:func:`uv_replace_allocator`.
+
+.. c:type:: void (*uv_free_func)(void* ptr)
+
+ Replacement function for :man:`free(3)`.
+ See :c:func:`uv_replace_allocator`.
+
+.. c:type:: uv_file
+
+ Cross platform representation of a file handle.
+
+.. c:type:: uv_os_sock_t
+
+ Cross platform representation of a socket handle.
+
+.. c:type:: uv_os_fd_t
+
+ Abstract representation of a file descriptor. On Unix systems this is a
+ `typedef` of `int` and on Windows a `HANDLE`.
+
+.. c:type:: uv_rusage_t
+
+ Data type for resource usage results.
+
+ ::
+
+ typedef struct {
+ uv_timeval_t ru_utime; /* user CPU time used */
+ uv_timeval_t ru_stime; /* system CPU time used */
+ uint64_t ru_maxrss; /* maximum resident set size */
+ uint64_t ru_ixrss; /* integral shared memory size */
+ uint64_t ru_idrss; /* integral unshared data size */
+ uint64_t ru_isrss; /* integral unshared stack size */
+ uint64_t ru_minflt; /* page reclaims (soft page faults) */
+ uint64_t ru_majflt; /* page faults (hard page faults) */
+ uint64_t ru_nswap; /* swaps */
+ uint64_t ru_inblock; /* block input operations */
+ uint64_t ru_oublock; /* block output operations */
+ uint64_t ru_msgsnd; /* IPC messages sent */
+ uint64_t ru_msgrcv; /* IPC messages received */
+ uint64_t ru_nsignals; /* signals received */
+ uint64_t ru_nvcsw; /* voluntary context switches */
+ uint64_t ru_nivcsw; /* involuntary context switches */
+ } uv_rusage_t;
+
+.. c:type:: uv_cpu_info_t
+
+ Data type for CPU information.
+
+ ::
+
+ typedef struct uv_cpu_info_s {
+ char* model;
+ int speed;
+ struct uv_cpu_times_s {
+ uint64_t user;
+ uint64_t nice;
+ uint64_t sys;
+ uint64_t idle;
+ uint64_t irq;
+ } cpu_times;
+ } uv_cpu_info_t;
+
+.. c:type:: uv_interface_address_t
+
+ Data type for interface addresses.
+
+ ::
+
+ typedef struct uv_interface_address_s {
+ char* name;
+ char phys_addr[6];
+ int is_internal;
+ union {
+ struct sockaddr_in address4;
+ struct sockaddr_in6 address6;
+ } address;
+ union {
+ struct sockaddr_in netmask4;
+ struct sockaddr_in6 netmask6;
+ } netmask;
+ } uv_interface_address_t;
+
+
+API
+---
+
+.. c:function:: uv_handle_type uv_guess_handle(uv_file file)
+
+ Used to detect what type of stream should be used with a given file
+ descriptor. Usually this will be used during initialization to guess the
+ type of the stdio streams.
+
+ For :man:`isatty(3)` equivalent functionality use this function and test
+ for ``UV_TTY``.
+
+.. c:function:: int uv_replace_allocator(uv_malloc_func malloc_func, uv_realloc_func realloc_func, uv_calloc_func calloc_func, uv_free_func free_func)
+
+ .. versionadded:: 1.6.0
+
+ Override the use of the standard library's :man:`malloc(3)`,
+ :man:`calloc(3)`, :man:`realloc(3)`, :man:`free(3)`, memory allocation
+ functions.
+
+ This function must be called before any other libuv function is called or
+ after all resources have been freed and thus libuv doesn't reference
+ any allocated memory chunk.
+
+ On success, it returns 0, if any of the function pointers is NULL it
+ returns UV_EINVAL.
+
+ .. warning:: There is no protection against changing the allocator multiple
+ times. If the user changes it they are responsible for making
+ sure the allocator is changed while no memory was allocated with
+ the previous allocator, or that they are compatible.
+
+.. c:function:: uv_buf_t uv_buf_init(char* base, unsigned int len)
+
+ Constructor for :c:type:`uv_buf_t`.
+
+ Due to platform differences the user cannot rely on the ordering of the
+ `base` and `len` members of the uv_buf_t struct. The user is responsible for
+ freeing `base` after the uv_buf_t is done. Return struct passed by value.
+
+.. c:function:: char** uv_setup_args(int argc, char** argv)
+
+ Store the program arguments. Required for getting / setting the process title.
+
+.. c:function:: int uv_get_process_title(char* buffer, size_t size)
+
+ Gets the title of the current process.
+
+.. c:function:: int uv_set_process_title(const char* title)
+
+ Sets the current process title.
+
+.. c:function:: int uv_resident_set_memory(size_t* rss)
+
+ Gets the resident set size (RSS) for the current process.
+
+.. c:function:: int uv_uptime(double* uptime)
+
+ Gets the current system uptime.
+
+.. c:function:: int uv_getrusage(uv_rusage_t* rusage)
+
+ Gets the resource usage measures for the current process.
+
+ .. note::
+ On Windows not all fields are set, the unsupported fields are filled with zeroes.
+
+.. c:function:: int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count)
+
+ Gets information about the CPUs on the system. The `cpu_infos` array will
+ have `count` elements and needs to be freed with :c:func:`uv_free_cpu_info`.
+
+.. c:function:: void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count)
+
+ Frees the `cpu_infos` array previously allocated with :c:func:`uv_cpu_info`.
+
+.. c:function:: int uv_interface_addresses(uv_interface_address_t** addresses, int* count)
+
+ Gets address information about the network interfaces on the system. An
+ array of `count` elements is allocated and returned in `addresses`. It must
+ be freed by the user, calling :c:func:`uv_free_interface_addresses`.
+
+.. c:function:: void uv_free_interface_addresses(uv_interface_address_t* addresses, int count)
+
+ Free an array of :c:type:`uv_interface_address_t` which was returned by
+ :c:func:`uv_interface_addresses`.
+
+.. c:function:: void uv_loadavg(double avg[3])
+
+ Gets the load average. See: `<http://en.wikipedia.org/wiki/Load_(computing)>`_
+
+ .. note::
+ Returns [0,0,0] on Windows (i.e., it's not implemented).
+
+.. c:function:: int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr)
+
+ Convert a string containing an IPv4 addresses to a binary structure.
+
+.. c:function:: int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr)
+
+ Convert a string containing an IPv6 addresses to a binary structure.
+
+.. c:function:: int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size)
+
+ Convert a binary structure containing an IPv4 address to a string.
+
+.. c:function:: int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size)
+
+ Convert a binary structure containing an IPv6 address to a string.
+
+.. c:function:: int uv_inet_ntop(int af, const void* src, char* dst, size_t size)
+.. c:function:: int uv_inet_pton(int af, const char* src, void* dst)
+
+ Cross-platform IPv6-capable implementation of :man:`inet_ntop(3)`
+ and :man:`inet_pton(3)`. On success they return 0. In case of error
+ the target `dst` pointer is unmodified.
+
+.. c:function:: int uv_exepath(char* buffer, size_t* size)
+
+ Gets the executable path.
+
+.. c:function:: int uv_cwd(char* buffer, size_t* size)
+
+ Gets the current working directory.
+
+ .. versionchanged:: 1.1.0
+
+ On Unix the path no longer ends in a slash.
+
+.. c:function:: int uv_chdir(const char* dir)
+
+ Changes the current working directory.
+
+.. c:function:: int uv_os_homedir(char* buffer, size_t* size)
+
+ Gets the current user's home directory. On Windows, `uv_os_homedir()` first
+ checks the `USERPROFILE` environment variable using
+ `GetEnvironmentVariableW()`. If `USERPROFILE` is not set,
+ `GetUserProfileDirectoryW()` is called. On all other operating systems,
+ `uv_os_homedir()` first checks the `HOME` environment variable using
+ :man:`getenv(3)`. If `HOME` is not set, :man:`getpwuid_r(3)` is called. The
+ user's home directory is stored in `buffer`. When `uv_os_homedir()` is
+ called, `size` indicates the maximum size of `buffer`. On success or
+ `UV_ENOBUFS` failure, `size` is set to the string length of `buffer`.
+
+ .. warning::
+ `uv_os_homedir()` is not thread safe.
+
+ .. versionadded:: 1.6.0
+
+.. uint64_t uv_get_free_memory(void)
+.. c:function:: uint64_t uv_get_total_memory(void)
+
+ Gets memory information (in bytes).
+
+.. c:function:: uint64_t uv_hrtime(void)
+
+ Returns the current high-resolution real time. This is expressed in
+ nanoseconds. It is relative to an arbitrary time in the past. It is not
+ related to the time of day and therefore not subject to clock drift. The
+ primary use is for measuring performance between intervals.
+
+ .. note::
+ Not every platform can support nanosecond resolution; however, this value will always
+ be in nanoseconds.
+
+.. c:function:: void uv_print_all_handles(uv_loop_t* loop, FILE* stream)
+
+ Prints all handles associated with the given `loop` to the given `stream`.
+
+ Example:
+
+ ::
+
+ uv_print_all_handles(uv_default_loop(), stderr);
+ /*
+ [--I] signal 0x1a25ea8
+ [-AI] async 0x1a25cf0
+ [R--] idle 0x1a7a8c8
+ */
+
+ The format is `[flags] handle-type handle-address`. For `flags`:
+
+ - `R` is printed for a handle that is referenced
+ - `A` is printed for a handle that is active
+ - `I` is printed for a handle that is internal
+
+ .. warning::
+ This function is meant for ad hoc debugging, there is no API/ABI
+ stability guarantees.
+
+ .. versionadded:: 1.8.0
+
+.. c:function:: void uv_print_active_handles(uv_loop_t* loop, FILE* stream)
+
+ This is the same as :c:func:`uv_print_all_handles` except only active handles
+ are printed.
+
+ .. warning::
+ This function is meant for ad hoc debugging, there is no API/ABI
+ stability guarantees.
+
+ .. versionadded:: 1.8.0
diff --git a/3rdparty/libuv/docs/src/pipe.rst b/3rdparty/libuv/docs/src/pipe.rst
new file mode 100644
index 00000000000..d33b0f2b977
--- /dev/null
+++ b/3rdparty/libuv/docs/src/pipe.rst
@@ -0,0 +1,104 @@
+
+.. _pipe:
+
+:c:type:`uv_pipe_t` --- Pipe handle
+===================================
+
+Pipe handles provide an abstraction over local domain sockets on Unix and named
+pipes on Windows.
+
+:c:type:`uv_pipe_t` is a 'subclass' of :c:type:`uv_stream_t`.
+
+
+Data types
+----------
+
+.. c:type:: uv_pipe_t
+
+ Pipe handle type.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_stream_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc)
+
+ Initialize a pipe handle. The `ipc` argument is a boolean to indicate if
+ this pipe will be used for handle passing between processes.
+
+.. c:function:: int uv_pipe_open(uv_pipe_t* handle, uv_file file)
+
+ Open an existing file descriptor or HANDLE as a pipe.
+
+ .. versionchanged:: 1.2.1 the file descriptor is set to non-blocking mode.
+
+ .. note::
+ The passed file descriptor or HANDLE is not checked for its type, but
+ it's required that it represents a valid pipe.
+
+.. c:function:: int uv_pipe_bind(uv_pipe_t* handle, const char* name)
+
+ Bind the pipe to a file path (Unix) or a name (Windows).
+
+ .. note::
+ Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, typically between
+ 92 and 108 bytes.
+
+.. c:function:: void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb)
+
+ Connect to the Unix domain socket or the named pipe.
+
+ .. note::
+ Paths on Unix get truncated to ``sizeof(sockaddr_un.sun_path)`` bytes, typically between
+ 92 and 108 bytes.
+
+.. c:function:: int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size)
+
+ Get the name of the Unix domain socket or the named pipe.
+
+ A preallocated buffer must be provided. The size parameter holds the length
+ of the buffer and it's set to the number of bytes written to the buffer on
+ output. If the buffer is not big enough ``UV_ENOBUFS`` will be returned and
+ len will contain the required size.
+
+ .. versionchanged:: 1.3.0 the returned length no longer includes the terminating null byte,
+ and the buffer is not null terminated.
+
+.. c:function:: int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size)
+
+ Get the name of the Unix domain socket or the named pipe to which the handle
+ is connected.
+
+ A preallocated buffer must be provided. The size parameter holds the length
+ of the buffer and it's set to the number of bytes written to the buffer on
+ output. If the buffer is not big enough ``UV_ENOBUFS`` will be returned and
+ len will contain the required size.
+
+ .. versionadded:: 1.3.0
+
+.. c:function:: void uv_pipe_pending_instances(uv_pipe_t* handle, int count)
+
+ Set the number of pending pipe instance handles when the pipe server is
+ waiting for connections.
+
+ .. note::
+ This setting applies to Windows only.
+
+.. c:function:: int uv_pipe_pending_count(uv_pipe_t* handle)
+.. c:function:: uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle)
+
+ Used to receive handles over IPC pipes.
+
+ First - call :c:func:`uv_pipe_pending_count`, if it's > 0 then initialize
+ a handle of the given `type`, returned by :c:func:`uv_pipe_pending_type`
+ and call ``uv_accept(pipe, handle)``.
+
+.. seealso:: The :c:type:`uv_stream_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/poll.rst b/3rdparty/libuv/docs/src/poll.rst
new file mode 100644
index 00000000000..6dc41839ac1
--- /dev/null
+++ b/3rdparty/libuv/docs/src/poll.rst
@@ -0,0 +1,103 @@
+
+.. _poll:
+
+:c:type:`uv_poll_t` --- Poll handle
+===================================
+
+Poll handles are used to watch file descriptors for readability and
+writability, similar to the purpose of :man:`poll(2)`.
+
+The purpose of poll handles is to enable integrating external libraries that
+rely on the event loop to signal it about the socket status changes, like
+c-ares or libssh2. Using uv_poll_t for any other purpose is not recommended;
+:c:type:`uv_tcp_t`, :c:type:`uv_udp_t`, etc. provide an implementation that is faster and
+more scalable than what can be achieved with :c:type:`uv_poll_t`, especially on
+Windows.
+
+It is possible that poll handles occasionally signal that a file descriptor is
+readable or writable even when it isn't. The user should therefore always
+be prepared to handle EAGAIN or equivalent when it attempts to read from or
+write to the fd.
+
+It is not okay to have multiple active poll handles for the same socket, this
+can cause libuv to busyloop or otherwise malfunction.
+
+The user should not close a file descriptor while it is being polled by an
+active poll handle. This can cause the handle to report an error,
+but it might also start polling another socket. However the fd can be safely
+closed immediately after a call to :c:func:`uv_poll_stop` or :c:func:`uv_close`.
+
+.. note::
+ On windows only sockets can be polled with poll handles. On Unix any file
+ descriptor that would be accepted by :man:`poll(2)` can be used.
+
+
+Data types
+----------
+
+.. c:type:: uv_poll_t
+
+ Poll handle type.
+
+.. c:type:: void (*uv_poll_cb)(uv_poll_t* handle, int status, int events)
+
+ Type definition for callback passed to :c:func:`uv_poll_start`.
+
+.. c:type:: uv_poll_event
+
+ Poll event types
+
+ ::
+
+ enum uv_poll_event {
+ UV_READABLE = 1,
+ UV_WRITABLE = 2
+ };
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd)
+
+ Initialize the handle using a file descriptor.
+
+ .. versionchanged:: 1.2.2 the file descriptor is set to non-blocking mode.
+
+.. c:function:: int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, uv_os_sock_t socket)
+
+ Initialize the handle using a socket descriptor. On Unix this is identical
+ to :c:func:`uv_poll_init`. On windows it takes a SOCKET handle.
+
+ .. versionchanged:: 1.2.2 the socket is set to non-blocking mode.
+
+.. c:function:: int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb)
+
+ Starts polling the file descriptor. `events` is a bitmask consisting made up
+ of UV_READABLE and UV_WRITABLE. As soon as an event is detected the callback
+ will be called with `status` set to 0, and the detected events set on the
+ `events` field.
+
+ If an error happens while polling, `status` will be < 0 and corresponds
+ with one of the UV_E* error codes (see :ref:`errors`). The user should
+ not close the socket while the handle is active. If the user does that
+ anyway, the callback *may* be called reporting an error status, but this
+ is **not** guaranteed.
+
+ .. note::
+ Calling :c:func:`uv_poll_start` on a handle that is already active is fine. Doing so
+ will update the events mask that is being watched for.
+
+.. c:function:: int uv_poll_stop(uv_poll_t* poll)
+
+ Stop polling the file descriptor, the callback will no longer be called.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/prepare.rst b/3rdparty/libuv/docs/src/prepare.rst
new file mode 100644
index 00000000000..aca58155809
--- /dev/null
+++ b/3rdparty/libuv/docs/src/prepare.rst
@@ -0,0 +1,46 @@
+
+.. _prepare:
+
+:c:type:`uv_prepare_t` --- Prepare handle
+=========================================
+
+Prepare handles will run the given callback once per loop iteration, right
+before polling for i/o.
+
+
+Data types
+----------
+
+.. c:type:: uv_prepare_t
+
+ Prepare handle type.
+
+.. c:type:: void (*uv_prepare_cb)(uv_prepare_t* handle)
+
+ Type definition for callback passed to :c:func:`uv_prepare_start`.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_prepare_init(uv_loop_t* loop, uv_prepare_t* prepare)
+
+ Initialize the handle.
+
+.. c:function:: int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb)
+
+ Start the handle with the given callback.
+
+.. c:function:: int uv_prepare_stop(uv_prepare_t* prepare)
+
+ Stop the handle, the callback will no longer be called.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/process.rst b/3rdparty/libuv/docs/src/process.rst
new file mode 100644
index 00000000000..b0380ddfb72
--- /dev/null
+++ b/3rdparty/libuv/docs/src/process.rst
@@ -0,0 +1,225 @@
+
+.. _process:
+
+:c:type:`uv_process_t` --- Process handle
+=========================================
+
+Process handles will spawn a new process and allow the user to control it and
+establish communication channels with it using streams.
+
+
+Data types
+----------
+
+.. c:type:: uv_process_t
+
+ Process handle type.
+
+.. c:type:: uv_process_options_t
+
+ Options for spawning the process (passed to :c:func:`uv_spawn`.
+
+ ::
+
+ typedef struct uv_process_options_s {
+ uv_exit_cb exit_cb;
+ const char* file;
+ char** args;
+ char** env;
+ const char* cwd;
+ unsigned int flags;
+ int stdio_count;
+ uv_stdio_container_t* stdio;
+ uv_uid_t uid;
+ uv_gid_t gid;
+ } uv_process_options_t;
+
+.. c:type:: void (*uv_exit_cb)(uv_process_t*, int64_t exit_status, int term_signal)
+
+ Type definition for callback passed in :c:type:`uv_process_options_t` which
+ will indicate the exit status and the signal that caused the process to
+ terminate, if any.
+
+.. c:type:: uv_process_flags
+
+ Flags to be set on the flags field of :c:type:`uv_process_options_t`.
+
+ ::
+
+ enum uv_process_flags {
+ /*
+ * Set the child process' user id.
+ */
+ UV_PROCESS_SETUID = (1 << 0),
+ /*
+ * Set the child process' group id.
+ */
+ UV_PROCESS_SETGID = (1 << 1),
+ /*
+ * Do not wrap any arguments in quotes, or perform any other escaping, when
+ * converting the argument list into a command line string. This option is
+ * only meaningful on Windows systems. On Unix it is silently ignored.
+ */
+ UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (1 << 2),
+ /*
+ * Spawn the child process in a detached state - this will make it a process
+ * group leader, and will effectively enable the child to keep running after
+ * the parent exits. Note that the child process will still keep the
+ * parent's event loop alive unless the parent process calls uv_unref() on
+ * the child's process handle.
+ */
+ UV_PROCESS_DETACHED = (1 << 3),
+ /*
+ * Hide the subprocess console window that would normally be created. This
+ * option is only meaningful on Windows systems. On Unix it is silently
+ * ignored.
+ */
+ UV_PROCESS_WINDOWS_HIDE = (1 << 4)
+ };
+
+.. c:type:: uv_stdio_container_t
+
+ Container for each stdio handle or fd passed to a child process.
+
+ ::
+
+ typedef struct uv_stdio_container_s {
+ uv_stdio_flags flags;
+ union {
+ uv_stream_t* stream;
+ int fd;
+ } data;
+ } uv_stdio_container_t;
+
+.. c:type:: uv_stdio_flags
+
+ Flags specifying how a stdio should be transmitted to the child process.
+
+ ::
+
+ typedef enum {
+ UV_IGNORE = 0x00,
+ UV_CREATE_PIPE = 0x01,
+ UV_INHERIT_FD = 0x02,
+ UV_INHERIT_STREAM = 0x04,
+ /*
+ * When UV_CREATE_PIPE is specified, UV_READABLE_PIPE and UV_WRITABLE_PIPE
+ * determine the direction of flow, from the child process' perspective. Both
+ * flags may be specified to create a duplex data stream.
+ */
+ UV_READABLE_PIPE = 0x10,
+ UV_WRITABLE_PIPE = 0x20
+ } uv_stdio_flags;
+
+
+Public members
+^^^^^^^^^^^^^^
+
+.. c:member:: uv_process_t.pid
+
+ The PID of the spawned process. It's set after calling :c:func:`uv_spawn`.
+
+.. note::
+ The :c:type:`uv_handle_t` members also apply.
+
+.. c:member:: uv_process_options_t.exit_cb
+
+ Callback called after the process exits.
+
+.. c:member:: uv_process_options_t.file
+
+ Path pointing to the program to be executed.
+
+.. c:member:: uv_process_options_t.args
+
+ Command line arguments. args[0] should be the path to the program. On
+ Windows this uses `CreateProcess` which concatenates the arguments into a
+ string this can cause some strange errors. See the
+ ``UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS`` flag on :c:type:`uv_process_flags`.
+
+.. c:member:: uv_process_options_t.env
+
+ Environment for the new process. If NULL the parents environment is used.
+
+.. c:member:: uv_process_options_t.cwd
+
+ Current working directory for the subprocess.
+
+.. c:member:: uv_process_options_t.flags
+
+ Various flags that control how :c:func:`uv_spawn` behaves. See
+ :c:type:`uv_process_flags`.
+
+.. c:member:: uv_process_options_t.stdio_count
+.. c:member:: uv_process_options_t.stdio
+
+ The `stdio` field points to an array of :c:type:`uv_stdio_container_t`
+ structs that describe the file descriptors that will be made available to
+ the child process. The convention is that stdio[0] points to stdin,
+ fd 1 is used for stdout, and fd 2 is stderr.
+
+ .. note::
+ On Windows file descriptors greater than 2 are available to the child process only if
+ the child processes uses the MSVCRT runtime.
+
+.. c:member:: uv_process_options_t.uid
+.. c:member:: uv_process_options_t.gid
+
+ Libuv can change the child process' user/group id. This happens only when
+ the appropriate bits are set in the flags fields.
+
+ .. note::
+ This is not supported on Windows, :c:func:`uv_spawn` will fail and set the error
+ to ``UV_ENOTSUP``.
+
+.. c:member:: uv_stdio_container_t.flags
+
+ Flags specifying how the stdio container should be passed to the child. See
+ :c:type:`uv_stdio_flags`.
+
+.. c:member:: uv_stdio_container_t.data
+
+ Union containing either the stream or fd to be passed on to the child
+ process.
+
+
+API
+---
+
+.. c:function:: void uv_disable_stdio_inheritance(void)
+
+ Disables inheritance for file descriptors / handles that this process
+ inherited from its parent. The effect is that child processes spawned by
+ this process don't accidentally inherit these handles.
+
+ It is recommended to call this function as early in your program as possible,
+ before the inherited file descriptors can be closed or duplicated.
+
+ .. note::
+ This function works on a best-effort basis: there is no guarantee that libuv can discover
+ all file descriptors that were inherited. In general it does a better job on Windows than
+ it does on Unix.
+
+.. c:function:: int uv_spawn(uv_loop_t* loop, uv_process_t* handle, const uv_process_options_t* options)
+
+ Initializes the process handle and starts the process. If the process is
+ successfully spawned, this function will return 0. Otherwise, the
+ negative error code corresponding to the reason it couldn't spawn is
+ returned.
+
+ Possible reasons for failing to spawn would include (but not be limited to)
+ the file to execute not existing, not having permissions to use the setuid or
+ setgid specified, or not having enough memory to allocate for the new
+ process.
+
+.. c:function:: int uv_process_kill(uv_process_t* handle, int signum)
+
+ Sends the specified signal to the given process handle. Check the documentation
+ on :c:ref:`signal` for signal support, specially on Windows.
+
+.. c:function:: int uv_kill(int pid, int signum)
+
+ Sends the specified signal to the given PID. Check the documentation
+ on :c:ref:`signal` for signal support, specially on Windows.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/request.rst b/3rdparty/libuv/docs/src/request.rst
new file mode 100644
index 00000000000..660b80ae957
--- /dev/null
+++ b/3rdparty/libuv/docs/src/request.rst
@@ -0,0 +1,82 @@
+
+.. _request:
+
+:c:type:`uv_req_t` --- Base request
+===================================
+
+`uv_req_t` is the base type for all libuv request types.
+
+Structures are aligned so that any libuv request can be cast to `uv_req_t`.
+All API functions defined here work with any request type.
+
+
+Data types
+----------
+
+.. c:type:: uv_req_t
+
+ The base libuv request structure.
+
+.. c:type:: uv_any_req
+
+ Union of all request types.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+.. c:member:: void* uv_req_t.data
+
+ Space for user-defined arbitrary data. libuv does not use this field.
+
+.. c:member:: uv_req_type uv_req_t.type
+
+ Indicated the type of request. Readonly.
+
+ ::
+
+ typedef enum {
+ UV_UNKNOWN_REQ = 0,
+ UV_REQ,
+ UV_CONNECT,
+ UV_WRITE,
+ UV_SHUTDOWN,
+ UV_UDP_SEND,
+ UV_FS,
+ UV_WORK,
+ UV_GETADDRINFO,
+ UV_GETNAMEINFO,
+ UV_REQ_TYPE_PRIVATE,
+ UV_REQ_TYPE_MAX,
+ } uv_req_type;
+
+
+API
+---
+
+.. c:function:: int uv_cancel(uv_req_t* req)
+
+ Cancel a pending request. Fails if the request is executing or has finished
+ executing.
+
+ Returns 0 on success, or an error code < 0 on failure.
+
+ Only cancellation of :c:type:`uv_fs_t`, :c:type:`uv_getaddrinfo_t`,
+ :c:type:`uv_getnameinfo_t` and :c:type:`uv_work_t` requests is
+ currently supported.
+
+ Cancelled requests have their callbacks invoked some time in the future.
+ It's **not** safe to free the memory associated with the request until the
+ callback is called.
+
+ Here is how cancellation is reported to the callback:
+
+ * A :c:type:`uv_fs_t` request has its req->result field set to `UV_ECANCELED`.
+
+ * A :c:type:`uv_work_t`, :c:type:`uv_getaddrinfo_t` or c:type:`uv_getnameinfo_t`
+ request has its callback invoked with status == `UV_ECANCELED`.
+
+.. c:function:: size_t uv_req_size(uv_req_type type)
+
+ Returns the size of the given request type. Useful for FFI binding writers
+ who don't want to know the structure layout.
diff --git a/3rdparty/libuv/docs/src/signal.rst b/3rdparty/libuv/docs/src/signal.rst
new file mode 100644
index 00000000000..dc1223b90ac
--- /dev/null
+++ b/3rdparty/libuv/docs/src/signal.rst
@@ -0,0 +1,77 @@
+
+.. _signal:
+
+:c:type:`uv_signal_t` --- Signal handle
+=======================================
+
+Signal handles implement Unix style signal handling on a per-event loop bases.
+
+Reception of some signals is emulated on Windows:
+
+* SIGINT is normally delivered when the user presses CTRL+C. However, like
+ on Unix, it is not generated when terminal raw mode is enabled.
+
+* SIGBREAK is delivered when the user pressed CTRL + BREAK.
+
+* SIGHUP is generated when the user closes the console window. On SIGHUP the
+ program is given approximately 10 seconds to perform cleanup. After that
+ Windows will unconditionally terminate it.
+
+* SIGWINCH is raised whenever libuv detects that the console has been
+ resized. SIGWINCH is emulated by libuv when the program uses a :c:type:`uv_tty_t`
+ handle to write to the console. SIGWINCH may not always be delivered in a
+ timely manner; libuv will only detect size changes when the cursor is
+ being moved. When a readable :c:type:`uv_tty_t` handle is used in raw mode,
+ resizing the console buffer will also trigger a SIGWINCH signal.
+
+Watchers for other signals can be successfully created, but these signals
+are never received. These signals are: `SIGILL`, `SIGABRT`, `SIGFPE`, `SIGSEGV`,
+`SIGTERM` and `SIGKILL.`
+
+Calls to raise() or abort() to programmatically raise a signal are
+not detected by libuv; these will not trigger a signal watcher.
+
+.. note::
+ On Linux SIGRT0 and SIGRT1 (signals 32 and 33) are used by the NPTL pthreads library to
+ manage threads. Installing watchers for those signals will lead to unpredictable behavior
+ and is strongly discouraged. Future versions of libuv may simply reject them.
+
+
+Data types
+----------
+
+.. c:type:: uv_signal_t
+
+ Signal handle type.
+
+.. c:type:: void (*uv_signal_cb)(uv_signal_t* handle, int signum)
+
+ Type definition for callback passed to :c:func:`uv_signal_start`.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+.. c:member:: int uv_signal_t.signum
+
+ Signal being monitored by this handle. Readonly.
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_signal_init(uv_loop_t* loop, uv_signal_t* signal)
+
+ Initialize the handle.
+
+.. c:function:: int uv_signal_start(uv_signal_t* signal, uv_signal_cb cb, int signum)
+
+ Start the handle with the given callback, watching for the given signal.
+
+.. c:function:: int uv_signal_stop(uv_signal_t* signal)
+
+ Stop the handle, the callback will no longer be called.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/sphinx-plugins/manpage.py b/3rdparty/libuv/docs/src/sphinx-plugins/manpage.py
new file mode 100644
index 00000000000..1d1dc379f41
--- /dev/null
+++ b/3rdparty/libuv/docs/src/sphinx-plugins/manpage.py
@@ -0,0 +1,46 @@
+# encoding: utf-8
+
+#
+# Copyright (c) 2013 Dariusz Dwornikowski. All rights reserved.
+#
+# Adapted from https://github.com/tdi/sphinxcontrib-manpage
+# License: Apache 2
+#
+
+
+import re
+
+from docutils import nodes, utils
+from docutils.parsers.rst.roles import set_classes
+from string import Template
+
+
+def make_link_node(rawtext, app, name, manpage_num, options):
+ ref = app.config.man_url_regex
+ if not ref:
+ ref = "http://linux.die.net/man/%s/%s" % (manpage_num, name)
+ else:
+ s = Template(ref)
+ ref = s.substitute(num=manpage_num, topic=name)
+ set_classes(options)
+ node = nodes.reference(rawtext, "%s(%s)" % (name, manpage_num), refuri=ref, **options)
+ return node
+
+
+def man_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
+ app = inliner.document.settings.env.app
+ p = re.compile("([a-zA-Z0-9_\.-_]+)\((\d)\)")
+ m = p.match(text)
+
+ manpage_num = m.group(2)
+ name = m.group(1)
+ node = make_link_node(rawtext, app, name, manpage_num, options)
+ return [node], []
+
+
+def setup(app):
+ app.info('Initializing manpage plugin')
+ app.add_role('man', man_role)
+ app.add_config_value('man_url_regex', None, 'env')
+ return
+
diff --git a/3rdparty/libuv/docs/src/static/architecture.png b/3rdparty/libuv/docs/src/static/architecture.png
new file mode 100644
index 00000000000..81e8749f249
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/architecture.png
Binary files differ
diff --git a/3rdparty/libuv/docs/src/static/diagrams.key/Data/st0-311.jpg b/3rdparty/libuv/docs/src/static/diagrams.key/Data/st0-311.jpg
new file mode 100644
index 00000000000..439f5810936
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/diagrams.key/Data/st0-311.jpg
Binary files differ
diff --git a/3rdparty/libuv/docs/src/static/diagrams.key/Data/st1-475.jpg b/3rdparty/libuv/docs/src/static/diagrams.key/Data/st1-475.jpg
new file mode 100644
index 00000000000..ffb21ff2245
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/diagrams.key/Data/st1-475.jpg
Binary files differ
diff --git a/3rdparty/libuv/docs/src/static/diagrams.key/Index.zip b/3rdparty/libuv/docs/src/static/diagrams.key/Index.zip
new file mode 100644
index 00000000000..17aedace14f
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/diagrams.key/Index.zip
Binary files differ
diff --git a/3rdparty/libuv/docs/src/static/diagrams.key/Metadata/BuildVersionHistory.plist b/3rdparty/libuv/docs/src/static/diagrams.key/Metadata/BuildVersionHistory.plist
new file mode 100644
index 00000000000..39dd4fe62fb
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/diagrams.key/Metadata/BuildVersionHistory.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<array>
+ <string>Template: White (2014-02-28 09:41)</string>
+ <string>M6.2.2-1878-1</string>
+</array>
+</plist>
diff --git a/3rdparty/libuv/docs/src/static/diagrams.key/Metadata/DocumentIdentifier b/3rdparty/libuv/docs/src/static/diagrams.key/Metadata/DocumentIdentifier
new file mode 100644
index 00000000000..ddb18f01f99
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/diagrams.key/Metadata/DocumentIdentifier
@@ -0,0 +1 @@
+F69E9CD9-EEF1-4223-9DA4-A1EA7FE112BA \ No newline at end of file
diff --git a/3rdparty/libuv/docs/src/static/diagrams.key/Metadata/Properties.plist b/3rdparty/libuv/docs/src/static/diagrams.key/Metadata/Properties.plist
new file mode 100644
index 00000000000..74bc69317de
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/diagrams.key/Metadata/Properties.plist
Binary files differ
diff --git a/3rdparty/libuv/docs/src/static/diagrams.key/preview-micro.jpg b/3rdparty/libuv/docs/src/static/diagrams.key/preview-micro.jpg
new file mode 100644
index 00000000000..dd8decd6303
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/diagrams.key/preview-micro.jpg
Binary files differ
diff --git a/3rdparty/libuv/docs/src/static/diagrams.key/preview-web.jpg b/3rdparty/libuv/docs/src/static/diagrams.key/preview-web.jpg
new file mode 100644
index 00000000000..aadd401f1f0
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/diagrams.key/preview-web.jpg
Binary files differ
diff --git a/3rdparty/libuv/docs/src/static/diagrams.key/preview.jpg b/3rdparty/libuv/docs/src/static/diagrams.key/preview.jpg
new file mode 100644
index 00000000000..fc80025a4be
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/diagrams.key/preview.jpg
Binary files differ
diff --git a/3rdparty/libuv/docs/src/static/favicon.ico b/3rdparty/libuv/docs/src/static/favicon.ico
new file mode 100644
index 00000000000..2c40694cd28
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/favicon.ico
Binary files differ
diff --git a/3rdparty/libuv/docs/src/static/logo.png b/3rdparty/libuv/docs/src/static/logo.png
new file mode 100644
index 00000000000..eaf1eee577b
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/logo.png
Binary files differ
diff --git a/3rdparty/libuv/docs/src/static/loop_iteration.png b/3rdparty/libuv/docs/src/static/loop_iteration.png
new file mode 100644
index 00000000000..e769cf338b4
--- /dev/null
+++ b/3rdparty/libuv/docs/src/static/loop_iteration.png
Binary files differ
diff --git a/3rdparty/libuv/docs/src/stream.rst b/3rdparty/libuv/docs/src/stream.rst
new file mode 100644
index 00000000000..9f0aacd1643
--- /dev/null
+++ b/3rdparty/libuv/docs/src/stream.rst
@@ -0,0 +1,219 @@
+
+.. _stream:
+
+:c:type:`uv_stream_t` --- Stream handle
+=======================================
+
+Stream handles provide an abstraction of a duplex communication channel.
+:c:type:`uv_stream_t` is an abstract type, libuv provides 3 stream implementations
+in the for of :c:type:`uv_tcp_t`, :c:type:`uv_pipe_t` and :c:type:`uv_tty_t`.
+
+
+Data types
+----------
+
+.. c:type:: uv_stream_t
+
+ Stream handle type.
+
+.. c:type:: uv_connect_t
+
+ Connect request type.
+
+.. c:type:: uv_shutdown_t
+
+ Shutdown request type.
+
+.. c:type:: uv_write_t
+
+ Write request type.
+
+.. c:type:: void (*uv_read_cb)(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
+
+ Callback called when data was read on a stream.
+
+ `nread` is > 0 if there is data available or < 0 on error. When we've
+ reached EOF, `nread` will be set to ``UV_EOF``. When `nread` < 0,
+ the `buf` parameter might not point to a valid buffer; in that case
+ `buf.len` and `buf.base` are both set to 0.
+
+ .. note::
+ `nread` might be 0, which does *not* indicate an error or EOF. This
+ is equivalent to ``EAGAIN`` or ``EWOULDBLOCK`` under ``read(2)``.
+
+ The callee is responsible for stopping closing the stream when an error happens
+ by calling :c:func:`uv_read_stop` or :c:func:`uv_close`. Trying to read
+ from the stream again is undefined.
+
+ The callee is responsible for freeing the buffer, libuv does not reuse it.
+ The buffer may be a null buffer (where buf->base=NULL and buf->len=0) on
+ error.
+
+.. c:type:: void (*uv_write_cb)(uv_write_t* req, int status)
+
+ Callback called after data was written on a stream. `status` will be 0 in
+ case of success, < 0 otherwise.
+
+.. c:type:: void (*uv_connect_cb)(uv_connect_t* req, int status)
+
+ Callback called after a connection started by :c:func:`uv_connect` is done.
+ `status` will be 0 in case of success, < 0 otherwise.
+
+.. c:type:: void (*uv_shutdown_cb)(uv_shutdown_t* req, int status)
+
+ Callback called after s shutdown request has been completed. `status` will
+ be 0 in case of success, < 0 otherwise.
+
+.. c:type:: void (*uv_connection_cb)(uv_stream_t* server, int status)
+
+ Callback called when a stream server has received an incoming connection.
+ The user can accept the connection by calling :c:func:`uv_accept`.
+ `status` will be 0 in case of success, < 0 otherwise.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+.. c:member:: size_t uv_stream_t.write_queue_size
+
+ Contains the amount of queued bytes waiting to be sent. Readonly.
+
+.. c:member:: uv_stream_t* uv_connect_t.handle
+
+ Pointer to the stream where this connection request is running.
+
+.. c:member:: uv_stream_t* uv_shutdown_t.handle
+
+ Pointer to the stream where this shutdown request is running.
+
+.. c:member:: uv_stream_t* uv_write_t.handle
+
+ Pointer to the stream where this write request is running.
+
+.. c:member:: uv_stream_t* uv_write_t.send_handle
+
+ Pointer to the stream being sent using this write request..
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb)
+
+ Shutdown the outgoing (write) side of a duplex stream. It waits for pending
+ write requests to complete. The `handle` should refer to a initialized stream.
+ `req` should be an uninitialized shutdown request struct. The `cb` is called
+ after shutdown is complete.
+
+.. c:function:: int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb)
+
+ Start listening for incoming connections. `backlog` indicates the number of
+ connections the kernel might queue, same as :man:`listen(2)`. When a new
+ incoming connection is received the :c:type:`uv_connection_cb` callback is
+ called.
+
+.. c:function:: int uv_accept(uv_stream_t* server, uv_stream_t* client)
+
+ This call is used in conjunction with :c:func:`uv_listen` to accept incoming
+ connections. Call this function after receiving a :c:type:`uv_connection_cb`
+ to accept the connection. Before calling this function the client handle must
+ be initialized. < 0 return value indicates an error.
+
+ When the :c:type:`uv_connection_cb` callback is called it is guaranteed that
+ this function will complete successfully the first time. If you attempt to use
+ it more than once, it may fail. It is suggested to only call this function once
+ per :c:type:`uv_connection_cb` call.
+
+ .. note::
+ `server` and `client` must be handles running on the same loop.
+
+.. c:function:: int uv_read_start(uv_stream_t* stream, uv_alloc_cb alloc_cb, uv_read_cb read_cb)
+
+ Read data from an incoming stream. The :c:type:`uv_read_cb` callback will
+ be made several times until there is no more data to read or
+ :c:func:`uv_read_stop` is called.
+
+.. c:function:: int uv_read_stop(uv_stream_t*)
+
+ Stop reading data from the stream. The :c:type:`uv_read_cb` callback will
+ no longer be called.
+
+ This function is idempotent and may be safely called on a stopped stream.
+
+.. c:function:: int uv_write(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb)
+
+ Write data to stream. Buffers are written in order. Example:
+
+ ::
+
+ uv_buf_t a[] = {
+ { .base = "1", .len = 1 },
+ { .base = "2", .len = 1 }
+ };
+
+ uv_buf_t b[] = {
+ { .base = "3", .len = 1 },
+ { .base = "4", .len = 1 }
+ };
+
+ uv_write_t req1;
+ uv_write_t req2;
+
+ /* writes "1234" */
+ uv_write(&req1, stream, a, 2);
+ uv_write(&req2, stream, b, 2);
+
+.. c:function:: int uv_write2(uv_write_t* req, uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle, uv_write_cb cb)
+
+ Extended write function for sending handles over a pipe. The pipe must be
+ initialized with `ipc` == 1.
+
+ .. note::
+ `send_handle` must be a TCP socket or pipe, which is a server or a connection (listening
+ or connected state). Bound sockets or pipes will be assumed to be servers.
+
+.. c:function:: int uv_try_write(uv_stream_t* handle, const uv_buf_t bufs[], unsigned int nbufs)
+
+ Same as :c:func:`uv_write`, but won't queue a write request if it can't be
+ completed immediately.
+
+ Will return either:
+
+ * > 0: number of bytes written (can be less than the supplied buffer size).
+ * < 0: negative error code (``UV_EAGAIN`` is returned if no data can be sent
+ immediately).
+
+.. c:function:: int uv_is_readable(const uv_stream_t* handle)
+
+ Returns 1 if the stream is readable, 0 otherwise.
+
+.. c:function:: int uv_is_writable(const uv_stream_t* handle)
+
+ Returns 1 if the stream is writable, 0 otherwise.
+
+.. c:function:: int uv_stream_set_blocking(uv_stream_t* handle, int blocking)
+
+ Enable or disable blocking mode for a stream.
+
+ When blocking mode is enabled all writes complete synchronously. The
+ interface remains unchanged otherwise, e.g. completion or failure of the
+ operation will still be reported through a callback which is made
+ asynchronously.
+
+ .. warning::
+ Relying too much on this API is not recommended. It is likely to change
+ significantly in the future.
+
+ Currently only works on Windows for :c:type:`uv_pipe_t` handles.
+ On UNIX platforms, all :c:type:`uv_stream_t` handles are supported.
+
+ Also libuv currently makes no ordering guarantee when the blocking mode
+ is changed after write requests have already been submitted. Therefore it is
+ recommended to set the blocking mode immediately after opening or creating
+ the stream.
+
+ .. versionchanged:: 1.4.0 UNIX implementation added.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/tcp.rst b/3rdparty/libuv/docs/src/tcp.rst
new file mode 100644
index 00000000000..ca0c9b4ac5a
--- /dev/null
+++ b/3rdparty/libuv/docs/src/tcp.rst
@@ -0,0 +1,108 @@
+
+.. _tcp:
+
+:c:type:`uv_tcp_t` --- TCP handle
+=================================
+
+TCP handles are used to represent both TCP streams and servers.
+
+:c:type:`uv_tcp_t` is a 'subclass' of :c:type:`uv_stream_t`.
+
+
+Data types
+----------
+
+.. c:type:: uv_tcp_t
+
+ TCP handle type.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_stream_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle)
+
+ Initialize the handle. No socket is created as of yet.
+
+.. c:function:: int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags)
+
+ Initialize the handle with the specified flags. At the moment only the lower 8 bits
+ of the `flags` parameter are used as the socket domain. A socket will be created
+ for the given domain. If the specified domain is ``AF_UNSPEC`` no socket is created,
+ just like :c:func:`uv_tcp_init`.
+
+ .. versionadded:: 1.7.0
+
+.. c:function:: int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock)
+
+ Open an existing file descriptor or SOCKET as a TCP handle.
+
+ .. versionchanged:: 1.2.1 the file descriptor is set to non-blocking mode.
+
+ .. note::
+ The passed file descriptor or SOCKET is not checked for its type, but
+ it's required that it represents a valid stream socket.
+
+.. c:function:: int uv_tcp_nodelay(uv_tcp_t* handle, int enable)
+
+ Enable / disable Nagle's algorithm.
+
+.. c:function:: int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay)
+
+ Enable / disable TCP keep-alive. `delay` is the initial delay in seconds,
+ ignored when `enable` is zero.
+
+.. c:function:: int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable)
+
+ Enable / disable simultaneous asynchronous accept requests that are
+ queued by the operating system when listening for new TCP connections.
+
+ This setting is used to tune a TCP server for the desired performance.
+ Having simultaneous accepts can significantly improve the rate of accepting
+ connections (which is why it is enabled by default) but may lead to uneven
+ load distribution in multi-process setups.
+
+.. c:function:: int uv_tcp_bind(uv_tcp_t* handle, const struct sockaddr* addr, unsigned int flags)
+
+ Bind the handle to an address and port. `addr` should point to an
+ initialized ``struct sockaddr_in`` or ``struct sockaddr_in6``.
+
+ When the port is already taken, you can expect to see an ``UV_EADDRINUSE``
+ error from either :c:func:`uv_tcp_bind`, :c:func:`uv_listen` or
+ :c:func:`uv_tcp_connect`. That is, a successful call to this function does
+ not guarantee that the call to :c:func:`uv_listen` or :c:func:`uv_tcp_connect`
+ will succeed as well.
+
+ `flags` can contain ``UV_TCP_IPV6ONLY``, in which case dual-stack support
+ is disabled and only IPv6 is used.
+
+.. c:function:: int uv_tcp_getsockname(const uv_tcp_t* handle, struct sockaddr* name, int* namelen)
+
+ Get the current address to which the handle is bound. `addr` must point to
+ a valid and big enough chunk of memory, ``struct sockaddr_storage`` is
+ recommended for IPv4 and IPv6 support.
+
+.. c:function:: int uv_tcp_getpeername(const uv_tcp_t* handle, struct sockaddr* name, int* namelen)
+
+ Get the address of the peer connected to the handle. `addr` must point to
+ a valid and big enough chunk of memory, ``struct sockaddr_storage`` is
+ recommended for IPv4 and IPv6 support.
+
+.. c:function:: int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle, const struct sockaddr* addr, uv_connect_cb cb)
+
+ Establish an IPv4 or IPv6 TCP connection. Provide an initialized TCP handle
+ and an uninitialized :c:type:`uv_connect_t`. `addr` should point to an
+ initialized ``struct sockaddr_in`` or ``struct sockaddr_in6``.
+
+ The callback is made when the connection has been established or when a
+ connection error happened.
+
+.. seealso:: The :c:type:`uv_stream_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/threading.rst b/3rdparty/libuv/docs/src/threading.rst
new file mode 100644
index 00000000000..e876dde1256
--- /dev/null
+++ b/3rdparty/libuv/docs/src/threading.rst
@@ -0,0 +1,160 @@
+
+.. _threading:
+
+Threading and synchronization utilities
+=======================================
+
+libuv provides cross-platform implementations for multiple threading and
+synchronization primitives. The API largely follows the pthreads API.
+
+
+Data types
+----------
+
+.. c:type:: uv_thread_t
+
+ Thread data type.
+
+.. c:type:: void (*uv_thread_cb)(void* arg)
+
+ Callback that is invoked to initialize thread execution. `arg` is the same
+ value that was passed to :c:func:`uv_thread_create`.
+
+.. c:type:: uv_key_t
+
+ Thread-local key data type.
+
+.. c:type:: uv_once_t
+
+ Once-only initializer data type.
+
+.. c:type:: uv_mutex_t
+
+ Mutex data type.
+
+.. c:type:: uv_rwlock_t
+
+ Read-write lock data type.
+
+.. c:type:: uv_sem_t
+
+ Semaphore data type.
+
+.. c:type:: uv_cond_t
+
+ Condition data type.
+
+.. c:type:: uv_barrier_t
+
+ Barrier data type.
+
+
+API
+---
+
+Threads
+^^^^^^^
+
+.. c:function:: int uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg)
+
+ .. versionchanged:: 1.4.1 returns a UV_E* error code on failure
+
+.. c:function:: uv_thread_t uv_thread_self(void)
+.. c:function:: int uv_thread_join(uv_thread_t *tid)
+.. c:function:: int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2)
+
+Thread-local storage
+^^^^^^^^^^^^^^^^^^^^
+
+.. note::
+ The total thread-local storage size may be limited. That is, it may not be possible to
+ create many TLS keys.
+
+.. c:function:: int uv_key_create(uv_key_t* key)
+.. c:function:: void uv_key_delete(uv_key_t* key)
+.. c:function:: void* uv_key_get(uv_key_t* key)
+.. c:function:: void uv_key_set(uv_key_t* key, void* value)
+
+Once-only initialization
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Runs a function once and only once. Concurrent calls to :c:func:`uv_once` with the
+same guard will block all callers except one (it's unspecified which one).
+The guard should be initialized statically with the UV_ONCE_INIT macro.
+
+.. c:function:: void uv_once(uv_once_t* guard, void (*callback)(void))
+
+Mutex locks
+^^^^^^^^^^^
+
+Functions return 0 on success or an error code < 0 (unless the
+return type is void, of course).
+
+.. c:function:: int uv_mutex_init(uv_mutex_t* handle)
+.. c:function:: void uv_mutex_destroy(uv_mutex_t* handle)
+.. c:function:: void uv_mutex_lock(uv_mutex_t* handle)
+.. c:function:: int uv_mutex_trylock(uv_mutex_t* handle)
+.. c:function:: void uv_mutex_unlock(uv_mutex_t* handle)
+
+Read-write locks
+^^^^^^^^^^^^^^^^
+
+Functions return 0 on success or an error code < 0 (unless the
+return type is void, of course).
+
+.. c:function:: int uv_rwlock_init(uv_rwlock_t* rwlock)
+.. c:function:: void uv_rwlock_destroy(uv_rwlock_t* rwlock)
+.. c:function:: void uv_rwlock_rdlock(uv_rwlock_t* rwlock)
+.. c:function:: int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock)
+.. c:function:: void uv_rwlock_rdunlock(uv_rwlock_t* rwlock)
+.. c:function:: void uv_rwlock_wrlock(uv_rwlock_t* rwlock)
+.. c:function:: int uv_rwlock_trywrlock(uv_rwlock_t* rwlock)
+.. c:function:: void uv_rwlock_wrunlock(uv_rwlock_t* rwlock)
+
+Semaphores
+^^^^^^^^^^
+
+Functions return 0 on success or an error code < 0 (unless the
+return type is void, of course).
+
+.. c:function:: int uv_sem_init(uv_sem_t* sem, unsigned int value)
+.. c:function:: void uv_sem_destroy(uv_sem_t* sem)
+.. c:function:: void uv_sem_post(uv_sem_t* sem)
+.. c:function:: void uv_sem_wait(uv_sem_t* sem)
+.. c:function:: int uv_sem_trywait(uv_sem_t* sem)
+
+Conditions
+^^^^^^^^^^
+
+Functions return 0 on success or an error code < 0 (unless the
+return type is void, of course).
+
+.. note::
+ Callers should be prepared to deal with spurious wakeups on :c:func:`uv_cond_wait` and
+ :c:func:`uv_cond_timedwait`.
+
+.. c:function:: int uv_cond_init(uv_cond_t* cond)
+.. c:function:: void uv_cond_destroy(uv_cond_t* cond)
+.. c:function:: void uv_cond_signal(uv_cond_t* cond)
+.. c:function:: void uv_cond_broadcast(uv_cond_t* cond)
+.. c:function:: void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex)
+.. c:function:: int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout)
+
+Barriers
+^^^^^^^^
+
+Functions return 0 on success or an error code < 0 (unless the
+return type is void, of course).
+
+.. note::
+ :c:func:`uv_barrier_wait` returns a value > 0 to an arbitrarily chosen "serializer" thread
+ to facilitate cleanup, i.e.
+
+ ::
+
+ if (uv_barrier_wait(&barrier) > 0)
+ uv_barrier_destroy(&barrier);
+
+.. c:function:: int uv_barrier_init(uv_barrier_t* barrier, unsigned int count)
+.. c:function:: void uv_barrier_destroy(uv_barrier_t* barrier)
+.. c:function:: int uv_barrier_wait(uv_barrier_t* barrier)
diff --git a/3rdparty/libuv/docs/src/threadpool.rst b/3rdparty/libuv/docs/src/threadpool.rst
new file mode 100644
index 00000000000..18949507e75
--- /dev/null
+++ b/3rdparty/libuv/docs/src/threadpool.rst
@@ -0,0 +1,67 @@
+
+.. _threadpool:
+
+Thread pool work scheduling
+===========================
+
+libuv provides a threadpool which can be used to run user code and get notified
+in the loop thread. This thread pool is internally used to run all filesystem
+operations, as well as getaddrinfo and getnameinfo requests.
+
+Its default size is 4, but it can be changed at startup time by setting the
+``UV_THREADPOOL_SIZE`` environment variable to any value (the absolute maximum
+is 128).
+
+The threadpool is global and shared across all event loops. When a particular
+function makes use of the threadpool (i.e. when using :c:func:`uv_queue_work`)
+libuv preallocates and initializes the maximum number of threads allowed by
+``UV_THREADPOOL_SIZE``. This causes a relatively minor memory overhead
+(~1MB for 128 threads) but increases the performance of threading at runtime.
+
+.. note::
+ Note that even though a global thread pool which is shared across all events
+ loops is used, the functions are not thread safe.
+
+
+Data types
+----------
+
+.. c:type:: uv_work_t
+
+ Work request type.
+
+.. c:type:: void (*uv_work_cb)(uv_work_t* req)
+
+ Callback passed to :c:func:`uv_queue_work` which will be run on the thread
+ pool.
+
+.. c:type:: void (*uv_after_work_cb)(uv_work_t* req, int status)
+
+ Callback passed to :c:func:`uv_queue_work` which will be called on the loop
+ thread after the work on the threadpool has been completed. If the work
+ was cancelled using :c:func:`uv_cancel` `status` will be ``UV_ECANCELED``.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+.. c:member:: uv_loop_t* uv_work_t.loop
+
+ Loop that started this request and where completion will be reported.
+ Readonly.
+
+.. seealso:: The :c:type:`uv_req_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_queue_work(uv_loop_t* loop, uv_work_t* req, uv_work_cb work_cb, uv_after_work_cb after_work_cb)
+
+ Initializes a work request which will run the given `work_cb` in a thread
+ from the threadpool. Once `work_cb` is completed, `after_work_cb` will be
+ called on the loop thread.
+
+ This request can be cancelled with :c:func:`uv_cancel`.
+
+.. seealso:: The :c:type:`uv_req_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/timer.rst b/3rdparty/libuv/docs/src/timer.rst
new file mode 100644
index 00000000000..31d733efc39
--- /dev/null
+++ b/3rdparty/libuv/docs/src/timer.rst
@@ -0,0 +1,76 @@
+
+.. _timer:
+
+:c:type:`uv_timer_t` --- Timer handle
+=====================================
+
+Timer handles are used to schedule callbacks to be called in the future.
+
+
+Data types
+----------
+
+.. c:type:: uv_timer_t
+
+ Timer handle type.
+
+.. c:type:: void (*uv_timer_cb)(uv_timer_t* handle)
+
+ Type definition for callback passed to :c:func:`uv_timer_start`.
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle)
+
+ Initialize the handle.
+
+.. c:function:: int uv_timer_start(uv_timer_t* handle, uv_timer_cb cb, uint64_t timeout, uint64_t repeat)
+
+ Start the timer. `timeout` and `repeat` are in milliseconds.
+
+ If `timeout` is zero, the callback fires on the next event loop iteration.
+ If `repeat` is non-zero, the callback fires first after `timeout`
+ milliseconds and then repeatedly after `repeat` milliseconds.
+
+.. c:function:: int uv_timer_stop(uv_timer_t* handle)
+
+ Stop the timer, the callback will not be called anymore.
+
+.. c:function:: int uv_timer_again(uv_timer_t* handle)
+
+ Stop the timer, and if it is repeating restart it using the repeat value
+ as the timeout. If the timer has never been started before it returns
+ UV_EINVAL.
+
+.. c:function:: void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat)
+
+ Set the repeat interval value in milliseconds. The timer will be scheduled
+ to run on the given interval, regardless of the callback execution
+ duration, and will follow normal timer semantics in the case of a
+ time-slice overrun.
+
+ For example, if a 50ms repeating timer first runs for 17ms, it will be
+ scheduled to run again 33ms later. If other tasks consume more than the
+ 33ms following the first timer callback, then the callback will run as soon
+ as possible.
+
+ .. note::
+ If the repeat value is set from a timer callback it does not immediately take effect.
+ If the timer was non-repeating before, it will have been stopped. If it was repeating,
+ then the old repeat value will have been used to schedule the next timeout.
+
+.. c:function:: uint64_t uv_timer_get_repeat(const uv_timer_t* handle)
+
+ Get the timer repeat value.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/tty.rst b/3rdparty/libuv/docs/src/tty.rst
new file mode 100644
index 00000000000..655dca9ca20
--- /dev/null
+++ b/3rdparty/libuv/docs/src/tty.rst
@@ -0,0 +1,93 @@
+
+.. _tty:
+
+:c:type:`uv_tty_t` --- TTY handle
+=================================
+
+TTY handles represent a stream for the console.
+
+:c:type:`uv_tty_t` is a 'subclass' of :c:type:`uv_stream_t`.
+
+
+Data types
+----------
+
+.. c:type:: uv_tty_t
+
+ TTY handle type.
+
+.. c:type:: uv_tty_mode_t
+
+ .. versionadded:: 1.2.0
+
+ TTY mode type:
+
+ ::
+
+ typedef enum {
+ /* Initial/normal terminal mode */
+ UV_TTY_MODE_NORMAL,
+ /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */
+ UV_TTY_MODE_RAW,
+ /* Binary-safe I/O mode for IPC (Unix-only) */
+ UV_TTY_MODE_IO
+ } uv_tty_mode_t;
+
+
+
+Public members
+^^^^^^^^^^^^^^
+
+N/A
+
+.. seealso:: The :c:type:`uv_stream_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_tty_init(uv_loop_t* loop, uv_tty_t* handle, uv_file fd, int readable)
+
+ Initialize a new TTY stream with the given file descriptor. Usually the
+ file descriptor will be:
+
+ * 0 = stdin
+ * 1 = stdout
+ * 2 = stderr
+
+ `readable`, specifies if you plan on calling :c:func:`uv_read_start` with
+ this stream. stdin is readable, stdout is not.
+
+ On Unix this function will try to open ``/dev/tty`` and use it if the passed
+ file descriptor refers to a TTY. This lets libuv put the tty in non-blocking
+ mode without affecting other processes that share the tty.
+
+ .. note::
+ If opening ``/dev/tty`` fails, libuv falls back to blocking writes for
+ non-readable TTY streams.
+
+ .. versionchanged:: 1.5.0: trying to initialize a TTY stream with a file
+ descriptor that refers to a file returns `UV_EINVAL`
+ on UNIX.
+
+.. c:function:: int uv_tty_set_mode(uv_tty_t* handle, uv_tty_mode_t mode)
+
+ .. versionchanged:: 1.2.0: the mode is specified as a
+ :c:type:`uv_tty_mode_t` value.
+
+ Set the TTY using the specified terminal mode.
+
+.. c:function:: int uv_tty_reset_mode(void)
+
+ To be called when the program exits. Resets TTY settings to default
+ values for the next process to take over.
+
+ This function is async signal-safe on Unix platforms but can fail with error
+ code ``UV_EBUSY`` if you call it when execution is inside
+ :c:func:`uv_tty_set_mode`.
+
+.. c:function:: int uv_tty_get_winsize(uv_tty_t* handle, int* width, int* height)
+
+ Gets the current Window size. On success it returns 0.
+
+.. seealso:: The :c:type:`uv_stream_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/udp.rst b/3rdparty/libuv/docs/src/udp.rst
new file mode 100644
index 00000000000..dd46603394e
--- /dev/null
+++ b/3rdparty/libuv/docs/src/udp.rst
@@ -0,0 +1,295 @@
+
+.. _udp:
+
+:c:type:`uv_udp_t` --- UDP handle
+=================================
+
+UDP handles encapsulate UDP communication for both clients and servers.
+
+
+Data types
+----------
+
+.. c:type:: uv_udp_t
+
+ UDP handle type.
+
+.. c:type:: uv_udp_send_t
+
+ UDP send request type.
+
+.. c:type:: uv_udp_flags
+
+ Flags used in :c:func:`uv_udp_bind` and :c:type:`uv_udp_recv_cb`..
+
+ ::
+
+ enum uv_udp_flags {
+ /* Disables dual stack mode. */
+ UV_UDP_IPV6ONLY = 1,
+ /*
+ * Indicates message was truncated because read buffer was too small. The
+ * remainder was discarded by the OS. Used in uv_udp_recv_cb.
+ */
+ UV_UDP_PARTIAL = 2,
+ /*
+ * Indicates if SO_REUSEADDR will be set when binding the handle in
+ * uv_udp_bind.
+ * This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other
+ * Unix platforms, it sets the SO_REUSEADDR flag. What that means is that
+ * multiple threads or processes can bind to the same address without error
+ * (provided they all set the flag) but only the last one to bind will receive
+ * any traffic, in effect "stealing" the port from the previous listener.
+ */
+ UV_UDP_REUSEADDR = 4
+ };
+
+.. c:type:: void (*uv_udp_send_cb)(uv_udp_send_t* req, int status)
+
+ Type definition for callback passed to :c:func:`uv_udp_send`, which is
+ called after the data was sent.
+
+.. c:type:: void (*uv_udp_recv_cb)(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags)
+
+ Type definition for callback passed to :c:func:`uv_udp_recv_start`, which
+ is called when the endpoint receives data.
+
+ * `handle`: UDP handle
+ * `nread`: Number of bytes that have been received.
+ 0 if there is no more data to read. You may discard or repurpose
+ the read buffer. Note that 0 may also mean that an empty datagram
+ was received (in this case `addr` is not NULL). < 0 if a transmission
+ error was detected.
+ * `buf`: :c:type:`uv_buf_t` with the received data.
+ * `addr`: ``struct sockaddr*`` containing the address of the sender.
+ Can be NULL. Valid for the duration of the callback only.
+ * `flags`: One or more or'ed UV_UDP_* constants. Right now only
+ ``UV_UDP_PARTIAL`` is used.
+
+ .. note::
+ The receive callback will be called with `nread` == 0 and `addr` == NULL when there is
+ nothing to read, and with `nread` == 0 and `addr` != NULL when an empty UDP packet is
+ received.
+
+.. c:type:: uv_membership
+
+ Membership type for a multicast address.
+
+ ::
+
+ typedef enum {
+ UV_LEAVE_GROUP = 0,
+ UV_JOIN_GROUP
+ } uv_membership;
+
+
+Public members
+^^^^^^^^^^^^^^
+
+.. c:member:: size_t uv_udp_t.send_queue_size
+
+ Number of bytes queued for sending. This field strictly shows how much
+ information is currently queued.
+
+.. c:member:: size_t uv_udp_t.send_queue_count
+
+ Number of send requests currently in the queue awaiting to be processed.
+
+.. c:member:: uv_udp_t* uv_udp_send_t.handle
+
+ UDP handle where this send request is taking place.
+
+.. seealso:: The :c:type:`uv_handle_t` members also apply.
+
+
+API
+---
+
+.. c:function:: int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle)
+
+ Initialize a new UDP handle. The actual socket is created lazily.
+ Returns 0 on success.
+
+.. c:function:: int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags)
+
+ Initialize the handle with the specified flags. At the moment the lower 8 bits
+ of the `flags` parameter are used as the socket domain. A socket will be created
+ for the given domain. If the specified domain is ``AF_UNSPEC`` no socket is created,
+ just like :c:func:`uv_udp_init`.
+
+ .. versionadded:: 1.7.0
+
+.. c:function:: int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock)
+
+ Opens an existing file descriptor or Windows SOCKET as a UDP handle.
+
+ Unix only:
+ The only requirement of the `sock` argument is that it follows the datagram
+ contract (works in unconnected mode, supports sendmsg()/recvmsg(), etc).
+ In other words, other datagram-type sockets like raw sockets or netlink
+ sockets can also be passed to this function.
+
+ .. versionchanged:: 1.2.1 the file descriptor is set to non-blocking mode.
+
+ .. note::
+ The passed file descriptor or SOCKET is not checked for its type, but
+ it's required that it represents a valid datagram socket.
+
+.. c:function:: int uv_udp_bind(uv_udp_t* handle, const struct sockaddr* addr, unsigned int flags)
+
+ Bind the UDP handle to an IP address and port.
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init`.
+
+ :param addr: `struct sockaddr_in` or `struct sockaddr_in6`
+ with the address and port to bind to.
+
+ :param flags: Indicate how the socket will be bound,
+ ``UV_UDP_IPV6ONLY`` and ``UV_UDP_REUSEADDR`` are supported.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. c:function:: int uv_udp_getsockname(const uv_udp_t* handle, struct sockaddr* name, int* namelen)
+
+ Get the local IP and port of the UDP handle.
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init` and bound.
+
+ :param name: Pointer to the structure to be filled with the address data.
+ In order to support IPv4 and IPv6 `struct sockaddr_storage` should be
+ used.
+
+ :param namelen: On input it indicates the data of the `name` field. On
+ output it indicates how much of it was filled.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. c:function:: int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, const char* interface_addr, uv_membership membership)
+
+ Set membership for a multicast address
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init`.
+
+ :param multicast_addr: Multicast address to set membership for.
+
+ :param interface_addr: Interface address.
+
+ :param membership: Should be ``UV_JOIN_GROUP`` or ``UV_LEAVE_GROUP``.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. c:function:: int uv_udp_set_multicast_loop(uv_udp_t* handle, int on)
+
+ Set IP multicast loop flag. Makes multicast packets loop back to
+ local sockets.
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init`.
+
+ :param on: 1 for on, 0 for off.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. c:function:: int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl)
+
+ Set the multicast ttl.
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init`.
+
+ :param ttl: 1 through 255.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. c:function:: int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr)
+
+ Set the multicast interface to send or receive data on.
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init`.
+
+ :param interface_addr: interface address.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. c:function:: int uv_udp_set_broadcast(uv_udp_t* handle, int on)
+
+ Set broadcast on or off.
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init`.
+
+ :param on: 1 for on, 0 for off.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. c:function:: int uv_udp_set_ttl(uv_udp_t* handle, int ttl)
+
+ Set the time to live.
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init`.
+
+ :param ttl: 1 through 255.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. c:function:: int uv_udp_send(uv_udp_send_t* req, uv_udp_t* handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr* addr, uv_udp_send_cb send_cb)
+
+ Send data over the UDP socket. If the socket has not previously been bound
+ with :c:func:`uv_udp_bind` it will be bound to 0.0.0.0
+ (the "all interfaces" IPv4 address) and a random port number.
+
+ :param req: UDP request handle. Need not be initialized.
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init`.
+
+ :param bufs: List of buffers to send.
+
+ :param nbufs: Number of buffers in `bufs`.
+
+ :param addr: `struct sockaddr_in` or `struct sockaddr_in6` with the
+ address and port of the remote peer.
+
+ :param send_cb: Callback to invoke when the data has been sent out.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. c:function:: int uv_udp_try_send(uv_udp_t* handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr* addr)
+
+ Same as :c:func:`uv_udp_send`, but won't queue a send request if it can't
+ be completed immediately.
+
+ :returns: >= 0: number of bytes sent (it matches the given buffer size).
+ < 0: negative error code (``UV_EAGAIN`` is returned when the message
+ can't be sent immediately).
+
+.. c:function:: int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb)
+
+ Prepare for receiving data. If the socket has not previously been bound
+ with :c:func:`uv_udp_bind` it is bound to 0.0.0.0 (the "all interfaces"
+ IPv4 address) and a random port number.
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init`.
+
+ :param alloc_cb: Callback to invoke when temporary storage is needed.
+
+ :param recv_cb: Callback to invoke with received data.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. c:function:: int uv_udp_recv_stop(uv_udp_t* handle)
+
+ Stop listening for incoming datagrams.
+
+ :param handle: UDP handle. Should have been initialized with
+ :c:func:`uv_udp_init`.
+
+ :returns: 0 on success, or an error code < 0 on failure.
+
+.. seealso:: The :c:type:`uv_handle_t` API functions also apply.
diff --git a/3rdparty/libuv/docs/src/version.rst b/3rdparty/libuv/docs/src/version.rst
new file mode 100644
index 00000000000..e1715b2d3c5
--- /dev/null
+++ b/3rdparty/libuv/docs/src/version.rst
@@ -0,0 +1,60 @@
+
+.. _version:
+
+Version-checking macros and functions
+=====================================
+
+Starting with version 1.0.0 libuv follows the `semantic versioning`_
+scheme. This means that new APIs can be introduced throughout the lifetime of
+a major release. In this section you'll find all macros and functions that
+will allow you to write or compile code conditionally, in order to work with
+multiple libuv versions.
+
+.. _semantic versioning: http://semver.org
+
+
+Macros
+------
+
+.. c:macro:: UV_VERSION_MAJOR
+
+ libuv version's major number.
+
+.. c:macro:: UV_VERSION_MINOR
+
+ libuv version's minor number.
+
+.. c:macro:: UV_VERSION_PATCH
+
+ libuv version's patch number.
+
+.. c:macro:: UV_VERSION_IS_RELEASE
+
+ Set to 1 to indicate a release version of libuv, 0 for a development
+ snapshot.
+
+.. c:macro:: UV_VERSION_SUFFIX
+
+ libuv version suffix. Certain development releases such as Release Candidates
+ might have a suffix such as "rc".
+
+.. c:macro:: UV_VERSION_HEX
+
+ Returns the libuv version packed into a single integer. 8 bits are used for
+ each component, with the patch number stored in the 8 least significant
+ bits. E.g. for libuv 1.2.3 this would be 0x010203.
+
+ .. versionadded:: 1.7.0
+
+
+Functions
+---------
+
+.. c:function:: unsigned int uv_version(void)
+
+ Returns :c:macro:`UV_VERSION_HEX`.
+
+.. c:function:: const char* uv_version_string(void)
+
+ Returns the libuv version number as a string. For non-release versions the
+ version suffix is included.
diff --git a/3rdparty/libuv/gyp_uv.py b/3rdparty/libuv/gyp_uv.py
new file mode 100644
index 00000000000..39933f624d5
--- /dev/null
+++ b/3rdparty/libuv/gyp_uv.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python
+
+import os
+import platform
+import sys
+
+try:
+ import multiprocessing.synchronize
+ gyp_parallel_support = True
+except ImportError:
+ gyp_parallel_support = False
+
+
+CC = os.environ.get('CC', 'cc')
+script_dir = os.path.dirname(__file__)
+uv_root = os.path.normpath(script_dir)
+output_dir = os.path.join(os.path.abspath(uv_root), 'out')
+
+sys.path.insert(0, os.path.join(uv_root, 'build', 'gyp', 'pylib'))
+try:
+ import gyp
+except ImportError:
+ print('You need to install gyp in build/gyp first. See the README.')
+ sys.exit(42)
+
+
+def host_arch():
+ machine = platform.machine()
+ if machine == 'i386': return 'ia32'
+ if machine == 'x86_64': return 'x64'
+ if machine.startswith('arm'): return 'arm'
+ if machine.startswith('mips'): return 'mips'
+ return machine # Return as-is and hope for the best.
+
+
+def run_gyp(args):
+ rc = gyp.main(args)
+ if rc != 0:
+ print 'Error running GYP'
+ sys.exit(rc)
+
+
+if __name__ == '__main__':
+ args = sys.argv[1:]
+
+ # GYP bug.
+ # On msvs it will crash if it gets an absolute path.
+ # On Mac/make it will crash if it doesn't get an absolute path.
+ if sys.platform == 'win32':
+ args.append(os.path.join(uv_root, 'uv.gyp'))
+ common_fn = os.path.join(uv_root, 'common.gypi')
+ options_fn = os.path.join(uv_root, 'options.gypi')
+ # we force vs 2010 over 2008 which would otherwise be the default for gyp
+ if not os.environ.get('GYP_MSVS_VERSION'):
+ os.environ['GYP_MSVS_VERSION'] = '2010'
+ else:
+ args.append(os.path.join(os.path.abspath(uv_root), 'uv.gyp'))
+ common_fn = os.path.join(os.path.abspath(uv_root), 'common.gypi')
+ options_fn = os.path.join(os.path.abspath(uv_root), 'options.gypi')
+
+ if os.path.exists(common_fn):
+ args.extend(['-I', common_fn])
+
+ if os.path.exists(options_fn):
+ args.extend(['-I', options_fn])
+
+ args.append('--depth=' + uv_root)
+
+ # There's a bug with windows which doesn't allow this feature.
+ if sys.platform != 'win32':
+ if '-f' not in args:
+ args.extend('-f make'.split())
+ if 'eclipse' not in args and 'ninja' not in args:
+ args.extend(['-Goutput_dir=' + output_dir])
+ args.extend(['--generator-output', output_dir])
+
+ if not any(a.startswith('-Dhost_arch=') for a in args):
+ args.append('-Dhost_arch=%s' % host_arch())
+
+ if not any(a.startswith('-Dtarget_arch=') for a in args):
+ args.append('-Dtarget_arch=%s' % host_arch())
+
+ if not any(a.startswith('-Duv_library=') for a in args):
+ args.append('-Duv_library=static_library')
+
+ # Some platforms (OpenBSD for example) don't have multiprocessing.synchronize
+ # so gyp must be run with --no-parallel
+ if not gyp_parallel_support:
+ args.append('--no-parallel')
+
+ gyp_args = list(args)
+ print gyp_args
+ run_gyp(gyp_args)
diff --git a/3rdparty/libuv/img/banner.png b/3rdparty/libuv/img/banner.png
new file mode 100644
index 00000000000..7187daa2e57
--- /dev/null
+++ b/3rdparty/libuv/img/banner.png
Binary files differ
diff --git a/3rdparty/libuv/img/logos.svg b/3rdparty/libuv/img/logos.svg
new file mode 100644
index 00000000000..d6185f8b191
--- /dev/null
+++ b/3rdparty/libuv/img/logos.svg
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="792pt"
+ height="612pt"
+ id="svg3069"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="New document 3">
+ <defs
+ id="defs3071">
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath70">
+ <path
+ inkscape:connector-curvature="0"
+ d="M 0,5952.81 0,0 l 8418.9,0 0,5952.81 -8418.9,0 z"
+ id="path72" />
+ </clipPath>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath70-6">
+ <path
+ inkscape:connector-curvature="0"
+ d="M 0,5952.81 0,0 l 8418.9,0 0,5952.81 -8418.9,0 z"
+ id="path72-5" />
+ </clipPath>
+ </defs>
+ <sodipodi:namedview
+ inkscape:document-units="in"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.43415836"
+ inkscape:cx="508.42646"
+ inkscape:cy="359.27024"
+ inkscape:current-layer="layer1"
+ id="namedview3073"
+ showgrid="false"
+ inkscape:window-width="1010"
+ inkscape:window-height="702"
+ inkscape:window-x="441"
+ inkscape:window-y="267"
+ inkscape:window-maximized="0" />
+ <metadata
+ id="metadata3075">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <g
+ transform="matrix(0.2288071,0,0,-0.2288071,130.84779,1169.4436)"
+ id="g66">
+ <g
+ id="g68"
+ clip-path="url(#clipPath70)">
+ <path
+ inkscape:connector-curvature="0"
+ d="m 3274.33,2372.2 c -42.27,-8.61 -87.28,-37.29 -122.12,-43.75 -77.01,-14.25 -122.4,-0.53 -81.76,16.27 59.03,24.45 253.75,30.55 274.1,175.05 20.36,144.5 6.1,209.66 -4.07,246.29 -4.87,17.57 -15.81,43.49 -25.9,65.76 -2.85,15.73 -6.59,29.07 -9.86,38.57 -1.82,4.29 -3.65,9.81 -5.46,16.78 0,0 -2.54,17.81 5.6,35.1 7.2,15.34 31.95,48.62 33.62,80.79 0.03,1.95 0.11,3.9 0.08,5.85 -0.1,2.18 -0.28,4.33 -0.63,6.48 l -0.18,1.9 c -3.17,18.05 -13.53,30.62 -27.6,39.98 -9.06,6.02 -21.4,7.92 -28.17,16.51 5.4,17.01 22.63,23.06 29.82,36.95 4.48,12.34 0.82,25.3 -5.99,37.08 -13.13,14.72 -38.92,27.49 -62.07,36.15 -28.97,10.87 -58.44,19.45 -78.35,35.06 -21.03,11.19 -35.17,32.83 -22.26,61.45 3.35,7.44 4.85,14.93 4.75,22.04 l -0.09,2.09 c -0.03,1.45 -0.23,2.76 -0.41,4.1 -0.15,1.04 -0.32,2.06 -0.55,3.08 l -0.47,1.77 -0.56,2.02 c -5.3,17.86 -33.44,22.88 -43.47,23.78 -22.72,2.04 -37.4,8.2 -49.46,12.01 9.7,-5.04 19.46,-11.78 31.9,-16.79 7.87,-3.21 19.17,-5.12 28.68,-8.29 l 0.09,0.02 c 0,0 17.55,-3.56 22.38,-15.78 4.84,-12.2 2.03,-22.9 0,-29.75 l -0.74,-1.99 c -1.75,-5.35 -3.72,-10.51 -4.13,-15.84 -1.65,-21.04 11.26,-32 18.12,-49.6 12.35,-11.73 29.93,-23.88 54.32,-34.88 21.92,-9.9 48.15,-15.89 64.4,-25.7 9.41,-5.68 26.55,-19.41 26.16,-29.4 -0.3,-7.65 -14.43,-18.09 -20.12,-25.7 -4.07,-5.42 -6.09,-12.62 -9.73,-17.74 -3.17,-5 -7.24,-8.22 -11.92,-8.22 -6.1,0 -20.01,-2.36 -10.86,-3.04 9.16,-0.68 32.91,-11.87 32.91,-11.87 l -0.02,-0.03 c 32.1,-13.28 53.67,-37.88 41.87,-72.96 -9.88,-29.39 -32.61,-53.97 -34.2,-86.3 -1.7,-34.4 14.07,-62.72 16.09,-90 3.41,-45.9 -3.18,-77.51 -12.06,-112.01 -4.17,-16.14 -6.39,-32.04 -10.06,-47.74 -15.68,-66.87 -56.09,-95.84 -110.68,-126.73 -23.67,-13.39 -49.07,-38.07 -74.45,-45.9 -4.09,-1.26 -10.39,0.66 -14.11,0 -23.38,-4.22 -44.42,-15.81 -68.41,-20.19 -22.59,-4.17 -46.27,-2.17 -73.08,-8.96 -13.6,-4.85 -31.03,-12.11 -41.21,-16.43 -15.74,-7.17 -31.16,-14.63 -46.55,-22.15 l -51.11,-29.2 c 0,0 -28.48,-16.49 3.06,-4.28 25.38,9.83 112.62,53.25 76.08,27.75 -25.2,-12.66 -38.87,-30.64 -61.16,-45.98 0,0 -74.99,-37.19 -86.24,-47.57 -12.37,-11.42 -27.49,-5.1 -37.41,-16.3 -11.65,-13.13 -25.94,-21.01 -36.13,-24.41 -10.17,-3.42 -21.7,-25.78 -37.31,-37.31 -15.61,-11.54 -49.52,-8.15 -79.38,-21.04 -29.85,-12.89 -60.79,-13.06 -60.79,-13.06 -2.96,-0.28 -5.83,-0.46 -8.58,-0.53 -1.18,-0.03 -2.27,-0.02 -3.4,-0.02 -17.46,-0.09 -30.81,3.32 -41.04,7.08 -12.47,4.58 -17.05,2.28 -14.25,0.76 2.8,-1.51 10.92,-9.11 10.92,-9.11 -34.83,0.04 -44.33,23.18 -60.37,40.37 7.29,1.04 28.08,-4.04 17.52,2.08 -20.85,9.97 -61.01,10.69 -61.8,34.67 -0.6,18.81 8.06,14.69 8.06,14.69 14.61,-25.44 59.69,-27.93 92.57,-27.57 61.24,0.74 102.68,34.32 142.82,53.32 13.01,7.82 28.21,18.1 28.21,18.1 l -0.08,-0.3 c 12.67,8.25 25.48,16.25 36.31,26.22 18.9,17.37 31.67,40.04 48.31,59.27 1.93,3.27 5.99,7.26 10.81,11.28 4.69,4.4 9.73,8.5 15.34,12.09 l 0.21,-0.45 2.18,1.46 -0.39,0.82 c 40.39,22.9 78.03,48.25 109.79,79.02 l 0.21,0.36 c 4.56,4.13 28.46,30.81 40,43.76 13.61,18.15 23.42,41.08 29.11,64.18 2.05,8.36 0.75,18.51 4.01,27.56 5.07,14.03 17.81,26.51 26.17,40.39 8.65,14.43 14.37,30.14 20.12,45.9 25.17,69.17 54.28,124.25 108.66,161.6 26.2,18.01 58.02,29.63 76.46,56.95 -13.39,-13.59 -30.82,-23.5 -51.87,-30.09 -59.79,-19.7 -98.68,-70.15 -118.23,-102.2 -15.01,-26.98 -26.61,-57.04 -35.14,-89.93 -2.83,40.54 -12.84,72.15 -26.17,102.84 -11.85,27.29 -22.33,56.15 -44.27,73.46 0,0 -0.84,-0.06 -4.25,1.99 -3.39,2.02 56.57,3.53 56.57,3.53 10.49,-0.38 21.17,-1.89 31.99,-3.29 2.03,0.22 4.51,0.1 7.56,-0.43 32.96,-5.82 67.21,6.45 88.55,21.98 11.08,8.06 30.34,14.52 46.32,18.89 0.26,0.69 1.82,1.47 5.81,2.23 0,0 24.42,7.63 50.37,14.76 17.58,4.81 30.38,8.5 39.27,12.89 5.15,3.28 10.05,7.22 13.85,11.91 7.61,9.39 7.76,20.66 14.1,36.73 6.31,16.03 15.96,28.49 16.1,42.24 0.45,45.08 -42.25,80.98 -88.54,56.95 45.58,11.75 77.9,-10.49 72.44,-53.28 -6.74,-52.87 -86.39,-92.05 -134.83,-112.01 -19.2,-7.91 -41.68,-17.9 -64.38,-20.19 -32.74,-3.32 -62.41,3.67 -90.56,1.84 -36.1,-2.38 -60.11,-21.47 -90.55,-23.89 -26.16,-2.07 -22.61,15.61 -45.31,17.62 -4.7,2.68 -18.98,0 -33.18,0.74 -39.25,-10.37 -64.5,7.57 -96.58,22.04 -23.14,10.45 -47.82,19.96 -72.44,22.04 -61.81,5.24 -99.39,-3.35 -149.91,2.01 -14.25,1.51 -43.81,3.31 -57.85,8.57 -43.71,16.35 -77.17,10.42 -124.65,11.1 -34.54,0.5 -66.59,2.31 -88.15,-1.47 -5.88,-1.06 -11.84,-2.57 -18.12,-3.67 -46.27,-8.09 -116.76,-12.28 -114.69,-53.26 3.44,2.35 2.48,8.74 8.04,9.18 -0.2,-7.53 -0.39,-15.05 2.01,-20.21 -26.91,0.7 -42.78,19.28 -42.25,40.41 0.9,35.93 58.71,50.95 98.59,60.61 39.98,9.64 81.5,20.94 110.69,25.7 -69.91,-10.27 -143.86,-16.88 -197.22,-42.25 -0.75,2.76 -1.23,5.42 -1.55,7.98 -4.22,19.4 -13.43,49.15 -19.91,78.07 -7.46,33.24 4.06,91.59 4.06,91.59 l 0.29,-0.34 c 4.81,29.66 10.94,42.88 16.88,60.61 12.65,37.82 53.52,49.69 82.13,53.28 -24.12,-17.04 -39.54,-38.17 -49.29,-66.46 -1.2,-10.04 -2.14,-19.46 -2.84,-27.77 21.65,67.41 82.07,92.64 82.07,92.64 l 19.34,20.86 -0.25,-0.95 c 33.36,32.26 77.42,57.26 133.43,58.83 28.22,0.79 62.32,-6.64 62.23,-34.32 -0.04,-15.65 -12.28,-28.93 -28.97,-36.27 4.91,-0.97 9.4,-0.29 13.47,1.39 l 17.34,19.41 c 5.74,14.18 5.23,32.1 -4.44,42.9 25.52,21.82 65.26,-2.65 62.36,-31.6 7.47,6.3 12.03,18.2 6.89,27.64 34.34,20.18 53.56,-28.74 88.11,-17.31 -3.25,9.79 -19.89,7.81 -24.95,15.97 45.17,6.46 84.78,-9.42 130.08,-5.82 2.84,-2.47 5.91,-4.93 9.19,-7.36 -84.73,-9.38 -15.9,-9.33 -15.9,-9.33 10.85,0.99 36.92,2.81 47.06,1.01 16.58,-3 27.29,1.04 41.95,6.77 0.35,-0.64 1.82,-0.58 2.71,1.08 7.6,3 16.35,6.31 27.47,9.31 4.31,0.61 8.64,1.72 12.84,3.09 l 1.81,0.37 0.26,0.29 c 5.8,2.02 11.27,4.44 15.96,6.71 42.69,20.52 78.1,68.84 114.56,94.19 60.42,41.99 117.63,-9.88 159.69,-43.54 l -0.27,-0.39 c 10.55,-7.2 24.46,-16.08 39.61,-25.35 39.58,-17.23 91.79,-32.28 119.67,-59.84 22.31,-22.04 29.9,-50.42 39.49,-79.88 8.96,-27.47 26.34,-51.77 36.12,-82.6 1.88,1.58 2.99,3.96 3.63,6.8 -0.27,2.63 -0.7,5.41 0.08,7.13 l 0.53,-0.48 c -0.11,5.38 -1.3,11.69 -3.14,18.33 -8.29,16.88 -22.78,36.11 -21,51.15 0,0 51.42,-26.57 109.76,-52.96 20.09,-9.09 38.48,-24.08 54.53,-41.21 l 4.69,0.1 c -0.55,-1.2 -0.5,-2.93 -0.33,-4.76 28.36,-31.78 48.46,-69.63 55.45,-91.51 1.44,-4.49 3.07,-9.04 4.83,-13.57 l 0.01,-0.05 c 2.2,-5.71 4.57,-11.35 7.02,-16.78 l 0.05,0.08 c 1.03,-1.85 1.68,-3.66 2.37,-5.49 8.42,-18.22 16.69,-33.01 18.99,-37.06 7.41,-9.21 13.39,-21.04 19.78,-31.05 2.22,-24.89 3.41,-50.09 3.41,-75.56 0,-199.46 -69.36,-382.69 -185.2,-527 -6.7,-0.78 -15.83,-2.33 -27.9,-4.8 z m -52.92,-82.53 c -40.52,-13.23 -81.83,-38.11 -108.21,-40.61 -79.4,-7.5 -93.63,27.79 -30.19,33.61 23.94,2.2 59.29,4.91 87.52,18.29 41.64,19.78 84.29,38.98 112.76,53.23 -19.47,-22.6 -40.15,-44.11 -61.88,-64.52 z m -865.53,-3.85 c -6.73,-2.26 -6.73,1.07 -6.73,1.07 0,0 -12.2,17.42 -14.09,33.64 -1.91,16.07 2.23,30.38 6.26,32.5 4.07,2.2 4.95,-7.16 8.26,-18.88 3.33,-11.84 19.78,-36.13 19.78,-36.13 2.34,-5 -6.65,-9.95 -13.48,-12.2 z m 42.43,-7.43 c -7.73,-2.57 -7.72,1.26 -7.72,1.26 0,0 -13.94,19.78 -16.06,38.24 -2.14,18.26 2.66,34.52 7.3,36.95 4.67,2.51 5.67,-8.16 9.42,-21.52 3.76,-13.43 22.6,-41.09 22.6,-41.09 2.67,-5.68 -7.71,-11.25 -15.54,-13.84 z m 14.34,51.42 c -2.66,23.12 3.53,43.78 9.47,46.91 5.98,3.19 7.21,-10.35 11.96,-27.27 4.76,-17.04 28.77,-52.08 28.77,-52.08 3.4,-7.18 -9.92,-14.29 -19.94,-17.55 -9.92,-3.24 -9.89,1.54 -9.89,1.54 0,0 -17.72,25.08 -20.37,48.45 z m 344.3,264.59 c 4.16,3.72 8.54,-4.1 16.65,-12.97 8.18,-8.98 36.92,-23.11 36.92,-23.11 4.63,-3.42 -4.59,-11.97 -12.08,-17.13 -7.47,-5.16 -8.66,-2.13 -8.66,-2.13 0,0 -21.16,9.99 -29.17,23.65 -7.97,13.46 -7.84,27.91 -3.66,31.69 z m -68.15,-36.32 c 5.11,4.79 10.57,-5.35 20.77,-16.86 10.31,-11.78 46.52,-30.52 46.52,-30.52 5.9,-4.44 -5.63,-15.55 -14.96,-22.21 -9.36,-6.66 -10.92,-2.72 -10.92,-2.72 0,0 -26.46,13.4 -36.55,31.17 -9.99,17.53 -10,36.37 -4.86,41.14 z m -60.8,-81.74 c -9,18.83 -8.22,38.34 -3.02,43.06 5.25,4.73 10.2,-6.14 19.69,-18.82 9.63,-12.88 44.35,-34.41 44.35,-34.41 5.56,-5 -6.19,-15.86 -15.65,-22.26 -9.41,-6.35 -10.8,-2.21 -10.8,-2.21 0,0 -25.38,15.51 -34.57,34.64 z m -55.66,-46.52 c -7.53,19.87 -5.51,39.81 -0.21,44.23 5.4,4.43 9.44,-7.08 17.74,-20.66 8.43,-13.86 40.51,-38.43 40.51,-38.43 5.09,-5.51 -6.92,-15.77 -16.52,-21.57 -9.48,-5.72 -10.46,-1.32 -10.46,-1.32 0,0 -23.45,17.66 -31.06,37.75 z m -75.01,-121.98 c -9.98,-3.02 -9.89,1.61 -9.89,1.61 0,0 -16.92,24.38 -18.9,46.94 -1.96,22.39 4.85,42.34 10.86,45.31 6.07,3.02 6.94,-10.05 11.14,-26.43 4.3,-16.56 27.21,-50.59 27.21,-50.59 3.18,-6.96 -10.3,-13.73 -20.42,-16.84 z m 20.3,78.13 c -4.88,22.44 -0.13,43.46 5.88,47.35 6.06,3.95 8.61,-9.17 15.12,-25.14 6.57,-16.04 35.41,-47.57 35.41,-47.57 4.31,-6.67 -9.23,-15.5 -19.66,-20.14 -10.27,-4.55 -10.72,0.28 -10.72,0.28 0,0 -21.1,22.52 -26.03,45.22 z m 271.98,527.71 c 0,0 5.87,-0.99 3.22,-9.29 -2.64,-8.28 -3.15,-33.94 4.88,-45 8.07,-11.09 -5.53,-6.88 -16.15,4.32 -10.63,11.15 -18.15,31.7 -15.86,45.66 0,0 -0.61,5.87 23.91,4.31 z m -37.52,-67.96 c 12.88,-14.37 -6.84,-10.53 -23.34,3.63 -16.48,14.11 -29.99,41.66 -28.75,61.54 0,0 -1.69,8.15 32.94,9.54 0,0 8.42,-0.53 5.81,-12.53 -2.47,-11.98 0.45,-47.93 13.34,-62.18 z m -87.89,-74.93 c 75.07,-4.92 128.89,21.11 167.01,47.73 10.04,7 23.31,24.05 40.27,12.85 -7.23,-14.98 -26.39,-24.85 -42.26,-33.04 -27.81,-14.37 -52.47,-26.94 -84.52,-34.9 54.02,8.26 92.4,30.76 132.81,51.42 4.95,-10.38 10.51,-31.21 14.16,-48.84 l 0.52,0.05 c 0,0 3.67,-9.88 2.58,-19.53 0.15,-4.6 -0.78,-8.56 -4.07,-10.74 -1.11,-1.42 -2.44,-2.73 -4.11,-3.82 -14.75,-9.67 -58.52,-31.04 -93.63,-33.58 -1.16,-0.07 -2.27,-0.22 -3.42,-0.33 l -2.59,-0.73 -0.07,0.48 c -31.84,-3.69 -52.44,-16.81 -11.72,-10.12 40.74,6.72 128,21.57 96.21,9.62 l 0.11,0.02 c -39.69,-15.51 -91.77,-30.69 -142.89,-25.71 -33.03,3.2 -67.2,19.4 -96.58,34.89 -29.34,15.45 -57.18,35.77 -88.54,42.22 -23.87,4.94 -43.59,-1.94 -64.39,-5.5 -13.85,-2.34 -33.15,-7.95 -41.54,0.7 -3.54,4.19 -0.72,8.49 -0.72,8.49 7.94,19.62 31.07,31.19 50.3,36.72 60.36,17.37 118.83,-14.55 177.08,-18.35 z m 17.01,65.76 c 12.62,-18.31 -9.29,-10.98 -26.04,7.72 -16.76,18.69 -28.07,52.35 -23.77,75.03 0,0 -0.73,9.53 38.96,5.89 0,0 9.52,-1.89 4.9,-15.19 -4.73,-13.42 -6.64,-55.1 5.95,-73.45 z m -79.92,8.72 c 12.44,-20.82 -10.82,-11.69 -27.75,9.78 -16.94,21.37 -27.09,59.1 -20.93,83.8 0,0 -0.14,10.62 42.73,4.68 0,0 10.14,-2.56 4.23,-17.09 -5.93,-14.48 -10.72,-60.33 1.72,-81.17 z m -82.62,11.5 c 12.72,-21.08 -10.85,-12.08 -28.06,9.58 -17.23,21.59 -27.69,59.9 -21.58,85.21 0,0 -0.23,10.74 43.13,5.29 0,0 10.28,-2.5 4.37,-17.35 -5.89,-14.84 -10.51,-61.7 2.14,-82.73 z m -75.72,-23.8 c 15.61,-27.27 -11.73,-15.72 -32.57,12.24 -20.82,27.97 -34.79,77.68 -29.28,110.62 0,0 -0.8,14.07 48.83,7.3 0,0 11.92,-3.09 6.02,-22.58 -5.92,-19.36 -8.62,-80.28 7,-107.58 z m -80.38,20.29 c 15.56,-23.8 -11.82,-14.71 -32.58,9.48 -20.74,24.17 -34.4,68.31 -28.65,98.18 0,0 -0.78,12.63 49.05,8.82 0,0 11.91,-2.29 5.83,-19.98 -6.03,-17.69 -9.15,-72.64 6.35,-96.5 z m -85.14,27.74 c 10.98,-20.46 -10.36,-11.36 -25.48,9.78 -15.12,21.03 -23.44,58.05 -17.05,82.25 0,0 0.14,10.39 39.73,4.3 0,0 9.4,-2.58 3.46,-16.71 -5.88,-14.2 -11.63,-59.14 -0.66,-79.62 z m -64.93,17.69 c 10.31,-16.32 -8.4,-9.23 -22.34,7.51 -13.92,16.76 -22.72,46.32 -18.28,65.79 0,0 -0.36,8.33 33.87,3.93 0,0 8.22,-1.94 3.71,-13.4 -4.32,-11.4 -7.32,-47.51 3.04,-63.83 z m -68.19,-11.78 c 12.6,-18.31 -9.3,-10.98 -26.05,7.74 -16.75,18.69 -28.06,52.34 -23.76,75.03 0,0 -0.74,9.51 38.95,5.89 0,0 9.52,-1.89 4.9,-15.21 -4.74,-13.41 -6.63,-55.07 5.96,-73.45 z m -55.02,4.85 c 12.88,-14.35 -6.83,-10.55 -23.32,3.6 -16.5,14.13 -30.01,41.69 -28.77,61.56 0,0 -1.68,8.15 32.94,9.54 0,0 8.42,-0.53 5.83,-12.55 -2.48,-11.98 0.43,-47.93 13.32,-62.15 z m 755.27,-755.37 c -38.14,-13.18 -105.91,-46.26 -160.35,-73.94 -13.01,-0.6 -26.11,-0.94 -39.29,-0.94 -465.3,0 -842.48,377.19 -842.48,842.49 0,360.48 226.45,668 544.82,788.29 1.61,-1.49 3.31,-2.93 5.11,-4.33 3.61,-2.81 9.58,-4.3 12.67,-8 4.11,-4.94 2.4,-14.97 4.19,-21.16 5.55,-19.11 17.35,-36.65 37,-50.99 2.87,-2.12 8.35,-3.14 10.85,-5.95 5.47,-6.21 3.88,-16.65 8.01,-23.83 4.35,-7.55 11.76,-16.67 20.9,-23.69 5.01,-3.86 12.5,-5.92 17.18,-10.52 3.79,-3.71 4.84,-10.39 7.55,-15.95 7.34,-15.01 26.73,-32.41 36.04,-48.12 1.23,-2.07 2.19,-4.27 3,-6.51 3.88,-7.99 13.26,-24.92 26.05,-32.75 0,0 1.33,-23.51 24.78,-50.31 -47.5,2.56 -93.32,29.42 -128.56,2.74 -10.17,11.1 -42.79,19.8 -56.75,4.23 -10.31,17.92 -64.99,29.36 -75.62,1.04 -77.73,34.87 -171.54,-14.85 -201.69,-64.76 -5.6,-2.67 -10.83,-5.48 -15.77,-8.37 -21.28,6.4 -50.1,8.67 -81.29,-13.82 -30.74,-22.18 -62.88,-121.66 -57.35,-190.53 0.6,-7.38 14.59,-24.8 19.62,-59.7 5,-34.62 8.81,-45.99 8.81,-45.99 -6.84,-11.93 -15,-17.26 -16.11,-31.22 -2.41,-30.21 23.42,-46.63 47.62,-62.1 8.61,-4.01 18.36,-6.89 28.94,-7.27 6.39,-10.12 31.01,-44.33 71.72,-44.33 1,0 2.03,0.07 3.03,0.13 15.54,-13.07 31.75,-16.58 20.56,-0.47 -0.92,1.33 -1.71,2.82 -2.45,4.35 7.48,-4.43 16.54,-8.77 24.61,-9.56 0.16,-0.01 3.96,-0.97 7.13,-0.97 1.12,0 4.46,0 5.64,2.57 1.17,2.58 -1.21,5.35 -1.99,6.23 -3.26,3.76 -6.93,13.54 -9.69,22.65 2.98,-5.46 6.23,-10.66 9.87,-15.13 19.37,-23.78 46.47,-35.02 31.34,-11.36 -4.86,7.58 -7.63,17.91 -8.98,28.88 7.5,-9.25 20.42,-19.99 41.43,-24.29 17.36,-16.51 38.94,-23.26 26.01,-5.71 -3.3,4.49 -5.46,10.27 -6.75,16.59 10.47,-12.55 28.17,-28.68 49.88,-28.68 l 1.58,0.04 0.44,0.02 c 14.89,-10.07 27.36,-11.75 16.22,2.77 -4.83,6.32 -7.46,15.08 -8.64,24.34 9.84,-20.08 28.82,-47.69 61.49,-56.57 0.24,-0.09 5.87,-1.65 10.52,-1.65 3.63,0 5.91,0.93 7,2.92 1.58,2.85 -0.5,6.17 -1.18,7.26 -2.11,3.38 -4.07,7.59 -5.77,11.74 14.67,-8.6 25.51,-9.33 14.1,4.68 -5.9,7.22 -9.05,17.42 -10.34,27.95 7.97,-21.31 24.22,-51.23 56.3,-70.83 0.24,-0.11 6.01,-2.84 12.42,-2.84 3.09,0 5.84,0.65 8.23,1.85 2.04,1.05 3.38,2.77 3.93,4.98 1.67,6.68 -4.67,16.16 -5.24,16.93 -2.64,5.2 -7.48,16.18 -9.86,25.78 l 0.24,-0.19 c 23.19,-18.71 53.29,-27.37 34.72,-8.72 -11.27,11.35 -15.62,30.79 -16,46.67 6.77,-19.01 23.24,-51.94 57.35,-58.45 0.23,-0.02 5.52,-1.04 9.42,-1.04 2.17,0 4.78,0.25 5.69,2.33 0.4,0.88 0.56,2.3 -0.99,4.04 -2.55,2.86 -6.18,11.52 -8.1,18.52 1.62,-1.24 3.19,-2.55 4.89,-3.63 16.54,-10.85 36.06,-16.54 38.61,-13.02 5.29,-4.34 13.57,-10.03 24.82,-14.99 1.05,-2.39 2.09,-4.82 2.93,-7.24 0,0 5.25,-14.59 7.27,-22.48 -26.76,6.93 -72.56,20.35 -106.65,12.83 -26.92,-5.92 -97.1,-44.72 -80.12,-71.99 1.13,-1.82 2.58,-3.09 4.24,-4.11 l 1.05,-0.4 c 6.7,-3.57 18.52,-5.67 30.95,-5.57 l 4.52,0.13 c 7.22,0.39 26.15,3.12 32.56,5.2 18.77,6.1 35.53,2.43 35.53,2.43 l -0.24,-0.17 c 13.34,-1.55 27.41,-6.24 41.94,-13.66 15.61,-7.94 36.85,-21.06 42.26,-27.53 9.76,-11.73 -5.19,-39.21 -10.76,-56.13 -0.27,-1 -0.61,-2.04 -0.93,-3.08 l -0.4,-1.4 -0.05,0.03 c -0.79,-2.37 -1.76,-4.86 -2.8,-7.4 -0.95,1.19 -1.79,2.34 -2.43,3.42 -5.34,8.98 -8.21,16.84 -10.97,13.23 -2.76,-3.62 -2.89,-17.96 2.36,-31.49 0.54,-1.4 1.2,-2.73 1.91,-4.06 -6.05,-11.06 -13.38,-22.64 -21.11,-33.75 -6.02,5.7 -12.11,12.11 -15.05,17.23 -6.87,11.76 -10.53,22.09 -14.04,17.35 -3.54,-4.72 -3.64,-23.77 3.09,-41.67 2.2,-5.83 5.55,-11.11 9.07,-15.73 -5.34,-6.74 -10.55,-12.95 -15.3,-18.23 -2.13,-2.34 -4.65,-4.99 -7.32,-7.74 -7.34,7.56 -16.63,17.94 -20.38,25.45 -6.54,13.12 -9.91,24.3 -13.63,19.54 -3.71,-4.8 -4.43,-24.95 1.75,-44.43 2.55,-7.98 6.93,-15.27 11.27,-21.19 -7.96,-7.58 -16.6,-15.59 -25.47,-23.67 -5.38,7.14 -10.69,14.98 -13.12,20.98 -5.83,14.19 -8.6,26.23 -12.54,21.61 -3.88,-4.63 -5.58,-25.57 -0.35,-46.44 1.29,-5.15 3.26,-10.09 5.5,-14.67 -8.79,-7.86 -17.3,-15.38 -25.11,-22.19 -2.29,4.97 -4.2,9.69 -5.26,13.58 -4.58,16.9 -6.3,30.85 -10.81,26.57 -4.51,-4.18 -8.35,-26.68 -5.05,-50.59 0.31,-2.3 0.76,-4.57 1.27,-6.85 l -2.2,-1.89 c -5.11,-4.41 -10.66,-9.72 -16.39,-15.56 -1.43,4.49 -2.54,8.7 -3.12,12.19 -2.91,17.61 -3.35,31.7 -7.98,28.33 -4.6,-3.31 -10.11,-25.03 -9,-49.33 0.17,-3.82 0.63,-7.68 1.27,-11.45 -6.74,-7.6 -13.41,-15.44 -19.69,-23.09 -3.64,9.35 -6.93,19.01 -8.2,26 -3.33,18.42 -4.03,33.23 -8.74,29.6 -4.31,-3.29 -9.05,-23.01 -8.53,-45.96 -4.7,-3.44 -10.79,-19.44 -10.99,-37.57 -0.09,-6.17 1.01,-12.49 2.51,-18.2 -3.05,-4.3 -8.38,-7.28 -12.11,-12.52 -19.24,-26.91 -11.39,-58.98 30.18,-66.11 12.74,-39.25 45.04,-58.31 94.58,-58.76 6.65,-0.06 13.6,2.26 20.12,1.85 7.36,-0.49 13.42,-3.48 20.13,-3.69 36.11,-1.1 55.04,10.39 82.49,18.39 20.47,5.94 41.6,7.84 54.34,12.84 19.51,7.65 28.78,28.62 44.26,38.56 5.77,3.7 16.64,5.44 26.17,11.01 8.04,4.73 15,13.32 22.13,16.53 6.23,2.82 16.6,2.26 24.14,5.51 12.64,5.48 26.6,17.31 42.27,25.73 32.81,17.55 59.51,30.53 94.57,45.89 16.75,7.34 34.47,24.6 44.27,25.71 11.62,1.34 25.15,-8.36 34.21,-7.34 18.46,-21.95 24.89,-52.62 24.12,-92.06 1.09,-0.11 0.29,-9.78 0.29,-9.78 0,0 6.45,-84.66 -125.77,-130.38 z M 2319.1,3773.92 c 13.83,-3.85 29.29,-11.71 14.56,-35.21 -9.06,9.68 -12.13,22.44 -14.56,35.21 z m 26.38,-30.96 c 4.42,7.74 0.02,11.68 2.36,16.37 39.74,-5.12 43.17,-33.03 26,-72.62 -26.49,8.95 -33.54,26.66 -38.58,44.64 4.25,4.61 7.55,6.9 10.22,11.61 z m 43.39,-7.87 c 36.99,-16.3 42.8,-57.19 17.22,-110.53 -8.74,5.74 -15.55,12.62 -20.46,20.22 -3.89,6.03 -9.35,15.9 -8.18,24.01 0.82,5.58 5.24,13.07 7.5,19.31 6.47,17.93 8.99,34.11 3.92,46.99 z m 177.23,-155.25 c -0.64,1.95 0.67,1.89 2.28,3.33 55.29,-11.22 59.69,-65.17 35.95,-105.83 -11.26,-19.25 -22.27,-29.38 -39.55,-24.01 -14.3,4.46 -16.25,15.95 -23.14,23.85 28.17,41.04 27.62,71.27 24.46,102.66 z m -63.91,40.61 c -0.24,5.01 -1.15,10.58 0.87,15.52 4.77,-0.4 13.12,-1.61 19.95,-5.23 31.05,-16.4 43.9,-75.07 25.85,-109.56 -7.75,-14.78 -15.59,-21.96 -30.09,-17.81 -23.4,6.72 -30.19,33.21 -39.62,44.17 25.51,27.2 24.04,51.08 23.04,72.91 z m -74.76,73.65 1.52,0.74 c 60.84,-21.44 95.74,-61.97 40.45,-136.4 -21.08,10.57 -32.94,24.68 -38.43,40.68 -3.23,9.38 -5.72,10.51 -3.53,22.15 4.69,25.14 6.27,52.87 -0.01,72.83 z m 236.11,-312.56 c -2.27,-1.01 -3.87,-1.76 -3.87,-1.76 -7.39,-3.78 -15.16,-6.03 -22.54,-7.31 -45.74,9.82 -59.56,61.95 -59.56,61.95 42.74,18.79 66.89,72.89 51.68,102.65 0.43,1.11 1.42,0.93 2.42,0.7 19.37,-8.54 39.75,-22.88 49.66,-38.41 18.83,-29.45 24.41,-73.75 8.73,-109.34 -6.98,-1.61 -11.46,-3.21 -17.08,-5.19 -0.95,-0.25 -1.94,-0.54 -2.92,-0.88 l -5.22,-1.92 -0.53,-0.21 -0.82,-0.27 0.05,-0.01 z m 73.78,36.96 c -3.13,-2.66 -6.21,-5.27 -9.06,-7.69 -2.62,-5.02 -10.66,-11.66 -20.93,-16.01 8.15,24.72 9.13,50.99 9.7,70.45 16.84,-8.75 28.08,-20.77 34.57,-34.43 -2.08,-1.8 -4.21,-3.66 -6.4,-5.55 -2.88,5.37 -6.87,10.23 -12.09,14.35 2.36,-6.86 3.71,-13.9 4.21,-21.12 z m -92.4,328 c 412.7,0 756.05,-296.74 828.41,-688.48 -7.89,5.56 -16.59,10.5 -26.45,14.61 -20.63,92.05 -65.01,150.17 -156.18,183.4 -30.56,11.13 -59.51,24.02 -89.66,37.15 1.74,97.97 -112.11,95.91 -183.06,146.34 -30.86,21.99 -65.84,62.56 -101.14,70.06 -68.27,14.52 -110.27,-33.06 -150.59,-66.3 -9.89,10.8 -24.72,21.35 -46.23,30.94 0,0 -38.48,54.88 -56.43,65.21 -1.19,0.68 -1.98,1.3 -2.5,1.92 -9.92,4.65 -22.34,7.27 -31.12,13.07 -8.67,5.7 -10.31,19.19 -18.99,25.7 -4.25,3.19 -10.84,6.65 -16.6,8.96 -6.96,2.79 -18.88,2.27 -25.88,6.1 -8.63,4.73 -9.32,20.11 -15.57,27.74 -6.89,8.43 -15.75,15.32 -30.08,20.14 -5.81,1.93 -14.59,2.06 -19.84,4.87 -5.86,3.17 -7.29,13.09 -11.83,19.17 -10.55,14.18 -28.36,25.18 -48.68,32.36 -4.37,1.54 -10.25,1.54 -13.45,3.69 -3.77,2.51 -4.21,8.78 -6.49,13.58 70.85,19.35 145.38,29.77 222.36,29.77 z m 836.59,-742.56 c -8.56,14.67 -16.48,28.78 -19.38,41.21 5.81,-3.84 10.91,-8.12 15.58,-12.68 1.44,-9.45 2.67,-18.97 3.8,-28.53 z m -836.59,785.09 c -91.12,0 -179,-13.85 -261.73,-39.43 -0.93,1.64 -1.92,3.24 -3.23,4.52 -7.64,7.44 -16.71,13.1 -35.56,8.27 -6.68,8.65 -15.49,15.6 -29.86,18.55 l -0.45,-0.77 c 1.82,-17.15 4.28,-34.48 17.33,-46.35 l -0.19,-2.08 C 1997.3,3605.11 1759.91,3282.33 1759.91,2904 c 0,-488.79 396.23,-885.02 885.01,-885.02 488.78,0 885.04,396.23 885.04,885.02 0,488.81 -396.26,885.03 -885.04,885.03 z M 2195.1,3323.54 c 0,0 -34.81,-7.93 -44.29,-69.48 0,0 -1.65,-31.07 8.08,-24.19 -8.2,37.31 27.27,54.21 35.41,58.01 11.45,5.09 20.91,3.38 21.63,-6.34 0.78,-10.49 -11.21,-15.13 -14.8,-25.94 12.73,7.18 41.2,24 38.24,45.9 -2.18,16.1 -17.34,30.4 -44.27,22.04 z m 457.68,-37.78 c -59.82,35.02 -214.44,28.94 -250.75,31.75 -35.74,2.72 -53.6,-42.72 -53.6,-42.72 -0.47,-9.62 7.4,1.41 7.4,1.41 23.35,42.08 43.88,34.38 43.88,34.38 73.99,-21.61 87.17,-130.29 90.25,-155.48 3.06,-25 9.38,-8.72 9.38,-8.72 7.19,62.54 -38.41,138.76 -48,148.55 -9.58,9.73 -0.43,15.23 30.13,6.68 92.03,-25.84 100.65,-173.22 106.2,-191.09 5.54,-17.8 9,-0.68 9,-0.68 -12.45,135.51 -63.96,168.92 -77.69,187.56 -5.7,7.73 40.82,8.9 61.31,-4.43 115.64,-74.71 102.66,-217.79 113.07,-197.37 10.55,20.85 -29.1,150.34 -84.81,194.41 -11.15,8.79 38.66,-6.58 57.02,-23.49 87,-80.41 97.7,-167.53 104.39,-192.7 6.57,-25 9.78,-16.53 9.78,-16.53 1.21,85.15 -66.26,193.01 -126.96,228.47 z m 167.67,59.29 c 12.83,6.96 27.96,52.1 59.04,33.35 23.1,-13.93 34.1,-17.46 34.1,-17.46 0,0 -16.13,-4.53 -23.47,-16.63 -7.34,-12.1 -16.14,-21.41 -41.81,-17.62 -26.95,4.02 -31.88,-0.21 -45.46,-2.42 0,0 4.76,13.79 17.6,20.78 z m -49.59,-36.2 c 19.79,-4.3 38.04,-11.99 56.34,-23.86 20.27,-13.17 42.21,-37.36 72.44,-34.91 9.64,0.77 27.16,10.1 34.21,14.7 8.82,5.75 29.74,19.45 24.15,40.39 -2.48,9.3 -13.54,10.78 -20.13,18.37 -9.13,10.56 -8.78,20.93 -16.09,33.05 15.93,-3.2 25.06,-12.64 42.24,-14.7 -27.07,24.28 -58.26,44.78 -96.58,58.78 2.88,1.63 4.71,8.31 14.09,11.01 8.45,2.44 35.7,-1.72 18.11,1.85 -17.66,4.94 -28.62,-0.09 -40.23,-7.36 -26.68,-16.67 -48.41,-54.95 -76.48,-71.6 -12.18,-7.27 -24.09,-5.6 -34.22,-18.39 6.56,-13.1 13.21,-5.39 22.15,-7.33 z m 209.28,23.88 c -6.66,-3.87 4.19,-7.38 6.03,-9.19 7.67,-7.55 24.8,-21.4 30.18,-33.05 11,-23.83 7.62,-60.3 -12.08,-73.48 -13.27,-8.86 -78.22,-33.08 -106.63,-33.05 -79.93,0.11 -88.04,87.86 -136.84,117.54 0.87,-8.4 7,-25.99 13.98,-35.11 27.44,-35.83 53.66,-109.66 130.81,-97.33 27.26,4.36 78.26,23.19 98.72,35.98 22.22,13.85 38.72,67.03 16.08,96.46 -10.14,13.18 -34.41,29.88 -40.25,31.23"
+ style="fill:#403c3d;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ id="path76" />
+ </g>
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ d="m 376.40655,56.024215 0,23.8525 24.42625,0 0,-23.8525 -24.42625,0 z m 0.09,131.692505 24.24875,0 0,-96.436255 -24.24875,0 0,96.436255 z m 305.7425,-96.436255 -35.3525,96.436255 -18.88,0 -35.5375,-96.436255 25.3575,0 19.61875,59.602505 19.43625,-59.602505 25.3575,0 z m -97.74375,96.436255 -23.5075,0 0,-8.885 c -6.29375,6.66375 -14.31625,9.995 -24.06125,9.995 -9.505,0 -17.09375,-2.83625 -22.76875,-8.51375 -6.54125,-6.53875 -9.80875,-15.67 -9.80875,-27.39375 l 0,-61.638755 24.2475,0 0,58.306255 c 0,6.04875 1.70625,10.61625 5.12125,13.6975 2.80625,2.5925 6.34375,3.8875 10.61125,3.8875 4.39,0 7.99,-1.295 10.79625,-3.8875 3.4125,-3.08125 5.12125,-7.64875 5.12125,-13.6975 l 0,-58.306255 24.24875,0 0,96.436255 z m -114.8675,-48.31 c 0,-8.51375 -0.67125,-14.6225 -2.0125,-18.32375 -2.44125,-6.17 -7.1375,-9.255 -14.09,-9.255 -6.95625,0 -11.6525,3.085 -14.09125,9.255 -1.34125,3.70125 -2.0125,9.81 -2.0125,18.32375 0,8.515 0.67125,14.62375 2.0125,18.32375 2.43875,6.295 7.135,9.44125 14.09125,9.44125 6.9525,0 11.64875,-3.14625 14.09,-9.44125 1.34125,-3.7 2.0125,-9.80875 2.0125,-18.32375 z m 24.24875,0 c 0,9.8725 -0.43375,17.2775 -1.29625,22.2125 -1.35875,8.02125 -4.1975,14.19125 -8.51375,18.5075 -5.80375,5.805 -13.63625,8.7 -23.50875,8.7 -9.8725,0 -17.8925,-3.3925 -24.06125,-10.18 l 0,9.07 -23.3225,0 0,-131.788755 24.2475,0 0,43.86875 c 5.77875,-6.415 13.53,-9.625 23.24625,-9.625 9.83875,0 17.64875,2.9 23.42875,8.7 4.305,4.318755 7.1325,10.488755 8.48625,18.508755 0.8625,4.93625 1.29375,12.28 1.29375,22.02625 z m -130.04375,48.31 -13.69625,0 c -9.255,0 -16.4125,-2.8975 -21.47125,-8.69875 -4.4425,-5.05875 -6.6625,-11.35125 -6.6625,-18.88 l 0,-104.210005 24.2475,0 0,102.730005 c 0,5.80125 2.8075,8.69875 8.42375,8.69875 l 9.15875,0 0,20.36"
+ style="fill:#403c3d;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path74" />
+ <g
+ transform="matrix(0.23169071,0,0,-0.23371708,-280.79355,1099.9435)"
+ id="g66-4">
+ <g
+ id="g68-1"
+ clip-path="url(#clipPath70-6)">
+ <g
+ id="g3197"
+ transform="translate(-350.10267,-350.10267)">
+ <path
+ id="path76-6"
+ style="fill:#e9e9e9;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 3504.81,2908.41 c 0,-483.58 -391.32,-875.6 -874.02,-875.6 -482.71,0 -874,392.02 -874,875.6 0,483.61 391.29,875.63 874,875.63 482.7,0 874.02,-392.02 874.02,-875.63"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path78"
+ style="fill:#403c3d;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 3482.08,2908.41 c 0,-471 -381.13,-852.83 -851.29,-852.83 -470.16,0 -851.27,381.83 -851.27,852.83 0,471.02 381.11,852.85 851.27,852.85 470.16,0 851.29,-381.83 851.29,-852.85"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path80"
+ style="fill:#adda1a;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 3473.33,3029.95 c -6.42,7.53 -13.81,14.41 -22.76,20.33 3.77,-16.2 15.99,-35.21 27.12,-54.62 -1.18,11.52 -2.73,22.91 -4.36,34.29 z M 3070.25,2284 c -63.63,-5.85 -49.36,-41.32 30.29,-33.77 29.21,2.77 76.64,33.01 121.13,44.56 22.41,21.66 43.74,44.44 63.68,68.43 -27,-14.62 -77.9,-37.33 -127.3,-60.84 -28.31,-13.46 -63.77,-16.17 -87.8,-18.38 z m 409,691.11 c -9.21,11.12 -16.63,28.08 -26.56,40.46 -2.32,4.07 -10.61,18.92 -19.05,37.24 -0.7,1.84 -1.35,3.66 -2.39,5.51 l -0.05,-0.07 c -2.45,5.45 -4.83,11.12 -7.04,16.85 l -0.01,0.06 c -1.76,4.55 -3.39,9.12 -4.84,13.64 -7.01,21.99 -27.18,60.03 -55.62,91.97 -0.17,1.83 -0.23,3.57 0.33,4.78 l -4.7,-0.11 c -16.1,17.22 -34.56,32.28 -54.71,41.42 -58.53,26.53 -110.11,53.23 -110.11,53.23 -1.79,-15.12 12.75,-34.44 21.07,-51.41 1.85,-6.68 3.04,-13.01 3.15,-18.42 l -0.53,0.48 c -0.79,-1.72 -0.36,-4.51 -0.09,-7.16 -0.63,-2.86 -1.75,-5.25 -3.64,-6.83 -9.8,30.98 -27.24,55.39 -36.22,83.01 -9.63,29.6 -17.24,58.12 -39.62,80.27 -27.97,27.69 -80.34,42.83 -120.05,60.13 -15.2,9.33 -29.15,18.25 -39.73,25.48 l 0.27,0.4 c -42.2,33.83 -99.59,85.95 -160.2,43.76 -36.58,-25.48 -72.09,-74.05 -114.92,-94.66 -4.7,-2.29 -10.18,-4.72 -16.01,-6.75 l -0.25,-0.29 -1.82,-0.38 c -4.22,-1.37 -8.56,-2.48 -12.88,-3.09 -11.15,-3.02 -19.94,-6.36 -27.56,-9.36 -0.89,-1.67 -2.36,-1.72 -2.72,-1.08 -14.7,-5.76 -25.44,-9.82 -42.09,-6.82 -10.16,1.82 -36.31,-0.01 -47.19,-1.01 0,0 -69.05,-0.05 15.93,9.37 -3.27,2.46 -6.36,4.92 -9.21,7.4 -45.43,-3.61 -85.18,12.35 -130.49,5.85 5.09,-8.21 21.77,-6.21 25.04,-16.05 -34.67,-11.48 -53.95,37.68 -88.39,17.4 5.15,-9.48 0.58,-21.45 -6.91,-27.78 2.9,29.09 -36.96,53.69 -62.56,31.76 9.7,-10.86 10.2,-28.86 4.46,-43.12 l -17.4,-19.5 c -4.08,-1.69 -8.59,-2.37 -13.51,-1.4 16.74,7.37 29.01,20.73 29.06,36.46 0.09,27.81 -34.12,35.28 -62.43,34.49 -56.18,-1.59 -100.39,-26.71 -133.84,-59.13 l 0.24,0.95 -19.4,-20.96 c 0,0 -60.6,-25.35 -82.33,-93.09 0.7,8.35 1.64,17.81 2.85,27.9 9.79,28.43 25.25,49.66 49.44,66.79 -28.7,-3.61 -69.69,-15.54 -82.38,-53.55 -5.96,-17.81 -12.11,-31.1 -16.94,-60.9 l -0.29,0.34 c 0,0 -11.55,-58.65 -4.07,-92.05 6.5,-29.06 15.74,-58.97 19.98,-78.46 0.31,-2.57 0.8,-5.25 1.55,-8.02 53.53,25.5 127.71,32.14 197.84,42.47 -29.28,-4.79 -70.93,-16.14 -111.03,-25.84 -40.01,-9.7 -98.01,-24.8 -98.91,-60.92 -0.53,-21.23 15.39,-39.9 42.38,-40.6 -2.4,5.18 -2.21,12.74 -2.01,20.32 -5.57,-0.46 -4.61,-6.86 -8.07,-9.23 -2.07,41.18 68.63,45.39 115.05,53.52 6.31,1.1 12.28,2.63 18.18,3.7 21.63,3.79 53.78,1.97 88.43,1.46 47.63,-0.67 81.2,5.28 125.04,-11.15 14.08,-5.29 43.74,-7.09 58.03,-8.62 50.68,-5.38 88.38,3.26 150.38,-2.01 24.7,-2.09 49.47,-11.64 72.68,-22.15 32.18,-14.54 57.5,-32.58 96.88,-22.16 14.24,-0.73 28.56,1.95 33.28,-0.73 22.77,-2.03 19.21,-19.81 45.45,-17.71 30.54,2.43 54.62,21.61 90.84,24.01 28.24,1.84 57.99,-5.19 90.84,-1.86 22.77,2.31 45.33,12.35 64.59,20.29 48.59,20.07 128.49,59.45 135.25,112.57 5.48,43.01 -26.95,65.35 -72.67,53.55 46.44,24.15 89.27,-11.93 88.81,-57.23 -0.13,-13.82 -9.81,-26.35 -16.14,-42.45 -6.37,-16.16 -6.51,-27.48 -14.14,-36.9 -3.81,-4.74 -8.73,-8.7 -13.9,-11.99 -8.91,-4.41 -21.76,-8.11 -39.39,-12.95 -26.03,-7.17 -50.53,-14.82 -50.53,-14.82 -4,-0.78 -5.56,-1.56 -5.83,-2.26 -16.03,-4.39 -35.35,-10.88 -46.46,-18.98 -21.4,-15.61 -55.77,-27.94 -88.83,-22.1 -3.06,0.55 -5.56,0.66 -7.59,0.44 -10.86,1.42 -21.56,2.92 -32.09,3.3 0,0 -60.14,-1.51 -56.74,-3.53 3.41,-2.07 4.26,-2.02 4.26,-2.02 22.01,-17.39 32.52,-46.38 44.41,-73.8 13.37,-30.85 23.4,-62.63 26.25,-103.36 8.55,33.04 20.19,63.26 35.25,90.38 19.61,32.19 58.62,82.91 118.6,102.69 21.12,6.63 38.61,16.58 52.03,30.26 -18.49,-27.47 -50.41,-39.13 -76.7,-57.24 -54.55,-37.54 -83.75,-92.88 -109,-162.4 -5.76,-15.84 -11.5,-31.64 -20.18,-46.15 -8.38,-13.93 -21.17,-26.48 -26.25,-40.58 -3.28,-9.09 -1.97,-19.3 -4.03,-27.7 -5.7,-23.21 -15.54,-46.26 -29.19,-64.5 -11.59,-13.02 -35.57,-39.82 -40.13,-43.98 l -0.22,-0.36 c -31.85,-30.92 -69.62,-56.39 -110.13,-79.41 l 0.39,-0.82 -2.18,-1.47 -0.22,0.45 c -5.62,-3.61 -10.68,-7.72 -15.38,-12.15 -4.84,-4.03 -8.91,-8.05 -10.85,-11.33 -16.68,-19.34 -29.5,-42.11 -48.46,-59.56 -10.87,-10.02 -23.71,-18.07 -36.43,-26.37 l 0.09,0.31 c 0,0 -15.25,-10.33 -28.3,-18.19 -40.26,-19.09 -81.84,-52.85 -143.27,-53.58 -32.98,-0.36 -78.22,2.15 -92.87,27.71 0,0 -8.68,4.13 -8.07,-14.77 0.78,-24.11 41.07,-24.82 61.99,-34.85 10.59,-6.14 -10.26,-1.04 -17.57,-2.08 16.08,-17.27 25.62,-40.53 60.55,-40.57 0,0 -8.15,7.62 -10.95,9.16 -2.81,1.52 1.78,3.83 14.29,-0.78 10.26,-3.78 23.65,-7.19 41.17,-7.09 1.13,0 2.23,-0.02 3.41,0 2.76,0.08 5.63,0.26 8.61,0.54 0,0 31.03,0.17 60.97,13.12 29.96,12.96 63.98,9.55 79.64,21.14 15.66,11.58 27.23,34.07 37.43,37.5 10.22,3.42 24.55,11.33 36.24,24.55 9.96,11.24 25.12,4.89 37.52,16.37 11.29,10.44 86.52,47.81 86.52,47.81 22.36,15.41 36.07,33.48 61.35,46.2 36.66,25.62 -50.85,-18.01 -76.31,-27.89 -31.65,-12.26 -3.07,4.31 -3.07,4.31 l 51.26,29.33 c 15.44,7.57 30.91,15.07 46.7,22.26 10.21,4.35 27.69,11.65 41.34,16.53 26.89,6.81 50.65,4.82 73.31,8.99 24.06,4.41 45.17,16.05 68.63,20.3 3.73,0.66 10.05,-1.26 14.14,0 25.47,7.85 50.95,32.67 74.69,46.13 54.76,31.04 95.31,60.15 111.03,127.36 3.69,15.78 5.91,31.75 10.09,47.96 8.91,34.68 15.52,66.46 12.1,112.58 -2.02,27.41 -17.84,55.88 -16.14,90.44 1.6,32.49 24.4,57.21 34.31,86.74 11.84,35.26 -9.8,59.99 -42,73.32 l 0.02,0.03 c 0,0 -23.83,11.25 -33.01,11.93 -9.19,0.69 4.77,3.06 10.89,3.06 4.7,0 8.77,3.24 11.96,8.26 3.64,5.15 5.68,12.38 9.75,17.83 5.72,7.65 19.89,18.14 20.19,25.82 0.39,10.04 -16.8,23.84 -26.25,29.55 -16.3,9.86 -42.61,15.88 -64.59,25.84 -24.47,11.05 -42.11,23.26 -54.5,35.05 -6.87,17.68 -19.82,28.7 -18.17,49.84 0.41,5.36 2.38,10.54 4.14,15.93 l 0.74,1.99 c 2.04,6.89 4.85,17.63 0,29.9 -4.84,12.28 -22.46,15.85 -22.46,15.85 l -0.07,-0.01 c -9.55,3.18 -20.88,5.11 -28.78,8.33 -12.47,5.03 -22.27,11.8 -32.01,16.88 12.11,-3.84 26.84,-10.03 49.63,-12.08 10.06,-0.89 38.28,-5.95 43.6,-23.9 l 0.56,-2.02 0.47,-1.79 c 0.23,-1.02 0.4,-2.05 0.56,-3.09 0.18,-1.35 0.38,-2.66 0.41,-4.12 l 0.09,-2.09 c 0.1,-7.16 -1.4,-14.68 -4.77,-22.16 -12.95,-28.75 1.23,-50.51 22.34,-61.76 19.97,-15.69 49.52,-24.31 78.59,-35.23 23.22,-8.71 49.09,-21.54 62.26,-36.33 6.84,-11.84 10.51,-24.87 6.01,-37.26 -7.2,-13.97 -24.49,-20.05 -29.91,-37.14 6.8,-8.64 19.17,-10.55 28.26,-16.59 14.11,-9.41 24.5,-22.04 27.69,-40.18 l 0.18,-1.91 c 0.34,-2.16 0.53,-4.32 0.63,-6.51 0.03,-1.96 -0.05,-3.92 -0.08,-5.88 -1.68,-32.34 -26.5,-65.77 -33.73,-81.2 -8.16,-17.37 -5.61,-35.28 -5.61,-35.28 1.81,-7 3.64,-12.54 5.48,-16.85 3.27,-9.56 7.03,-22.96 9.88,-38.76 10.13,-22.39 21.09,-48.44 25.98,-66.09 10.22,-36.81 24.51,-102.3 4.09,-247.53 -20.41,-145.21 -215.75,-151.34 -274.96,-175.91 -40.77,-16.9 4.76,-30.67 82.01,-16.35 34.95,6.5 80.11,35.32 122.51,43.97 17.97,3.67 29.54,5.36 36.09,5.44 114.98,145.4 183.81,329.08 183.81,528.99 0,22.48 -1.13,44.67 -2.83,66.7"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path82"
+ style="fill:#f4f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2527.18,3484.46 c 28.26,41.24 27.7,71.63 24.53,103.17 -0.63,1.96 0.68,1.9 2.29,3.34 55.47,-11.28 59.88,-65.49 36.07,-106.35 -11.3,-19.34 -22.34,-29.53 -39.67,-24.13 -14.35,4.48 -16.31,16.03 -23.22,23.97 z m -22.94,26.32 c -23.48,6.74 -30.28,33.38 -39.75,44.39 25.59,27.33 24.12,51.34 23.12,73.26 -0.25,5.04 -1.16,10.64 0.87,15.61 4.78,-0.4 13.16,-1.62 20.01,-5.26 31.15,-16.48 44.04,-75.44 25.93,-110.1 -7.77,-14.86 -15.64,-22.08 -30.18,-17.9 z m -49.53,55.34 c -21.15,10.63 -33.04,24.8 -38.55,40.89 -3.24,9.42 -5.73,10.56 -3.54,22.26 4.71,25.26 6.29,53.13 -0.01,73.19 l 1.52,0.74 c 61.04,-21.54 96.06,-62.27 40.58,-137.08 z m 160.36,-21.48 c 0.43,1.12 1.42,0.94 2.43,0.7 19.43,-8.58 39.87,-22.99 49.81,-38.59 18.89,-29.6 24.49,-74.11 8.75,-109.89 -6.99,-1.61 -11.49,-3.22 -17.12,-5.22 -0.96,-0.25 -1.96,-0.53 -2.93,-0.88 l -5.24,-1.92 -0.53,-0.22 -0.83,-0.27 0.06,-0.02 c -2.29,-1 -3.88,-1.76 -3.88,-1.76 -7.42,-3.8 -15.21,-6.06 -22.62,-7.34 -45.89,9.86 -59.74,62.26 -59.74,62.26 42.87,18.87 67.1,73.24 51.84,103.15 z m 88.05,-72.17 c 16.89,-8.8 28.17,-20.87 34.68,-34.6 -2.09,-1.82 -4.23,-3.69 -6.42,-5.58 -2.89,5.4 -6.88,10.28 -12.13,14.42 2.37,-6.9 3.73,-13.96 4.23,-21.22 -3.14,-2.68 -6.23,-5.31 -9.09,-7.73 -2.63,-5.05 -10.69,-11.72 -20.99,-16.09 8.17,24.85 9.15,51.24 9.72,70.8 z m -311.91,160.11 c -8.77,5.76 -15.6,12.68 -20.53,20.31 -3.9,6.06 -9.38,15.98 -8.2,24.13 0.81,5.61 5.25,13.13 7.51,19.41 6.49,18.02 9.03,34.28 3.94,47.21 37.11,-16.36 42.93,-57.47 17.28,-111.06 z m -71.06,107.31 c 4.27,4.64 7.57,6.94 10.26,11.67 4.42,7.78 0.01,11.73 2.36,16.45 39.87,-5.15 43.3,-33.2 26.09,-72.98 -26.57,9 -33.65,26.79 -38.71,44.86 z m -16.21,42.78 c 13.88,-3.86 29.39,-11.76 14.6,-35.37 -9.08,9.72 -12.16,22.55 -14.6,35.37"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path84"
+ style="fill:#f6836c;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2529.01,2752.37 c -23.94,4.97 -43.72,-1.93 -64.59,-5.52 -13.88,-2.35 -33.24,-7.99 -41.67,0.71 -3.55,4.21 -0.72,8.52 -0.72,8.52 7.97,19.73 31.16,31.35 50.46,36.91 60.55,17.46 119.21,-14.63 177.64,-18.45 75.3,-4.94 129.29,21.21 167.54,47.98 10.06,7.04 23.37,24.16 40.39,12.92 -7.25,-15.06 -26.47,-24.97 -42.4,-33.22 -27.89,-14.43 -52.63,-27.06 -84.78,-35.07 54.18,8.3 92.69,30.91 133.23,51.69 4.96,-10.44 10.54,-31.37 14.21,-49.1 l 0.51,0.06 c 0,0 3.69,-9.93 2.6,-19.63 0.14,-4.63 -0.79,-8.61 -4.09,-10.8 -1.11,-1.42 -2.45,-2.74 -4.12,-3.84 -14.8,-9.71 -58.71,-31.2 -93.93,-33.75 -1.16,-0.06 -2.28,-0.21 -3.43,-0.33 l -2.59,-0.73 -0.08,0.49 c -31.94,-3.71 -52.6,-16.9 -11.76,-10.17 40.88,6.75 128.41,21.66 96.52,9.67 l 0.11,0.01 c -39.82,-15.58 -92.06,-30.84 -143.33,-25.84 -33.14,3.22 -67.42,19.51 -96.89,35.07 -29.44,15.53 -57.36,35.95 -88.83,42.42"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path86"
+ style="fill:#f4f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2326.23,2354.71 c 4.08,2.22 4.97,-7.19 8.29,-18.98 3.33,-11.89 19.84,-36.31 19.84,-36.31 2.35,-5.03 -6.67,-9.99 -13.52,-12.26 -6.76,-2.27 -6.76,1.09 -6.76,1.09 0,0 -12.23,17.5 -14.12,33.81 -1.92,16.13 2.23,30.52 6.27,32.65 z m 40.64,1.81 c 4.69,2.53 5.68,-8.19 9.45,-21.63 3.78,-13.49 22.67,-41.28 22.67,-41.28 2.68,-5.7 -7.73,-11.3 -15.59,-13.92 -7.76,-2.56 -7.75,1.26 -7.75,1.26 0,0 -13.98,19.89 -16.1,38.44 -2.15,18.35 2.67,34.69 7.32,37.13 z m 40.42,22 c 6,3.2 7.23,-10.4 12,-27.41 4.77,-17.13 28.86,-52.33 28.86,-52.33 3.41,-7.23 -9.95,-14.37 -20.01,-17.65 -9.95,-3.25 -9.92,1.56 -9.92,1.56 0,0 -17.78,25.2 -20.43,48.68 -2.68,23.23 3.53,44 9.5,47.15 z m 57.45,25.09 c 6.09,3.05 6.97,-10.1 11.18,-26.55 4.31,-16.64 27.29,-50.85 27.29,-50.85 3.2,-6.99 -10.33,-13.79 -20.48,-16.91 -10.02,-3.04 -9.92,1.62 -9.92,1.62 0,0 -16.98,24.48 -18.95,47.17 -1.98,22.49 4.86,42.54 10.88,45.52 z m 44.26,31.78 c 6.07,3.98 8.64,-9.21 15.17,-25.27 6.58,-16.12 35.51,-47.78 35.51,-47.78 4.33,-6.72 -9.26,-15.58 -19.72,-20.26 -10.3,-4.57 -10.76,0.29 -10.76,0.29 0,0 -21.15,22.63 -26.1,45.45 -4.9,22.54 -0.14,43.66 5.9,47.57 z m 48.77,40.94 c 5.41,4.47 9.46,-7.11 17.8,-20.77 8.45,-13.93 40.63,-38.61 40.63,-38.61 5.1,-5.54 -6.94,-15.85 -16.57,-21.68 -9.51,-5.74 -10.49,-1.34 -10.49,-1.34 0,0 -23.53,17.77 -31.17,37.94 -7.55,19.98 -5.51,40.01 -0.2,44.46 z m 185.39,120.94 c 4.18,3.75 8.57,-4.11 16.71,-13.01 8.21,-9.05 37.03,-23.24 37.03,-23.24 4.66,-3.43 -4.6,-12.04 -12.11,-17.22 -7.5,-5.19 -8.69,-2.14 -8.69,-2.14 0,0 -21.23,10.05 -29.26,23.76 -7.99,13.54 -7.86,28.06 -3.68,31.85 z m -83.83,-151.23 c -9.45,-6.38 -10.83,-2.22 -10.83,-2.22 0,0 -25.47,15.59 -34.69,34.81 -9.02,18.94 -8.25,38.54 -3.03,43.27 5.27,4.75 10.24,-6.17 19.76,-18.9 9.66,-12.94 44.48,-34.59 44.48,-34.59 5.58,-5.02 -6.2,-15.95 -15.69,-22.37 z m 15.48,114.75 c 5.12,4.8 10.6,-5.38 20.83,-16.95 10.35,-11.84 46.67,-30.68 46.67,-30.68 5.91,-4.46 -5.65,-15.61 -15.02,-22.3 -9.37,-6.71 -10.94,-2.75 -10.94,-2.75 0,0 -26.56,13.47 -36.67,31.33 -10.02,17.62 -10.04,36.54 -4.87,41.35 z m 101.12,357.36 c 0,0 5.89,-0.99 3.23,-9.33 -2.65,-8.32 -3.16,-34.13 4.89,-45.23 8.1,-11.15 -5.54,-6.92 -16.19,4.34 -10.67,11.21 -18.21,31.85 -15.91,45.89 0,0 -0.61,5.9 23.98,4.33 z m -37.63,-68.3 c 12.91,-14.43 -6.86,-10.58 -23.41,3.64 -16.55,14.19 -30.1,41.88 -28.85,61.86 0,0 -1.69,8.18 33.05,9.59 0,0 8.44,-0.55 5.83,-12.61 -2.48,-12.03 0.45,-48.16 13.38,-62.48 z m -71.11,-9.21 c 12.65,-18.42 -9.32,-11.03 -26.12,7.75 -16.81,18.79 -28.16,52.61 -23.84,75.41 0,0 -0.74,9.57 39.08,5.91 0,0 9.54,-1.9 4.91,-15.26 -4.74,-13.49 -6.65,-55.37 5.97,-73.81 z m -108.01,18.58 c -16.99,21.48 -27.18,59.39 -21,84.23 0,0 -0.14,10.67 42.87,4.7 0,0 10.17,-2.58 4.24,-17.17 -5.94,-14.56 -10.76,-60.64 1.73,-81.59 12.48,-20.92 -10.85,-11.75 -27.84,9.83 z m -83.19,11.35 c -17.28,21.7 -27.77,60.21 -21.65,85.66 0,0 -0.23,10.79 43.27,5.3 0,0 10.31,-2.5 4.38,-17.43 -5.91,-14.92 -10.54,-62 2.15,-83.15 12.76,-21.18 -10.88,-12.13 -28.15,9.62 z m -80.49,-21.24 c -20.89,28.13 -34.89,78.07 -29.36,111.18 0,0 -0.81,14.15 48.98,7.34 0,0 11.95,-3.12 6.04,-22.7 -5.94,-19.46 -8.65,-80.67 7.02,-108.11 15.66,-27.4 -11.77,-15.8 -32.68,12.29 z m -80.64,17.63 c -20.8,24.29 -34.51,68.64 -28.73,98.66 0,0 -0.78,12.7 49.2,8.87 0,0 11.96,-2.3 5.84,-20.09 -6.04,-17.77 -9.17,-73 6.38,-96.98 15.61,-23.92 -11.86,-14.78 -32.69,9.54 z m -78.28,28.17 c -15.16,21.15 -23.52,58.34 -17.11,82.67 0,0 0.15,10.43 39.86,4.32 0,0 9.42,-2.59 3.47,-16.79 -5.9,-14.27 -11.67,-59.43 -0.66,-80.02 11.02,-20.57 -10.39,-11.43 -25.56,9.82 z m -61.99,15.5 c -13.96,16.84 -22.79,46.55 -18.34,66.13 0,0 -0.35,8.36 33.98,3.94 0,0 8.25,-1.95 3.73,-13.46 -4.34,-11.46 -7.34,-47.75 3.05,-64.16 10.34,-16.4 -8.43,-9.27 -22.42,7.55 z m -72.12,-11.61 c -16.8,18.79 -28.15,52.6 -23.84,75.42 0,0 -0.74,9.55 39.08,5.91 0,0 9.55,-1.9 4.91,-15.28 -4.74,-13.48 -6.65,-55.36 5.98,-73.82 12.64,-18.41 -9.33,-11.03 -26.13,7.77 z m -52.45,0.72 c -16.56,14.2 -30.11,41.9 -28.86,61.87 0,0 -1.69,8.18 33.03,9.58 0,0 8.46,-0.53 5.86,-12.6 -2.5,-12.04 0.43,-48.17 13.36,-62.48 12.91,-14.42 -6.86,-10.6 -23.39,3.63"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path88"
+ style="fill:#f4f4f4;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2806.87,3351.66 c 12.87,7 28.05,52.37 59.22,33.53 23.17,-14 34.21,-17.55 34.21,-17.55 0,0 -16.18,-4.55 -23.54,-16.71 -7.37,-12.16 -16.19,-21.52 -41.94,-17.7 -27.04,4.02 -31.99,-0.22 -45.6,-2.44 0,0 4.76,13.86 17.65,20.87"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path90"
+ style="fill:#403c3d;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 2731.38,3432.29 c -2.89,5.4 -6.88,10.28 -12.13,14.42 2.37,-6.9 3.73,-13.96 4.23,-21.22 -3.14,-2.68 -6.23,-5.31 -9.09,-7.73 -2.63,-5.05 -10.69,-11.72 -20.99,-16.09 8.17,24.85 9.15,51.24 9.72,70.8 16.89,-8.8 28.17,-20.87 34.68,-34.6 -2.09,-1.82 -4.23,-3.69 -6.42,-5.58 z m -55.32,-35.43 c -6.99,-1.61 -11.49,-3.22 -17.12,-5.22 -0.96,-0.25 -1.96,-0.53 -2.93,-0.88 l -5.24,-1.92 -0.53,-0.22 -0.83,-0.27 0.06,-0.02 c -2.29,-1 -3.88,-1.76 -3.88,-1.76 -7.42,-3.8 -15.21,-6.06 -22.62,-7.34 -45.89,9.86 -59.74,62.26 -59.74,62.26 42.87,18.87 67.1,73.24 51.84,103.15 0.43,1.12 1.42,0.94 2.43,0.7 19.43,-8.58 39.87,-22.99 49.81,-38.59 18.89,-29.6 24.49,-74.11 8.75,-109.89 z m -125.66,63.63 c -14.35,4.48 -16.31,16.03 -23.22,23.97 28.26,41.24 27.7,71.63 24.53,103.17 -0.63,1.96 0.68,1.9 2.29,3.34 55.47,-11.28 59.88,-65.49 36.07,-106.35 -11.3,-19.34 -22.34,-29.53 -39.67,-24.13 z m -46.16,50.29 c -23.48,6.74 -30.28,33.38 -39.75,44.39 25.59,27.33 24.12,51.34 23.12,73.26 -0.25,5.04 -1.16,10.64 0.87,15.61 4.78,-0.4 13.16,-1.62 20.01,-5.26 31.15,-16.48 44.04,-75.44 25.93,-110.1 -7.77,-14.86 -15.64,-22.08 -30.18,-17.9 z m -49.53,55.34 c -21.15,10.63 -33.04,24.8 -38.55,40.89 -3.24,9.42 -5.73,10.56 -3.54,22.26 4.71,25.26 6.29,53.13 -0.01,73.19 l 1.52,0.74 c 61.04,-21.54 96.06,-62.27 40.58,-137.08 z m -400.52,-594.93 c 0,0 8.46,-0.53 5.86,-12.6 -2.5,-12.04 0.43,-48.17 13.36,-62.48 12.91,-14.42 -6.86,-10.6 -23.39,3.63 -16.56,14.2 -30.11,41.9 -28.86,61.87 0,0 -1.69,8.18 33.03,9.58 z m 24.44,3.25 c 0,0 -0.74,9.55 39.08,5.91 0,0 9.55,-1.9 4.91,-15.28 -4.74,-13.48 -6.65,-55.36 5.98,-73.82 12.64,-18.41 -9.33,-11.03 -26.13,7.77 -16.8,18.79 -28.15,52.6 -23.84,75.42 z m 77.62,2.32 c 0,0 -0.35,8.36 33.98,3.94 0,0 8.25,-1.95 3.73,-13.46 -4.34,-11.46 -7.34,-47.75 3.05,-64.16 10.34,-16.4 -8.43,-9.27 -22.42,7.55 -13.96,16.84 -22.79,46.55 -18.34,66.13 z m 63.22,1.04 c 0,0 0.15,10.43 39.86,4.32 0,0 9.42,-2.59 3.47,-16.79 -5.9,-14.27 -11.67,-59.43 -0.66,-80.02 11.02,-20.57 -10.39,-11.43 -25.56,9.82 -15.16,21.15 -23.52,58.34 -17.11,82.67 z m 66.66,-12.18 c 0,0 -0.78,12.7 49.2,8.87 0,0 11.96,-2.3 5.84,-20.09 -6.04,-17.77 -9.17,-73 6.38,-96.98 15.61,-23.92 -11.86,-14.78 -32.69,9.54 -20.8,24.29 -34.51,68.64 -28.73,98.66 z m 80.01,-5.11 c 0,0 -0.81,14.15 48.98,7.34 0,0 11.95,-3.12 6.04,-22.7 -5.94,-19.46 -8.65,-80.67 7.02,-108.11 15.66,-27.4 -11.77,-15.8 -32.68,12.29 -20.89,28.13 -34.89,78.07 -29.36,111.18 z m 88.2,-4.28 c 0,0 -0.23,10.79 43.27,5.3 0,0 10.31,-2.5 4.38,-17.43 -5.91,-14.92 -10.54,-62 2.15,-83.15 12.76,-21.18 -10.88,-12.13 -28.15,9.62 -17.28,21.7 -27.77,60.21 -21.65,85.66 z m 83.84,-12.78 c 0,0 -0.14,10.67 42.87,4.7 0,0 10.17,-2.58 4.24,-17.17 -5.94,-14.56 -10.76,-60.64 1.73,-81.59 12.48,-20.92 -10.85,-11.75 -27.84,9.83 -16.99,21.48 -27.18,59.39 -21,84.23 z m 79.05,-19.65 c 0,0 -0.74,9.57 39.08,5.91 0,0 9.54,-1.9 4.91,-15.26 -4.74,-13.49 -6.65,-55.37 5.97,-73.81 12.65,-18.42 -9.32,-11.03 -26.12,7.75 -16.81,18.79 -28.16,52.61 -23.84,75.41 z m 101.86,1.14 c 0,0 8.44,-0.55 5.83,-12.61 -2.48,-12.03 0.45,-48.16 13.38,-62.48 12.91,-14.43 -6.86,-10.58 -23.41,3.64 -16.55,14.19 -30.1,41.88 -28.85,61.86 0,0 -1.69,8.18 33.05,9.59 z m 98.58,-102.42 c 10.06,7.04 23.37,24.16 40.39,12.92 -7.25,-15.06 -26.47,-24.97 -42.4,-33.22 -27.89,-14.43 -52.63,-27.06 -84.78,-35.07 54.18,8.3 92.69,30.91 133.23,51.69 4.96,-10.44 10.54,-31.37 14.21,-49.1 l 0.51,0.06 c 0,0 3.69,-9.93 2.6,-19.63 0.14,-4.63 -0.79,-8.61 -4.09,-10.8 -1.11,-1.42 -2.45,-2.74 -4.12,-3.84 -14.8,-9.71 -58.71,-31.2 -93.93,-33.75 -1.16,-0.06 -2.28,-0.21 -3.43,-0.33 l -2.59,-0.73 -0.08,0.49 c -31.94,-3.71 -52.6,-16.9 -11.76,-10.17 40.88,6.75 128.41,21.66 96.52,9.67 l 0.11,0.01 c -39.82,-15.58 -92.06,-30.84 -143.33,-25.84 -33.14,3.22 -67.42,19.51 -96.89,35.07 -29.44,15.53 -57.36,35.95 -88.83,42.42 -23.94,4.97 -43.72,-1.93 -64.59,-5.52 -13.88,-2.35 -33.24,-7.99 -41.67,0.71 -3.55,4.21 -0.72,8.52 -0.72,8.52 7.97,19.73 31.16,31.35 50.46,36.91 60.55,17.46 119.21,-14.63 177.64,-18.45 75.3,-4.94 129.29,21.21 167.54,47.98 z m -41.74,95.63 c 0,0 5.89,-0.99 3.23,-9.33 -2.65,-8.32 -3.16,-34.13 4.89,-45.23 8.1,-11.15 -5.54,-6.92 -16.19,4.34 -10.67,11.21 -18.21,31.85 -15.91,45.89 0,0 -0.61,5.9 23.98,4.33 z m 8.86,-374.35 c -7.5,-5.19 -8.69,-2.14 -8.69,-2.14 0,0 -21.23,10.05 -29.26,23.76 -7.99,13.54 -7.86,28.06 -3.68,31.85 4.18,3.75 8.57,-4.11 16.71,-13.01 8.21,-9.05 37.03,-23.24 37.03,-23.24 4.66,-3.43 -4.6,-12.04 -12.11,-17.22 z m -57.5,-52.94 c -9.37,-6.71 -10.94,-2.75 -10.94,-2.75 0,0 -26.56,13.47 -36.67,31.33 -10.02,17.62 -10.04,36.54 -4.87,41.35 5.12,4.8 10.6,-5.38 20.83,-16.95 10.35,-11.84 46.67,-30.68 46.67,-30.68 5.91,-4.46 -5.65,-15.61 -15.02,-22.3 z m -67.96,-44.82 c -9.45,-6.38 -10.83,-2.22 -10.83,-2.22 0,0 -25.47,15.59 -34.69,34.81 -9.02,18.94 -8.25,38.54 -3.03,43.27 5.27,4.75 10.24,-6.17 19.76,-18.9 9.66,-12.94 44.48,-34.59 44.48,-34.59 5.58,-5.02 -6.2,-15.95 -15.69,-22.37 z m -59.7,-50.77 c -9.51,-5.74 -10.49,-1.34 -10.49,-1.34 0,0 -23.53,17.77 -31.17,37.94 -7.55,19.98 -5.51,40.01 -0.2,44.46 5.41,4.47 9.46,-7.11 17.8,-20.77 8.45,-13.93 40.63,-38.61 40.63,-38.61 5.1,-5.54 -6.94,-15.85 -16.57,-21.68 z m -59.67,-53.19 c -10.3,-4.57 -10.76,0.29 -10.76,0.29 0,0 -21.15,22.63 -26.1,45.45 -4.9,22.54 -0.14,43.66 5.9,47.57 6.07,3.98 8.64,-9.21 15.17,-25.27 6.58,-16.12 35.51,-47.78 35.51,-47.78 4.33,-6.72 -9.26,-15.58 -19.72,-20.26 z m -57.23,-32.78 c -10.02,-3.04 -9.92,1.62 -9.92,1.62 0,0 -16.98,24.48 -18.95,47.17 -1.98,22.49 4.86,42.54 10.88,45.52 6.09,3.05 6.97,-10.1 11.18,-26.55 4.31,-16.64 27.29,-50.85 27.29,-50.85 3.2,-6.99 -10.33,-13.79 -20.48,-16.91 z m -54.59,-28.17 c -9.95,-3.25 -9.92,1.56 -9.92,1.56 0,0 -17.78,25.2 -20.43,48.68 -2.68,23.23 3.53,44 9.5,47.15 6,3.2 7.23,-10.4 12,-27.41 4.77,-17.13 28.86,-52.33 28.86,-52.33 3.41,-7.23 -9.95,-14.37 -20.01,-17.65 z m -44.74,-1.44 c -7.76,-2.56 -7.75,1.26 -7.75,1.26 0,0 -13.98,19.89 -16.1,38.44 -2.15,18.35 2.67,34.69 7.32,37.13 4.69,2.53 5.68,-8.19 9.45,-21.63 3.78,-13.49 22.67,-41.28 22.67,-41.28 2.68,-5.7 -7.73,-11.3 -15.59,-13.92 z m -42.56,7.47 c -6.76,-2.27 -6.76,1.09 -6.76,1.09 0,0 -12.23,17.5 -14.12,33.81 -1.92,16.13 2.23,30.52 6.27,32.65 4.08,2.22 4.97,-7.19 8.29,-18.98 3.33,-11.89 19.84,-36.31 19.84,-36.31 2.35,-5.03 -6.67,-9.99 -13.52,-12.26 z m 50.37,1345.42 c -8.77,5.76 -15.6,12.68 -20.53,20.31 -3.9,6.06 -9.38,15.98 -8.2,24.13 0.81,5.61 5.25,13.13 7.51,19.41 6.49,18.02 9.03,34.28 3.94,47.21 37.11,-16.36 42.93,-57.47 17.28,-111.06 z m -71.06,107.31 c 4.27,4.64 7.57,6.94 10.26,11.67 4.42,7.78 0.01,11.73 2.36,16.45 39.87,-5.15 43.3,-33.2 26.09,-72.98 -26.57,9 -33.65,26.79 -38.71,44.86 z m -16.21,42.78 c 13.88,-3.86 29.39,-11.76 14.6,-35.37 -9.08,9.72 -12.16,22.55 -14.6,35.37 z m 1173.75,-787.01 c -11.13,19.41 -23.35,38.42 -27.12,54.62 8.95,-5.92 16.34,-12.8 22.76,-20.33 -1.34,9.41 -2.92,18.74 -4.57,28.06 -9.71,7.73 -20.63,14.52 -33.49,19.89 -20.69,92.5 -65.21,150.91 -156.67,184.3 -30.66,11.19 -59.7,24.15 -89.94,37.34 1.75,98.46 -112.47,96.39 -183.64,147.07 -30.95,22.1 -66.05,62.87 -101.46,70.41 -68.48,14.6 -110.62,-33.23 -151.06,-66.63 -9.93,10.85 -24.8,21.45 -46.38,31.1 0,0 -38.6,55.15 -56.6,65.52 -1.19,0.69 -2,1.32 -2.52,1.93 -9.94,4.68 -22.41,7.31 -31.21,13.14 -8.7,5.73 -10.35,19.28 -19.05,25.84 -4.26,3.2 -10.87,6.67 -16.65,8.99 -6.98,2.81 -18.94,2.29 -25.97,6.14 -8.65,4.75 -9.34,20.2 -15.61,27.87 -6.91,8.47 -15.8,15.4 -30.18,20.24 -5.83,1.94 -14.63,2.07 -19.9,4.9 -5.88,3.18 -7.32,13.15 -11.87,19.26 -10.58,14.26 -28.45,25.31 -48.83,32.52 -4.39,1.55 -10.28,1.55 -13.49,3.71 -4.03,2.7 -4.19,9.73 -6.94,14.64 -4.25,7.58 -9.92,15.28 -19.06,19.99 -3.91,2.04 -9.92,1.85 -13.75,4.03 -4.5,2.58 -5.71,8.88 -9.5,12.57 -7.66,7.48 -16.76,13.16 -35.67,8.31 -6.7,8.69 -15.55,15.67 -29.96,18.64 l -0.44,-0.77 c 1.82,-17.24 4.29,-34.66 17.38,-46.59 -3.32,-19.81 5.98,-34.36 21.01,-46.08 3.62,-2.83 9.62,-4.32 12.72,-8.05 4.11,-4.96 2.41,-15.04 4.2,-21.26 5.56,-19.2 17.41,-36.84 37.11,-51.25 2.88,-2.12 8.38,-3.14 10.88,-5.97 5.5,-6.25 3.9,-16.74 8.05,-23.95 4.36,-7.59 11.79,-16.75 20.96,-23.81 5.03,-3.88 12.53,-5.95 17.23,-10.57 3.81,-3.73 4.86,-10.44 7.58,-16.02 7.35,-15.1 26.81,-32.59 36.15,-48.37 1.23,-2.08 2.2,-4.3 3.01,-6.54 3.89,-8.03 13.3,-25.05 26.13,-32.91 0,0 1.34,-23.63 24.86,-50.57 -47.65,2.58 -93.62,29.56 -128.96,2.76 -10.2,11.15 -42.93,19.9 -56.94,4.25 -10.33,18.01 -65.18,29.5 -75.85,1.04 -77.98,35.05 -172.08,-14.92 -202.33,-65.08 -5.61,-2.68 -10.86,-5.51 -15.82,-8.41 -21.34,6.43 -50.25,8.71 -81.54,-13.89 -30.84,-22.29 -63.08,-122.26 -57.53,-191.48 0.6,-7.41 14.64,-24.92 19.68,-59.99 5.02,-34.8 8.83,-46.22 8.83,-46.22 -6.86,-11.99 -15.04,-17.35 -16.15,-31.38 -2.42,-30.36 23.49,-46.85 47.76,-62.4 8.65,-4.04 18.42,-6.93 29.04,-7.32 6.41,-10.15 31.11,-44.55 71.94,-44.55 1.01,0 2.04,0.07 3.04,0.13 15.59,-13.13 31.86,-16.66 20.63,-0.47 -0.93,1.33 -1.72,2.83 -2.46,4.38 7.51,-4.47 16.59,-8.82 24.69,-9.61 0.16,-0.02 3.98,-0.98 7.14,-0.98 1.14,0 4.48,0 5.66,2.57 1.18,2.6 -1.2,5.38 -1.99,6.28 -3.27,3.77 -6.95,13.59 -9.72,22.76 3,-5.5 6.25,-10.71 9.9,-15.21 19.43,-23.89 46.63,-35.2 31.44,-11.41 -4.87,7.61 -7.65,17.99 -9.01,29.01 7.53,-9.28 20.49,-20.09 41.56,-24.4 17.42,-16.59 39.07,-23.38 26.1,-5.74 -3.32,4.51 -5.48,10.33 -6.77,16.68 10.5,-12.62 28.26,-28.83 50.03,-28.83 l 1.59,0.03 0.44,0.02 c 14.94,-10.11 27.45,-11.8 16.27,2.79 -4.84,6.36 -7.48,15.16 -8.67,24.45 9.87,-20.16 28.91,-47.92 61.69,-56.83 0.24,-0.1 5.89,-1.65 10.55,-1.65 3.63,0 5.93,0.93 7.02,2.92 1.59,2.87 -0.5,6.19 -1.19,7.28 -2.11,3.41 -4.08,7.64 -5.78,11.82 14.71,-8.64 25.59,-9.38 14.13,4.7 -5.91,7.26 -9.06,17.5 -10.36,28.08 8,-21.41 24.29,-51.48 56.48,-71.19 0.23,-0.11 6.03,-2.83 12.45,-2.83 3.1,0 5.87,0.64 8.26,1.84 2.05,1.07 3.39,2.8 3.94,5 1.68,6.71 -4.68,16.25 -5.25,17.03 -2.65,5.22 -7.5,16.25 -9.89,25.91 l 0.24,-0.2 c 23.26,-18.8 53.46,-27.51 34.83,-8.75 -11.31,11.4 -15.67,30.94 -16.06,46.89 6.8,-19.1 23.32,-52.18 57.54,-58.74 0.23,-0.02 5.53,-1.04 9.45,-1.04 2.17,0 4.79,0.24 5.71,2.34 0.39,0.88 0.55,2.32 -1,4.06 -2.56,2.89 -6.19,11.58 -8.12,18.61 1.62,-1.24 3.2,-2.56 4.89,-3.65 16.6,-10.91 36.19,-16.61 38.75,-13.08 5.3,-4.36 13.61,-10.09 24.89,-15.06 1.06,-2.42 2.1,-4.84 2.95,-7.27 0,0 5.26,-14.67 7.29,-22.61 -26.85,6.97 -72.8,20.47 -106.99,12.91 -27.01,-5.96 -97.4,-44.95 -80.38,-72.36 1.14,-1.83 2.59,-3.1 4.26,-4.14 l 1.05,-0.4 c 6.73,-3.59 18.58,-5.69 31.05,-5.59 l 4.53,0.13 c 7.25,0.4 26.23,3.13 32.67,5.22 18.82,6.13 35.64,2.45 35.64,2.45 l -0.25,-0.17 c 13.38,-1.57 27.5,-6.27 42.08,-13.73 15.66,-7.98 36.97,-21.16 42.4,-27.67 9.78,-11.78 -5.21,-39.4 -10.8,-56.41 -0.27,-1 -0.61,-2.05 -0.94,-3.09 l -0.39,-1.41 -0.06,0.04 c -0.79,-2.39 -1.76,-4.89 -2.81,-7.45 -0.95,1.2 -1.8,2.36 -2.43,3.44 -5.35,9.03 -8.24,16.93 -11,13.3 -2.77,-3.64 -2.9,-18.05 2.36,-31.66 0.54,-1.4 1.2,-2.73 1.91,-4.06 -6.06,-11.12 -13.42,-22.77 -21.18,-33.92 -6.03,5.72 -12.13,12.17 -15.09,17.31 -6.89,11.83 -10.56,22.21 -14.08,17.43 -3.56,-4.74 -3.65,-23.89 3.1,-41.86 2.2,-5.87 5.57,-11.18 9.09,-15.82 -5.35,-6.76 -10.57,-13.01 -15.34,-18.31 -2.14,-2.37 -4.66,-5.02 -7.34,-7.8 -7.36,7.62 -16.68,18.03 -20.45,25.58 -6.56,13.19 -9.94,24.43 -13.67,19.64 -3.72,-4.82 -4.45,-25.07 1.76,-44.65 2.55,-8.02 6.95,-15.34 11.3,-21.3 -7.98,-7.6 -16.65,-15.65 -25.55,-23.79 -5.4,7.18 -10.72,15.06 -13.16,21.1 -5.85,14.26 -8.62,26.35 -12.58,21.72 -3.89,-4.67 -5.6,-25.71 -0.35,-46.68 1.29,-5.17 3.26,-10.14 5.51,-14.74 -8.82,-7.89 -17.35,-15.45 -25.18,-22.31 -2.3,5.01 -4.22,9.75 -5.28,13.66 -4.6,16.98 -6.32,31 -10.84,26.71 -4.53,-4.2 -8.38,-26.82 -5.07,-50.86 0.31,-2.3 0.76,-4.59 1.27,-6.88 l -2.21,-1.9 c -5.11,-4.43 -10.68,-9.77 -16.44,-15.64 -1.43,4.52 -2.54,8.74 -3.13,12.25 -2.91,17.7 -3.36,31.85 -7.99,28.47 -4.62,-3.32 -10.15,-25.15 -9.04,-49.57 0.17,-3.84 0.64,-7.72 1.27,-11.52 -6.76,-7.62 -13.45,-15.51 -19.75,-23.18 -3.65,9.38 -6.95,19.1 -8.23,26.11 -3.34,18.53 -4.03,33.4 -8.76,29.75 -4.33,-3.29 -9.08,-23.12 -8.56,-46.19 -4.71,-3.45 -10.82,-19.53 -11.02,-37.76 -0.09,-6.2 1.01,-12.55 2.51,-18.29 -3.05,-4.31 -8.4,-7.29 -12.14,-12.57 -19.3,-27.05 -11.43,-59.27 30.28,-66.44 12.78,-39.46 45.17,-58.61 94.87,-59.05 6.68,-0.07 13.64,2.27 20.18,1.86 7.38,-0.5 13.46,-3.5 20.2,-3.71 36.22,-1.09 55.22,10.43 82.74,18.48 20.55,5.96 41.74,7.89 54.52,12.9 19.57,7.68 28.87,28.77 44.4,38.76 5.78,3.71 16.69,5.46 26.25,11.06 8.07,4.75 15.05,13.39 22.2,16.6 6.24,2.85 16.65,2.28 24.22,5.55 12.67,5.51 26.68,17.4 42.4,25.86 32.91,17.63 59.7,30.68 94.87,46.11 16.8,7.38 34.58,24.72 44.41,25.84 11.65,1.35 25.22,-8.4 34.31,-7.37 18.52,-22.06 24.98,-52.89 24.2,-92.52 1.1,-0.11 0.29,-9.83 0.29,-9.83 0,0 6.47,-85.09 -126.17,-131.03 -41.25,-14.28 -117.07,-51.81 -173.39,-80.72 218.91,6.81 416.91,96.33 564.01,238.52 -44.49,-11.55 -91.92,-41.79 -121.13,-44.56 -79.65,-7.55 -93.92,27.92 -30.29,33.77 24.03,2.21 59.49,4.92 87.8,18.38 49.4,23.51 100.3,46.22 127.3,60.84 4.41,5.31 8.63,10.78 12.92,16.2 -6.55,-0.08 -18.12,-1.77 -36.09,-5.44 -42.4,-8.65 -87.56,-37.47 -122.51,-43.97 -77.25,-14.32 -122.78,-0.55 -82.01,16.35 59.21,24.57 254.55,30.7 274.96,175.91 20.42,145.23 6.13,210.72 -4.09,247.53 -4.89,17.65 -15.85,43.7 -25.98,66.09 -2.85,15.8 -6.61,29.2 -9.88,38.76 -1.84,4.31 -3.67,9.85 -5.48,16.85 0,0 -2.55,17.91 5.61,35.28 7.23,15.43 32.05,48.86 33.73,81.2 0.03,1.96 0.11,3.92 0.08,5.88 -0.1,2.19 -0.29,4.35 -0.63,6.51 l -0.18,1.91 c -3.19,18.14 -13.58,30.77 -27.69,40.18 -9.09,6.04 -21.46,7.95 -28.26,16.59 5.42,17.09 22.71,23.17 29.91,37.14 4.5,12.39 0.83,25.42 -6.01,37.26 -13.17,14.79 -39.04,27.62 -62.26,36.33 -29.07,10.92 -58.62,19.54 -78.59,35.23 -21.11,11.25 -35.29,33.01 -22.34,61.76 3.37,7.48 4.87,15 4.77,22.16 l -0.09,2.09 c -0.03,1.46 -0.23,2.77 -0.41,4.12 -0.16,1.04 -0.33,2.07 -0.56,3.09 l -0.47,1.79 -0.56,2.02 c -5.32,17.95 -33.54,23.01 -43.6,23.9 -22.79,2.05 -37.52,8.24 -49.63,12.08 9.74,-5.08 19.54,-11.85 32.01,-16.88 7.9,-3.22 19.23,-5.15 28.78,-8.33 l 0.07,0.01 c 0,0 17.62,-3.57 22.46,-15.85 4.85,-12.27 2.04,-23.01 0,-29.9 l -0.74,-1.99 c -1.76,-5.39 -3.73,-10.57 -4.14,-15.93 -1.65,-21.14 11.3,-32.16 18.17,-49.84 12.39,-11.79 30.03,-24 54.5,-35.05 21.98,-9.96 48.29,-15.98 64.59,-25.84 9.45,-5.71 26.64,-19.51 26.25,-29.55 -0.3,-7.68 -14.47,-18.17 -20.19,-25.82 -4.07,-5.45 -6.11,-12.68 -9.75,-17.83 -3.19,-5.02 -7.26,-8.26 -11.96,-8.26 -6.12,0 -20.08,-2.37 -10.89,-3.06 9.18,-0.68 33.01,-11.93 33.01,-11.93 l -0.02,-0.03 c 32.2,-13.33 53.84,-38.06 42,-73.32 -9.91,-29.53 -32.71,-54.25 -34.31,-86.74 -1.7,-34.56 14.12,-63.03 16.14,-90.44 3.42,-46.12 -3.19,-77.9 -12.1,-112.58 -4.18,-16.21 -6.4,-32.18 -10.09,-47.96 -15.72,-67.21 -56.27,-96.32 -111.03,-127.36 -23.74,-13.46 -49.22,-38.28 -74.69,-46.13 -4.09,-1.26 -10.41,0.66 -14.14,0 -23.46,-4.25 -44.57,-15.89 -68.63,-20.3 -22.66,-4.17 -46.42,-2.18 -73.31,-8.99 -13.65,-4.88 -31.13,-12.18 -41.34,-16.53 -15.79,-7.19 -31.26,-14.69 -46.7,-22.26 L 2782.7,2380 c 0,0 -28.58,-16.57 3.07,-4.31 25.46,9.88 112.97,53.51 76.31,27.89 -25.28,-12.72 -38.99,-30.79 -61.35,-46.2 0,0 -75.23,-37.37 -86.52,-47.81 -12.4,-11.48 -27.56,-5.13 -37.52,-16.37 -11.69,-13.22 -26.02,-21.13 -36.24,-24.55 -10.2,-3.43 -21.77,-25.92 -37.43,-37.5 -15.66,-11.59 -49.68,-8.18 -79.64,-21.14 -29.94,-12.95 -60.97,-13.12 -60.97,-13.12 -2.98,-0.28 -5.85,-0.46 -8.61,-0.54 -1.18,-0.02 -2.28,0 -3.41,0 -17.52,-0.1 -30.91,3.31 -41.17,7.09 -12.51,4.61 -17.1,2.3 -14.29,0.78 2.8,-1.54 10.95,-9.16 10.95,-9.16 -34.93,0.04 -44.47,23.3 -60.55,40.57 7.31,1.04 28.16,-4.06 17.57,2.08 -20.92,10.03 -61.21,10.74 -61.99,34.85 -0.61,18.9 8.07,14.77 8.07,14.77 14.65,-25.56 59.89,-28.07 92.87,-27.71 61.43,0.73 103.01,34.49 143.27,53.58 13.05,7.86 28.3,18.19 28.3,18.19 l -0.09,-0.31 c 12.72,8.3 25.56,16.35 36.43,26.37 18.96,17.45 31.78,40.22 48.46,59.56 1.94,3.28 6.01,7.3 10.85,11.33 4.7,4.43 9.76,8.54 15.38,12.15 l 0.22,-0.45 2.18,1.47 -0.39,0.82 c 40.51,23.02 78.28,48.49 110.13,79.41 l 0.22,0.36 c 4.56,4.16 28.54,30.96 40.13,43.98 13.65,18.24 23.49,41.29 29.19,64.5 2.06,8.4 0.75,18.61 4.03,27.7 5.08,14.1 17.87,26.65 26.25,40.58 8.68,14.51 14.42,30.31 20.18,46.15 25.25,69.52 54.45,124.86 109,162.4 26.29,18.11 58.21,29.77 76.7,57.24 -13.42,-13.68 -30.91,-23.63 -52.03,-30.26 -59.98,-19.78 -98.99,-70.5 -118.6,-102.69 -15.06,-27.12 -26.7,-57.34 -35.25,-90.38 -2.85,40.73 -12.88,72.51 -26.25,103.36 -11.89,27.42 -22.4,56.41 -44.41,73.8 0,0 -0.85,-0.05 -4.26,2.02 -3.4,2.02 56.74,3.53 56.74,3.53 10.53,-0.38 21.23,-1.88 32.09,-3.3 2.03,0.22 4.53,0.11 7.59,-0.44 33.06,-5.84 67.43,6.49 88.83,22.1 11.11,8.1 30.43,14.59 46.46,18.98 0.27,0.7 1.83,1.48 5.83,2.26 0,0 24.5,7.65 50.53,14.82 17.63,4.84 30.48,8.54 39.39,12.95 5.17,3.29 10.09,7.25 13.9,11.99 7.63,9.42 7.77,20.74 14.14,36.9 6.33,16.1 16.01,28.63 16.14,42.45 0.46,45.3 -42.37,81.38 -88.81,57.23 45.72,11.8 78.15,-10.54 72.67,-53.55 -6.76,-53.12 -86.66,-92.5 -135.25,-112.57 -19.26,-7.94 -41.82,-17.98 -64.59,-20.29 -32.85,-3.33 -62.6,3.7 -90.84,1.86 -36.22,-2.4 -60.3,-21.58 -90.84,-24.01 -26.24,-2.1 -22.68,15.68 -45.45,17.71 -4.72,2.68 -19.04,0 -33.28,0.73 -39.38,-10.42 -64.7,7.62 -96.88,22.16 -23.21,10.51 -47.98,20.06 -72.68,22.15 -62,5.27 -99.7,-3.37 -150.38,2.01 -14.29,1.53 -43.95,3.33 -58.03,8.62 -43.84,16.43 -77.41,10.48 -125.04,11.15 -34.65,0.51 -66.8,2.33 -88.43,-1.46 -5.9,-1.07 -11.87,-2.6 -18.18,-3.7 -46.42,-8.13 -117.12,-12.34 -115.05,-53.52 3.46,2.37 2.5,8.77 8.07,9.23 -0.2,-7.58 -0.39,-15.14 2.01,-20.32 -26.99,0.7 -42.91,19.37 -42.38,40.6 0.9,36.12 58.9,51.22 98.91,60.92 40.1,9.7 81.75,21.05 111.03,25.84 -70.13,-10.33 -144.31,-16.97 -197.84,-42.47 -0.75,2.77 -1.24,5.45 -1.55,8.02 -4.24,19.49 -13.48,49.4 -19.98,78.46 -7.48,33.4 4.07,92.05 4.07,92.05 l 0.29,-0.34 c 4.83,29.8 10.98,43.09 16.94,60.9 12.69,38.01 53.68,49.94 82.38,53.55 -24.19,-17.13 -39.65,-38.36 -49.44,-66.79 -1.21,-10.09 -2.15,-19.55 -2.85,-27.9 21.73,67.74 82.33,93.09 82.33,93.09 l 19.4,20.96 -0.24,-0.95 c 33.45,32.42 77.66,57.54 133.84,59.13 28.31,0.79 62.52,-6.68 62.43,-34.49 -0.05,-15.73 -12.32,-29.09 -29.06,-36.46 4.92,-0.97 9.43,-0.29 13.51,1.4 l 17.4,19.5 c 5.74,14.26 5.24,32.26 -4.46,43.12 25.6,21.93 65.46,-2.67 62.56,-31.76 7.49,6.33 12.06,18.3 6.91,27.78 34.44,20.28 53.72,-28.88 88.39,-17.4 -3.27,9.84 -19.95,7.84 -25.04,16.05 45.31,6.5 85.06,-9.46 130.49,-5.85 2.85,-2.48 5.94,-4.94 9.21,-7.4 -84.98,-9.42 -15.93,-9.37 -15.93,-9.37 10.88,1 37.03,2.83 47.19,1.01 16.65,-3 27.39,1.06 42.09,6.82 0.36,-0.64 1.83,-0.59 2.72,1.08 7.62,3 16.41,6.34 27.56,9.36 4.32,0.61 8.66,1.72 12.88,3.09 l 1.82,0.38 0.25,0.29 c 5.83,2.03 11.31,4.46 16.01,6.75 42.83,20.61 78.34,69.18 114.92,94.66 60.61,42.19 118,-9.93 160.2,-43.76 l -0.27,-0.4 c 10.58,-7.23 24.53,-16.15 39.73,-25.48 39.71,-17.3 92.08,-32.44 120.05,-60.13 22.38,-22.15 29.99,-50.67 39.62,-80.27 8.98,-27.62 26.42,-52.03 36.22,-83.01 1.89,1.58 3.01,3.97 3.64,6.83 -0.27,2.65 -0.7,5.44 0.09,7.16 l 0.53,-0.48 c -0.11,5.41 -1.3,11.74 -3.15,18.42 -8.32,16.97 -22.86,36.29 -21.07,51.41 0,0 51.58,-26.7 110.11,-53.23 20.15,-9.14 38.61,-24.2 54.71,-41.42 l 4.7,0.11 c -0.56,-1.21 -0.5,-2.95 -0.33,-4.78 28.44,-31.94 48.61,-69.98 55.62,-91.97 1.45,-4.52 3.08,-9.09 4.84,-13.64 l 0.01,-0.06 c 2.21,-5.73 4.59,-11.4 7.04,-16.85 l 0.05,0.07 c 1.04,-1.85 1.69,-3.67 2.39,-5.51 8.44,-18.32 16.73,-33.17 19.05,-37.24 9.93,-12.38 17.35,-29.34 26.56,-40.46 -0.53,6.85 -0.88,13.75 -1.56,20.55 z m -826.19,277.09 c 87.27,-80.81 98.01,-168.37 104.71,-193.66 6.6,-25.12 9.82,-16.62 9.82,-16.62 1.21,85.58 -66.47,193.97 -127.36,229.62 -60,35.19 -215.11,29.07 -251.54,31.9 -35.85,2.74 -53.77,-42.93 -53.77,-42.93 -0.46,-9.67 7.43,1.42 7.43,1.42 23.42,42.28 44.01,34.55 44.01,34.55 74.22,-21.72 87.45,-130.94 90.54,-156.26 3.07,-25.11 9.41,-8.76 9.41,-8.76 7.21,62.85 -38.53,139.45 -48.15,149.3 -9.61,9.76 -0.43,15.3 30.23,6.7 92.32,-25.96 100.96,-174.08 106.52,-192.04 5.57,-17.89 9.03,-0.68 9.03,-0.68 -12.48,136.19 -64.16,169.77 -77.93,188.5 -5.72,7.77 40.96,8.94 61.5,-4.45 116.01,-75.08 102.99,-218.89 113.43,-198.36 10.58,20.95 -29.19,151.09 -85.08,195.37 -11.18,8.84 38.79,-6.6 57.2,-23.6 z m 214.59,112.44 c 23.17,-14 34.21,-17.55 34.21,-17.55 0,0 -16.18,-4.55 -23.54,-16.71 -7.37,-12.16 -16.19,-21.52 -41.94,-17.7 -27.04,4.02 -31.99,-0.22 -45.6,-2.44 0,0 4.76,13.86 17.65,20.87 12.87,7 28.05,52.37 59.22,33.53 z m 2.05,33.45 c 8.47,2.44 35.81,-1.73 18.17,1.85 -17.72,4.96 -28.72,-0.09 -40.36,-7.4 -26.76,-16.75 -48.56,-55.22 -76.72,-71.95 -12.22,-7.31 -24.17,-5.63 -34.33,-18.48 6.58,-13.17 13.26,-5.42 22.22,-7.38 19.86,-4.32 38.16,-12.04 56.52,-23.96 20.33,-13.25 42.35,-37.56 72.67,-35.09 9.67,0.77 27.24,10.15 34.32,14.77 8.84,5.77 29.83,19.54 24.22,40.6 -2.49,9.33 -13.59,10.83 -20.2,18.46 -9.15,10.61 -8.8,21.03 -16.13,33.21 15.98,-3.22 25.13,-12.71 42.37,-14.77 -27.15,24.39 -58.44,45 -96.88,59.07 2.88,1.64 4.72,8.35 14.13,11.07 z M 2223.96,3307.9 c -2.19,16.18 -17.4,30.55 -44.41,22.16 0,0 -34.92,-7.98 -44.43,-69.84 0,0 -1.66,-31.21 8.1,-24.31 -8.22,37.5 27.37,54.49 35.53,58.3 11.48,5.13 20.97,3.4 21.69,-6.37 0.79,-10.54 -11.24,-15.2 -14.84,-26.07 12.77,7.22 41.33,24.13 38.36,46.13 z m 668.31,-133.09 c 27.34,4.37 78.51,23.3 99.04,36.15 22.28,13.93 38.84,67.36 16.13,96.94 -10.17,13.24 -34.52,30.03 -40.38,31.38 -6.68,-3.88 4.2,-7.41 6.05,-9.22 7.7,-7.6 24.88,-21.51 30.28,-33.22 11.03,-23.95 7.65,-60.6 -12.12,-73.85 -13.32,-8.9 -78.47,-33.25 -106.97,-33.21 -80.17,0.11 -88.31,88.29 -137.27,118.12 0.87,-8.43 7.02,-26.13 14.02,-35.28 27.53,-36 53.83,-110.21 131.22,-97.81"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path92"
+ style="fill:#5d802f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2433.33,2370.61 c 0.44,-4.18 2.32,-8.2 3.64,-12.03 0.27,19.49 1.09,47.95 21.49,59.93 3.2,1.86 6.38,2.84 9.52,2.84 8.01,0 13.14,-5.65 16.36,-12.02 -0.35,15.85 1.93,31.07 12.45,38.27 5.18,3.59 10,5.32 14.61,5.32 13.21,0 18.54,-13.65 21.4,-20.98 0.47,-1.15 0.86,-2.18 1.27,-3.11 5.43,-12.42 19.9,-37.76 26.67,-43.33 2.68,2.13 6.03,4.9 7.08,6.42 -0.37,0.5 -0.99,1.17 -1.78,2.1 -42.06,48.68 -29.05,81.43 -10.7,100.35 1.31,1.51 4.77,4.85 9.87,4.85 6.26,0 11.15,-4.56 14.53,-13.49 5.33,-14.1 26.51,-41.61 30.55,-44.43 l 0.99,-0.49 c 2.07,-1.05 4.66,-2.36 6.14,-2.36 l 1.2,0.74 c 1.32,1.41 2.02,2.65 2.41,3.58 -8.82,10.66 -39.16,50.51 -27.93,82.65 1.66,4.78 6.74,19.34 18.65,19.34 10.99,0 18.37,-13.19 20.89,-18.44 6.44,-8.21 23.48,-28.51 32.54,-33.85 2.24,-1.27 4.78,-1.95 7.56,-1.95 4.48,0 8.36,1.68 10.27,2.81 -10.65,8.04 -31.32,39.91 -24.68,67.59 2.94,12.3 13.27,17.81 22.2,17.81 4.37,0 8.25,-1.27 10.93,-3.61 1.01,-0.87 3.11,-3.14 5.94,-6.27 7.87,-8.61 26.27,-28.86 37.27,-32.77 2.14,-0.75 4.09,-1.15 5.87,-1.15 4.13,0 6.86,2.09 9.5,4.82 -0.73,0.56 -1.66,1.22 -2.86,2.02 -4.97,3.36 -29.76,28.79 -19.55,60.6 3.72,11.63 12.01,12.88 15.4,12.88 7.95,0 15.18,-5.84 18.19,-9.31 5.35,-6.09 26.76,-24.07 32.16,-24.45 4.01,0.71 2.25,2.71 8.31,10.37 5,11.5 -10.48,12.08 -25.14,16.79 -8.01,2.57 -25.83,21.87 -41.9,14.16 -16.06,-7.69 -172.23,-113.68 -103.34,-29.72 28.99,35.32 66.68,50.35 63.89,59.45 -4.26,13.83 -48.2,14.69 -60.75,23.8 -6.53,4.73 -12.16,-5.39 -16.07,-14.7 -39.01,-152.94 -175.78,-233.82 -188.79,-242.48 0,0 -35.95,-22.04 -26.53,-21.68 9.43,0.34 27.02,3.64 30.27,-26.87"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path94"
+ style="fill:#5d802f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 2747.21,2810.08 c -62.51,-19.99 -119.08,-11.38 -119.08,-11.38 -22.18,0.52 -23.98,27.54 -27.27,49.98 -3.36,23 22.07,-23.5 53.19,-30.48 29.63,-6.74 40.8,-4.57 37.8,18.39 -3.21,24.06 27.8,-3.65 46.52,-7.14 0,0 2.3,-1.48 12,-0.96 9.68,0.53 27.48,-6.91 -3.16,-18.41"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/3rdparty/libuv/include/android-ifaddrs.h b/3rdparty/libuv/include/android-ifaddrs.h
new file mode 100644
index 00000000000..9cd19fec129
--- /dev/null
+++ b/3rdparty/libuv/include/android-ifaddrs.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995, 1999
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
+ */
+
+#ifndef _IFADDRS_H_
+#define _IFADDRS_H_
+
+struct ifaddrs {
+ struct ifaddrs *ifa_next;
+ char *ifa_name;
+ unsigned int ifa_flags;
+ struct sockaddr *ifa_addr;
+ struct sockaddr *ifa_netmask;
+ struct sockaddr *ifa_dstaddr;
+ void *ifa_data;
+};
+
+/*
+ * This may have been defined in <net/if.h>. Note that if <net/if.h> is
+ * to be included it must be included before this header file.
+ */
+#ifndef ifa_broadaddr
+#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
+#endif
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+extern int getifaddrs(struct ifaddrs **ifap);
+extern void freeifaddrs(struct ifaddrs *ifa);
+__END_DECLS
+
+#endif
diff --git a/3rdparty/libuv/include/pthread-fixes.h b/3rdparty/libuv/include/pthread-fixes.h
new file mode 100644
index 00000000000..88c6b66987a
--- /dev/null
+++ b/3rdparty/libuv/include/pthread-fixes.h
@@ -0,0 +1,72 @@
+/* Copyright (c) 2013, Sony Mobile Communications AB
+ * Copyright (c) 2012, Google Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Google Inc. nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H
+#define GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H
+
+#include <pthread.h>
+
+
+/*Android doesn't provide pthread_barrier_t for now.*/
+#ifndef PTHREAD_BARRIER_SERIAL_THREAD
+
+/* Anything except 0 will do here.*/
+#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345
+
+typedef struct {
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ unsigned count;
+} pthread_barrier_t;
+
+int pthread_barrier_init(pthread_barrier_t* barrier,
+ const void* barrier_attr,
+ unsigned count);
+
+int pthread_barrier_wait(pthread_barrier_t* barrier);
+int pthread_barrier_destroy(pthread_barrier_t *barrier);
+#endif /* defined(PTHREAD_BARRIER_SERIAL_THREAD) */
+
+int pthread_yield(void);
+
+/* Workaround pthread_sigmask() returning EINVAL on versions < 4.1 by
+ * replacing all calls to pthread_sigmask with sigprocmask. See:
+ * https://android.googlesource.com/platform/bionic/+/9bf330b5
+ * https://code.google.com/p/android/issues/detail?id=15337
+ */
+int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
+
+#ifdef pthread_sigmask
+#undef pthread_sigmask
+#endif
+#define pthread_sigmask(how, set, oldset) uv__pthread_sigmask(how, set, oldset)
+
+#endif /* GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H */
diff --git a/3rdparty/libuv/include/stdint-msvc2008.h b/3rdparty/libuv/include/stdint-msvc2008.h
new file mode 100644
index 00000000000..d02608a5972
--- /dev/null
+++ b/3rdparty/libuv/include/stdint-msvc2008.h
@@ -0,0 +1,247 @@
+// ISO C9x compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006-2008 Alexander Chemeris
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. The name of the author may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include <limits.h>
+
+// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
+// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
+// or compiler give many errors like this:
+// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#ifdef __cplusplus
+extern "C" {
+#endif
+# include <wchar.h>
+#ifdef __cplusplus
+}
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+# define _W64 __w64
+# else
+# define _W64
+# endif
+#endif
+
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+
+// Visual Studio 6 and Embedded Visual C++ 4 doesn't
+// realize that, e.g. char has the same size as __int8
+// so we give up on __intX for them.
+#if (_MSC_VER < 1300)
+ typedef signed char int8_t;
+ typedef signed short int16_t;
+ typedef signed int int32_t;
+ typedef unsigned char uint8_t;
+ typedef unsigned short uint16_t;
+ typedef unsigned int uint32_t;
+#else
+ typedef signed __int8 int8_t;
+ typedef signed __int16 int16_t;
+ typedef signed __int32 int32_t;
+ typedef unsigned __int8 uint8_t;
+ typedef unsigned __int16 uint16_t;
+ typedef unsigned __int32 uint32_t;
+#endif
+typedef signed __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t int_fast8_t;
+typedef int16_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef int64_t int_fast64_t;
+typedef uint8_t uint_fast8_t;
+typedef uint16_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+typedef uint64_t uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+ typedef signed __int64 intptr_t;
+ typedef unsigned __int64 uintptr_t;
+#else // _WIN64 ][
+ typedef _W64 signed int intptr_t;
+ typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN ((int8_t)_I8_MIN)
+#define INT8_MAX _I8_MAX
+#define INT16_MIN ((int16_t)_I16_MIN)
+#define INT16_MAX _I16_MAX
+#define INT32_MIN ((int32_t)_I32_MIN)
+#define INT32_MAX _I32_MAX
+#define INT64_MIN ((int64_t)_I64_MIN)
+#define INT64_MAX _I64_MAX
+#define UINT8_MAX _UI8_MAX
+#define UINT16_MAX _UI16_MAX
+#define UINT32_MAX _UI32_MAX
+#define UINT64_MAX _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST16_MAX INT16_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+# define INTPTR_MIN INT64_MIN
+# define INTPTR_MAX INT64_MAX
+# define UINTPTR_MAX UINT64_MAX
+#else // _WIN64 ][
+# define INTPTR_MIN INT32_MIN
+# define INTPTR_MAX INT32_MAX
+# define UINTPTR_MAX UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+# define PTRDIFF_MIN _I64_MIN
+# define PTRDIFF_MAX _I64_MAX
+#else // _WIN64 ][
+# define PTRDIFF_MIN _I32_MIN
+# define PTRDIFF_MAX _I32_MAX
+#endif // _WIN64 ]
+
+#define SIG_ATOMIC_MIN INT_MIN
+#define SIG_ATOMIC_MAX INT_MAX
+
+#ifndef SIZE_MAX // [
+# ifdef _WIN64 // [
+# define SIZE_MAX _UI64_MAX
+# else // _WIN64 ][
+# define SIZE_MAX _UI32_MAX
+# endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
+#ifndef WCHAR_MIN // [
+# define WCHAR_MIN 0
+#endif // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+# define WCHAR_MAX _UI16_MAX
+#endif // WCHAR_MAX ]
+
+#define WINT_MIN 0
+#define WINT_MAX _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val) val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val) val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+#define INTMAX_C INT64_C
+#define UINTMAX_C UINT64_C
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+
+#endif // _MSC_STDINT_H_ ]
diff --git a/3rdparty/libuv/include/tree.h b/3rdparty/libuv/include/tree.h
new file mode 100644
index 00000000000..f936416e3d8
--- /dev/null
+++ b/3rdparty/libuv/include/tree.h
@@ -0,0 +1,768 @@
+/*-
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UV_TREE_H_
+#define UV_TREE_H_
+
+#ifndef UV__UNUSED
+# if __GNUC__
+# define UV__UNUSED __attribute__((unused))
+# else
+# define UV__UNUSED
+# endif
+#endif
+
+/*
+ * This file defines data structures for different types of trees:
+ * splay trees and red-black trees.
+ *
+ * A splay tree is a self-organizing data structure. Every operation
+ * on the tree causes a splay to happen. The splay moves the requested
+ * node to the root of the tree and partly rebalances it.
+ *
+ * This has the benefit that request locality causes faster lookups as
+ * the requested nodes move to the top of the tree. On the other hand,
+ * every lookup causes memory writes.
+ *
+ * The Balance Theorem bounds the total access time for m operations
+ * and n inserts on an initially empty tree as O((m + n)lg n). The
+ * amortized cost for a sequence of m accesses to a splay tree is O(lg n);
+ *
+ * A red-black tree is a binary search tree with the node color as an
+ * extra attribute. It fulfills a set of conditions:
+ * - every search path from the root to a leaf consists of the
+ * same number of black nodes,
+ * - each red node (except for the root) has a black parent,
+ * - each leaf node is black.
+ *
+ * Every operation on a red-black tree is bounded as O(lg n).
+ * The maximum height of a red-black tree is 2lg (n+1).
+ */
+
+#define SPLAY_HEAD(name, type) \
+struct name { \
+ struct type *sph_root; /* root of the tree */ \
+}
+
+#define SPLAY_INITIALIZER(root) \
+ { NULL }
+
+#define SPLAY_INIT(root) do { \
+ (root)->sph_root = NULL; \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ENTRY(type) \
+struct { \
+ struct type *spe_left; /* left element */ \
+ struct type *spe_right; /* right element */ \
+}
+
+#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
+#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
+#define SPLAY_ROOT(head) (head)->sph_root
+#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
+
+/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
+#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
+ (head)->sph_root = tmp; \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
+ (head)->sph_root = tmp; \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_LINKLEFT(head, tmp, field) do { \
+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
+ tmp = (head)->sph_root; \
+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_LINKRIGHT(head, tmp, field) do { \
+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
+ tmp = (head)->sph_root; \
+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
+ SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
+ SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field); \
+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
+} while (/*CONSTCOND*/ 0)
+
+/* Generates prototypes and inline functions */
+
+#define SPLAY_PROTOTYPE(name, type, field, cmp) \
+void name##_SPLAY(struct name *, struct type *); \
+void name##_SPLAY_MINMAX(struct name *, int); \
+struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
+struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
+ \
+/* Finds the node with the same key as elm */ \
+static __inline struct type * \
+name##_SPLAY_FIND(struct name *head, struct type *elm) \
+{ \
+ if (SPLAY_EMPTY(head)) \
+ return(NULL); \
+ name##_SPLAY(head, elm); \
+ if ((cmp)(elm, (head)->sph_root) == 0) \
+ return (head->sph_root); \
+ return (NULL); \
+} \
+ \
+static __inline struct type * \
+name##_SPLAY_NEXT(struct name *head, struct type *elm) \
+{ \
+ name##_SPLAY(head, elm); \
+ if (SPLAY_RIGHT(elm, field) != NULL) { \
+ elm = SPLAY_RIGHT(elm, field); \
+ while (SPLAY_LEFT(elm, field) != NULL) { \
+ elm = SPLAY_LEFT(elm, field); \
+ } \
+ } else \
+ elm = NULL; \
+ return (elm); \
+} \
+ \
+static __inline struct type * \
+name##_SPLAY_MIN_MAX(struct name *head, int val) \
+{ \
+ name##_SPLAY_MINMAX(head, val); \
+ return (SPLAY_ROOT(head)); \
+}
+
+/* Main splay operation.
+ * Moves node close to the key of elm to top
+ */
+#define SPLAY_GENERATE(name, type, field, cmp) \
+struct type * \
+name##_SPLAY_INSERT(struct name *head, struct type *elm) \
+{ \
+ if (SPLAY_EMPTY(head)) { \
+ SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
+ } else { \
+ int __comp; \
+ name##_SPLAY(head, elm); \
+ __comp = (cmp)(elm, (head)->sph_root); \
+ if(__comp < 0) { \
+ SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field); \
+ SPLAY_RIGHT(elm, field) = (head)->sph_root; \
+ SPLAY_LEFT((head)->sph_root, field) = NULL; \
+ } else if (__comp > 0) { \
+ SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field); \
+ SPLAY_LEFT(elm, field) = (head)->sph_root; \
+ SPLAY_RIGHT((head)->sph_root, field) = NULL; \
+ } else \
+ return ((head)->sph_root); \
+ } \
+ (head)->sph_root = (elm); \
+ return (NULL); \
+} \
+ \
+struct type * \
+name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
+{ \
+ struct type *__tmp; \
+ if (SPLAY_EMPTY(head)) \
+ return (NULL); \
+ name##_SPLAY(head, elm); \
+ if ((cmp)(elm, (head)->sph_root) == 0) { \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
+ } else { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
+ name##_SPLAY(head, elm); \
+ SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
+ } \
+ return (elm); \
+ } \
+ return (NULL); \
+} \
+ \
+void \
+name##_SPLAY(struct name *head, struct type *elm) \
+{ \
+ struct type __node, *__left, *__right, *__tmp; \
+ int __comp; \
+ \
+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
+ __left = __right = &__node; \
+ \
+ while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
+ if (__comp < 0) { \
+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if ((cmp)(elm, __tmp) < 0){ \
+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
+ break; \
+ } \
+ SPLAY_LINKLEFT(head, __right, field); \
+ } else if (__comp > 0) { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if ((cmp)(elm, __tmp) > 0){ \
+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
+ break; \
+ } \
+ SPLAY_LINKRIGHT(head, __left, field); \
+ } \
+ } \
+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
+} \
+ \
+/* Splay with either the minimum or the maximum element \
+ * Used to find minimum or maximum element in tree. \
+ */ \
+void name##_SPLAY_MINMAX(struct name *head, int __comp) \
+{ \
+ struct type __node, *__left, *__right, *__tmp; \
+ \
+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
+ __left = __right = &__node; \
+ \
+ while (1) { \
+ if (__comp < 0) { \
+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if (__comp < 0){ \
+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
+ break; \
+ } \
+ SPLAY_LINKLEFT(head, __right, field); \
+ } else if (__comp > 0) { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if (__comp > 0) { \
+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
+ break; \
+ } \
+ SPLAY_LINKRIGHT(head, __left, field); \
+ } \
+ } \
+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
+}
+
+#define SPLAY_NEGINF -1
+#define SPLAY_INF 1
+
+#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
+#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
+#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
+#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
+#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
+ : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
+#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
+ : name##_SPLAY_MIN_MAX(x, SPLAY_INF))
+
+#define SPLAY_FOREACH(x, name, head) \
+ for ((x) = SPLAY_MIN(name, head); \
+ (x) != NULL; \
+ (x) = SPLAY_NEXT(name, head, x))
+
+/* Macros that define a red-black tree */
+#define RB_HEAD(name, type) \
+struct name { \
+ struct type *rbh_root; /* root of the tree */ \
+}
+
+#define RB_INITIALIZER(root) \
+ { NULL }
+
+#define RB_INIT(root) do { \
+ (root)->rbh_root = NULL; \
+} while (/*CONSTCOND*/ 0)
+
+#define RB_BLACK 0
+#define RB_RED 1
+#define RB_ENTRY(type) \
+struct { \
+ struct type *rbe_left; /* left element */ \
+ struct type *rbe_right; /* right element */ \
+ struct type *rbe_parent; /* parent element */ \
+ int rbe_color; /* node color */ \
+}
+
+#define RB_LEFT(elm, field) (elm)->field.rbe_left
+#define RB_RIGHT(elm, field) (elm)->field.rbe_right
+#define RB_PARENT(elm, field) (elm)->field.rbe_parent
+#define RB_COLOR(elm, field) (elm)->field.rbe_color
+#define RB_ROOT(head) (head)->rbh_root
+#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
+
+#define RB_SET(elm, parent, field) do { \
+ RB_PARENT(elm, field) = parent; \
+ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
+ RB_COLOR(elm, field) = RB_RED; \
+} while (/*CONSTCOND*/ 0)
+
+#define RB_SET_BLACKRED(black, red, field) do { \
+ RB_COLOR(black, field) = RB_BLACK; \
+ RB_COLOR(red, field) = RB_RED; \
+} while (/*CONSTCOND*/ 0)
+
+#ifndef RB_AUGMENT
+#define RB_AUGMENT(x) do {} while (0)
+#endif
+
+#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
+ (tmp) = RB_RIGHT(elm, field); \
+ if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
+ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
+ } \
+ RB_AUGMENT(elm); \
+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ RB_LEFT(tmp, field) = (elm); \
+ RB_PARENT(elm, field) = (tmp); \
+ RB_AUGMENT(tmp); \
+ if ((RB_PARENT(tmp, field))) \
+ RB_AUGMENT(RB_PARENT(tmp, field)); \
+} while (/*CONSTCOND*/ 0)
+
+#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
+ (tmp) = RB_LEFT(elm, field); \
+ if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
+ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
+ } \
+ RB_AUGMENT(elm); \
+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ RB_RIGHT(tmp, field) = (elm); \
+ RB_PARENT(elm, field) = (tmp); \
+ RB_AUGMENT(tmp); \
+ if ((RB_PARENT(tmp, field))) \
+ RB_AUGMENT(RB_PARENT(tmp, field)); \
+} while (/*CONSTCOND*/ 0)
+
+/* Generates prototypes and inline functions */
+#define RB_PROTOTYPE(name, type, field, cmp) \
+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
+#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp, UV__UNUSED static)
+#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
+attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \
+attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
+attr struct type *name##_RB_REMOVE(struct name *, struct type *); \
+attr struct type *name##_RB_INSERT(struct name *, struct type *); \
+attr struct type *name##_RB_FIND(struct name *, struct type *); \
+attr struct type *name##_RB_NFIND(struct name *, struct type *); \
+attr struct type *name##_RB_NEXT(struct type *); \
+attr struct type *name##_RB_PREV(struct type *); \
+attr struct type *name##_RB_MINMAX(struct name *, int); \
+ \
+
+/* Main rb operation.
+ * Moves node close to the key of elm to top
+ */
+#define RB_GENERATE(name, type, field, cmp) \
+ RB_GENERATE_INTERNAL(name, type, field, cmp,)
+#define RB_GENERATE_STATIC(name, type, field, cmp) \
+ RB_GENERATE_INTERNAL(name, type, field, cmp, UV__UNUSED static)
+#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
+attr void \
+name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
+{ \
+ struct type *parent, *gparent, *tmp; \
+ while ((parent = RB_PARENT(elm, field)) != NULL && \
+ RB_COLOR(parent, field) == RB_RED) { \
+ gparent = RB_PARENT(parent, field); \
+ if (parent == RB_LEFT(gparent, field)) { \
+ tmp = RB_RIGHT(gparent, field); \
+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
+ RB_COLOR(tmp, field) = RB_BLACK; \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ elm = gparent; \
+ continue; \
+ } \
+ if (RB_RIGHT(parent, field) == elm) { \
+ RB_ROTATE_LEFT(head, parent, tmp, field); \
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ RB_ROTATE_RIGHT(head, gparent, tmp, field); \
+ } else { \
+ tmp = RB_LEFT(gparent, field); \
+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
+ RB_COLOR(tmp, field) = RB_BLACK; \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ elm = gparent; \
+ continue; \
+ } \
+ if (RB_LEFT(parent, field) == elm) { \
+ RB_ROTATE_RIGHT(head, parent, tmp, field); \
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ RB_ROTATE_LEFT(head, gparent, tmp, field); \
+ } \
+ } \
+ RB_COLOR(head->rbh_root, field) = RB_BLACK; \
+} \
+ \
+attr void \
+name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, \
+ struct type *elm) \
+{ \
+ struct type *tmp; \
+ while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
+ elm != RB_ROOT(head)) { \
+ if (RB_LEFT(parent, field) == elm) { \
+ tmp = RB_RIGHT(parent, field); \
+ if (RB_COLOR(tmp, field) == RB_RED) { \
+ RB_SET_BLACKRED(tmp, parent, field); \
+ RB_ROTATE_LEFT(head, parent, tmp, field); \
+ tmp = RB_RIGHT(parent, field); \
+ } \
+ if ((RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
+ (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \
+ RB_COLOR(tmp, field) = RB_RED; \
+ elm = parent; \
+ parent = RB_PARENT(elm, field); \
+ } else { \
+ if (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) { \
+ struct type *oleft; \
+ if ((oleft = RB_LEFT(tmp, field)) \
+ != NULL) \
+ RB_COLOR(oleft, field) = RB_BLACK; \
+ RB_COLOR(tmp, field) = RB_RED; \
+ RB_ROTATE_RIGHT(head, tmp, oleft, field); \
+ tmp = RB_RIGHT(parent, field); \
+ } \
+ RB_COLOR(tmp, field) = RB_COLOR(parent, field); \
+ RB_COLOR(parent, field) = RB_BLACK; \
+ if (RB_RIGHT(tmp, field)) \
+ RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK; \
+ RB_ROTATE_LEFT(head, parent, tmp, field); \
+ elm = RB_ROOT(head); \
+ break; \
+ } \
+ } else { \
+ tmp = RB_LEFT(parent, field); \
+ if (RB_COLOR(tmp, field) == RB_RED) { \
+ RB_SET_BLACKRED(tmp, parent, field); \
+ RB_ROTATE_RIGHT(head, parent, tmp, field); \
+ tmp = RB_LEFT(parent, field); \
+ } \
+ if ((RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
+ (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \
+ RB_COLOR(tmp, field) = RB_RED; \
+ elm = parent; \
+ parent = RB_PARENT(elm, field); \
+ } else { \
+ if (RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) { \
+ struct type *oright; \
+ if ((oright = RB_RIGHT(tmp, field)) \
+ != NULL) \
+ RB_COLOR(oright, field) = RB_BLACK; \
+ RB_COLOR(tmp, field) = RB_RED; \
+ RB_ROTATE_LEFT(head, tmp, oright, field); \
+ tmp = RB_LEFT(parent, field); \
+ } \
+ RB_COLOR(tmp, field) = RB_COLOR(parent, field); \
+ RB_COLOR(parent, field) = RB_BLACK; \
+ if (RB_LEFT(tmp, field)) \
+ RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK; \
+ RB_ROTATE_RIGHT(head, parent, tmp, field); \
+ elm = RB_ROOT(head); \
+ break; \
+ } \
+ } \
+ } \
+ if (elm) \
+ RB_COLOR(elm, field) = RB_BLACK; \
+} \
+ \
+attr struct type * \
+name##_RB_REMOVE(struct name *head, struct type *elm) \
+{ \
+ struct type *child, *parent, *old = elm; \
+ int color; \
+ if (RB_LEFT(elm, field) == NULL) \
+ child = RB_RIGHT(elm, field); \
+ else if (RB_RIGHT(elm, field) == NULL) \
+ child = RB_LEFT(elm, field); \
+ else { \
+ struct type *left; \
+ elm = RB_RIGHT(elm, field); \
+ while ((left = RB_LEFT(elm, field)) != NULL) \
+ elm = left; \
+ child = RB_RIGHT(elm, field); \
+ parent = RB_PARENT(elm, field); \
+ color = RB_COLOR(elm, field); \
+ if (child) \
+ RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (RB_LEFT(parent, field) == elm) \
+ RB_LEFT(parent, field) = child; \
+ else \
+ RB_RIGHT(parent, field) = child; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = child; \
+ if (RB_PARENT(elm, field) == old) \
+ parent = elm; \
+ (elm)->field = (old)->field; \
+ if (RB_PARENT(old, field)) { \
+ if (RB_LEFT(RB_PARENT(old, field), field) == old) \
+ RB_LEFT(RB_PARENT(old, field), field) = elm; \
+ else \
+ RB_RIGHT(RB_PARENT(old, field), field) = elm; \
+ RB_AUGMENT(RB_PARENT(old, field)); \
+ } else \
+ RB_ROOT(head) = elm; \
+ RB_PARENT(RB_LEFT(old, field), field) = elm; \
+ if (RB_RIGHT(old, field)) \
+ RB_PARENT(RB_RIGHT(old, field), field) = elm; \
+ if (parent) { \
+ left = parent; \
+ do { \
+ RB_AUGMENT(left); \
+ } while ((left = RB_PARENT(left, field)) != NULL); \
+ } \
+ goto color; \
+ } \
+ parent = RB_PARENT(elm, field); \
+ color = RB_COLOR(elm, field); \
+ if (child) \
+ RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (RB_LEFT(parent, field) == elm) \
+ RB_LEFT(parent, field) = child; \
+ else \
+ RB_RIGHT(parent, field) = child; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = child; \
+color: \
+ if (color == RB_BLACK) \
+ name##_RB_REMOVE_COLOR(head, parent, child); \
+ return (old); \
+} \
+ \
+/* Inserts a node into the RB tree */ \
+attr struct type * \
+name##_RB_INSERT(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp; \
+ struct type *parent = NULL; \
+ int comp = 0; \
+ tmp = RB_ROOT(head); \
+ while (tmp) { \
+ parent = tmp; \
+ comp = (cmp)(elm, parent); \
+ if (comp < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ RB_SET(elm, parent, field); \
+ if (parent != NULL) { \
+ if (comp < 0) \
+ RB_LEFT(parent, field) = elm; \
+ else \
+ RB_RIGHT(parent, field) = elm; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = elm; \
+ name##_RB_INSERT_COLOR(head, elm); \
+ return (NULL); \
+} \
+ \
+/* Finds the node with the same key as elm */ \
+attr struct type * \
+name##_RB_FIND(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (NULL); \
+} \
+ \
+/* Finds the first node greater than or equal to the search key */ \
+attr struct type * \
+name##_RB_NFIND(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ struct type *res = NULL; \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) { \
+ res = tmp; \
+ tmp = RB_LEFT(tmp, field); \
+ } \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (res); \
+} \
+ \
+/* ARGSUSED */ \
+attr struct type * \
+name##_RB_NEXT(struct type *elm) \
+{ \
+ if (RB_RIGHT(elm, field)) { \
+ elm = RB_RIGHT(elm, field); \
+ while (RB_LEFT(elm, field)) \
+ elm = RB_LEFT(elm, field); \
+ } else { \
+ if (RB_PARENT(elm, field) && \
+ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ else { \
+ while (RB_PARENT(elm, field) && \
+ (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ elm = RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+} \
+ \
+/* ARGSUSED */ \
+attr struct type * \
+name##_RB_PREV(struct type *elm) \
+{ \
+ if (RB_LEFT(elm, field)) { \
+ elm = RB_LEFT(elm, field); \
+ while (RB_RIGHT(elm, field)) \
+ elm = RB_RIGHT(elm, field); \
+ } else { \
+ if (RB_PARENT(elm, field) && \
+ (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ else { \
+ while (RB_PARENT(elm, field) && \
+ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ elm = RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+} \
+ \
+attr struct type * \
+name##_RB_MINMAX(struct name *head, int val) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ struct type *parent = NULL; \
+ while (tmp) { \
+ parent = tmp; \
+ if (val < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else \
+ tmp = RB_RIGHT(tmp, field); \
+ } \
+ return (parent); \
+}
+
+#define RB_NEGINF -1
+#define RB_INF 1
+
+#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
+#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
+#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
+#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
+#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
+#define RB_PREV(name, x, y) name##_RB_PREV(y)
+#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
+#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
+
+#define RB_FOREACH(x, name, head) \
+ for ((x) = RB_MIN(name, head); \
+ (x) != NULL; \
+ (x) = name##_RB_NEXT(x))
+
+#define RB_FOREACH_FROM(x, name, y) \
+ for ((x) = (y); \
+ ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
+ (x) = (y))
+
+#define RB_FOREACH_SAFE(x, name, head, y) \
+ for ((x) = RB_MIN(name, head); \
+ ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
+ (x) = (y))
+
+#define RB_FOREACH_REVERSE(x, name, head) \
+ for ((x) = RB_MAX(name, head); \
+ (x) != NULL; \
+ (x) = name##_RB_PREV(x))
+
+#define RB_FOREACH_REVERSE_FROM(x, name, y) \
+ for ((x) = (y); \
+ ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
+ (x) = (y))
+
+#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \
+ for ((x) = RB_MAX(name, head); \
+ ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
+ (x) = (y))
+
+#endif /* UV_TREE_H_ */
diff --git a/3rdparty/libuv/include/uv-aix.h b/3rdparty/libuv/include/uv-aix.h
new file mode 100644
index 00000000000..7dc992fa6d7
--- /dev/null
+++ b/3rdparty/libuv/include/uv-aix.h
@@ -0,0 +1,32 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_AIX_H
+#define UV_AIX_H
+
+#define UV_PLATFORM_LOOP_FIELDS \
+ int fs_fd; \
+
+#define UV_PLATFORM_FS_EVENT_FIELDS \
+ uv__io_t event_watcher; \
+ char *dir_filename; \
+
+#endif /* UV_AIX_H */
diff --git a/3rdparty/libuv/include/uv-bsd.h b/3rdparty/libuv/include/uv-bsd.h
new file mode 100644
index 00000000000..2d72b3d7711
--- /dev/null
+++ b/3rdparty/libuv/include/uv-bsd.h
@@ -0,0 +1,34 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_BSD_H
+#define UV_BSD_H
+
+#define UV_PLATFORM_FS_EVENT_FIELDS \
+ uv__io_t event_watcher; \
+
+#define UV_IO_PRIVATE_PLATFORM_FIELDS \
+ int rcount; \
+ int wcount; \
+
+#define UV_HAVE_KQUEUE 1
+
+#endif /* UV_BSD_H */
diff --git a/3rdparty/libuv/include/uv-darwin.h b/3rdparty/libuv/include/uv-darwin.h
new file mode 100644
index 00000000000..d226415820b
--- /dev/null
+++ b/3rdparty/libuv/include/uv-darwin.h
@@ -0,0 +1,61 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_DARWIN_H
+#define UV_DARWIN_H
+
+#if defined(__APPLE__) && defined(__MACH__)
+# include <mach/mach.h>
+# include <mach/task.h>
+# include <mach/semaphore.h>
+# include <TargetConditionals.h>
+# define UV_PLATFORM_SEM_T semaphore_t
+#endif
+
+#define UV_IO_PRIVATE_PLATFORM_FIELDS \
+ int rcount; \
+ int wcount; \
+
+#define UV_PLATFORM_LOOP_FIELDS \
+ uv_thread_t cf_thread; \
+ void* _cf_reserved; \
+ void* cf_state; \
+ uv_mutex_t cf_mutex; \
+ uv_sem_t cf_sem; \
+ void* cf_signals[2]; \
+
+#define UV_PLATFORM_FS_EVENT_FIELDS \
+ uv__io_t event_watcher; \
+ char* realpath; \
+ int realpath_len; \
+ int cf_flags; \
+ uv_async_t* cf_cb; \
+ void* cf_events[2]; \
+ void* cf_member[2]; \
+ int cf_error; \
+ uv_mutex_t cf_mutex; \
+
+#define UV_STREAM_PRIVATE_PLATFORM_FIELDS \
+ void* select; \
+
+#define UV_HAVE_KQUEUE 1
+
+#endif /* UV_DARWIN_H */
diff --git a/3rdparty/libuv/include/uv-errno.h b/3rdparty/libuv/include/uv-errno.h
new file mode 100644
index 00000000000..53f30296c1c
--- /dev/null
+++ b/3rdparty/libuv/include/uv-errno.h
@@ -0,0 +1,418 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_ERRNO_H_
+#define UV_ERRNO_H_
+
+#include <errno.h>
+
+#define UV__EOF (-4095)
+#define UV__UNKNOWN (-4094)
+
+#define UV__EAI_ADDRFAMILY (-3000)
+#define UV__EAI_AGAIN (-3001)
+#define UV__EAI_BADFLAGS (-3002)
+#define UV__EAI_CANCELED (-3003)
+#define UV__EAI_FAIL (-3004)
+#define UV__EAI_FAMILY (-3005)
+#define UV__EAI_MEMORY (-3006)
+#define UV__EAI_NODATA (-3007)
+#define UV__EAI_NONAME (-3008)
+#define UV__EAI_OVERFLOW (-3009)
+#define UV__EAI_SERVICE (-3010)
+#define UV__EAI_SOCKTYPE (-3011)
+#define UV__EAI_BADHINTS (-3013)
+#define UV__EAI_PROTOCOL (-3014)
+
+/* Only map to the system errno on non-Windows platforms. It's apparently
+ * a fairly common practice for Windows programmers to redefine errno codes.
+ */
+#if defined(E2BIG) && !defined(_WIN32)
+# define UV__E2BIG (-E2BIG)
+#else
+# define UV__E2BIG (-4093)
+#endif
+
+#if defined(EACCES) && !defined(_WIN32)
+# define UV__EACCES (-EACCES)
+#else
+# define UV__EACCES (-4092)
+#endif
+
+#if defined(EADDRINUSE) && !defined(_WIN32)
+# define UV__EADDRINUSE (-EADDRINUSE)
+#else
+# define UV__EADDRINUSE (-4091)
+#endif
+
+#if defined(EADDRNOTAVAIL) && !defined(_WIN32)
+# define UV__EADDRNOTAVAIL (-EADDRNOTAVAIL)
+#else
+# define UV__EADDRNOTAVAIL (-4090)
+#endif
+
+#if defined(EAFNOSUPPORT) && !defined(_WIN32)
+# define UV__EAFNOSUPPORT (-EAFNOSUPPORT)
+#else
+# define UV__EAFNOSUPPORT (-4089)
+#endif
+
+#if defined(EAGAIN) && !defined(_WIN32)
+# define UV__EAGAIN (-EAGAIN)
+#else
+# define UV__EAGAIN (-4088)
+#endif
+
+#if defined(EALREADY) && !defined(_WIN32)
+# define UV__EALREADY (-EALREADY)
+#else
+# define UV__EALREADY (-4084)
+#endif
+
+#if defined(EBADF) && !defined(_WIN32)
+# define UV__EBADF (-EBADF)
+#else
+# define UV__EBADF (-4083)
+#endif
+
+#if defined(EBUSY) && !defined(_WIN32)
+# define UV__EBUSY (-EBUSY)
+#else
+# define UV__EBUSY (-4082)
+#endif
+
+#if defined(ECANCELED) && !defined(_WIN32)
+# define UV__ECANCELED (-ECANCELED)
+#else
+# define UV__ECANCELED (-4081)
+#endif
+
+#if defined(ECHARSET) && !defined(_WIN32)
+# define UV__ECHARSET (-ECHARSET)
+#else
+# define UV__ECHARSET (-4080)
+#endif
+
+#if defined(ECONNABORTED) && !defined(_WIN32)
+# define UV__ECONNABORTED (-ECONNABORTED)
+#else
+# define UV__ECONNABORTED (-4079)
+#endif
+
+#if defined(ECONNREFUSED) && !defined(_WIN32)
+# define UV__ECONNREFUSED (-ECONNREFUSED)
+#else
+# define UV__ECONNREFUSED (-4078)
+#endif
+
+#if defined(ECONNRESET) && !defined(_WIN32)
+# define UV__ECONNRESET (-ECONNRESET)
+#else
+# define UV__ECONNRESET (-4077)
+#endif
+
+#if defined(EDESTADDRREQ) && !defined(_WIN32)
+# define UV__EDESTADDRREQ (-EDESTADDRREQ)
+#else
+# define UV__EDESTADDRREQ (-4076)
+#endif
+
+#if defined(EEXIST) && !defined(_WIN32)
+# define UV__EEXIST (-EEXIST)
+#else
+# define UV__EEXIST (-4075)
+#endif
+
+#if defined(EFAULT) && !defined(_WIN32)
+# define UV__EFAULT (-EFAULT)
+#else
+# define UV__EFAULT (-4074)
+#endif
+
+#if defined(EHOSTUNREACH) && !defined(_WIN32)
+# define UV__EHOSTUNREACH (-EHOSTUNREACH)
+#else
+# define UV__EHOSTUNREACH (-4073)
+#endif
+
+#if defined(EINTR) && !defined(_WIN32)
+# define UV__EINTR (-EINTR)
+#else
+# define UV__EINTR (-4072)
+#endif
+
+#if defined(EINVAL) && !defined(_WIN32)
+# define UV__EINVAL (-EINVAL)
+#else
+# define UV__EINVAL (-4071)
+#endif
+
+#if defined(EIO) && !defined(_WIN32)
+# define UV__EIO (-EIO)
+#else
+# define UV__EIO (-4070)
+#endif
+
+#if defined(EISCONN) && !defined(_WIN32)
+# define UV__EISCONN (-EISCONN)
+#else
+# define UV__EISCONN (-4069)
+#endif
+
+#if defined(EISDIR) && !defined(_WIN32)
+# define UV__EISDIR (-EISDIR)
+#else
+# define UV__EISDIR (-4068)
+#endif
+
+#if defined(ELOOP) && !defined(_WIN32)
+# define UV__ELOOP (-ELOOP)
+#else
+# define UV__ELOOP (-4067)
+#endif
+
+#if defined(EMFILE) && !defined(_WIN32)
+# define UV__EMFILE (-EMFILE)
+#else
+# define UV__EMFILE (-4066)
+#endif
+
+#if defined(EMSGSIZE) && !defined(_WIN32)
+# define UV__EMSGSIZE (-EMSGSIZE)
+#else
+# define UV__EMSGSIZE (-4065)
+#endif
+
+#if defined(ENAMETOOLONG) && !defined(_WIN32)
+# define UV__ENAMETOOLONG (-ENAMETOOLONG)
+#else
+# define UV__ENAMETOOLONG (-4064)
+#endif
+
+#if defined(ENETDOWN) && !defined(_WIN32)
+# define UV__ENETDOWN (-ENETDOWN)
+#else
+# define UV__ENETDOWN (-4063)
+#endif
+
+#if defined(ENETUNREACH) && !defined(_WIN32)
+# define UV__ENETUNREACH (-ENETUNREACH)
+#else
+# define UV__ENETUNREACH (-4062)
+#endif
+
+#if defined(ENFILE) && !defined(_WIN32)
+# define UV__ENFILE (-ENFILE)
+#else
+# define UV__ENFILE (-4061)
+#endif
+
+#if defined(ENOBUFS) && !defined(_WIN32)
+# define UV__ENOBUFS (-ENOBUFS)
+#else
+# define UV__ENOBUFS (-4060)
+#endif
+
+#if defined(ENODEV) && !defined(_WIN32)
+# define UV__ENODEV (-ENODEV)
+#else
+# define UV__ENODEV (-4059)
+#endif
+
+#if defined(ENOENT) && !defined(_WIN32)
+# define UV__ENOENT (-ENOENT)
+#else
+# define UV__ENOENT (-4058)
+#endif
+
+#if defined(ENOMEM) && !defined(_WIN32)
+# define UV__ENOMEM (-ENOMEM)
+#else
+# define UV__ENOMEM (-4057)
+#endif
+
+#if defined(ENONET) && !defined(_WIN32)
+# define UV__ENONET (-ENONET)
+#else
+# define UV__ENONET (-4056)
+#endif
+
+#if defined(ENOSPC) && !defined(_WIN32)
+# define UV__ENOSPC (-ENOSPC)
+#else
+# define UV__ENOSPC (-4055)
+#endif
+
+#if defined(ENOSYS) && !defined(_WIN32)
+# define UV__ENOSYS (-ENOSYS)
+#else
+# define UV__ENOSYS (-4054)
+#endif
+
+#if defined(ENOTCONN) && !defined(_WIN32)
+# define UV__ENOTCONN (-ENOTCONN)
+#else
+# define UV__ENOTCONN (-4053)
+#endif
+
+#if defined(ENOTDIR) && !defined(_WIN32)
+# define UV__ENOTDIR (-ENOTDIR)
+#else
+# define UV__ENOTDIR (-4052)
+#endif
+
+#if defined(ENOTEMPTY) && !defined(_WIN32)
+# define UV__ENOTEMPTY (-ENOTEMPTY)
+#else
+# define UV__ENOTEMPTY (-4051)
+#endif
+
+#if defined(ENOTSOCK) && !defined(_WIN32)
+# define UV__ENOTSOCK (-ENOTSOCK)
+#else
+# define UV__ENOTSOCK (-4050)
+#endif
+
+#if defined(ENOTSUP) && !defined(_WIN32)
+# define UV__ENOTSUP (-ENOTSUP)
+#else
+# define UV__ENOTSUP (-4049)
+#endif
+
+#if defined(EPERM) && !defined(_WIN32)
+# define UV__EPERM (-EPERM)
+#else
+# define UV__EPERM (-4048)
+#endif
+
+#if defined(EPIPE) && !defined(_WIN32)
+# define UV__EPIPE (-EPIPE)
+#else
+# define UV__EPIPE (-4047)
+#endif
+
+#if defined(EPROTO) && !defined(_WIN32)
+# define UV__EPROTO (-EPROTO)
+#else
+# define UV__EPROTO (-4046)
+#endif
+
+#if defined(EPROTONOSUPPORT) && !defined(_WIN32)
+# define UV__EPROTONOSUPPORT (-EPROTONOSUPPORT)
+#else
+# define UV__EPROTONOSUPPORT (-4045)
+#endif
+
+#if defined(EPROTOTYPE) && !defined(_WIN32)
+# define UV__EPROTOTYPE (-EPROTOTYPE)
+#else
+# define UV__EPROTOTYPE (-4044)
+#endif
+
+#if defined(EROFS) && !defined(_WIN32)
+# define UV__EROFS (-EROFS)
+#else
+# define UV__EROFS (-4043)
+#endif
+
+#if defined(ESHUTDOWN) && !defined(_WIN32)
+# define UV__ESHUTDOWN (-ESHUTDOWN)
+#else
+# define UV__ESHUTDOWN (-4042)
+#endif
+
+#if defined(ESPIPE) && !defined(_WIN32)
+# define UV__ESPIPE (-ESPIPE)
+#else
+# define UV__ESPIPE (-4041)
+#endif
+
+#if defined(ESRCH) && !defined(_WIN32)
+# define UV__ESRCH (-ESRCH)
+#else
+# define UV__ESRCH (-4040)
+#endif
+
+#if defined(ETIMEDOUT) && !defined(_WIN32)
+# define UV__ETIMEDOUT (-ETIMEDOUT)
+#else
+# define UV__ETIMEDOUT (-4039)
+#endif
+
+#if defined(ETXTBSY) && !defined(_WIN32)
+# define UV__ETXTBSY (-ETXTBSY)
+#else
+# define UV__ETXTBSY (-4038)
+#endif
+
+#if defined(EXDEV) && !defined(_WIN32)
+# define UV__EXDEV (-EXDEV)
+#else
+# define UV__EXDEV (-4037)
+#endif
+
+#if defined(EFBIG) && !defined(_WIN32)
+# define UV__EFBIG (-EFBIG)
+#else
+# define UV__EFBIG (-4036)
+#endif
+
+#if defined(ENOPROTOOPT) && !defined(_WIN32)
+# define UV__ENOPROTOOPT (-ENOPROTOOPT)
+#else
+# define UV__ENOPROTOOPT (-4035)
+#endif
+
+#if defined(ERANGE) && !defined(_WIN32)
+# define UV__ERANGE (-ERANGE)
+#else
+# define UV__ERANGE (-4034)
+#endif
+
+#if defined(ENXIO) && !defined(_WIN32)
+# define UV__ENXIO (-ENXIO)
+#else
+# define UV__ENXIO (-4033)
+#endif
+
+#if defined(EMLINK) && !defined(_WIN32)
+# define UV__EMLINK (-EMLINK)
+#else
+# define UV__EMLINK (-4032)
+#endif
+
+/* EHOSTDOWN is not visible on BSD-like systems when _POSIX_C_SOURCE is
+ * defined. Fortunately, its value is always 64 so it's possible albeit
+ * icky to hard-code it.
+ */
+#if defined(EHOSTDOWN) && !defined(_WIN32)
+# define UV__EHOSTDOWN (-EHOSTDOWN)
+#elif defined(__APPLE__) || \
+ defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__NetBSD__) || \
+ defined(__OpenBSD__)
+# define UV__EHOSTDOWN (-64)
+#else
+# define UV__EHOSTDOWN (-4031)
+#endif
+
+#endif /* UV_ERRNO_H_ */
diff --git a/3rdparty/libuv/include/uv-linux.h b/3rdparty/libuv/include/uv-linux.h
new file mode 100644
index 00000000000..9b38405a190
--- /dev/null
+++ b/3rdparty/libuv/include/uv-linux.h
@@ -0,0 +1,34 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_LINUX_H
+#define UV_LINUX_H
+
+#define UV_PLATFORM_LOOP_FIELDS \
+ uv__io_t inotify_read_watcher; \
+ void* inotify_watchers; \
+ int inotify_fd; \
+
+#define UV_PLATFORM_FS_EVENT_FIELDS \
+ void* watchers[2]; \
+ int wd; \
+
+#endif /* UV_LINUX_H */
diff --git a/3rdparty/libuv/include/uv-sunos.h b/3rdparty/libuv/include/uv-sunos.h
new file mode 100644
index 00000000000..042166424e5
--- /dev/null
+++ b/3rdparty/libuv/include/uv-sunos.h
@@ -0,0 +1,44 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_SUNOS_H
+#define UV_SUNOS_H
+
+#include <sys/port.h>
+#include <port.h>
+
+/* For the sake of convenience and reduced #ifdef-ery in src/unix/sunos.c,
+ * add the fs_event fields even when this version of SunOS doesn't support
+ * file watching.
+ */
+#define UV_PLATFORM_LOOP_FIELDS \
+ uv__io_t fs_event_watcher; \
+ int fs_fd; \
+
+#if defined(PORT_SOURCE_FILE)
+
+# define UV_PLATFORM_FS_EVENT_FIELDS \
+ file_obj_t fo; \
+ int fd; \
+
+#endif /* defined(PORT_SOURCE_FILE) */
+
+#endif /* UV_SUNOS_H */
diff --git a/3rdparty/libuv/include/uv-threadpool.h b/3rdparty/libuv/include/uv-threadpool.h
new file mode 100644
index 00000000000..9708ebdd530
--- /dev/null
+++ b/3rdparty/libuv/include/uv-threadpool.h
@@ -0,0 +1,37 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/*
+ * This file is private to libuv. It provides common functionality to both
+ * Windows and Unix backends.
+ */
+
+#ifndef UV_THREADPOOL_H_
+#define UV_THREADPOOL_H_
+
+struct uv__work {
+ void (*work)(struct uv__work *w);
+ void (*done)(struct uv__work *w, int status);
+ struct uv_loop_s* loop;
+ void* wq[2];
+};
+
+#endif /* UV_THREADPOOL_H_ */
diff --git a/3rdparty/libuv/include/uv-unix.h b/3rdparty/libuv/include/uv-unix.h
new file mode 100644
index 00000000000..82d193bdca4
--- /dev/null
+++ b/3rdparty/libuv/include/uv-unix.h
@@ -0,0 +1,383 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_UNIX_H
+#define UV_UNIX_H
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <termios.h>
+#include <pwd.h>
+
+#include <semaphore.h>
+#include <pthread.h>
+#ifdef __ANDROID__
+#include "pthread-fixes.h"
+#endif
+#include <signal.h>
+
+#include "uv-threadpool.h"
+
+#if defined(__linux__)
+# include "uv-linux.h"
+#elif defined(_AIX)
+# include "uv-aix.h"
+#elif defined(__sun)
+# include "uv-sunos.h"
+#elif defined(__APPLE__)
+# include "uv-darwin.h"
+#elif defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__)
+# include "uv-bsd.h"
+#endif
+
+#ifndef NI_MAXHOST
+# define NI_MAXHOST 1025
+#endif
+
+#ifndef NI_MAXSERV
+# define NI_MAXSERV 32
+#endif
+
+#ifndef UV_IO_PRIVATE_PLATFORM_FIELDS
+# define UV_IO_PRIVATE_PLATFORM_FIELDS /* empty */
+#endif
+
+struct uv__io_s;
+struct uv__async;
+struct uv_loop_s;
+
+typedef void (*uv__io_cb)(struct uv_loop_s* loop,
+ struct uv__io_s* w,
+ unsigned int events);
+typedef struct uv__io_s uv__io_t;
+
+struct uv__io_s {
+ uv__io_cb cb;
+ void* pending_queue[2];
+ void* watcher_queue[2];
+ unsigned int pevents; /* Pending event mask i.e. mask at next tick. */
+ unsigned int events; /* Current event mask. */
+ int fd;
+ UV_IO_PRIVATE_PLATFORM_FIELDS
+};
+
+typedef void (*uv__async_cb)(struct uv_loop_s* loop,
+ struct uv__async* w,
+ unsigned int nevents);
+
+struct uv__async {
+ uv__async_cb cb;
+ uv__io_t io_watcher;
+ int wfd;
+};
+
+#ifndef UV_PLATFORM_SEM_T
+# define UV_PLATFORM_SEM_T sem_t
+#endif
+
+#ifndef UV_PLATFORM_LOOP_FIELDS
+# define UV_PLATFORM_LOOP_FIELDS /* empty */
+#endif
+
+#ifndef UV_PLATFORM_FS_EVENT_FIELDS
+# define UV_PLATFORM_FS_EVENT_FIELDS /* empty */
+#endif
+
+#ifndef UV_STREAM_PRIVATE_PLATFORM_FIELDS
+# define UV_STREAM_PRIVATE_PLATFORM_FIELDS /* empty */
+#endif
+
+/* Note: May be cast to struct iovec. See writev(2). */
+typedef struct uv_buf_t {
+ char* base;
+ size_t len;
+} uv_buf_t;
+
+typedef int uv_file;
+typedef int uv_os_sock_t;
+typedef int uv_os_fd_t;
+
+#define UV_ONCE_INIT PTHREAD_ONCE_INIT
+
+typedef pthread_once_t uv_once_t;
+typedef pthread_t uv_thread_t;
+typedef pthread_mutex_t uv_mutex_t;
+typedef pthread_rwlock_t uv_rwlock_t;
+typedef UV_PLATFORM_SEM_T uv_sem_t;
+typedef pthread_cond_t uv_cond_t;
+typedef pthread_key_t uv_key_t;
+
+#if defined(__APPLE__) && defined(__MACH__)
+
+typedef struct {
+ unsigned int n;
+ unsigned int count;
+ uv_mutex_t mutex;
+ uv_sem_t turnstile1;
+ uv_sem_t turnstile2;
+} uv_barrier_t;
+
+#else /* defined(__APPLE__) && defined(__MACH__) */
+
+typedef pthread_barrier_t uv_barrier_t;
+
+#endif /* defined(__APPLE__) && defined(__MACH__) */
+
+/* Platform-specific definitions for uv_spawn support. */
+typedef gid_t uv_gid_t;
+typedef uid_t uv_uid_t;
+
+typedef struct dirent uv__dirent_t;
+
+#if defined(DT_UNKNOWN)
+# define HAVE_DIRENT_TYPES
+# if defined(DT_REG)
+# define UV__DT_FILE DT_REG
+# else
+# define UV__DT_FILE -1
+# endif
+# if defined(DT_DIR)
+# define UV__DT_DIR DT_DIR
+# else
+# define UV__DT_DIR -2
+# endif
+# if defined(DT_LNK)
+# define UV__DT_LINK DT_LNK
+# else
+# define UV__DT_LINK -3
+# endif
+# if defined(DT_FIFO)
+# define UV__DT_FIFO DT_FIFO
+# else
+# define UV__DT_FIFO -4
+# endif
+# if defined(DT_SOCK)
+# define UV__DT_SOCKET DT_SOCK
+# else
+# define UV__DT_SOCKET -5
+# endif
+# if defined(DT_CHR)
+# define UV__DT_CHAR DT_CHR
+# else
+# define UV__DT_CHAR -6
+# endif
+# if defined(DT_BLK)
+# define UV__DT_BLOCK DT_BLK
+# else
+# define UV__DT_BLOCK -7
+# endif
+#endif
+
+/* Platform-specific definitions for uv_dlopen support. */
+#define UV_DYNAMIC /* empty */
+
+typedef struct {
+ void* handle;
+ char* errmsg;
+} uv_lib_t;
+
+#define UV_LOOP_PRIVATE_FIELDS \
+ unsigned long flags; \
+ int backend_fd; \
+ void* pending_queue[2]; \
+ void* watcher_queue[2]; \
+ uv__io_t** watchers; \
+ unsigned int nwatchers; \
+ unsigned int nfds; \
+ void* wq[2]; \
+ uv_mutex_t wq_mutex; \
+ uv_async_t wq_async; \
+ uv_rwlock_t cloexec_lock; \
+ uv_handle_t* closing_handles; \
+ void* process_handles[2]; \
+ void* prepare_handles[2]; \
+ void* check_handles[2]; \
+ void* idle_handles[2]; \
+ void* async_handles[2]; \
+ struct uv__async async_watcher; \
+ struct { \
+ void* min; \
+ unsigned int nelts; \
+ } timer_heap; \
+ uint64_t timer_counter; \
+ uint64_t time; \
+ int signal_pipefd[2]; \
+ uv__io_t signal_io_watcher; \
+ uv_signal_t child_watcher; \
+ int emfile_fd; \
+ UV_PLATFORM_LOOP_FIELDS \
+
+#define UV_REQ_TYPE_PRIVATE /* empty */
+
+#define UV_REQ_PRIVATE_FIELDS /* empty */
+
+#define UV_PRIVATE_REQ_TYPES /* empty */
+
+#define UV_WRITE_PRIVATE_FIELDS \
+ void* queue[2]; \
+ unsigned int write_index; \
+ uv_buf_t* bufs; \
+ unsigned int nbufs; \
+ int error; \
+ uv_buf_t bufsml[4]; \
+
+#define UV_CONNECT_PRIVATE_FIELDS \
+ void* queue[2]; \
+
+#define UV_SHUTDOWN_PRIVATE_FIELDS /* empty */
+
+#define UV_UDP_SEND_PRIVATE_FIELDS \
+ void* queue[2]; \
+ struct sockaddr_storage addr; \
+ unsigned int nbufs; \
+ uv_buf_t* bufs; \
+ ssize_t status; \
+ uv_udp_send_cb send_cb; \
+ uv_buf_t bufsml[4]; \
+
+#define UV_HANDLE_PRIVATE_FIELDS \
+ uv_handle_t* next_closing; \
+ unsigned int flags; \
+
+#define UV_STREAM_PRIVATE_FIELDS \
+ uv_connect_t *connect_req; \
+ uv_shutdown_t *shutdown_req; \
+ uv__io_t io_watcher; \
+ void* write_queue[2]; \
+ void* write_completed_queue[2]; \
+ uv_connection_cb connection_cb; \
+ int delayed_error; \
+ int accepted_fd; \
+ void* queued_fds; \
+ UV_STREAM_PRIVATE_PLATFORM_FIELDS \
+
+#define UV_TCP_PRIVATE_FIELDS /* empty */
+
+#define UV_UDP_PRIVATE_FIELDS \
+ uv_alloc_cb alloc_cb; \
+ uv_udp_recv_cb recv_cb; \
+ uv__io_t io_watcher; \
+ void* write_queue[2]; \
+ void* write_completed_queue[2]; \
+
+#define UV_PIPE_PRIVATE_FIELDS \
+ const char* pipe_fname; /* strdup'ed */
+
+#define UV_POLL_PRIVATE_FIELDS \
+ uv__io_t io_watcher;
+
+#define UV_PREPARE_PRIVATE_FIELDS \
+ uv_prepare_cb prepare_cb; \
+ void* queue[2]; \
+
+#define UV_CHECK_PRIVATE_FIELDS \
+ uv_check_cb check_cb; \
+ void* queue[2]; \
+
+#define UV_IDLE_PRIVATE_FIELDS \
+ uv_idle_cb idle_cb; \
+ void* queue[2]; \
+
+#define UV_ASYNC_PRIVATE_FIELDS \
+ uv_async_cb async_cb; \
+ void* queue[2]; \
+ int pending; \
+
+#define UV_TIMER_PRIVATE_FIELDS \
+ uv_timer_cb timer_cb; \
+ void* heap_node[3]; \
+ uint64_t timeout; \
+ uint64_t repeat; \
+ uint64_t start_id;
+
+#define UV_GETADDRINFO_PRIVATE_FIELDS \
+ struct uv__work work_req; \
+ uv_getaddrinfo_cb cb; \
+ struct addrinfo* hints; \
+ char* hostname; \
+ char* service; \
+ struct addrinfo* addrinfo; \
+ int retcode;
+
+#define UV_GETNAMEINFO_PRIVATE_FIELDS \
+ struct uv__work work_req; \
+ uv_getnameinfo_cb getnameinfo_cb; \
+ struct sockaddr_storage storage; \
+ int flags; \
+ char host[NI_MAXHOST]; \
+ char service[NI_MAXSERV]; \
+ int retcode;
+
+#define UV_PROCESS_PRIVATE_FIELDS \
+ void* queue[2]; \
+ int status; \
+
+#define UV_FS_PRIVATE_FIELDS \
+ const char *new_path; \
+ uv_file file; \
+ int flags; \
+ mode_t mode; \
+ unsigned int nbufs; \
+ uv_buf_t* bufs; \
+ off_t off; \
+ uv_uid_t uid; \
+ uv_gid_t gid; \
+ double atime; \
+ double mtime; \
+ struct uv__work work_req; \
+ uv_buf_t bufsml[4]; \
+
+#define UV_WORK_PRIVATE_FIELDS \
+ struct uv__work work_req;
+
+#define UV_TTY_PRIVATE_FIELDS \
+ struct termios orig_termios; \
+ int mode;
+
+#define UV_SIGNAL_PRIVATE_FIELDS \
+ /* RB_ENTRY(uv_signal_s) tree_entry; */ \
+ struct { \
+ struct uv_signal_s* rbe_left; \
+ struct uv_signal_s* rbe_right; \
+ struct uv_signal_s* rbe_parent; \
+ int rbe_color; \
+ } tree_entry; \
+ /* Use two counters here so we don have to fiddle with atomics. */ \
+ unsigned int caught_signals; \
+ unsigned int dispatched_signals;
+
+#define UV_FS_EVENT_PRIVATE_FIELDS \
+ uv_fs_event_cb cb; \
+ UV_PLATFORM_FS_EVENT_FIELDS \
+
+#endif /* UV_UNIX_H */
diff --git a/3rdparty/libuv/include/uv-version.h b/3rdparty/libuv/include/uv-version.h
new file mode 100644
index 00000000000..6e61f55ed20
--- /dev/null
+++ b/3rdparty/libuv/include/uv-version.h
@@ -0,0 +1,43 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_VERSION_H
+#define UV_VERSION_H
+
+ /*
+ * Versions with the same major number are ABI stable. API is allowed to
+ * evolve between minor releases, but only in a backwards compatible way.
+ * Make sure you update the -soname directives in configure.ac
+ * and uv.gyp whenever you bump UV_VERSION_MAJOR or UV_VERSION_MINOR (but
+ * not UV_VERSION_PATCH.)
+ */
+
+#define UV_VERSION_MAJOR 1
+#define UV_VERSION_MINOR 8
+#define UV_VERSION_PATCH 0
+#define UV_VERSION_IS_RELEASE 1
+#define UV_VERSION_SUFFIX ""
+
+#define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \
+ (UV_VERSION_MINOR << 8) | \
+ (UV_VERSION_PATCH))
+
+#endif /* UV_VERSION_H */
diff --git a/3rdparty/libuv/include/uv-win.h b/3rdparty/libuv/include/uv-win.h
new file mode 100644
index 00000000000..300be476203
--- /dev/null
+++ b/3rdparty/libuv/include/uv-win.h
@@ -0,0 +1,653 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _WIN32_WINNT
+# define _WIN32_WINNT 0x0502
+#endif
+
+#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
+typedef intptr_t ssize_t;
+# define _SSIZE_T_
+# define _SSIZE_T_DEFINED
+#endif
+
+#include <winsock2.h>
+
+#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
+typedef struct pollfd {
+ SOCKET fd;
+ short events;
+ short revents;
+} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD;
+#endif
+
+#ifndef LOCALE_INVARIANT
+# define LOCALE_INVARIANT 0x007f
+#endif
+
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+
+#include <process.h>
+#include <signal.h>
+#include <sys/stat.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+# include "stdint-msvc2008.h"
+#else
+# include <stdint.h>
+#endif
+
+#include "tree.h"
+#include "uv-threadpool.h"
+
+#define MAX_PIPENAME_LEN 256
+
+#ifndef S_IFLNK
+# define S_IFLNK 0xA000
+#endif
+
+/* Additional signals supported by uv_signal and or uv_kill. The CRT defines
+ * the following signals already:
+ *
+ * #define SIGINT 2
+ * #define SIGILL 4
+ * #define SIGABRT_COMPAT 6
+ * #define SIGFPE 8
+ * #define SIGSEGV 11
+ * #define SIGTERM 15
+ * #define SIGBREAK 21
+ * #define SIGABRT 22
+ *
+ * The additional signals have values that are common on other Unix
+ * variants (Linux and Darwin)
+ */
+#define SIGHUP 1
+#define SIGKILL 9
+#define SIGWINCH 28
+
+/* The CRT defines SIGABRT_COMPAT as 6, which equals SIGABRT on many */
+/* unix-like platforms. However MinGW doesn't define it, so we do. */
+#ifndef SIGABRT_COMPAT
+# define SIGABRT_COMPAT 6
+#endif
+
+/*
+ * Guids and typedefs for winsock extension functions
+ * Mingw32 doesn't have these :-(
+ */
+#ifndef WSAID_ACCEPTEX
+# define WSAID_ACCEPTEX \
+ {0xb5367df1, 0xcbac, 0x11cf, \
+ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
+
+# define WSAID_CONNECTEX \
+ {0x25a207b9, 0xddf3, 0x4660, \
+ {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}}
+
+# define WSAID_GETACCEPTEXSOCKADDRS \
+ {0xb5367df2, 0xcbac, 0x11cf, \
+ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
+
+# define WSAID_DISCONNECTEX \
+ {0x7fda2e11, 0x8630, 0x436f, \
+ {0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
+
+# define WSAID_TRANSMITFILE \
+ {0xb5367df0, 0xcbac, 0x11cf, \
+ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
+
+ typedef BOOL PASCAL (*LPFN_ACCEPTEX)
+ (SOCKET sListenSocket,
+ SOCKET sAcceptSocket,
+ PVOID lpOutputBuffer,
+ DWORD dwReceiveDataLength,
+ DWORD dwLocalAddressLength,
+ DWORD dwRemoteAddressLength,
+ LPDWORD lpdwBytesReceived,
+ LPOVERLAPPED lpOverlapped);
+
+ typedef BOOL PASCAL (*LPFN_CONNECTEX)
+ (SOCKET s,
+ const struct sockaddr* name,
+ int namelen,
+ PVOID lpSendBuffer,
+ DWORD dwSendDataLength,
+ LPDWORD lpdwBytesSent,
+ LPOVERLAPPED lpOverlapped);
+
+ typedef void PASCAL (*LPFN_GETACCEPTEXSOCKADDRS)
+ (PVOID lpOutputBuffer,
+ DWORD dwReceiveDataLength,
+ DWORD dwLocalAddressLength,
+ DWORD dwRemoteAddressLength,
+ LPSOCKADDR* LocalSockaddr,
+ LPINT LocalSockaddrLength,
+ LPSOCKADDR* RemoteSockaddr,
+ LPINT RemoteSockaddrLength);
+
+ typedef BOOL PASCAL (*LPFN_DISCONNECTEX)
+ (SOCKET hSocket,
+ LPOVERLAPPED lpOverlapped,
+ DWORD dwFlags,
+ DWORD reserved);
+
+ typedef BOOL PASCAL (*LPFN_TRANSMITFILE)
+ (SOCKET hSocket,
+ HANDLE hFile,
+ DWORD nNumberOfBytesToWrite,
+ DWORD nNumberOfBytesPerSend,
+ LPOVERLAPPED lpOverlapped,
+ LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers,
+ DWORD dwFlags);
+
+ typedef PVOID RTL_SRWLOCK;
+ typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK;
+#endif
+
+typedef int (WSAAPI* LPFN_WSARECV)
+ (SOCKET socket,
+ LPWSABUF buffers,
+ DWORD buffer_count,
+ LPDWORD bytes,
+ LPDWORD flags,
+ LPWSAOVERLAPPED overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
+
+typedef int (WSAAPI* LPFN_WSARECVFROM)
+ (SOCKET socket,
+ LPWSABUF buffers,
+ DWORD buffer_count,
+ LPDWORD bytes,
+ LPDWORD flags,
+ struct sockaddr* addr,
+ LPINT addr_len,
+ LPWSAOVERLAPPED overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
+
+#ifndef _NTDEF_
+ typedef LONG NTSTATUS;
+ typedef NTSTATUS *PNTSTATUS;
+#endif
+
+#ifndef RTL_CONDITION_VARIABLE_INIT
+ typedef PVOID CONDITION_VARIABLE, *PCONDITION_VARIABLE;
+#endif
+
+typedef struct _AFD_POLL_HANDLE_INFO {
+ HANDLE Handle;
+ ULONG Events;
+ NTSTATUS Status;
+} AFD_POLL_HANDLE_INFO, *PAFD_POLL_HANDLE_INFO;
+
+typedef struct _AFD_POLL_INFO {
+ LARGE_INTEGER Timeout;
+ ULONG NumberOfHandles;
+ ULONG Exclusive;
+ AFD_POLL_HANDLE_INFO Handles[1];
+} AFD_POLL_INFO, *PAFD_POLL_INFO;
+
+#define UV_MSAFD_PROVIDER_COUNT 3
+
+
+/**
+ * It should be possible to cast uv_buf_t[] to WSABUF[]
+ * see http://msdn.microsoft.com/en-us/library/ms741542(v=vs.85).aspx
+ */
+typedef struct uv_buf_t {
+ ULONG len;
+ char* base;
+} uv_buf_t;
+
+typedef int uv_file;
+typedef SOCKET uv_os_sock_t;
+typedef HANDLE uv_os_fd_t;
+
+typedef HANDLE uv_thread_t;
+
+typedef HANDLE uv_sem_t;
+
+typedef CRITICAL_SECTION uv_mutex_t;
+
+/* This condition variable implementation is based on the SetEvent solution
+ * (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
+ * We could not use the SignalObjectAndWait solution (section 3.4) because
+ * it want the 2nd argument (type uv_mutex_t) of uv_cond_wait() and
+ * uv_cond_timedwait() to be HANDLEs, but we use CRITICAL_SECTIONs.
+ */
+
+typedef union {
+ CONDITION_VARIABLE cond_var;
+ struct {
+ unsigned int waiters_count;
+ CRITICAL_SECTION waiters_count_lock;
+ HANDLE signal_event;
+ HANDLE broadcast_event;
+ } fallback;
+} uv_cond_t;
+
+typedef union {
+ struct {
+ unsigned int num_readers_;
+ CRITICAL_SECTION num_readers_lock_;
+ HANDLE write_semaphore_;
+ } state_;
+ /* TODO: remove me in v2.x. */
+ struct {
+ SRWLOCK unused_;
+ } unused1_;
+ /* TODO: remove me in v2.x. */
+ struct {
+ uv_mutex_t unused1_;
+ uv_mutex_t unused2_;
+ } unused2_;
+} uv_rwlock_t;
+
+typedef struct {
+ unsigned int n;
+ unsigned int count;
+ uv_mutex_t mutex;
+ uv_sem_t turnstile1;
+ uv_sem_t turnstile2;
+} uv_barrier_t;
+
+typedef struct {
+ DWORD tls_index;
+} uv_key_t;
+
+#define UV_ONCE_INIT { 0, NULL }
+
+typedef struct uv_once_s {
+ unsigned char ran;
+ HANDLE event;
+} uv_once_t;
+
+/* Platform-specific definitions for uv_spawn support. */
+typedef unsigned char uv_uid_t;
+typedef unsigned char uv_gid_t;
+
+typedef struct uv__dirent_s {
+ int d_type;
+ char d_name[1];
+} uv__dirent_t;
+
+#define HAVE_DIRENT_TYPES
+#define UV__DT_DIR UV_DIRENT_DIR
+#define UV__DT_FILE UV_DIRENT_FILE
+#define UV__DT_LINK UV_DIRENT_LINK
+#define UV__DT_FIFO UV_DIRENT_FIFO
+#define UV__DT_SOCKET UV_DIRENT_SOCKET
+#define UV__DT_CHAR UV_DIRENT_CHAR
+#define UV__DT_BLOCK UV_DIRENT_BLOCK
+
+/* Platform-specific definitions for uv_dlopen support. */
+#define UV_DYNAMIC FAR WINAPI
+typedef struct {
+ HMODULE handle;
+ char* errmsg;
+} uv_lib_t;
+
+RB_HEAD(uv_timer_tree_s, uv_timer_s);
+
+#define UV_LOOP_PRIVATE_FIELDS \
+ /* The loop's I/O completion port */ \
+ HANDLE iocp; \
+ /* The current time according to the event loop. in msecs. */ \
+ uint64_t time; \
+ /* Tail of a single-linked circular queue of pending reqs. If the queue */ \
+ /* is empty, tail_ is NULL. If there is only one item, */ \
+ /* tail_->next_req == tail_ */ \
+ uv_req_t* pending_reqs_tail; \
+ /* Head of a single-linked list of closed handles */ \
+ uv_handle_t* endgame_handles; \
+ /* The head of the timers tree */ \
+ struct uv_timer_tree_s timers; \
+ /* Lists of active loop (prepare / check / idle) watchers */ \
+ uv_prepare_t* prepare_handles; \
+ uv_check_t* check_handles; \
+ uv_idle_t* idle_handles; \
+ /* This pointer will refer to the prepare/check/idle handle whose */ \
+ /* callback is scheduled to be called next. This is needed to allow */ \
+ /* safe removal from one of the lists above while that list being */ \
+ /* iterated over. */ \
+ uv_prepare_t* next_prepare_handle; \
+ uv_check_t* next_check_handle; \
+ uv_idle_t* next_idle_handle; \
+ /* This handle holds the peer sockets for the fast variant of uv_poll_t */ \
+ SOCKET poll_peer_sockets[UV_MSAFD_PROVIDER_COUNT]; \
+ /* Counter to keep track of active tcp streams */ \
+ unsigned int active_tcp_streams; \
+ /* Counter to keep track of active udp streams */ \
+ unsigned int active_udp_streams; \
+ /* Counter to started timer */ \
+ uint64_t timer_counter; \
+ /* Threadpool */ \
+ void* wq[2]; \
+ uv_mutex_t wq_mutex; \
+ uv_async_t wq_async;
+
+#define UV_REQ_TYPE_PRIVATE \
+ /* TODO: remove the req suffix */ \
+ UV_ACCEPT, \
+ UV_FS_EVENT_REQ, \
+ UV_POLL_REQ, \
+ UV_PROCESS_EXIT, \
+ UV_READ, \
+ UV_UDP_RECV, \
+ UV_WAKEUP, \
+ UV_SIGNAL_REQ,
+
+#define UV_REQ_PRIVATE_FIELDS \
+ union { \
+ /* Used by I/O operations */ \
+ struct { \
+ OVERLAPPED overlapped; \
+ size_t queued_bytes; \
+ } io; \
+ } u; \
+ struct uv_req_s* next_req;
+
+#define UV_WRITE_PRIVATE_FIELDS \
+ int ipc_header; \
+ uv_buf_t write_buffer; \
+ HANDLE event_handle; \
+ HANDLE wait_handle;
+
+#define UV_CONNECT_PRIVATE_FIELDS \
+ /* empty */
+
+#define UV_SHUTDOWN_PRIVATE_FIELDS \
+ /* empty */
+
+#define UV_UDP_SEND_PRIVATE_FIELDS \
+ /* empty */
+
+#define UV_PRIVATE_REQ_TYPES \
+ typedef struct uv_pipe_accept_s { \
+ UV_REQ_FIELDS \
+ HANDLE pipeHandle; \
+ struct uv_pipe_accept_s* next_pending; \
+ } uv_pipe_accept_t; \
+ \
+ typedef struct uv_tcp_accept_s { \
+ UV_REQ_FIELDS \
+ SOCKET accept_socket; \
+ char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32]; \
+ HANDLE event_handle; \
+ HANDLE wait_handle; \
+ struct uv_tcp_accept_s* next_pending; \
+ } uv_tcp_accept_t; \
+ \
+ typedef struct uv_read_s { \
+ UV_REQ_FIELDS \
+ HANDLE event_handle; \
+ HANDLE wait_handle; \
+ } uv_read_t;
+
+#define uv_stream_connection_fields \
+ unsigned int write_reqs_pending; \
+ uv_shutdown_t* shutdown_req;
+
+#define uv_stream_server_fields \
+ uv_connection_cb connection_cb;
+
+#define UV_STREAM_PRIVATE_FIELDS \
+ unsigned int reqs_pending; \
+ int activecnt; \
+ uv_read_t read_req; \
+ union { \
+ struct { uv_stream_connection_fields } conn; \
+ struct { uv_stream_server_fields } serv; \
+ } stream;
+
+#define uv_tcp_server_fields \
+ uv_tcp_accept_t* accept_reqs; \
+ unsigned int processed_accepts; \
+ uv_tcp_accept_t* pending_accepts; \
+ LPFN_ACCEPTEX func_acceptex;
+
+#define uv_tcp_connection_fields \
+ uv_buf_t read_buffer; \
+ LPFN_CONNECTEX func_connectex;
+
+#define UV_TCP_PRIVATE_FIELDS \
+ SOCKET socket; \
+ int delayed_error; \
+ union { \
+ struct { uv_tcp_server_fields } serv; \
+ struct { uv_tcp_connection_fields } conn; \
+ } tcp;
+
+#define UV_UDP_PRIVATE_FIELDS \
+ SOCKET socket; \
+ unsigned int reqs_pending; \
+ int activecnt; \
+ uv_req_t recv_req; \
+ uv_buf_t recv_buffer; \
+ struct sockaddr_storage recv_from; \
+ int recv_from_len; \
+ uv_udp_recv_cb recv_cb; \
+ uv_alloc_cb alloc_cb; \
+ LPFN_WSARECV func_wsarecv; \
+ LPFN_WSARECVFROM func_wsarecvfrom;
+
+#define uv_pipe_server_fields \
+ int pending_instances; \
+ uv_pipe_accept_t* accept_reqs; \
+ uv_pipe_accept_t* pending_accepts;
+
+#define uv_pipe_connection_fields \
+ uv_timer_t* eof_timer; \
+ uv_write_t ipc_header_write_req; \
+ int ipc_pid; \
+ uint64_t remaining_ipc_rawdata_bytes; \
+ struct { \
+ void* queue[2]; \
+ int queue_len; \
+ } pending_ipc_info; \
+ uv_write_t* non_overlapped_writes_tail; \
+ uv_mutex_t readfile_mutex; \
+ volatile HANDLE readfile_thread;
+
+#define UV_PIPE_PRIVATE_FIELDS \
+ HANDLE handle; \
+ WCHAR* name; \
+ union { \
+ struct { uv_pipe_server_fields } serv; \
+ struct { uv_pipe_connection_fields } conn; \
+ } pipe;
+
+/* TODO: put the parser states in an union - TTY handles are always */
+/* half-duplex so read-state can safely overlap write-state. */
+#define UV_TTY_PRIVATE_FIELDS \
+ HANDLE handle; \
+ union { \
+ struct { \
+ /* Used for readable TTY handles */ \
+ HANDLE read_line_handle; \
+ uv_buf_t read_line_buffer; \
+ HANDLE read_raw_wait; \
+ /* Fields used for translating win keystrokes into vt100 characters */ \
+ char last_key[8]; \
+ unsigned char last_key_offset; \
+ unsigned char last_key_len; \
+ WCHAR last_utf16_high_surrogate; \
+ INPUT_RECORD last_input_record; \
+ } rd; \
+ struct { \
+ /* Used for writable TTY handles */ \
+ /* utf8-to-utf16 conversion state */ \
+ unsigned int utf8_codepoint; \
+ unsigned char utf8_bytes_left; \
+ /* eol conversion state */ \
+ unsigned char previous_eol; \
+ /* ansi parser state */ \
+ unsigned char ansi_parser_state; \
+ unsigned char ansi_csi_argc; \
+ unsigned short ansi_csi_argv[4]; \
+ COORD saved_position; \
+ WORD saved_attributes; \
+ } wr; \
+ } tty;
+
+#define UV_POLL_PRIVATE_FIELDS \
+ SOCKET socket; \
+ /* Used in fast mode */ \
+ SOCKET peer_socket; \
+ AFD_POLL_INFO afd_poll_info_1; \
+ AFD_POLL_INFO afd_poll_info_2; \
+ /* Used in fast and slow mode. */ \
+ uv_req_t poll_req_1; \
+ uv_req_t poll_req_2; \
+ unsigned char submitted_events_1; \
+ unsigned char submitted_events_2; \
+ unsigned char mask_events_1; \
+ unsigned char mask_events_2; \
+ unsigned char events;
+
+#define UV_TIMER_PRIVATE_FIELDS \
+ RB_ENTRY(uv_timer_s) tree_entry; \
+ uint64_t due; \
+ uint64_t repeat; \
+ uint64_t start_id; \
+ uv_timer_cb timer_cb;
+
+#define UV_ASYNC_PRIVATE_FIELDS \
+ struct uv_req_s async_req; \
+ uv_async_cb async_cb; \
+ /* char to avoid alignment issues */ \
+ char volatile async_sent;
+
+#define UV_PREPARE_PRIVATE_FIELDS \
+ uv_prepare_t* prepare_prev; \
+ uv_prepare_t* prepare_next; \
+ uv_prepare_cb prepare_cb;
+
+#define UV_CHECK_PRIVATE_FIELDS \
+ uv_check_t* check_prev; \
+ uv_check_t* check_next; \
+ uv_check_cb check_cb;
+
+#define UV_IDLE_PRIVATE_FIELDS \
+ uv_idle_t* idle_prev; \
+ uv_idle_t* idle_next; \
+ uv_idle_cb idle_cb;
+
+#define UV_HANDLE_PRIVATE_FIELDS \
+ uv_handle_t* endgame_next; \
+ unsigned int flags;
+
+#define UV_GETADDRINFO_PRIVATE_FIELDS \
+ struct uv__work work_req; \
+ uv_getaddrinfo_cb getaddrinfo_cb; \
+ void* alloc; \
+ WCHAR* node; \
+ WCHAR* service; \
+ /* The addrinfoW field is used to store a pointer to the hints, and */ \
+ /* later on to store the result of GetAddrInfoW. The final result will */ \
+ /* be converted to struct addrinfo* and stored in the addrinfo field. */ \
+ struct addrinfoW* addrinfow; \
+ struct addrinfo* addrinfo; \
+ int retcode;
+
+#define UV_GETNAMEINFO_PRIVATE_FIELDS \
+ struct uv__work work_req; \
+ uv_getnameinfo_cb getnameinfo_cb; \
+ struct sockaddr_storage storage; \
+ int flags; \
+ char host[NI_MAXHOST]; \
+ char service[NI_MAXSERV]; \
+ int retcode;
+
+#define UV_PROCESS_PRIVATE_FIELDS \
+ struct uv_process_exit_s { \
+ UV_REQ_FIELDS \
+ } exit_req; \
+ BYTE* child_stdio_buffer; \
+ int exit_signal; \
+ HANDLE wait_handle; \
+ HANDLE process_handle; \
+ volatile char exit_cb_pending;
+
+#define UV_FS_PRIVATE_FIELDS \
+ struct uv__work work_req; \
+ int flags; \
+ DWORD sys_errno_; \
+ union { \
+ /* TODO: remove me in 0.9. */ \
+ WCHAR* pathw; \
+ int fd; \
+ } file; \
+ union { \
+ struct { \
+ int mode; \
+ WCHAR* new_pathw; \
+ int file_flags; \
+ int fd_out; \
+ unsigned int nbufs; \
+ uv_buf_t* bufs; \
+ int64_t offset; \
+ uv_buf_t bufsml[4]; \
+ } info; \
+ struct { \
+ double atime; \
+ double mtime; \
+ } time; \
+ } fs;
+
+#define UV_WORK_PRIVATE_FIELDS \
+ struct uv__work work_req;
+
+#define UV_FS_EVENT_PRIVATE_FIELDS \
+ struct uv_fs_event_req_s { \
+ UV_REQ_FIELDS \
+ } req; \
+ HANDLE dir_handle; \
+ int req_pending; \
+ uv_fs_event_cb cb; \
+ WCHAR* filew; \
+ WCHAR* short_filew; \
+ WCHAR* dirw; \
+ char* buffer;
+
+#define UV_SIGNAL_PRIVATE_FIELDS \
+ RB_ENTRY(uv_signal_s) tree_entry; \
+ struct uv_req_s signal_req; \
+ unsigned long pending_signum;
+
+int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size,
+ char* utf8Buffer, size_t utf8Size);
+int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer,
+ size_t utf16Size);
+
+#ifndef F_OK
+#define F_OK 0
+#endif
+#ifndef R_OK
+#define R_OK 4
+#endif
+#ifndef W_OK
+#define W_OK 2
+#endif
+#ifndef X_OK
+#define X_OK 1
+#endif
diff --git a/3rdparty/libuv/include/uv.h b/3rdparty/libuv/include/uv.h
new file mode 100644
index 00000000000..dd3111a960e
--- /dev/null
+++ b/3rdparty/libuv/include/uv.h
@@ -0,0 +1,1482 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* See https://github.com/libuv/libuv#documentation for documentation. */
+
+#ifndef UV_H
+#define UV_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _WIN32
+ /* Windows - set up dll import/export decorators. */
+# if defined(BUILDING_UV_SHARED)
+ /* Building shared library. */
+# define UV_EXTERN __declspec(dllexport)
+# elif defined(USING_UV_SHARED)
+ /* Using shared library. */
+# define UV_EXTERN __declspec(dllimport)
+# else
+ /* Building static library. */
+# define UV_EXTERN /* nothing */
+# endif
+#elif __GNUC__ >= 4
+# define UV_EXTERN __attribute__((visibility("default")))
+#else
+# define UV_EXTERN /* nothing */
+#endif
+
+#include "uv-errno.h"
+#include "uv-version.h"
+#include <stddef.h>
+#include <stdio.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+# include "stdint-msvc2008.h"
+#else
+# include <stdint.h>
+#endif
+
+#if defined(_WIN32)
+# include "uv-win.h"
+#else
+# include "uv-unix.h"
+#endif
+
+/* Expand this list if necessary. */
+#define UV_ERRNO_MAP(XX) \
+ XX(E2BIG, "argument list too long") \
+ XX(EACCES, "permission denied") \
+ XX(EADDRINUSE, "address already in use") \
+ XX(EADDRNOTAVAIL, "address not available") \
+ XX(EAFNOSUPPORT, "address family not supported") \
+ XX(EAGAIN, "resource temporarily unavailable") \
+ XX(EAI_ADDRFAMILY, "address family not supported") \
+ XX(EAI_AGAIN, "temporary failure") \
+ XX(EAI_BADFLAGS, "bad ai_flags value") \
+ XX(EAI_BADHINTS, "invalid value for hints") \
+ XX(EAI_CANCELED, "request canceled") \
+ XX(EAI_FAIL, "permanent failure") \
+ XX(EAI_FAMILY, "ai_family not supported") \
+ XX(EAI_MEMORY, "out of memory") \
+ XX(EAI_NODATA, "no address") \
+ XX(EAI_NONAME, "unknown node or service") \
+ XX(EAI_OVERFLOW, "argument buffer overflow") \
+ XX(EAI_PROTOCOL, "resolved protocol is unknown") \
+ XX(EAI_SERVICE, "service not available for socket type") \
+ XX(EAI_SOCKTYPE, "socket type not supported") \
+ XX(EALREADY, "connection already in progress") \
+ XX(EBADF, "bad file descriptor") \
+ XX(EBUSY, "resource busy or locked") \
+ XX(ECANCELED, "operation canceled") \
+ XX(ECHARSET, "invalid Unicode character") \
+ XX(ECONNABORTED, "software caused connection abort") \
+ XX(ECONNREFUSED, "connection refused") \
+ XX(ECONNRESET, "connection reset by peer") \
+ XX(EDESTADDRREQ, "destination address required") \
+ XX(EEXIST, "file already exists") \
+ XX(EFAULT, "bad address in system call argument") \
+ XX(EFBIG, "file too large") \
+ XX(EHOSTUNREACH, "host is unreachable") \
+ XX(EINTR, "interrupted system call") \
+ XX(EINVAL, "invalid argument") \
+ XX(EIO, "i/o error") \
+ XX(EISCONN, "socket is already connected") \
+ XX(EISDIR, "illegal operation on a directory") \
+ XX(ELOOP, "too many symbolic links encountered") \
+ XX(EMFILE, "too many open files") \
+ XX(EMSGSIZE, "message too long") \
+ XX(ENAMETOOLONG, "name too long") \
+ XX(ENETDOWN, "network is down") \
+ XX(ENETUNREACH, "network is unreachable") \
+ XX(ENFILE, "file table overflow") \
+ XX(ENOBUFS, "no buffer space available") \
+ XX(ENODEV, "no such device") \
+ XX(ENOENT, "no such file or directory") \
+ XX(ENOMEM, "not enough memory") \
+ XX(ENONET, "machine is not on the network") \
+ XX(ENOPROTOOPT, "protocol not available") \
+ XX(ENOSPC, "no space left on device") \
+ XX(ENOSYS, "function not implemented") \
+ XX(ENOTCONN, "socket is not connected") \
+ XX(ENOTDIR, "not a directory") \
+ XX(ENOTEMPTY, "directory not empty") \
+ XX(ENOTSOCK, "socket operation on non-socket") \
+ XX(ENOTSUP, "operation not supported on socket") \
+ XX(EPERM, "operation not permitted") \
+ XX(EPIPE, "broken pipe") \
+ XX(EPROTO, "protocol error") \
+ XX(EPROTONOSUPPORT, "protocol not supported") \
+ XX(EPROTOTYPE, "protocol wrong type for socket") \
+ XX(ERANGE, "result too large") \
+ XX(EROFS, "read-only file system") \
+ XX(ESHUTDOWN, "cannot send after transport endpoint shutdown") \
+ XX(ESPIPE, "invalid seek") \
+ XX(ESRCH, "no such process") \
+ XX(ETIMEDOUT, "connection timed out") \
+ XX(ETXTBSY, "text file is busy") \
+ XX(EXDEV, "cross-device link not permitted") \
+ XX(UNKNOWN, "unknown error") \
+ XX(EOF, "end of file") \
+ XX(ENXIO, "no such device or address") \
+ XX(EMLINK, "too many links") \
+ XX(EHOSTDOWN, "host is down") \
+
+#define UV_HANDLE_TYPE_MAP(XX) \
+ XX(ASYNC, async) \
+ XX(CHECK, check) \
+ XX(FS_EVENT, fs_event) \
+ XX(FS_POLL, fs_poll) \
+ XX(HANDLE, handle) \
+ XX(IDLE, idle) \
+ XX(NAMED_PIPE, pipe) \
+ XX(POLL, poll) \
+ XX(PREPARE, prepare) \
+ XX(PROCESS, process) \
+ XX(STREAM, stream) \
+ XX(TCP, tcp) \
+ XX(TIMER, timer) \
+ XX(TTY, tty) \
+ XX(UDP, udp) \
+ XX(SIGNAL, signal) \
+
+#define UV_REQ_TYPE_MAP(XX) \
+ XX(REQ, req) \
+ XX(CONNECT, connect) \
+ XX(WRITE, write) \
+ XX(SHUTDOWN, shutdown) \
+ XX(UDP_SEND, udp_send) \
+ XX(FS, fs) \
+ XX(WORK, work) \
+ XX(GETADDRINFO, getaddrinfo) \
+ XX(GETNAMEINFO, getnameinfo) \
+
+typedef enum {
+#define XX(code, _) UV_ ## code = UV__ ## code,
+ UV_ERRNO_MAP(XX)
+#undef XX
+ UV_ERRNO_MAX = UV__EOF - 1
+} uv_errno_t;
+
+typedef enum {
+ UV_UNKNOWN_HANDLE = 0,
+#define XX(uc, lc) UV_##uc,
+ UV_HANDLE_TYPE_MAP(XX)
+#undef XX
+ UV_FILE,
+ UV_HANDLE_TYPE_MAX
+} uv_handle_type;
+
+typedef enum {
+ UV_UNKNOWN_REQ = 0,
+#define XX(uc, lc) UV_##uc,
+ UV_REQ_TYPE_MAP(XX)
+#undef XX
+ UV_REQ_TYPE_PRIVATE
+ UV_REQ_TYPE_MAX
+} uv_req_type;
+
+
+/* Handle types. */
+typedef struct uv_loop_s uv_loop_t;
+typedef struct uv_handle_s uv_handle_t;
+typedef struct uv_stream_s uv_stream_t;
+typedef struct uv_tcp_s uv_tcp_t;
+typedef struct uv_udp_s uv_udp_t;
+typedef struct uv_pipe_s uv_pipe_t;
+typedef struct uv_tty_s uv_tty_t;
+typedef struct uv_poll_s uv_poll_t;
+typedef struct uv_timer_s uv_timer_t;
+typedef struct uv_prepare_s uv_prepare_t;
+typedef struct uv_check_s uv_check_t;
+typedef struct uv_idle_s uv_idle_t;
+typedef struct uv_async_s uv_async_t;
+typedef struct uv_process_s uv_process_t;
+typedef struct uv_fs_event_s uv_fs_event_t;
+typedef struct uv_fs_poll_s uv_fs_poll_t;
+typedef struct uv_signal_s uv_signal_t;
+
+/* Request types. */
+typedef struct uv_req_s uv_req_t;
+typedef struct uv_getaddrinfo_s uv_getaddrinfo_t;
+typedef struct uv_getnameinfo_s uv_getnameinfo_t;
+typedef struct uv_shutdown_s uv_shutdown_t;
+typedef struct uv_write_s uv_write_t;
+typedef struct uv_connect_s uv_connect_t;
+typedef struct uv_udp_send_s uv_udp_send_t;
+typedef struct uv_fs_s uv_fs_t;
+typedef struct uv_work_s uv_work_t;
+
+/* None of the above. */
+typedef struct uv_cpu_info_s uv_cpu_info_t;
+typedef struct uv_interface_address_s uv_interface_address_t;
+typedef struct uv_dirent_s uv_dirent_t;
+
+typedef enum {
+ UV_LOOP_BLOCK_SIGNAL
+} uv_loop_option;
+
+typedef enum {
+ UV_RUN_DEFAULT = 0,
+ UV_RUN_ONCE,
+ UV_RUN_NOWAIT
+} uv_run_mode;
+
+
+UV_EXTERN unsigned int uv_version(void);
+UV_EXTERN const char* uv_version_string(void);
+
+typedef void* (*uv_malloc_func)(size_t size);
+typedef void* (*uv_realloc_func)(void* ptr, size_t size);
+typedef void* (*uv_calloc_func)(size_t count, size_t size);
+typedef void (*uv_free_func)(void* ptr);
+
+UV_EXTERN int uv_replace_allocator(uv_malloc_func malloc_func,
+ uv_realloc_func realloc_func,
+ uv_calloc_func calloc_func,
+ uv_free_func free_func);
+
+UV_EXTERN uv_loop_t* uv_default_loop(void);
+UV_EXTERN int uv_loop_init(uv_loop_t* loop);
+UV_EXTERN int uv_loop_close(uv_loop_t* loop);
+/*
+ * NOTE:
+ * This function is DEPRECATED (to be removed after 0.12), users should
+ * allocate the loop manually and use uv_loop_init instead.
+ */
+UV_EXTERN uv_loop_t* uv_loop_new(void);
+/*
+ * NOTE:
+ * This function is DEPRECATED (to be removed after 0.12). Users should use
+ * uv_loop_close and free the memory manually instead.
+ */
+UV_EXTERN void uv_loop_delete(uv_loop_t*);
+UV_EXTERN size_t uv_loop_size(void);
+UV_EXTERN int uv_loop_alive(const uv_loop_t* loop);
+UV_EXTERN int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...);
+
+UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode);
+UV_EXTERN void uv_stop(uv_loop_t*);
+
+UV_EXTERN void uv_ref(uv_handle_t*);
+UV_EXTERN void uv_unref(uv_handle_t*);
+UV_EXTERN int uv_has_ref(const uv_handle_t*);
+
+UV_EXTERN void uv_update_time(uv_loop_t*);
+UV_EXTERN uint64_t uv_now(const uv_loop_t*);
+
+UV_EXTERN int uv_backend_fd(const uv_loop_t*);
+UV_EXTERN int uv_backend_timeout(const uv_loop_t*);
+
+typedef void (*uv_alloc_cb)(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf);
+typedef void (*uv_read_cb)(uv_stream_t* stream,
+ ssize_t nread,
+ const uv_buf_t* buf);
+typedef void (*uv_write_cb)(uv_write_t* req, int status);
+typedef void (*uv_connect_cb)(uv_connect_t* req, int status);
+typedef void (*uv_shutdown_cb)(uv_shutdown_t* req, int status);
+typedef void (*uv_connection_cb)(uv_stream_t* server, int status);
+typedef void (*uv_close_cb)(uv_handle_t* handle);
+typedef void (*uv_poll_cb)(uv_poll_t* handle, int status, int events);
+typedef void (*uv_timer_cb)(uv_timer_t* handle);
+typedef void (*uv_async_cb)(uv_async_t* handle);
+typedef void (*uv_prepare_cb)(uv_prepare_t* handle);
+typedef void (*uv_check_cb)(uv_check_t* handle);
+typedef void (*uv_idle_cb)(uv_idle_t* handle);
+typedef void (*uv_exit_cb)(uv_process_t*, int64_t exit_status, int term_signal);
+typedef void (*uv_walk_cb)(uv_handle_t* handle, void* arg);
+typedef void (*uv_fs_cb)(uv_fs_t* req);
+typedef void (*uv_work_cb)(uv_work_t* req);
+typedef void (*uv_after_work_cb)(uv_work_t* req, int status);
+typedef void (*uv_getaddrinfo_cb)(uv_getaddrinfo_t* req,
+ int status,
+ struct addrinfo* res);
+typedef void (*uv_getnameinfo_cb)(uv_getnameinfo_t* req,
+ int status,
+ const char* hostname,
+ const char* service);
+
+typedef struct {
+ long tv_sec;
+ long tv_nsec;
+} uv_timespec_t;
+
+
+typedef struct {
+ uint64_t st_dev;
+ uint64_t st_mode;
+ uint64_t st_nlink;
+ uint64_t st_uid;
+ uint64_t st_gid;
+ uint64_t st_rdev;
+ uint64_t st_ino;
+ uint64_t st_size;
+ uint64_t st_blksize;
+ uint64_t st_blocks;
+ uint64_t st_flags;
+ uint64_t st_gen;
+ uv_timespec_t st_atim;
+ uv_timespec_t st_mtim;
+ uv_timespec_t st_ctim;
+ uv_timespec_t st_birthtim;
+} uv_stat_t;
+
+
+typedef void (*uv_fs_event_cb)(uv_fs_event_t* handle,
+ const char* filename,
+ int events,
+ int status);
+
+typedef void (*uv_fs_poll_cb)(uv_fs_poll_t* handle,
+ int status,
+ const uv_stat_t* prev,
+ const uv_stat_t* curr);
+
+typedef void (*uv_signal_cb)(uv_signal_t* handle, int signum);
+
+
+typedef enum {
+ UV_LEAVE_GROUP = 0,
+ UV_JOIN_GROUP
+} uv_membership;
+
+
+UV_EXTERN const char* uv_strerror(int err);
+UV_EXTERN const char* uv_err_name(int err);
+
+
+#define UV_REQ_FIELDS \
+ /* public */ \
+ void* data; \
+ /* read-only */ \
+ uv_req_type type; \
+ /* private */ \
+ void* active_queue[2]; \
+ void* reserved[4]; \
+ UV_REQ_PRIVATE_FIELDS \
+
+/* Abstract base class of all requests. */
+struct uv_req_s {
+ UV_REQ_FIELDS
+};
+
+
+/* Platform-specific request types. */
+UV_PRIVATE_REQ_TYPES
+
+
+UV_EXTERN int uv_shutdown(uv_shutdown_t* req,
+ uv_stream_t* handle,
+ uv_shutdown_cb cb);
+
+struct uv_shutdown_s {
+ UV_REQ_FIELDS
+ uv_stream_t* handle;
+ uv_shutdown_cb cb;
+ UV_SHUTDOWN_PRIVATE_FIELDS
+};
+
+
+#define UV_HANDLE_FIELDS \
+ /* public */ \
+ void* data; \
+ /* read-only */ \
+ uv_loop_t* loop; \
+ uv_handle_type type; \
+ /* private */ \
+ uv_close_cb close_cb; \
+ void* handle_queue[2]; \
+ union { \
+ int fd; \
+ void* reserved[4]; \
+ } u; \
+ UV_HANDLE_PRIVATE_FIELDS \
+
+/* The abstract base class of all handles. */
+struct uv_handle_s {
+ UV_HANDLE_FIELDS
+};
+
+UV_EXTERN size_t uv_handle_size(uv_handle_type type);
+UV_EXTERN size_t uv_req_size(uv_req_type type);
+
+UV_EXTERN int uv_is_active(const uv_handle_t* handle);
+
+UV_EXTERN void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg);
+
+/* Helpers for ad hoc debugging, no API/ABI stability guaranteed. */
+UV_EXTERN void uv_print_all_handles(uv_loop_t* loop, FILE* stream);
+UV_EXTERN void uv_print_active_handles(uv_loop_t* loop, FILE* stream);
+
+UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb);
+
+UV_EXTERN int uv_send_buffer_size(uv_handle_t* handle, int* value);
+UV_EXTERN int uv_recv_buffer_size(uv_handle_t* handle, int* value);
+
+UV_EXTERN int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd);
+
+UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len);
+
+
+#define UV_STREAM_FIELDS \
+ /* number of bytes queued for writing */ \
+ size_t write_queue_size; \
+ uv_alloc_cb alloc_cb; \
+ uv_read_cb read_cb; \
+ /* private */ \
+ UV_STREAM_PRIVATE_FIELDS
+
+/*
+ * uv_stream_t is a subclass of uv_handle_t.
+ *
+ * uv_stream is an abstract class.
+ *
+ * uv_stream_t is the parent class of uv_tcp_t, uv_pipe_t and uv_tty_t.
+ */
+struct uv_stream_s {
+ UV_HANDLE_FIELDS
+ UV_STREAM_FIELDS
+};
+
+UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);
+UV_EXTERN int uv_accept(uv_stream_t* server, uv_stream_t* client);
+
+UV_EXTERN int uv_read_start(uv_stream_t*,
+ uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb);
+UV_EXTERN int uv_read_stop(uv_stream_t*);
+
+UV_EXTERN int uv_write(uv_write_t* req,
+ uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb);
+UV_EXTERN int uv_write2(uv_write_t* req,
+ uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle,
+ uv_write_cb cb);
+UV_EXTERN int uv_try_write(uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs);
+
+/* uv_write_t is a subclass of uv_req_t. */
+struct uv_write_s {
+ UV_REQ_FIELDS
+ uv_write_cb cb;
+ uv_stream_t* send_handle;
+ uv_stream_t* handle;
+ UV_WRITE_PRIVATE_FIELDS
+};
+
+
+UV_EXTERN int uv_is_readable(const uv_stream_t* handle);
+UV_EXTERN int uv_is_writable(const uv_stream_t* handle);
+
+UV_EXTERN int uv_stream_set_blocking(uv_stream_t* handle, int blocking);
+
+UV_EXTERN int uv_is_closing(const uv_handle_t* handle);
+
+
+/*
+ * uv_tcp_t is a subclass of uv_stream_t.
+ *
+ * Represents a TCP stream or TCP server.
+ */
+struct uv_tcp_s {
+ UV_HANDLE_FIELDS
+ UV_STREAM_FIELDS
+ UV_TCP_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_tcp_init(uv_loop_t*, uv_tcp_t* handle);
+UV_EXTERN int uv_tcp_init_ex(uv_loop_t*, uv_tcp_t* handle, unsigned int flags);
+UV_EXTERN int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock);
+UV_EXTERN int uv_tcp_nodelay(uv_tcp_t* handle, int enable);
+UV_EXTERN int uv_tcp_keepalive(uv_tcp_t* handle,
+ int enable,
+ unsigned int delay);
+UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable);
+
+enum uv_tcp_flags {
+ /* Used with uv_tcp_bind, when an IPv6 address is used. */
+ UV_TCP_IPV6ONLY = 1
+};
+
+UV_EXTERN int uv_tcp_bind(uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int flags);
+UV_EXTERN int uv_tcp_getsockname(const uv_tcp_t* handle,
+ struct sockaddr* name,
+ int* namelen);
+UV_EXTERN int uv_tcp_getpeername(const uv_tcp_t* handle,
+ struct sockaddr* name,
+ int* namelen);
+UV_EXTERN int uv_tcp_connect(uv_connect_t* req,
+ uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ uv_connect_cb cb);
+
+/* uv_connect_t is a subclass of uv_req_t. */
+struct uv_connect_s {
+ UV_REQ_FIELDS
+ uv_connect_cb cb;
+ uv_stream_t* handle;
+ UV_CONNECT_PRIVATE_FIELDS
+};
+
+
+/*
+ * UDP support.
+ */
+
+enum uv_udp_flags {
+ /* Disables dual stack mode. */
+ UV_UDP_IPV6ONLY = 1,
+ /*
+ * Indicates message was truncated because read buffer was too small. The
+ * remainder was discarded by the OS. Used in uv_udp_recv_cb.
+ */
+ UV_UDP_PARTIAL = 2,
+ /*
+ * Indicates if SO_REUSEADDR will be set when binding the handle.
+ * This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other
+ * Unix platforms, it sets the SO_REUSEADDR flag. What that means is that
+ * multiple threads or processes can bind to the same address without error
+ * (provided they all set the flag) but only the last one to bind will receive
+ * any traffic, in effect "stealing" the port from the previous listener.
+ */
+ UV_UDP_REUSEADDR = 4
+};
+
+typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status);
+typedef void (*uv_udp_recv_cb)(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags);
+
+/* uv_udp_t is a subclass of uv_handle_t. */
+struct uv_udp_s {
+ UV_HANDLE_FIELDS
+ /* read-only */
+ /*
+ * Number of bytes queued for sending. This field strictly shows how much
+ * information is currently queued.
+ */
+ size_t send_queue_size;
+ /*
+ * Number of send requests currently in the queue awaiting to be processed.
+ */
+ size_t send_queue_count;
+ UV_UDP_PRIVATE_FIELDS
+};
+
+/* uv_udp_send_t is a subclass of uv_req_t. */
+struct uv_udp_send_s {
+ UV_REQ_FIELDS
+ uv_udp_t* handle;
+ uv_udp_send_cb cb;
+ UV_UDP_SEND_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_udp_init(uv_loop_t*, uv_udp_t* handle);
+UV_EXTERN int uv_udp_init_ex(uv_loop_t*, uv_udp_t* handle, unsigned int flags);
+UV_EXTERN int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock);
+UV_EXTERN int uv_udp_bind(uv_udp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int flags);
+
+UV_EXTERN int uv_udp_getsockname(const uv_udp_t* handle,
+ struct sockaddr* name,
+ int* namelen);
+UV_EXTERN int uv_udp_set_membership(uv_udp_t* handle,
+ const char* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership);
+UV_EXTERN int uv_udp_set_multicast_loop(uv_udp_t* handle, int on);
+UV_EXTERN int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl);
+UV_EXTERN int uv_udp_set_multicast_interface(uv_udp_t* handle,
+ const char* interface_addr);
+UV_EXTERN int uv_udp_set_broadcast(uv_udp_t* handle, int on);
+UV_EXTERN int uv_udp_set_ttl(uv_udp_t* handle, int ttl);
+UV_EXTERN int uv_udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ uv_udp_send_cb send_cb);
+UV_EXTERN int uv_udp_try_send(uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr);
+UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle,
+ uv_alloc_cb alloc_cb,
+ uv_udp_recv_cb recv_cb);
+UV_EXTERN int uv_udp_recv_stop(uv_udp_t* handle);
+
+
+/*
+ * uv_tty_t is a subclass of uv_stream_t.
+ *
+ * Representing a stream for the console.
+ */
+struct uv_tty_s {
+ UV_HANDLE_FIELDS
+ UV_STREAM_FIELDS
+ UV_TTY_PRIVATE_FIELDS
+};
+
+typedef enum {
+ /* Initial/normal terminal mode */
+ UV_TTY_MODE_NORMAL,
+ /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */
+ UV_TTY_MODE_RAW,
+ /* Binary-safe I/O mode for IPC (Unix-only) */
+ UV_TTY_MODE_IO
+} uv_tty_mode_t;
+
+UV_EXTERN int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable);
+UV_EXTERN int uv_tty_set_mode(uv_tty_t*, uv_tty_mode_t mode);
+UV_EXTERN int uv_tty_reset_mode(void);
+UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height);
+
+#ifdef __cplusplus
+extern "C++" {
+
+inline int uv_tty_set_mode(uv_tty_t* handle, int mode) {
+ return uv_tty_set_mode(handle, static_cast<uv_tty_mode_t>(mode));
+}
+
+}
+#endif
+
+UV_EXTERN uv_handle_type uv_guess_handle(uv_file file);
+
+/*
+ * uv_pipe_t is a subclass of uv_stream_t.
+ *
+ * Representing a pipe stream or pipe server. On Windows this is a Named
+ * Pipe. On Unix this is a Unix domain socket.
+ */
+struct uv_pipe_s {
+ UV_HANDLE_FIELDS
+ UV_STREAM_FIELDS
+ int ipc; /* non-zero if this pipe is used for passing handles */
+ UV_PIPE_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_pipe_init(uv_loop_t*, uv_pipe_t* handle, int ipc);
+UV_EXTERN int uv_pipe_open(uv_pipe_t*, uv_file file);
+UV_EXTERN int uv_pipe_bind(uv_pipe_t* handle, const char* name);
+UV_EXTERN void uv_pipe_connect(uv_connect_t* req,
+ uv_pipe_t* handle,
+ const char* name,
+ uv_connect_cb cb);
+UV_EXTERN int uv_pipe_getsockname(const uv_pipe_t* handle,
+ char* buffer,
+ size_t* size);
+UV_EXTERN int uv_pipe_getpeername(const uv_pipe_t* handle,
+ char* buffer,
+ size_t* size);
+UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count);
+UV_EXTERN int uv_pipe_pending_count(uv_pipe_t* handle);
+UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle);
+
+
+struct uv_poll_s {
+ UV_HANDLE_FIELDS
+ uv_poll_cb poll_cb;
+ UV_POLL_PRIVATE_FIELDS
+};
+
+enum uv_poll_event {
+ UV_READABLE = 1,
+ UV_WRITABLE = 2
+};
+
+UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd);
+UV_EXTERN int uv_poll_init_socket(uv_loop_t* loop,
+ uv_poll_t* handle,
+ uv_os_sock_t socket);
+UV_EXTERN int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb);
+UV_EXTERN int uv_poll_stop(uv_poll_t* handle);
+
+
+struct uv_prepare_s {
+ UV_HANDLE_FIELDS
+ UV_PREPARE_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_prepare_init(uv_loop_t*, uv_prepare_t* prepare);
+UV_EXTERN int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb);
+UV_EXTERN int uv_prepare_stop(uv_prepare_t* prepare);
+
+
+struct uv_check_s {
+ UV_HANDLE_FIELDS
+ UV_CHECK_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_check_init(uv_loop_t*, uv_check_t* check);
+UV_EXTERN int uv_check_start(uv_check_t* check, uv_check_cb cb);
+UV_EXTERN int uv_check_stop(uv_check_t* check);
+
+
+struct uv_idle_s {
+ UV_HANDLE_FIELDS
+ UV_IDLE_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_idle_init(uv_loop_t*, uv_idle_t* idle);
+UV_EXTERN int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb);
+UV_EXTERN int uv_idle_stop(uv_idle_t* idle);
+
+
+struct uv_async_s {
+ UV_HANDLE_FIELDS
+ UV_ASYNC_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_async_init(uv_loop_t*,
+ uv_async_t* async,
+ uv_async_cb async_cb);
+UV_EXTERN int uv_async_send(uv_async_t* async);
+
+
+/*
+ * uv_timer_t is a subclass of uv_handle_t.
+ *
+ * Used to get woken up at a specified time in the future.
+ */
+struct uv_timer_s {
+ UV_HANDLE_FIELDS
+ UV_TIMER_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_timer_init(uv_loop_t*, uv_timer_t* handle);
+UV_EXTERN int uv_timer_start(uv_timer_t* handle,
+ uv_timer_cb cb,
+ uint64_t timeout,
+ uint64_t repeat);
+UV_EXTERN int uv_timer_stop(uv_timer_t* handle);
+UV_EXTERN int uv_timer_again(uv_timer_t* handle);
+UV_EXTERN void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat);
+UV_EXTERN uint64_t uv_timer_get_repeat(const uv_timer_t* handle);
+
+
+/*
+ * uv_getaddrinfo_t is a subclass of uv_req_t.
+ *
+ * Request object for uv_getaddrinfo.
+ */
+struct uv_getaddrinfo_s {
+ UV_REQ_FIELDS
+ /* read-only */
+ uv_loop_t* loop;
+ /* struct addrinfo* addrinfo is marked as private, but it really isn't. */
+ UV_GETADDRINFO_PRIVATE_FIELDS
+};
+
+
+UV_EXTERN int uv_getaddrinfo(uv_loop_t* loop,
+ uv_getaddrinfo_t* req,
+ uv_getaddrinfo_cb getaddrinfo_cb,
+ const char* node,
+ const char* service,
+ const struct addrinfo* hints);
+UV_EXTERN void uv_freeaddrinfo(struct addrinfo* ai);
+
+
+/*
+* uv_getnameinfo_t is a subclass of uv_req_t.
+*
+* Request object for uv_getnameinfo.
+*/
+struct uv_getnameinfo_s {
+ UV_REQ_FIELDS
+ /* read-only */
+ uv_loop_t* loop;
+ /* host and service are marked as private, but they really aren't. */
+ UV_GETNAMEINFO_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_getnameinfo(uv_loop_t* loop,
+ uv_getnameinfo_t* req,
+ uv_getnameinfo_cb getnameinfo_cb,
+ const struct sockaddr* addr,
+ int flags);
+
+
+/* uv_spawn() options. */
+typedef enum {
+ UV_IGNORE = 0x00,
+ UV_CREATE_PIPE = 0x01,
+ UV_INHERIT_FD = 0x02,
+ UV_INHERIT_STREAM = 0x04,
+
+ /*
+ * When UV_CREATE_PIPE is specified, UV_READABLE_PIPE and UV_WRITABLE_PIPE
+ * determine the direction of flow, from the child process' perspective. Both
+ * flags may be specified to create a duplex data stream.
+ */
+ UV_READABLE_PIPE = 0x10,
+ UV_WRITABLE_PIPE = 0x20
+} uv_stdio_flags;
+
+typedef struct uv_stdio_container_s {
+ uv_stdio_flags flags;
+
+ union {
+ uv_stream_t* stream;
+ int fd;
+ } data;
+} uv_stdio_container_t;
+
+typedef struct uv_process_options_s {
+ uv_exit_cb exit_cb; /* Called after the process exits. */
+ const char* file; /* Path to program to execute. */
+ /*
+ * Command line arguments. args[0] should be the path to the program. On
+ * Windows this uses CreateProcess which concatenates the arguments into a
+ * string this can cause some strange errors. See the note at
+ * windows_verbatim_arguments.
+ */
+ char** args;
+ /*
+ * This will be set as the environ variable in the subprocess. If this is
+ * NULL then the parents environ will be used.
+ */
+ char** env;
+ /*
+ * If non-null this represents a directory the subprocess should execute
+ * in. Stands for current working directory.
+ */
+ const char* cwd;
+ /*
+ * Various flags that control how uv_spawn() behaves. See the definition of
+ * `enum uv_process_flags` below.
+ */
+ unsigned int flags;
+ /*
+ * The `stdio` field points to an array of uv_stdio_container_t structs that
+ * describe the file descriptors that will be made available to the child
+ * process. The convention is that stdio[0] points to stdin, fd 1 is used for
+ * stdout, and fd 2 is stderr.
+ *
+ * Note that on windows file descriptors greater than 2 are available to the
+ * child process only if the child processes uses the MSVCRT runtime.
+ */
+ int stdio_count;
+ uv_stdio_container_t* stdio;
+ /*
+ * Libuv can change the child process' user/group id. This happens only when
+ * the appropriate bits are set in the flags fields. This is not supported on
+ * windows; uv_spawn() will fail and set the error to UV_ENOTSUP.
+ */
+ uv_uid_t uid;
+ uv_gid_t gid;
+} uv_process_options_t;
+
+/*
+ * These are the flags that can be used for the uv_process_options.flags field.
+ */
+enum uv_process_flags {
+ /*
+ * Set the child process' user id. The user id is supplied in the `uid` field
+ * of the options struct. This does not work on windows; setting this flag
+ * will cause uv_spawn() to fail.
+ */
+ UV_PROCESS_SETUID = (1 << 0),
+ /*
+ * Set the child process' group id. The user id is supplied in the `gid`
+ * field of the options struct. This does not work on windows; setting this
+ * flag will cause uv_spawn() to fail.
+ */
+ UV_PROCESS_SETGID = (1 << 1),
+ /*
+ * Do not wrap any arguments in quotes, or perform any other escaping, when
+ * converting the argument list into a command line string. This option is
+ * only meaningful on Windows systems. On Unix it is silently ignored.
+ */
+ UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (1 << 2),
+ /*
+ * Spawn the child process in a detached state - this will make it a process
+ * group leader, and will effectively enable the child to keep running after
+ * the parent exits. Note that the child process will still keep the
+ * parent's event loop alive unless the parent process calls uv_unref() on
+ * the child's process handle.
+ */
+ UV_PROCESS_DETACHED = (1 << 3),
+ /*
+ * Hide the subprocess console window that would normally be created. This
+ * option is only meaningful on Windows systems. On Unix it is silently
+ * ignored.
+ */
+ UV_PROCESS_WINDOWS_HIDE = (1 << 4)
+};
+
+/*
+ * uv_process_t is a subclass of uv_handle_t.
+ */
+struct uv_process_s {
+ UV_HANDLE_FIELDS
+ uv_exit_cb exit_cb;
+ int pid;
+ UV_PROCESS_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_spawn(uv_loop_t* loop,
+ uv_process_t* handle,
+ const uv_process_options_t* options);
+UV_EXTERN int uv_process_kill(uv_process_t*, int signum);
+UV_EXTERN int uv_kill(int pid, int signum);
+
+
+/*
+ * uv_work_t is a subclass of uv_req_t.
+ */
+struct uv_work_s {
+ UV_REQ_FIELDS
+ uv_loop_t* loop;
+ uv_work_cb work_cb;
+ uv_after_work_cb after_work_cb;
+ UV_WORK_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_queue_work(uv_loop_t* loop,
+ uv_work_t* req,
+ uv_work_cb work_cb,
+ uv_after_work_cb after_work_cb);
+
+UV_EXTERN int uv_cancel(uv_req_t* req);
+
+
+struct uv_cpu_info_s {
+ char* model;
+ int speed;
+ struct uv_cpu_times_s {
+ uint64_t user;
+ uint64_t nice;
+ uint64_t sys;
+ uint64_t idle;
+ uint64_t irq;
+ } cpu_times;
+};
+
+struct uv_interface_address_s {
+ char* name;
+ char phys_addr[6];
+ int is_internal;
+ union {
+ struct sockaddr_in address4;
+ struct sockaddr_in6 address6;
+ } address;
+ union {
+ struct sockaddr_in netmask4;
+ struct sockaddr_in6 netmask6;
+ } netmask;
+};
+
+typedef enum {
+ UV_DIRENT_UNKNOWN,
+ UV_DIRENT_FILE,
+ UV_DIRENT_DIR,
+ UV_DIRENT_LINK,
+ UV_DIRENT_FIFO,
+ UV_DIRENT_SOCKET,
+ UV_DIRENT_CHAR,
+ UV_DIRENT_BLOCK
+} uv_dirent_type_t;
+
+struct uv_dirent_s {
+ const char* name;
+ uv_dirent_type_t type;
+};
+
+UV_EXTERN char** uv_setup_args(int argc, char** argv);
+UV_EXTERN int uv_get_process_title(char* buffer, size_t size);
+UV_EXTERN int uv_set_process_title(const char* title);
+UV_EXTERN int uv_resident_set_memory(size_t* rss);
+UV_EXTERN int uv_uptime(double* uptime);
+
+typedef struct {
+ long tv_sec;
+ long tv_usec;
+} uv_timeval_t;
+
+typedef struct {
+ uv_timeval_t ru_utime; /* user CPU time used */
+ uv_timeval_t ru_stime; /* system CPU time used */
+ uint64_t ru_maxrss; /* maximum resident set size */
+ uint64_t ru_ixrss; /* integral shared memory size */
+ uint64_t ru_idrss; /* integral unshared data size */
+ uint64_t ru_isrss; /* integral unshared stack size */
+ uint64_t ru_minflt; /* page reclaims (soft page faults) */
+ uint64_t ru_majflt; /* page faults (hard page faults) */
+ uint64_t ru_nswap; /* swaps */
+ uint64_t ru_inblock; /* block input operations */
+ uint64_t ru_oublock; /* block output operations */
+ uint64_t ru_msgsnd; /* IPC messages sent */
+ uint64_t ru_msgrcv; /* IPC messages received */
+ uint64_t ru_nsignals; /* signals received */
+ uint64_t ru_nvcsw; /* voluntary context switches */
+ uint64_t ru_nivcsw; /* involuntary context switches */
+} uv_rusage_t;
+
+UV_EXTERN int uv_getrusage(uv_rusage_t* rusage);
+
+UV_EXTERN int uv_os_homedir(char* buffer, size_t* size);
+
+UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count);
+UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count);
+
+UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses,
+ int* count);
+UV_EXTERN void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count);
+
+
+typedef enum {
+ UV_FS_UNKNOWN = -1,
+ UV_FS_CUSTOM,
+ UV_FS_OPEN,
+ UV_FS_CLOSE,
+ UV_FS_READ,
+ UV_FS_WRITE,
+ UV_FS_SENDFILE,
+ UV_FS_STAT,
+ UV_FS_LSTAT,
+ UV_FS_FSTAT,
+ UV_FS_FTRUNCATE,
+ UV_FS_UTIME,
+ UV_FS_FUTIME,
+ UV_FS_ACCESS,
+ UV_FS_CHMOD,
+ UV_FS_FCHMOD,
+ UV_FS_FSYNC,
+ UV_FS_FDATASYNC,
+ UV_FS_UNLINK,
+ UV_FS_RMDIR,
+ UV_FS_MKDIR,
+ UV_FS_MKDTEMP,
+ UV_FS_RENAME,
+ UV_FS_SCANDIR,
+ UV_FS_LINK,
+ UV_FS_SYMLINK,
+ UV_FS_READLINK,
+ UV_FS_CHOWN,
+ UV_FS_FCHOWN,
+ UV_FS_REALPATH
+} uv_fs_type;
+
+/* uv_fs_t is a subclass of uv_req_t. */
+struct uv_fs_s {
+ UV_REQ_FIELDS
+ uv_fs_type fs_type;
+ uv_loop_t* loop;
+ uv_fs_cb cb;
+ ssize_t result;
+ void* ptr;
+ const char* path;
+ uv_stat_t statbuf; /* Stores the result of uv_fs_stat() and uv_fs_fstat(). */
+ UV_FS_PRIVATE_FIELDS
+};
+
+UV_EXTERN void uv_fs_req_cleanup(uv_fs_t* req);
+UV_EXTERN int uv_fs_close(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_open(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int flags,
+ int mode,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_read(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ int64_t offset,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_unlink(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_write(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ int64_t offset,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_mkdir(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int mode,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_mkdtemp(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* tpl,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_rmdir(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_scandir(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int flags,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_scandir_next(uv_fs_t* req,
+ uv_dirent_t* ent);
+UV_EXTERN int uv_fs_stat(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_fstat(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_rename(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_fsync(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_fdatasync(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_ftruncate(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ int64_t offset,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_sendfile(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file out_fd,
+ uv_file in_fd,
+ int64_t in_offset,
+ size_t length,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_access(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int mode,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_chmod(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int mode,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_utime(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ double atime,
+ double mtime,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_futime(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ double atime,
+ double mtime,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_lstat(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_link(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ uv_fs_cb cb);
+
+/*
+ * This flag can be used with uv_fs_symlink() on Windows to specify whether
+ * path argument points to a directory.
+ */
+#define UV_FS_SYMLINK_DIR 0x0001
+
+/*
+ * This flag can be used with uv_fs_symlink() on Windows to specify whether
+ * the symlink is to be created using junction points.
+ */
+#define UV_FS_SYMLINK_JUNCTION 0x0002
+
+UV_EXTERN int uv_fs_symlink(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ int flags,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_readlink(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_realpath(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_fchmod(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ int mode,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_chown(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_uid_t uid,
+ uv_gid_t gid,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_fchown(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ uv_uid_t uid,
+ uv_gid_t gid,
+ uv_fs_cb cb);
+
+
+enum uv_fs_event {
+ UV_RENAME = 1,
+ UV_CHANGE = 2
+};
+
+
+struct uv_fs_event_s {
+ UV_HANDLE_FIELDS
+ /* private */
+ char* path;
+ UV_FS_EVENT_PRIVATE_FIELDS
+};
+
+
+/*
+ * uv_fs_stat() based polling file watcher.
+ */
+struct uv_fs_poll_s {
+ UV_HANDLE_FIELDS
+ /* Private, don't touch. */
+ void* poll_ctx;
+};
+
+UV_EXTERN int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle);
+UV_EXTERN int uv_fs_poll_start(uv_fs_poll_t* handle,
+ uv_fs_poll_cb poll_cb,
+ const char* path,
+ unsigned int interval);
+UV_EXTERN int uv_fs_poll_stop(uv_fs_poll_t* handle);
+UV_EXTERN int uv_fs_poll_getpath(uv_fs_poll_t* handle,
+ char* buffer,
+ size_t* size);
+
+
+struct uv_signal_s {
+ UV_HANDLE_FIELDS
+ uv_signal_cb signal_cb;
+ int signum;
+ UV_SIGNAL_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle);
+UV_EXTERN int uv_signal_start(uv_signal_t* handle,
+ uv_signal_cb signal_cb,
+ int signum);
+UV_EXTERN int uv_signal_stop(uv_signal_t* handle);
+
+UV_EXTERN void uv_loadavg(double avg[3]);
+
+
+/*
+ * Flags to be passed to uv_fs_event_start().
+ */
+enum uv_fs_event_flags {
+ /*
+ * By default, if the fs event watcher is given a directory name, we will
+ * watch for all events in that directory. This flags overrides this behavior
+ * and makes fs_event report only changes to the directory entry itself. This
+ * flag does not affect individual files watched.
+ * This flag is currently not implemented yet on any backend.
+ */
+ UV_FS_EVENT_WATCH_ENTRY = 1,
+
+ /*
+ * By default uv_fs_event will try to use a kernel interface such as inotify
+ * or kqueue to detect events. This may not work on remote filesystems such
+ * as NFS mounts. This flag makes fs_event fall back to calling stat() on a
+ * regular interval.
+ * This flag is currently not implemented yet on any backend.
+ */
+ UV_FS_EVENT_STAT = 2,
+
+ /*
+ * By default, event watcher, when watching directory, is not registering
+ * (is ignoring) changes in it's subdirectories.
+ * This flag will override this behaviour on platforms that support it.
+ */
+ UV_FS_EVENT_RECURSIVE = 4
+};
+
+
+UV_EXTERN int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle);
+UV_EXTERN int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* path,
+ unsigned int flags);
+UV_EXTERN int uv_fs_event_stop(uv_fs_event_t* handle);
+UV_EXTERN int uv_fs_event_getpath(uv_fs_event_t* handle,
+ char* buffer,
+ size_t* size);
+
+UV_EXTERN int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr);
+UV_EXTERN int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr);
+
+UV_EXTERN int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size);
+UV_EXTERN int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size);
+
+UV_EXTERN int uv_inet_ntop(int af, const void* src, char* dst, size_t size);
+UV_EXTERN int uv_inet_pton(int af, const char* src, void* dst);
+
+UV_EXTERN int uv_exepath(char* buffer, size_t* size);
+
+UV_EXTERN int uv_cwd(char* buffer, size_t* size);
+
+UV_EXTERN int uv_chdir(const char* dir);
+
+UV_EXTERN uint64_t uv_get_free_memory(void);
+UV_EXTERN uint64_t uv_get_total_memory(void);
+
+UV_EXTERN uint64_t uv_hrtime(void);
+
+UV_EXTERN void uv_disable_stdio_inheritance(void);
+
+UV_EXTERN int uv_dlopen(const char* filename, uv_lib_t* lib);
+UV_EXTERN void uv_dlclose(uv_lib_t* lib);
+UV_EXTERN int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr);
+UV_EXTERN const char* uv_dlerror(const uv_lib_t* lib);
+
+UV_EXTERN int uv_mutex_init(uv_mutex_t* handle);
+UV_EXTERN void uv_mutex_destroy(uv_mutex_t* handle);
+UV_EXTERN void uv_mutex_lock(uv_mutex_t* handle);
+UV_EXTERN int uv_mutex_trylock(uv_mutex_t* handle);
+UV_EXTERN void uv_mutex_unlock(uv_mutex_t* handle);
+
+UV_EXTERN int uv_rwlock_init(uv_rwlock_t* rwlock);
+UV_EXTERN void uv_rwlock_destroy(uv_rwlock_t* rwlock);
+UV_EXTERN void uv_rwlock_rdlock(uv_rwlock_t* rwlock);
+UV_EXTERN int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock);
+UV_EXTERN void uv_rwlock_rdunlock(uv_rwlock_t* rwlock);
+UV_EXTERN void uv_rwlock_wrlock(uv_rwlock_t* rwlock);
+UV_EXTERN int uv_rwlock_trywrlock(uv_rwlock_t* rwlock);
+UV_EXTERN void uv_rwlock_wrunlock(uv_rwlock_t* rwlock);
+
+UV_EXTERN int uv_sem_init(uv_sem_t* sem, unsigned int value);
+UV_EXTERN void uv_sem_destroy(uv_sem_t* sem);
+UV_EXTERN void uv_sem_post(uv_sem_t* sem);
+UV_EXTERN void uv_sem_wait(uv_sem_t* sem);
+UV_EXTERN int uv_sem_trywait(uv_sem_t* sem);
+
+UV_EXTERN int uv_cond_init(uv_cond_t* cond);
+UV_EXTERN void uv_cond_destroy(uv_cond_t* cond);
+UV_EXTERN void uv_cond_signal(uv_cond_t* cond);
+UV_EXTERN void uv_cond_broadcast(uv_cond_t* cond);
+
+UV_EXTERN int uv_barrier_init(uv_barrier_t* barrier, unsigned int count);
+UV_EXTERN void uv_barrier_destroy(uv_barrier_t* barrier);
+UV_EXTERN int uv_barrier_wait(uv_barrier_t* barrier);
+
+UV_EXTERN void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex);
+UV_EXTERN int uv_cond_timedwait(uv_cond_t* cond,
+ uv_mutex_t* mutex,
+ uint64_t timeout);
+
+UV_EXTERN void uv_once(uv_once_t* guard, void (*callback)(void));
+
+UV_EXTERN int uv_key_create(uv_key_t* key);
+UV_EXTERN void uv_key_delete(uv_key_t* key);
+UV_EXTERN void* uv_key_get(uv_key_t* key);
+UV_EXTERN void uv_key_set(uv_key_t* key, void* value);
+
+typedef void (*uv_thread_cb)(void* arg);
+
+UV_EXTERN int uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg);
+UV_EXTERN uv_thread_t uv_thread_self(void);
+UV_EXTERN int uv_thread_join(uv_thread_t *tid);
+UV_EXTERN int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2);
+
+/* The presence of these unions force similar struct layout. */
+#define XX(_, name) uv_ ## name ## _t name;
+union uv_any_handle {
+ UV_HANDLE_TYPE_MAP(XX)
+};
+
+union uv_any_req {
+ UV_REQ_TYPE_MAP(XX)
+};
+#undef XX
+
+
+struct uv_loop_s {
+ /* User data - use this for whatever. */
+ void* data;
+ /* Loop reference counting. */
+ unsigned int active_handles;
+ void* handle_queue[2];
+ void* active_reqs[2];
+ /* Internal flag to signal loop stop. */
+ unsigned int stop_flag;
+ UV_LOOP_PRIVATE_FIELDS
+};
+
+
+/* Don't export the private CPP symbols. */
+#undef UV_HANDLE_TYPE_PRIVATE
+#undef UV_REQ_TYPE_PRIVATE
+#undef UV_REQ_PRIVATE_FIELDS
+#undef UV_STREAM_PRIVATE_FIELDS
+#undef UV_TCP_PRIVATE_FIELDS
+#undef UV_PREPARE_PRIVATE_FIELDS
+#undef UV_CHECK_PRIVATE_FIELDS
+#undef UV_IDLE_PRIVATE_FIELDS
+#undef UV_ASYNC_PRIVATE_FIELDS
+#undef UV_TIMER_PRIVATE_FIELDS
+#undef UV_GETADDRINFO_PRIVATE_FIELDS
+#undef UV_GETNAMEINFO_PRIVATE_FIELDS
+#undef UV_FS_REQ_PRIVATE_FIELDS
+#undef UV_WORK_PRIVATE_FIELDS
+#undef UV_FS_EVENT_PRIVATE_FIELDS
+#undef UV_SIGNAL_PRIVATE_FIELDS
+#undef UV_LOOP_PRIVATE_FIELDS
+#undef UV_LOOP_PRIVATE_PLATFORM_FIELDS
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* UV_H */
diff --git a/3rdparty/libuv/libuv.nsi b/3rdparty/libuv/libuv.nsi
new file mode 100644
index 00000000000..159756e196c
--- /dev/null
+++ b/3rdparty/libuv/libuv.nsi
@@ -0,0 +1,86 @@
+; NSIS installer script for libuv
+
+!include "MUI2.nsh"
+
+Name "libuv"
+OutFile "libuv-${ARCH}-${VERSION}.exe"
+
+!include "x64.nsh"
+# Default install location, for 32-bit files
+InstallDir "$PROGRAMFILES\libuv"
+
+# Override install and registry locations if this is a 64-bit install.
+function .onInit
+ ${If} ${ARCH} == "x64"
+ SetRegView 64
+ StrCpy $INSTDIR "$PROGRAMFILES64\libuv"
+ ${EndIf}
+functionEnd
+
+;--------------------------------
+; Installer pages
+!insertmacro MUI_PAGE_WELCOME
+!insertmacro MUI_PAGE_DIRECTORY
+!insertmacro MUI_PAGE_INSTFILES
+!insertmacro MUI_PAGE_FINISH
+
+
+;--------------------------------
+; Uninstaller pages
+!insertmacro MUI_UNPAGE_WELCOME
+!insertmacro MUI_UNPAGE_CONFIRM
+!insertmacro MUI_UNPAGE_INSTFILES
+!insertmacro MUI_UNPAGE_FINISH
+
+;--------------------------------
+; Languages
+!insertmacro MUI_LANGUAGE "English"
+
+;--------------------------------
+; Installer sections
+
+Section "Files" SecInstall
+ SectionIn RO
+ SetOutPath "$INSTDIR"
+ File "Release\*.dll"
+ File "Release\*.lib"
+ File "LICENSE"
+ File "README.md"
+
+ SetOutPath "$INSTDIR\include"
+ File "include\uv.h"
+ File "include\uv-errno.h"
+ File "include\uv-threadpool.h"
+ File "include\uv-version.h"
+ File "include\uv-win.h"
+ File "include\tree.h"
+
+ WriteUninstaller "$INSTDIR\Uninstall.exe"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "DisplayName" "libuv-${ARCH}-${VERSION}"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "UninstallString" "$\"$INSTDIR\Uninstall.exe$\""
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "QuietUninstallString" "$\"$INSTDIR\Uninstall.exe$\" /S"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "HelpLink" "http://libuv.org/"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "URLInfoAbout" "http://libuv.org/"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "DisplayVersion" "${VERSION}"
+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "NoModify" "1"
+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}" "NoRepair" "1"
+SectionEnd
+
+Section "Uninstall"
+ Delete "$INSTDIR\libuv.dll"
+ Delete "$INSTDIR\libuv.lib"
+ Delete "$INSTDIR\LICENSE"
+ Delete "$INSTDIR\README.md"
+
+ Delete "$INSTDIR\include\uv.h"
+ Delete "$INSTDIR\include\uv-errno.h"
+ Delete "$INSTDIR\include\uv-threadpool.h"
+ Delete "$INSTDIR\include\uv-version.h"
+ Delete "$INSTDIR\include\uv-win.h"
+ Delete "$INSTDIR\include\tree.h"
+
+ Delete "$INSTDIR\Uninstall.exe"
+ RMDir "$INSTDIR"
+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\libuv-${ARCH}-${VERSION}"
+SectionEnd
+
diff --git a/3rdparty/libuv/libuv.pc.in b/3rdparty/libuv/libuv.pc.in
new file mode 100644
index 00000000000..2933ec22526
--- /dev/null
+++ b/3rdparty/libuv/libuv.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: @PACKAGE_NAME@
+Version: @PACKAGE_VERSION@
+Description: multi-platform support library with a focus on asynchronous I/O.
+
+Libs: -L${libdir} -luv @LIBS@
+Cflags: -I${includedir}
diff --git a/3rdparty/libuv/m4/.gitignore b/3rdparty/libuv/m4/.gitignore
new file mode 100644
index 00000000000..c44e4c2929a
--- /dev/null
+++ b/3rdparty/libuv/m4/.gitignore
@@ -0,0 +1,4 @@
+# Ignore libtoolize-generated files.
+*.m4
+!as_case.m4
+!libuv-check-flags.m4
diff --git a/3rdparty/libuv/m4/as_case.m4 b/3rdparty/libuv/m4/as_case.m4
new file mode 100644
index 00000000000..c7ae0f0f5ed
--- /dev/null
+++ b/3rdparty/libuv/m4/as_case.m4
@@ -0,0 +1,21 @@
+# AS_CASE(WORD, [PATTERN1], [IF-MATCHED1]...[DEFAULT])
+# ----------------------------------------------------
+# Expand into
+# | case WORD in
+# | PATTERN1) IF-MATCHED1 ;;
+# | ...
+# | *) DEFAULT ;;
+# | esac
+m4_define([_AS_CASE],
+[m4_if([$#], 0, [m4_fatal([$0: too few arguments: $#])],
+ [$#], 1, [ *) $1 ;;],
+ [$#], 2, [ $1) m4_default([$2], [:]) ;;],
+ [ $1) m4_default([$2], [:]) ;;
+$0(m4_shiftn(2, $@))])dnl
+])
+m4_defun([AS_CASE],
+[m4_ifval([$2$3],
+[case $1 in
+_AS_CASE(m4_shift($@))
+esac])])
+
diff --git a/3rdparty/libuv/m4/libuv-check-flags.m4 b/3rdparty/libuv/m4/libuv-check-flags.m4
new file mode 100644
index 00000000000..59c30635577
--- /dev/null
+++ b/3rdparty/libuv/m4/libuv-check-flags.m4
@@ -0,0 +1,319 @@
+dnl Macros to check the presence of generic (non-typed) symbols.
+dnl Copyright (c) 2006-2008 Diego Pettenà <flameeyes gmail com>
+dnl Copyright (c) 2006-2008 xine project
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 3, or (at your option)
+dnl any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+dnl 02110-1301, USA.
+dnl
+dnl As a special exception, the copyright owners of the
+dnl macro gives unlimited permission to copy, distribute and modify the
+dnl configure scripts that are the output of Autoconf when processing the
+dnl Macro. You need not follow the terms of the GNU General Public
+dnl License when using or distributing such scripts, even though portions
+dnl of the text of the Macro appear in them. The GNU General Public
+dnl License (GPL) does govern all other use of the material that
+dnl constitutes the Autoconf Macro.
+dnl
+dnl This special exception to the GPL applies to versions of the
+dnl Autoconf Macro released by this project. When you make and
+dnl distribute a modified version of the Autoconf Macro, you may extend
+dnl this special exception to the GPL to apply to your modified version as
+dnl well.
+
+dnl Check if the flag is supported by compiler
+dnl CC_CHECK_CFLAGS_SILENT([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND])
+
+AC_DEFUN([CC_CHECK_CFLAGS_SILENT], [
+ AC_CACHE_VAL(AS_TR_SH([cc_cv_cflags_$1]),
+ [ac_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $1"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([int a;])],
+ [eval "AS_TR_SH([cc_cv_cflags_$1])='yes'"],
+ [eval "AS_TR_SH([cc_cv_cflags_$1])='no'"])
+ CFLAGS="$ac_save_CFLAGS"
+ ])
+
+ AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes],
+ [$2], [$3])
+])
+
+dnl Check if the flag is supported by compiler (cacheable)
+dnl CC_CHECK_CFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND])
+
+AC_DEFUN([CC_CHECK_CFLAGS], [
+ AC_CACHE_CHECK([if $CC supports $1 flag],
+ AS_TR_SH([cc_cv_cflags_$1]),
+ CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here!
+ )
+
+ AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes],
+ [$2], [$3])
+])
+
+dnl CC_CHECK_CFLAG_APPEND(FLAG, [action-if-found], [action-if-not-found])
+dnl Check for CFLAG and appends them to CFLAGS if supported
+AC_DEFUN([CC_CHECK_CFLAG_APPEND], [
+ AC_CACHE_CHECK([if $CC supports $1 flag],
+ AS_TR_SH([cc_cv_cflags_$1]),
+ CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here!
+ )
+
+ AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes],
+ [CFLAGS="$CFLAGS $1"; DEBUG_CFLAGS="$DEBUG_CFLAGS $1"; $2], [$3])
+])
+
+dnl CC_CHECK_CFLAGS_APPEND([FLAG1 FLAG2], [action-if-found], [action-if-not])
+AC_DEFUN([CC_CHECK_CFLAGS_APPEND], [
+ for flag in $1; do
+ CC_CHECK_CFLAG_APPEND($flag, [$2], [$3])
+ done
+])
+
+dnl Check if the flag is supported by linker (cacheable)
+dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND])
+
+AC_DEFUN([CC_CHECK_LDFLAGS], [
+ AC_CACHE_CHECK([if $CC supports $1 flag],
+ AS_TR_SH([cc_cv_ldflags_$1]),
+ [ac_save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $1"
+ AC_LANG_PUSH([C])
+ AC_LINK_IFELSE([AC_LANG_SOURCE([int main() { return 1; }])],
+ [eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"],
+ [eval "AS_TR_SH([cc_cv_ldflags_$1])="])
+ AC_LANG_POP([C])
+ LDFLAGS="$ac_save_LDFLAGS"
+ ])
+
+ AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes],
+ [$2], [$3])
+])
+
+dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for
+dnl the current linker to avoid undefined references in a shared object.
+AC_DEFUN([CC_NOUNDEFINED], [
+ dnl We check $host for which systems to enable this for.
+ AC_REQUIRE([AC_CANONICAL_HOST])
+
+ case $host in
+ dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads
+ dnl are requested, as different implementations are present; to avoid problems
+ dnl use -Wl,-z,defs only for those platform not behaving this way.
+ *-freebsd* | *-openbsd*) ;;
+ *)
+ dnl First of all check for the --no-undefined variant of GNU ld. This allows
+ dnl for a much more readable commandline, so that people can understand what
+ dnl it does without going to look for what the heck -z defs does.
+ for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do
+ CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"])
+ break
+ done
+ ;;
+ esac
+
+ AC_SUBST([LDFLAGS_NOUNDEFINED])
+])
+
+dnl Check for a -Werror flag or equivalent. -Werror is the GCC
+dnl and ICC flag that tells the compiler to treat all the warnings
+dnl as fatal. We usually need this option to make sure that some
+dnl constructs (like attributes) are not simply ignored.
+dnl
+dnl Other compilers don't support -Werror per se, but they support
+dnl an equivalent flag:
+dnl - Sun Studio compiler supports -errwarn=%all
+AC_DEFUN([CC_CHECK_WERROR], [
+ AC_CACHE_CHECK(
+ [for $CC way to treat warnings as errors],
+ [cc_cv_werror],
+ [CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror],
+ [CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])])
+ ])
+])
+
+AC_DEFUN([CC_CHECK_ATTRIBUTE], [
+ AC_REQUIRE([CC_CHECK_WERROR])
+ AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))],
+ AS_TR_SH([cc_cv_attribute_$1]),
+ [ac_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $cc_cv_werror"
+ AC_LANG_PUSH([C])
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])],
+ [eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"],
+ [eval "AS_TR_SH([cc_cv_attribute_$1])='no'"])
+ AC_LANG_POP([C])
+ CFLAGS="$ac_save_CFLAGS"
+ ])
+
+ AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes],
+ [AC_DEFINE(
+ AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1,
+ [Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))]
+ )
+ $4],
+ [$5])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [
+ CC_CHECK_ATTRIBUTE(
+ [constructor],,
+ [void __attribute__((constructor)) ctor() { int a; }],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_FORMAT], [
+ CC_CHECK_ATTRIBUTE(
+ [format], [format(printf, n, n)],
+ [void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [
+ CC_CHECK_ATTRIBUTE(
+ [format_arg], [format_arg(printf)],
+ [char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [
+ CC_CHECK_ATTRIBUTE(
+ [visibility_$1], [visibility("$1")],
+ [void __attribute__((visibility("$1"))) $1_function() { }],
+ [$2], [$3])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_NONNULL], [
+ CC_CHECK_ATTRIBUTE(
+ [nonnull], [nonnull()],
+ [void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_UNUSED], [
+ CC_CHECK_ATTRIBUTE(
+ [unused], ,
+ [void some_function(void *foo, __attribute__((unused)) void *bar);],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [
+ CC_CHECK_ATTRIBUTE(
+ [sentinel], ,
+ [void some_function(void *foo, ...) __attribute__((sentinel));],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [
+ CC_CHECK_ATTRIBUTE(
+ [deprecated], ,
+ [void some_function(void *foo, ...) __attribute__((deprecated));],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_ALIAS], [
+ CC_CHECK_ATTRIBUTE(
+ [alias], [weak, alias],
+ [void other_function(void *foo) { }
+ void some_function(void *foo) __attribute__((weak, alias("other_function")));],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_MALLOC], [
+ CC_CHECK_ATTRIBUTE(
+ [malloc], ,
+ [void * __attribute__((malloc)) my_alloc(int n);],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_PACKED], [
+ CC_CHECK_ATTRIBUTE(
+ [packed], ,
+ [struct astructure { char a; int b; long c; void *d; } __attribute__((packed));],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_CONST], [
+ CC_CHECK_ATTRIBUTE(
+ [const], ,
+ [int __attribute__((const)) twopow(int n) { return 1 << n; } ],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_FLAG_VISIBILITY], [
+ AC_REQUIRE([CC_CHECK_WERROR])
+ AC_CACHE_CHECK([if $CC supports -fvisibility=hidden],
+ [cc_cv_flag_visibility],
+ [cc_flag_visibility_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $cc_cv_werror"
+ CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden],
+ cc_cv_flag_visibility='yes',
+ cc_cv_flag_visibility='no')
+ CFLAGS="$cc_flag_visibility_save_CFLAGS"])
+
+ AS_IF([test "x$cc_cv_flag_visibility" = "xyes"],
+ [AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1,
+ [Define this if the compiler supports the -fvisibility flag])
+ $1],
+ [$2])
+])
+
+AC_DEFUN([CC_FUNC_EXPECT], [
+ AC_REQUIRE([CC_CHECK_WERROR])
+ AC_CACHE_CHECK([if compiler has __builtin_expect function],
+ [cc_cv_func_expect],
+ [ac_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $cc_cv_werror"
+ AC_LANG_PUSH([C])
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE(
+ [int some_function() {
+ int a = 3;
+ return (int)__builtin_expect(a, 3);
+ }])],
+ [cc_cv_func_expect=yes],
+ [cc_cv_func_expect=no])
+ AC_LANG_POP([C])
+ CFLAGS="$ac_save_CFLAGS"
+ ])
+
+ AS_IF([test "x$cc_cv_func_expect" = "xyes"],
+ [AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1,
+ [Define this if the compiler supports __builtin_expect() function])
+ $1],
+ [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [
+ AC_REQUIRE([CC_CHECK_WERROR])
+ AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported],
+ [cc_cv_attribute_aligned],
+ [ac_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $cc_cv_werror"
+ AC_LANG_PUSH([C])
+ for cc_attribute_align_try in 64 32 16 8 4 2; do
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([
+ int main() {
+ static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0;
+ return c;
+ }])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break])
+ done
+ AC_LANG_POP([C])
+ CFLAGS="$ac_save_CFLAGS"
+ ])
+
+ if test "x$cc_cv_attribute_aligned" != "x"; then
+ AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned],
+ [Define the highest alignment supported])
+ fi
+]) \ No newline at end of file
diff --git a/3rdparty/libuv/samples/.gitignore b/3rdparty/libuv/samples/.gitignore
new file mode 100644
index 00000000000..f868091ba32
--- /dev/null
+++ b/3rdparty/libuv/samples/.gitignore
@@ -0,0 +1,22 @@
+# Copyright StrongLoop, Inc. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+*.mk
+*.Makefile
diff --git a/3rdparty/libuv/samples/socks5-proxy/.gitignore b/3rdparty/libuv/samples/socks5-proxy/.gitignore
new file mode 100644
index 00000000000..c177f374510
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/.gitignore
@@ -0,0 +1,21 @@
+# Copyright StrongLoop, Inc. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+/build/
diff --git a/3rdparty/libuv/samples/socks5-proxy/LICENSE b/3rdparty/libuv/samples/socks5-proxy/LICENSE
new file mode 100644
index 00000000000..63c1447fc55
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/LICENSE
@@ -0,0 +1,53 @@
+Files: *
+========
+
+Copyright StrongLoop, Inc. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+
+
+Files: getopt.c
+===============
+
+Copyright (c) 1987, 1993, 1994
+The Regents of the University of California. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/3rdparty/libuv/samples/socks5-proxy/build.gyp b/3rdparty/libuv/samples/socks5-proxy/build.gyp
new file mode 100644
index 00000000000..771a1e146db
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/build.gyp
@@ -0,0 +1,46 @@
+# Copyright StrongLoop, Inc. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+{
+ 'targets': [
+ {
+ 'dependencies': ['../../uv.gyp:libuv'],
+ 'target_name': 's5-proxy',
+ 'type': 'executable',
+ 'sources': [
+ 'client.c',
+ 'defs.h',
+ 'main.c',
+ 's5.c',
+ 's5.h',
+ 'server.c',
+ 'util.c',
+ ],
+ 'conditions': [
+ ['OS=="win"', {
+ 'defines': ['HAVE_UNISTD_H=0'],
+ 'sources': ['getopt.c']
+ }, {
+ 'defines': ['HAVE_UNISTD_H=1']
+ }]
+ ]
+ }
+ ]
+}
diff --git a/3rdparty/libuv/samples/socks5-proxy/client.c b/3rdparty/libuv/samples/socks5-proxy/client.c
new file mode 100644
index 00000000000..ae9913a1c6e
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/client.c
@@ -0,0 +1,737 @@
+/* Copyright StrongLoop, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "defs.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* A connection is modeled as an abstraction on top of two simple state
+ * machines, one for reading and one for writing. Either state machine
+ * is, when active, in one of three states: busy, done or stop; the fourth
+ * and final state, dead, is an end state and only relevant when shutting
+ * down the connection. A short overview:
+ *
+ * busy done stop
+ * ----------|---------------------------|--------------------|------|
+ * readable | waiting for incoming data | have incoming data | idle |
+ * writable | busy writing out data | completed write | idle |
+ *
+ * We could remove the done state from the writable state machine. For our
+ * purposes, it's functionally equivalent to the stop state.
+ *
+ * When the connection with upstream has been established, the client_ctx
+ * moves into a state where incoming data from the client is sent upstream
+ * and vice versa, incoming data from upstream is sent to the client. In
+ * other words, we're just piping data back and forth. See conn_cycle()
+ * for details.
+ *
+ * An interesting deviation from libuv's I/O model is that reads are discrete
+ * rather than continuous events. In layman's terms, when a read operation
+ * completes, the connection stops reading until further notice.
+ *
+ * The rationale for this approach is that we have to wait until the data
+ * has been sent out again before we can reuse the read buffer.
+ *
+ * It also pleasingly unifies with the request model that libuv uses for
+ * writes and everything else; libuv may switch to a request model for
+ * reads in the future.
+ */
+enum conn_state {
+ c_busy, /* Busy; waiting for incoming data or for a write to complete. */
+ c_done, /* Done; read incoming data or write finished. */
+ c_stop, /* Stopped. */
+ c_dead
+};
+
+/* Session states. */
+enum sess_state {
+ s_handshake, /* Wait for client handshake. */
+ s_handshake_auth, /* Wait for client authentication data. */
+ s_req_start, /* Start waiting for request data. */
+ s_req_parse, /* Wait for request data. */
+ s_req_lookup, /* Wait for upstream hostname DNS lookup to complete. */
+ s_req_connect, /* Wait for uv_tcp_connect() to complete. */
+ s_proxy_start, /* Connected. Start piping data. */
+ s_proxy, /* Connected. Pipe data back and forth. */
+ s_kill, /* Tear down session. */
+ s_almost_dead_0, /* Waiting for finalizers to complete. */
+ s_almost_dead_1, /* Waiting for finalizers to complete. */
+ s_almost_dead_2, /* Waiting for finalizers to complete. */
+ s_almost_dead_3, /* Waiting for finalizers to complete. */
+ s_almost_dead_4, /* Waiting for finalizers to complete. */
+ s_dead /* Dead. Safe to free now. */
+};
+
+static void do_next(client_ctx *cx);
+static int do_handshake(client_ctx *cx);
+static int do_handshake_auth(client_ctx *cx);
+static int do_req_start(client_ctx *cx);
+static int do_req_parse(client_ctx *cx);
+static int do_req_lookup(client_ctx *cx);
+static int do_req_connect_start(client_ctx *cx);
+static int do_req_connect(client_ctx *cx);
+static int do_proxy_start(client_ctx *cx);
+static int do_proxy(client_ctx *cx);
+static int do_kill(client_ctx *cx);
+static int do_almost_dead(client_ctx *cx);
+static int conn_cycle(const char *who, conn *a, conn *b);
+static void conn_timer_reset(conn *c);
+static void conn_timer_expire(uv_timer_t *handle, int status);
+static void conn_getaddrinfo(conn *c, const char *hostname);
+static void conn_getaddrinfo_done(uv_getaddrinfo_t *req,
+ int status,
+ struct addrinfo *ai);
+static int conn_connect(conn *c);
+static void conn_connect_done(uv_connect_t *req, int status);
+static void conn_read(conn *c);
+static void conn_read_done(uv_stream_t *handle,
+ ssize_t nread,
+ const uv_buf_t *buf);
+static void conn_alloc(uv_handle_t *handle, size_t size, uv_buf_t *buf);
+static void conn_write(conn *c, const void *data, unsigned int len);
+static void conn_write_done(uv_write_t *req, int status);
+static void conn_close(conn *c);
+static void conn_close_done(uv_handle_t *handle);
+
+/* |incoming| has been initialized by server.c when this is called. */
+void client_finish_init(server_ctx *sx, client_ctx *cx) {
+ conn *incoming;
+ conn *outgoing;
+
+ cx->sx = sx;
+ cx->state = s_handshake;
+ s5_init(&cx->parser);
+
+ incoming = &cx->incoming;
+ incoming->client = cx;
+ incoming->result = 0;
+ incoming->rdstate = c_stop;
+ incoming->wrstate = c_stop;
+ incoming->idle_timeout = sx->idle_timeout;
+ CHECK(0 == uv_timer_init(sx->loop, &incoming->timer_handle));
+
+ outgoing = &cx->outgoing;
+ outgoing->client = cx;
+ outgoing->result = 0;
+ outgoing->rdstate = c_stop;
+ outgoing->wrstate = c_stop;
+ outgoing->idle_timeout = sx->idle_timeout;
+ CHECK(0 == uv_tcp_init(cx->sx->loop, &outgoing->handle.tcp));
+ CHECK(0 == uv_timer_init(cx->sx->loop, &outgoing->timer_handle));
+
+ /* Wait for the initial packet. */
+ conn_read(incoming);
+}
+
+/* This is the core state machine that drives the client <-> upstream proxy.
+ * We move through the initial handshake and authentication steps first and
+ * end up (if all goes well) in the proxy state where we're just proxying
+ * data between the client and upstream.
+ */
+static void do_next(client_ctx *cx) {
+ int new_state;
+
+ ASSERT(cx->state != s_dead);
+ switch (cx->state) {
+ case s_handshake:
+ new_state = do_handshake(cx);
+ break;
+ case s_handshake_auth:
+ new_state = do_handshake_auth(cx);
+ break;
+ case s_req_start:
+ new_state = do_req_start(cx);
+ break;
+ case s_req_parse:
+ new_state = do_req_parse(cx);
+ break;
+ case s_req_lookup:
+ new_state = do_req_lookup(cx);
+ break;
+ case s_req_connect:
+ new_state = do_req_connect(cx);
+ break;
+ case s_proxy_start:
+ new_state = do_proxy_start(cx);
+ break;
+ case s_proxy:
+ new_state = do_proxy(cx);
+ break;
+ case s_kill:
+ new_state = do_kill(cx);
+ break;
+ case s_almost_dead_0:
+ case s_almost_dead_1:
+ case s_almost_dead_2:
+ case s_almost_dead_3:
+ case s_almost_dead_4:
+ new_state = do_almost_dead(cx);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ cx->state = new_state;
+
+ if (cx->state == s_dead) {
+ if (DEBUG_CHECKS) {
+ memset(cx, -1, sizeof(*cx));
+ }
+ free(cx);
+ }
+}
+
+static int do_handshake(client_ctx *cx) {
+ unsigned int methods;
+ conn *incoming;
+ s5_ctx *parser;
+ uint8_t *data;
+ size_t size;
+ int err;
+
+ parser = &cx->parser;
+ incoming = &cx->incoming;
+ ASSERT(incoming->rdstate == c_done);
+ ASSERT(incoming->wrstate == c_stop);
+ incoming->rdstate = c_stop;
+
+ if (incoming->result < 0) {
+ pr_err("read error: %s", uv_strerror(incoming->result));
+ return do_kill(cx);
+ }
+
+ data = (uint8_t *) incoming->t.buf;
+ size = (size_t) incoming->result;
+ err = s5_parse(parser, &data, &size);
+ if (err == s5_ok) {
+ conn_read(incoming);
+ return s_handshake; /* Need more data. */
+ }
+
+ if (size != 0) {
+ /* Could allow a round-trip saving shortcut here if the requested auth
+ * method is S5_AUTH_NONE (provided unauthenticated traffic is allowed.)
+ * Requires client support however.
+ */
+ pr_err("junk in handshake");
+ return do_kill(cx);
+ }
+
+ if (err != s5_auth_select) {
+ pr_err("handshake error: %s", s5_strerror(err));
+ return do_kill(cx);
+ }
+
+ methods = s5_auth_methods(parser);
+ if ((methods & S5_AUTH_NONE) && can_auth_none(cx->sx, cx)) {
+ s5_select_auth(parser, S5_AUTH_NONE);
+ conn_write(incoming, "\5\0", 2); /* No auth required. */
+ return s_req_start;
+ }
+
+ if ((methods & S5_AUTH_PASSWD) && can_auth_passwd(cx->sx, cx)) {
+ /* TODO(bnoordhuis) Implement username/password auth. */
+ }
+
+ conn_write(incoming, "\5\377", 2); /* No acceptable auth. */
+ return s_kill;
+}
+
+/* TODO(bnoordhuis) Implement username/password auth. */
+static int do_handshake_auth(client_ctx *cx) {
+ UNREACHABLE();
+ return do_kill(cx);
+}
+
+static int do_req_start(client_ctx *cx) {
+ conn *incoming;
+
+ incoming = &cx->incoming;
+ ASSERT(incoming->rdstate == c_stop);
+ ASSERT(incoming->wrstate == c_done);
+ incoming->wrstate = c_stop;
+
+ if (incoming->result < 0) {
+ pr_err("write error: %s", uv_strerror(incoming->result));
+ return do_kill(cx);
+ }
+
+ conn_read(incoming);
+ return s_req_parse;
+}
+
+static int do_req_parse(client_ctx *cx) {
+ conn *incoming;
+ conn *outgoing;
+ s5_ctx *parser;
+ uint8_t *data;
+ size_t size;
+ int err;
+
+ parser = &cx->parser;
+ incoming = &cx->incoming;
+ outgoing = &cx->outgoing;
+ ASSERT(incoming->rdstate == c_done);
+ ASSERT(incoming->wrstate == c_stop);
+ ASSERT(outgoing->rdstate == c_stop);
+ ASSERT(outgoing->wrstate == c_stop);
+ incoming->rdstate = c_stop;
+
+ if (incoming->result < 0) {
+ pr_err("read error: %s", uv_strerror(incoming->result));
+ return do_kill(cx);
+ }
+
+ data = (uint8_t *) incoming->t.buf;
+ size = (size_t) incoming->result;
+ err = s5_parse(parser, &data, &size);
+ if (err == s5_ok) {
+ conn_read(incoming);
+ return s_req_parse; /* Need more data. */
+ }
+
+ if (size != 0) {
+ pr_err("junk in request %u", (unsigned) size);
+ return do_kill(cx);
+ }
+
+ if (err != s5_exec_cmd) {
+ pr_err("request error: %s", s5_strerror(err));
+ return do_kill(cx);
+ }
+
+ if (parser->cmd == s5_cmd_tcp_bind) {
+ /* Not supported but relatively straightforward to implement. */
+ pr_warn("BIND requests are not supported.");
+ return do_kill(cx);
+ }
+
+ if (parser->cmd == s5_cmd_udp_assoc) {
+ /* Not supported. Might be hard to implement because libuv has no
+ * functionality for detecting the MTU size which the RFC mandates.
+ */
+ pr_warn("UDP ASSOC requests are not supported.");
+ return do_kill(cx);
+ }
+ ASSERT(parser->cmd == s5_cmd_tcp_connect);
+
+ if (parser->atyp == s5_atyp_host) {
+ conn_getaddrinfo(outgoing, (const char *) parser->daddr);
+ return s_req_lookup;
+ }
+
+ if (parser->atyp == s5_atyp_ipv4) {
+ memset(&outgoing->t.addr4, 0, sizeof(outgoing->t.addr4));
+ outgoing->t.addr4.sin_family = AF_INET;
+ outgoing->t.addr4.sin_port = htons(parser->dport);
+ memcpy(&outgoing->t.addr4.sin_addr,
+ parser->daddr,
+ sizeof(outgoing->t.addr4.sin_addr));
+ } else if (parser->atyp == s5_atyp_ipv6) {
+ memset(&outgoing->t.addr6, 0, sizeof(outgoing->t.addr6));
+ outgoing->t.addr6.sin6_family = AF_INET6;
+ outgoing->t.addr6.sin6_port = htons(parser->dport);
+ memcpy(&outgoing->t.addr6.sin6_addr,
+ parser->daddr,
+ sizeof(outgoing->t.addr6.sin6_addr));
+ } else {
+ UNREACHABLE();
+ }
+
+ return do_req_connect_start(cx);
+}
+
+static int do_req_lookup(client_ctx *cx) {
+ s5_ctx *parser;
+ conn *incoming;
+ conn *outgoing;
+
+ parser = &cx->parser;
+ incoming = &cx->incoming;
+ outgoing = &cx->outgoing;
+ ASSERT(incoming->rdstate == c_stop);
+ ASSERT(incoming->wrstate == c_stop);
+ ASSERT(outgoing->rdstate == c_stop);
+ ASSERT(outgoing->wrstate == c_stop);
+
+ if (outgoing->result < 0) {
+ /* TODO(bnoordhuis) Escape control characters in parser->daddr. */
+ pr_err("lookup error for \"%s\": %s",
+ parser->daddr,
+ uv_strerror(outgoing->result));
+ /* Send back a 'Host unreachable' reply. */
+ conn_write(incoming, "\5\4\0\1\0\0\0\0\0\0", 10);
+ return s_kill;
+ }
+
+ /* Don't make assumptions about the offset of sin_port/sin6_port. */
+ switch (outgoing->t.addr.sa_family) {
+ case AF_INET:
+ outgoing->t.addr4.sin_port = htons(parser->dport);
+ break;
+ case AF_INET6:
+ outgoing->t.addr6.sin6_port = htons(parser->dport);
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ return do_req_connect_start(cx);
+}
+
+/* Assumes that cx->outgoing.t.sa contains a valid AF_INET/AF_INET6 address. */
+static int do_req_connect_start(client_ctx *cx) {
+ conn *incoming;
+ conn *outgoing;
+ int err;
+
+ incoming = &cx->incoming;
+ outgoing = &cx->outgoing;
+ ASSERT(incoming->rdstate == c_stop);
+ ASSERT(incoming->wrstate == c_stop);
+ ASSERT(outgoing->rdstate == c_stop);
+ ASSERT(outgoing->wrstate == c_stop);
+
+ if (!can_access(cx->sx, cx, &outgoing->t.addr)) {
+ pr_warn("connection not allowed by ruleset");
+ /* Send a 'Connection not allowed by ruleset' reply. */
+ conn_write(incoming, "\5\2\0\1\0\0\0\0\0\0", 10);
+ return s_kill;
+ }
+
+ err = conn_connect(outgoing);
+ if (err != 0) {
+ pr_err("connect error: %s\n", uv_strerror(err));
+ return do_kill(cx);
+ }
+
+ return s_req_connect;
+}
+
+static int do_req_connect(client_ctx *cx) {
+ const struct sockaddr_in6 *in6;
+ const struct sockaddr_in *in;
+ char addr_storage[sizeof(*in6)];
+ conn *incoming;
+ conn *outgoing;
+ uint8_t *buf;
+ int addrlen;
+
+ incoming = &cx->incoming;
+ outgoing = &cx->outgoing;
+ ASSERT(incoming->rdstate == c_stop);
+ ASSERT(incoming->wrstate == c_stop);
+ ASSERT(outgoing->rdstate == c_stop);
+ ASSERT(outgoing->wrstate == c_stop);
+
+ /* Build and send the reply. Not very pretty but gets the job done. */
+ buf = (uint8_t *) incoming->t.buf;
+ if (outgoing->result == 0) {
+ /* The RFC mandates that the SOCKS server must include the local port
+ * and address in the reply. So that's what we do.
+ */
+ addrlen = sizeof(addr_storage);
+ CHECK(0 == uv_tcp_getsockname(&outgoing->handle.tcp,
+ (struct sockaddr *) addr_storage,
+ &addrlen));
+ buf[0] = 5; /* Version. */
+ buf[1] = 0; /* Success. */
+ buf[2] = 0; /* Reserved. */
+ if (addrlen == sizeof(*in)) {
+ buf[3] = 1; /* IPv4. */
+ in = (const struct sockaddr_in *) &addr_storage;
+ memcpy(buf + 4, &in->sin_addr, 4);
+ memcpy(buf + 8, &in->sin_port, 2);
+ conn_write(incoming, buf, 10);
+ } else if (addrlen == sizeof(*in6)) {
+ buf[3] = 4; /* IPv6. */
+ in6 = (const struct sockaddr_in6 *) &addr_storage;
+ memcpy(buf + 4, &in6->sin6_addr, 16);
+ memcpy(buf + 20, &in6->sin6_port, 2);
+ conn_write(incoming, buf, 22);
+ } else {
+ UNREACHABLE();
+ }
+ return s_proxy_start;
+ } else {
+ pr_err("upstream connection error: %s\n", uv_strerror(outgoing->result));
+ /* Send a 'Connection refused' reply. */
+ conn_write(incoming, "\5\5\0\1\0\0\0\0\0\0", 10);
+ return s_kill;
+ }
+
+ UNREACHABLE();
+ return s_kill;
+}
+
+static int do_proxy_start(client_ctx *cx) {
+ conn *incoming;
+ conn *outgoing;
+
+ incoming = &cx->incoming;
+ outgoing = &cx->outgoing;
+ ASSERT(incoming->rdstate == c_stop);
+ ASSERT(incoming->wrstate == c_done);
+ ASSERT(outgoing->rdstate == c_stop);
+ ASSERT(outgoing->wrstate == c_stop);
+ incoming->wrstate = c_stop;
+
+ if (incoming->result < 0) {
+ pr_err("write error: %s", uv_strerror(incoming->result));
+ return do_kill(cx);
+ }
+
+ conn_read(incoming);
+ conn_read(outgoing);
+ return s_proxy;
+}
+
+/* Proxy incoming data back and forth. */
+static int do_proxy(client_ctx *cx) {
+ if (conn_cycle("client", &cx->incoming, &cx->outgoing)) {
+ return do_kill(cx);
+ }
+
+ if (conn_cycle("upstream", &cx->outgoing, &cx->incoming)) {
+ return do_kill(cx);
+ }
+
+ return s_proxy;
+}
+
+static int do_kill(client_ctx *cx) {
+ int new_state;
+
+ if (cx->state >= s_almost_dead_0) {
+ return cx->state;
+ }
+
+ /* Try to cancel the request. The callback still runs but if the
+ * cancellation succeeded, it gets called with status=UV_ECANCELED.
+ */
+ new_state = s_almost_dead_1;
+ if (cx->state == s_req_lookup) {
+ new_state = s_almost_dead_0;
+ uv_cancel(&cx->outgoing.t.req);
+ }
+
+ conn_close(&cx->incoming);
+ conn_close(&cx->outgoing);
+ return new_state;
+}
+
+static int do_almost_dead(client_ctx *cx) {
+ ASSERT(cx->state >= s_almost_dead_0);
+ return cx->state + 1; /* Another finalizer completed. */
+}
+
+static int conn_cycle(const char *who, conn *a, conn *b) {
+ if (a->result < 0) {
+ if (a->result != UV_EOF) {
+ pr_err("%s error: %s", who, uv_strerror(a->result));
+ }
+ return -1;
+ }
+
+ if (b->result < 0) {
+ return -1;
+ }
+
+ if (a->wrstate == c_done) {
+ a->wrstate = c_stop;
+ }
+
+ /* The logic is as follows: read when we don't write and write when we don't
+ * read. That gives us back-pressure handling for free because if the peer
+ * sends data faster than we consume it, TCP congestion control kicks in.
+ */
+ if (a->wrstate == c_stop) {
+ if (b->rdstate == c_stop) {
+ conn_read(b);
+ } else if (b->rdstate == c_done) {
+ conn_write(a, b->t.buf, b->result);
+ b->rdstate = c_stop; /* Triggers the call to conn_read() above. */
+ }
+ }
+
+ return 0;
+}
+
+static void conn_timer_reset(conn *c) {
+ CHECK(0 == uv_timer_start(&c->timer_handle,
+ conn_timer_expire,
+ c->idle_timeout,
+ 0));
+}
+
+static void conn_timer_expire(uv_timer_t *handle, int status) {
+ conn *c;
+
+ CHECK(0 == status);
+ c = CONTAINER_OF(handle, conn, timer_handle);
+ c->result = UV_ETIMEDOUT;
+ do_next(c->client);
+}
+
+static void conn_getaddrinfo(conn *c, const char *hostname) {
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ CHECK(0 == uv_getaddrinfo(c->client->sx->loop,
+ &c->t.addrinfo_req,
+ conn_getaddrinfo_done,
+ hostname,
+ NULL,
+ &hints));
+ conn_timer_reset(c);
+}
+
+static void conn_getaddrinfo_done(uv_getaddrinfo_t *req,
+ int status,
+ struct addrinfo *ai) {
+ conn *c;
+
+ c = CONTAINER_OF(req, conn, t.addrinfo_req);
+ c->result = status;
+
+ if (status == 0) {
+ /* FIXME(bnoordhuis) Should try all addresses. */
+ if (ai->ai_family == AF_INET) {
+ c->t.addr4 = *(const struct sockaddr_in *) ai->ai_addr;
+ } else if (ai->ai_family == AF_INET6) {
+ c->t.addr6 = *(const struct sockaddr_in6 *) ai->ai_addr;
+ } else {
+ UNREACHABLE();
+ }
+ }
+
+ uv_freeaddrinfo(ai);
+ do_next(c->client);
+}
+
+/* Assumes that c->t.sa contains a valid AF_INET or AF_INET6 address. */
+static int conn_connect(conn *c) {
+ ASSERT(c->t.addr.sa_family == AF_INET ||
+ c->t.addr.sa_family == AF_INET6);
+ conn_timer_reset(c);
+ return uv_tcp_connect(&c->t.connect_req,
+ &c->handle.tcp,
+ &c->t.addr,
+ conn_connect_done);
+}
+
+static void conn_connect_done(uv_connect_t *req, int status) {
+ conn *c;
+
+ if (status == UV_ECANCELED) {
+ return; /* Handle has been closed. */
+ }
+
+ c = CONTAINER_OF(req, conn, t.connect_req);
+ c->result = status;
+ do_next(c->client);
+}
+
+static void conn_read(conn *c) {
+ ASSERT(c->rdstate == c_stop);
+ CHECK(0 == uv_read_start(&c->handle.stream, conn_alloc, conn_read_done));
+ c->rdstate = c_busy;
+ conn_timer_reset(c);
+}
+
+static void conn_read_done(uv_stream_t *handle,
+ ssize_t nread,
+ const uv_buf_t *buf) {
+ conn *c;
+
+ c = CONTAINER_OF(handle, conn, handle);
+ ASSERT(c->t.buf == buf->base);
+ ASSERT(c->rdstate == c_busy);
+ c->rdstate = c_done;
+ c->result = nread;
+
+ uv_read_stop(&c->handle.stream);
+ do_next(c->client);
+}
+
+static void conn_alloc(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
+ conn *c;
+
+ c = CONTAINER_OF(handle, conn, handle);
+ ASSERT(c->rdstate == c_busy);
+ buf->base = c->t.buf;
+ buf->len = sizeof(c->t.buf);
+}
+
+static void conn_write(conn *c, const void *data, unsigned int len) {
+ uv_buf_t buf;
+
+ ASSERT(c->wrstate == c_stop || c->wrstate == c_done);
+ c->wrstate = c_busy;
+
+ /* It's okay to cast away constness here, uv_write() won't modify the
+ * memory.
+ */
+ buf.base = (char *) data;
+ buf.len = len;
+
+ CHECK(0 == uv_write(&c->write_req,
+ &c->handle.stream,
+ &buf,
+ 1,
+ conn_write_done));
+ conn_timer_reset(c);
+}
+
+static void conn_write_done(uv_write_t *req, int status) {
+ conn *c;
+
+ if (status == UV_ECANCELED) {
+ return; /* Handle has been closed. */
+ }
+
+ c = CONTAINER_OF(req, conn, write_req);
+ ASSERT(c->wrstate == c_busy);
+ c->wrstate = c_done;
+ c->result = status;
+ do_next(c->client);
+}
+
+static void conn_close(conn *c) {
+ ASSERT(c->rdstate != c_dead);
+ ASSERT(c->wrstate != c_dead);
+ c->rdstate = c_dead;
+ c->wrstate = c_dead;
+ c->timer_handle.data = c;
+ c->handle.handle.data = c;
+ uv_close(&c->handle.handle, conn_close_done);
+ uv_close((uv_handle_t *) &c->timer_handle, conn_close_done);
+}
+
+static void conn_close_done(uv_handle_t *handle) {
+ conn *c;
+
+ c = handle->data;
+ do_next(c->client);
+}
diff --git a/3rdparty/libuv/samples/socks5-proxy/defs.h b/3rdparty/libuv/samples/socks5-proxy/defs.h
new file mode 100644
index 00000000000..99ee8160c8a
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/defs.h
@@ -0,0 +1,139 @@
+/* Copyright StrongLoop, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef DEFS_H_
+#define DEFS_H_
+
+#include "s5.h"
+#include "uv.h"
+
+#include <assert.h>
+#include <netinet/in.h> /* sockaddr_in, sockaddr_in6 */
+#include <stddef.h> /* size_t, ssize_t */
+#include <stdint.h>
+#include <sys/socket.h> /* sockaddr */
+
+struct client_ctx;
+
+typedef struct {
+ const char *bind_host;
+ unsigned short bind_port;
+ unsigned int idle_timeout;
+} server_config;
+
+typedef struct {
+ unsigned int idle_timeout; /* Connection idle timeout in ms. */
+ uv_tcp_t tcp_handle;
+ uv_loop_t *loop;
+} server_ctx;
+
+typedef struct {
+ unsigned char rdstate;
+ unsigned char wrstate;
+ unsigned int idle_timeout;
+ struct client_ctx *client; /* Backlink to owning client context. */
+ ssize_t result;
+ union {
+ uv_handle_t handle;
+ uv_stream_t stream;
+ uv_tcp_t tcp;
+ uv_udp_t udp;
+ } handle;
+ uv_timer_t timer_handle; /* For detecting timeouts. */
+ uv_write_t write_req;
+ /* We only need one of these at a time so make them share memory. */
+ union {
+ uv_getaddrinfo_t addrinfo_req;
+ uv_connect_t connect_req;
+ uv_req_t req;
+ struct sockaddr_in6 addr6;
+ struct sockaddr_in addr4;
+ struct sockaddr addr;
+ char buf[2048]; /* Scratch space. Used to read data into. */
+ } t;
+} conn;
+
+typedef struct client_ctx {
+ unsigned int state;
+ server_ctx *sx; /* Backlink to owning server context. */
+ s5_ctx parser; /* The SOCKS protocol parser. */
+ conn incoming; /* Connection with the SOCKS client. */
+ conn outgoing; /* Connection with upstream. */
+} client_ctx;
+
+/* server.c */
+int server_run(const server_config *cf, uv_loop_t *loop);
+int can_auth_none(const server_ctx *sx, const client_ctx *cx);
+int can_auth_passwd(const server_ctx *sx, const client_ctx *cx);
+int can_access(const server_ctx *sx,
+ const client_ctx *cx,
+ const struct sockaddr *addr);
+
+/* client.c */
+void client_finish_init(server_ctx *sx, client_ctx *cx);
+
+/* util.c */
+#if defined(__GNUC__)
+# define ATTRIBUTE_FORMAT_PRINTF(a, b) __attribute__((format(printf, a, b)))
+#else
+# define ATTRIBUTE_FORMAT_PRINTF(a, b)
+#endif
+void pr_info(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2);
+void pr_warn(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2);
+void pr_err(const char *fmt, ...) ATTRIBUTE_FORMAT_PRINTF(1, 2);
+void *xmalloc(size_t size);
+
+/* main.c */
+const char *_getprogname(void);
+
+/* getopt.c */
+#if !HAVE_UNISTD_H
+extern char *optarg;
+int getopt(int argc, char **argv, const char *options);
+#endif
+
+/* ASSERT() is for debug checks, CHECK() for run-time sanity checks.
+ * DEBUG_CHECKS is for expensive debug checks that we only want to
+ * enable in debug builds but still want type-checked by the compiler
+ * in release builds.
+ */
+#if defined(NDEBUG)
+# define ASSERT(exp)
+# define CHECK(exp) do { if (!(exp)) abort(); } while (0)
+# define DEBUG_CHECKS (0)
+#else
+# define ASSERT(exp) assert(exp)
+# define CHECK(exp) assert(exp)
+# define DEBUG_CHECKS (1)
+#endif
+
+#define UNREACHABLE() CHECK(!"Unreachable code reached.")
+
+/* This macro looks complicated but it's not: it calculates the address
+ * of the embedding struct through the address of the embedded struct.
+ * In other words, if struct A embeds struct B, then we can obtain
+ * the address of A by taking the address of B and subtracting the
+ * field offset of B in A.
+ */
+#define CONTAINER_OF(ptr, type, field) \
+ ((type *) ((char *) (ptr) - ((char *) &((type *) 0)->field)))
+
+#endif /* DEFS_H_ */
diff --git a/3rdparty/libuv/samples/socks5-proxy/getopt.c b/3rdparty/libuv/samples/socks5-proxy/getopt.c
new file mode 100644
index 00000000000..8481b2264f2
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/getopt.c
@@ -0,0 +1,131 @@
+/* $NetBSD: getopt.c,v 1.26 2003/08/07 16:43:40 agc Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+extern const char *_getprogname(void);
+
+int opterr = 1, /* if error message should be printed */
+ optind = 1, /* index into parent argv vector */
+ optopt, /* character checked for validity */
+ optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt(nargc, nargv, ostr)
+ int nargc;
+ char * const nargv[];
+ const char *ostr;
+{
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+
+ if (optreset || *place == 0) { /* update scanning pointer */
+ optreset = 0;
+ place = nargv[optind];
+ if (optind >= nargc || *place++ != '-') {
+ /* Argument is absent or is not an option */
+ place = EMSG;
+ return (-1);
+ }
+ optopt = *place++;
+ if (optopt == '-' && *place == 0) {
+ /* "--" => end of options */
+ ++optind;
+ place = EMSG;
+ return (-1);
+ }
+ if (optopt == 0) {
+ /* Solitary '-', treat as a '-' option
+ if the program (eg su) is looking for it. */
+ place = EMSG;
+ if (strchr(ostr, '-') == NULL)
+ return (-1);
+ optopt = '-';
+ }
+ } else
+ optopt = *place++;
+
+ /* See if option letter is one the caller wanted... */
+ if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
+ if (*place == 0)
+ ++optind;
+ if (opterr && *ostr != ':')
+ (void)fprintf(stderr,
+ "%s: illegal option -- %c\n", _getprogname(),
+ optopt);
+ return (BADCH);
+ }
+
+ /* Does this option need an argument? */
+ if (oli[1] != ':') {
+ /* don't need argument */
+ optarg = NULL;
+ if (*place == 0)
+ ++optind;
+ } else {
+ /* Option-argument is either the rest of this argument or the
+ entire next argument. */
+ if (*place)
+ optarg = place;
+ else if (nargc > ++optind)
+ optarg = nargv[optind];
+ else {
+ /* option-argument absent */
+ place = EMSG;
+ if (*ostr == ':')
+ return (BADARG);
+ if (opterr)
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ _getprogname(), optopt);
+ return (BADCH);
+ }
+ place = EMSG;
+ ++optind;
+ }
+ return (optopt); /* return option letter */
+}
diff --git a/3rdparty/libuv/samples/socks5-proxy/main.c b/3rdparty/libuv/samples/socks5-proxy/main.c
new file mode 100644
index 00000000000..04020cbd3ad
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/main.c
@@ -0,0 +1,99 @@
+/* Copyright StrongLoop, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "defs.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h> /* getopt */
+#endif
+
+#define DEFAULT_BIND_HOST "127.0.0.1"
+#define DEFAULT_BIND_PORT 1080
+#define DEFAULT_IDLE_TIMEOUT (60 * 1000)
+
+static void parse_opts(server_config *cf, int argc, char **argv);
+static void usage(void);
+
+static const char *progname = __FILE__; /* Reset in main(). */
+
+int main(int argc, char **argv) {
+ server_config config;
+ int err;
+
+ progname = argv[0];
+ memset(&config, 0, sizeof(config));
+ config.bind_host = DEFAULT_BIND_HOST;
+ config.bind_port = DEFAULT_BIND_PORT;
+ config.idle_timeout = DEFAULT_IDLE_TIMEOUT;
+ parse_opts(&config, argc, argv);
+
+ err = server_run(&config, uv_default_loop());
+ if (err) {
+ exit(1);
+ }
+
+ return 0;
+}
+
+const char *_getprogname(void) {
+ return progname;
+}
+
+static void parse_opts(server_config *cf, int argc, char **argv) {
+ int opt;
+
+ while (-1 != (opt = getopt(argc, argv, "H:hp:"))) {
+ switch (opt) {
+ case 'H':
+ cf->bind_host = optarg;
+ break;
+
+ case 'p':
+ if (1 != sscanf(optarg, "%hu", &cf->bind_port)) {
+ pr_err("bad port number: %s", optarg);
+ usage();
+ }
+ break;
+
+ default:
+ usage();
+ }
+ }
+}
+
+static void usage(void) {
+ printf("Usage:\n"
+ "\n"
+ " %s [-b <address> [-h] [-p <port>]\n"
+ "\n"
+ "Options:\n"
+ "\n"
+ " -b <hostname|address> Bind to this address or hostname.\n"
+ " Default: \"127.0.0.1\"\n"
+ " -h Show this help message.\n"
+ " -p <port> Bind to this port number. Default: 1080\n"
+ "",
+ progname);
+ exit(1);
+}
diff --git a/3rdparty/libuv/samples/socks5-proxy/s5.c b/3rdparty/libuv/samples/socks5-proxy/s5.c
new file mode 100644
index 00000000000..4f08e345247
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/s5.c
@@ -0,0 +1,271 @@
+/* Copyright StrongLoop, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "s5.h"
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h> /* abort() */
+#include <string.h> /* memset() */
+
+enum {
+ s5_version,
+ s5_nmethods,
+ s5_methods,
+ s5_auth_pw_version,
+ s5_auth_pw_userlen,
+ s5_auth_pw_username,
+ s5_auth_pw_passlen,
+ s5_auth_pw_password,
+ s5_req_version,
+ s5_req_cmd,
+ s5_req_reserved,
+ s5_req_atyp,
+ s5_req_atyp_host,
+ s5_req_daddr,
+ s5_req_dport0,
+ s5_req_dport1,
+ s5_dead
+};
+
+void s5_init(s5_ctx *cx) {
+ memset(cx, 0, sizeof(*cx));
+ cx->state = s5_version;
+}
+
+s5_err s5_parse(s5_ctx *cx, uint8_t **data, size_t *size) {
+ s5_err err;
+ uint8_t *p;
+ uint8_t c;
+ size_t i;
+ size_t n;
+
+ p = *data;
+ n = *size;
+ i = 0;
+
+ while (i < n) {
+ c = p[i];
+ i += 1;
+ switch (cx->state) {
+ case s5_version:
+ if (c != 5) {
+ err = s5_bad_version;
+ goto out;
+ }
+ cx->state = s5_nmethods;
+ break;
+
+ case s5_nmethods:
+ cx->arg0 = 0;
+ cx->arg1 = c; /* Number of bytes to read. */
+ cx->state = s5_methods;
+ break;
+
+ case s5_methods:
+ if (cx->arg0 < cx->arg1) {
+ switch (c) {
+ case 0:
+ cx->methods |= S5_AUTH_NONE;
+ break;
+ case 1:
+ cx->methods |= S5_AUTH_GSSAPI;
+ break;
+ case 2:
+ cx->methods |= S5_AUTH_PASSWD;
+ break;
+ /* Ignore everything we don't understand. */
+ }
+ cx->arg0 += 1;
+ }
+ if (cx->arg0 == cx->arg1) {
+ err = s5_auth_select;
+ goto out;
+ }
+ break;
+
+ case s5_auth_pw_version:
+ if (c != 1) {
+ err = s5_bad_version;
+ goto out;
+ }
+ cx->state = s5_auth_pw_userlen;
+ break;
+
+ case s5_auth_pw_userlen:
+ cx->arg0 = 0;
+ cx->userlen = c;
+ cx->state = s5_auth_pw_username;
+ break;
+
+ case s5_auth_pw_username:
+ if (cx->arg0 < cx->userlen) {
+ cx->username[cx->arg0] = c;
+ cx->arg0 += 1;
+ }
+ if (cx->arg0 == cx->userlen) {
+ cx->username[cx->userlen] = '\0';
+ cx->state = s5_auth_pw_passlen;
+ }
+ break;
+
+ case s5_auth_pw_passlen:
+ cx->arg0 = 0;
+ cx->passlen = c;
+ cx->state = s5_auth_pw_password;
+ break;
+
+ case s5_auth_pw_password:
+ if (cx->arg0 < cx->passlen) {
+ cx->password[cx->arg0] = c;
+ cx->arg0 += 1;
+ }
+ if (cx->arg0 == cx->passlen) {
+ cx->password[cx->passlen] = '\0';
+ cx->state = s5_req_version;
+ err = s5_auth_verify;
+ goto out;
+ }
+ break;
+
+ case s5_req_version:
+ if (c != 5) {
+ err = s5_bad_version;
+ goto out;
+ }
+ cx->state = s5_req_cmd;
+ break;
+
+ case s5_req_cmd:
+ switch (c) {
+ case 1: /* TCP connect */
+ cx->cmd = s5_cmd_tcp_connect;
+ break;
+ case 3: /* UDP associate */
+ cx->cmd = s5_cmd_udp_assoc;
+ break;
+ default:
+ err = s5_bad_cmd;
+ goto out;
+ }
+ cx->state = s5_req_reserved;
+ break;
+
+ case s5_req_reserved:
+ cx->state = s5_req_atyp;
+ break;
+
+ case s5_req_atyp:
+ cx->arg0 = 0;
+ switch (c) {
+ case 1: /* IPv4, four octets. */
+ cx->state = s5_req_daddr;
+ cx->atyp = s5_atyp_ipv4;
+ cx->arg1 = 4;
+ break;
+ case 3: /* Hostname. First byte is length. */
+ cx->state = s5_req_atyp_host;
+ cx->atyp = s5_atyp_host;
+ cx->arg1 = 0;
+ break;
+ case 4: /* IPv6, sixteen octets. */
+ cx->state = s5_req_daddr;
+ cx->atyp = s5_atyp_ipv6;
+ cx->arg1 = 16;
+ break;
+ default:
+ err = s5_bad_atyp;
+ goto out;
+ }
+ break;
+
+ case s5_req_atyp_host:
+ cx->arg1 = c;
+ cx->state = s5_req_daddr;
+ break;
+
+ case s5_req_daddr:
+ if (cx->arg0 < cx->arg1) {
+ cx->daddr[cx->arg0] = c;
+ cx->arg0 += 1;
+ }
+ if (cx->arg0 == cx->arg1) {
+ cx->daddr[cx->arg1] = '\0';
+ cx->state = s5_req_dport0;
+ }
+ break;
+
+ case s5_req_dport0:
+ cx->dport = c << 8;
+ cx->state = s5_req_dport1;
+ break;
+
+ case s5_req_dport1:
+ cx->dport |= c;
+ cx->state = s5_dead;
+ err = s5_exec_cmd;
+ goto out;
+
+ case s5_dead:
+ break;
+
+ default:
+ abort();
+ }
+ }
+ err = s5_ok;
+
+out:
+ *data = p + i;
+ *size = n - i;
+ return err;
+}
+
+unsigned int s5_auth_methods(const s5_ctx *cx) {
+ return cx->methods;
+}
+
+int s5_select_auth(s5_ctx *cx, s5_auth_method method) {
+ int err;
+
+ err = 0;
+ switch (method) {
+ case S5_AUTH_NONE:
+ cx->state = s5_req_version;
+ break;
+ case S5_AUTH_PASSWD:
+ cx->state = s5_auth_pw_version;
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+const char *s5_strerror(s5_err err) {
+#define S5_ERR_GEN(_, name, errmsg) case s5_ ## name: return errmsg;
+ switch (err) {
+ S5_ERR_MAP(S5_ERR_GEN)
+ default: ; /* Silence s5_max_errors -Wswitch warning. */
+ }
+#undef S5_ERR_GEN
+ return "Unknown error.";
+}
diff --git a/3rdparty/libuv/samples/socks5-proxy/s5.h b/3rdparty/libuv/samples/socks5-proxy/s5.h
new file mode 100644
index 00000000000..715f322287d
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/s5.h
@@ -0,0 +1,94 @@
+/* Copyright StrongLoop, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef S5_H_
+#define S5_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#define S5_ERR_MAP(V) \
+ V(-1, bad_version, "Bad protocol version.") \
+ V(-2, bad_cmd, "Bad protocol command.") \
+ V(-3, bad_atyp, "Bad address type.") \
+ V(0, ok, "No error.") \
+ V(1, auth_select, "Select authentication method.") \
+ V(2, auth_verify, "Verify authentication.") \
+ V(3, exec_cmd, "Execute command.") \
+
+typedef enum {
+#define S5_ERR_GEN(code, name, _) s5_ ## name = code,
+ S5_ERR_MAP(S5_ERR_GEN)
+#undef S5_ERR_GEN
+ s5_max_errors
+} s5_err;
+
+typedef enum {
+ S5_AUTH_NONE = 1 << 0,
+ S5_AUTH_GSSAPI = 1 << 1,
+ S5_AUTH_PASSWD = 1 << 2
+} s5_auth_method;
+
+typedef enum {
+ s5_auth_allow,
+ s5_auth_deny
+} s5_auth_result;
+
+typedef enum {
+ s5_atyp_ipv4,
+ s5_atyp_ipv6,
+ s5_atyp_host
+} s5_atyp;
+
+typedef enum {
+ s5_cmd_tcp_connect,
+ s5_cmd_tcp_bind,
+ s5_cmd_udp_assoc
+} s5_cmd;
+
+typedef struct {
+ uint32_t arg0; /* Scratch space for the state machine. */
+ uint32_t arg1; /* Scratch space for the state machine. */
+ uint8_t state;
+ uint8_t methods;
+ uint8_t cmd;
+ uint8_t atyp;
+ uint8_t userlen;
+ uint8_t passlen;
+ uint16_t dport;
+ uint8_t username[257];
+ uint8_t password[257];
+ uint8_t daddr[257]; /* TODO(bnoordhuis) Merge with username/password. */
+} s5_ctx;
+
+void s5_init(s5_ctx *ctx);
+
+s5_err s5_parse(s5_ctx *cx, uint8_t **data, size_t *size);
+
+/* Only call after s5_parse() has returned s5_want_auth_method. */
+unsigned int s5_auth_methods(const s5_ctx *cx);
+
+/* Call after s5_parse() has returned s5_want_auth_method. */
+int s5_select_auth(s5_ctx *cx, s5_auth_method method);
+
+const char *s5_strerror(s5_err err);
+
+#endif /* S5_H_ */
diff --git a/3rdparty/libuv/samples/socks5-proxy/server.c b/3rdparty/libuv/samples/socks5-proxy/server.c
new file mode 100644
index 00000000000..3f1ba42c9e1
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/server.c
@@ -0,0 +1,241 @@
+/* Copyright StrongLoop, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "defs.h"
+#include <netinet/in.h> /* INET6_ADDRSTRLEN */
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef INET6_ADDRSTRLEN
+# define INET6_ADDRSTRLEN 63
+#endif
+
+typedef struct {
+ uv_getaddrinfo_t getaddrinfo_req;
+ server_config config;
+ server_ctx *servers;
+ uv_loop_t *loop;
+} server_state;
+
+static void do_bind(uv_getaddrinfo_t *req, int status, struct addrinfo *ai);
+static void on_connection(uv_stream_t *server, int status);
+
+int server_run(const server_config *cf, uv_loop_t *loop) {
+ struct addrinfo hints;
+ server_state state;
+ int err;
+
+ memset(&state, 0, sizeof(state));
+ state.servers = NULL;
+ state.config = *cf;
+ state.loop = loop;
+
+ /* Resolve the address of the interface that we should bind to.
+ * The getaddrinfo callback starts the server and everything else.
+ */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ err = uv_getaddrinfo(loop,
+ &state.getaddrinfo_req,
+ do_bind,
+ cf->bind_host,
+ NULL,
+ &hints);
+ if (err != 0) {
+ pr_err("getaddrinfo: %s", uv_strerror(err));
+ return err;
+ }
+
+ /* Start the event loop. Control continues in do_bind(). */
+ if (uv_run(loop, UV_RUN_DEFAULT)) {
+ abort();
+ }
+
+ /* Please Valgrind. */
+ uv_loop_delete(loop);
+ free(state.servers);
+ return 0;
+}
+
+/* Bind a server to each address that getaddrinfo() reported. */
+static void do_bind(uv_getaddrinfo_t *req, int status, struct addrinfo *addrs) {
+ char addrbuf[INET6_ADDRSTRLEN + 1];
+ unsigned int ipv4_naddrs;
+ unsigned int ipv6_naddrs;
+ server_state *state;
+ server_config *cf;
+ struct addrinfo *ai;
+ const void *addrv;
+ const char *what;
+ uv_loop_t *loop;
+ server_ctx *sx;
+ unsigned int n;
+ int err;
+ union {
+ struct sockaddr addr;
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+ } s;
+
+ state = CONTAINER_OF(req, server_state, getaddrinfo_req);
+ loop = state->loop;
+ cf = &state->config;
+
+ if (status < 0) {
+ pr_err("getaddrinfo(\"%s\"): %s", cf->bind_host, uv_strerror(status));
+ uv_freeaddrinfo(addrs);
+ return;
+ }
+
+ ipv4_naddrs = 0;
+ ipv6_naddrs = 0;
+ for (ai = addrs; ai != NULL; ai = ai->ai_next) {
+ if (ai->ai_family == AF_INET) {
+ ipv4_naddrs += 1;
+ } else if (ai->ai_family == AF_INET6) {
+ ipv6_naddrs += 1;
+ }
+ }
+
+ if (ipv4_naddrs == 0 && ipv6_naddrs == 0) {
+ pr_err("%s has no IPv4/6 addresses", cf->bind_host);
+ uv_freeaddrinfo(addrs);
+ return;
+ }
+
+ state->servers =
+ xmalloc((ipv4_naddrs + ipv6_naddrs) * sizeof(state->servers[0]));
+
+ n = 0;
+ for (ai = addrs; ai != NULL; ai = ai->ai_next) {
+ if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) {
+ continue;
+ }
+
+ if (ai->ai_family == AF_INET) {
+ s.addr4 = *(const struct sockaddr_in *) ai->ai_addr;
+ s.addr4.sin_port = htons(cf->bind_port);
+ addrv = &s.addr4.sin_addr;
+ } else if (ai->ai_family == AF_INET6) {
+ s.addr6 = *(const struct sockaddr_in6 *) ai->ai_addr;
+ s.addr6.sin6_port = htons(cf->bind_port);
+ addrv = &s.addr6.sin6_addr;
+ } else {
+ UNREACHABLE();
+ }
+
+ if (uv_inet_ntop(s.addr.sa_family, addrv, addrbuf, sizeof(addrbuf))) {
+ UNREACHABLE();
+ }
+
+ sx = state->servers + n;
+ sx->loop = loop;
+ sx->idle_timeout = state->config.idle_timeout;
+ CHECK(0 == uv_tcp_init(loop, &sx->tcp_handle));
+
+ what = "uv_tcp_bind";
+ err = uv_tcp_bind(&sx->tcp_handle, &s.addr, 0);
+ if (err == 0) {
+ what = "uv_listen";
+ err = uv_listen((uv_stream_t *) &sx->tcp_handle, 128, on_connection);
+ }
+
+ if (err != 0) {
+ pr_err("%s(\"%s:%hu\"): %s",
+ what,
+ addrbuf,
+ cf->bind_port,
+ uv_strerror(err));
+ while (n > 0) {
+ n -= 1;
+ uv_close((uv_handle_t *) (state->servers + n), NULL);
+ }
+ break;
+ }
+
+ pr_info("listening on %s:%hu", addrbuf, cf->bind_port);
+ n += 1;
+ }
+
+ uv_freeaddrinfo(addrs);
+}
+
+static void on_connection(uv_stream_t *server, int status) {
+ server_ctx *sx;
+ client_ctx *cx;
+
+ CHECK(status == 0);
+ sx = CONTAINER_OF(server, server_ctx, tcp_handle);
+ cx = xmalloc(sizeof(*cx));
+ CHECK(0 == uv_tcp_init(sx->loop, &cx->incoming.handle.tcp));
+ CHECK(0 == uv_accept(server, &cx->incoming.handle.stream));
+ client_finish_init(sx, cx);
+}
+
+int can_auth_none(const server_ctx *sx, const client_ctx *cx) {
+ return 1;
+}
+
+int can_auth_passwd(const server_ctx *sx, const client_ctx *cx) {
+ return 0;
+}
+
+int can_access(const server_ctx *sx,
+ const client_ctx *cx,
+ const struct sockaddr *addr) {
+ const struct sockaddr_in6 *addr6;
+ const struct sockaddr_in *addr4;
+ const uint32_t *p;
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+
+ /* TODO(bnoordhuis) Implement proper access checks. For now, just reject
+ * traffic to localhost.
+ */
+ if (addr->sa_family == AF_INET) {
+ addr4 = (const struct sockaddr_in *) addr;
+ d = ntohl(addr4->sin_addr.s_addr);
+ return (d >> 24) != 0x7F;
+ }
+
+ if (addr->sa_family == AF_INET6) {
+ addr6 = (const struct sockaddr_in6 *) addr;
+ p = (const uint32_t *) &addr6->sin6_addr.s6_addr;
+ a = ntohl(p[0]);
+ b = ntohl(p[1]);
+ c = ntohl(p[2]);
+ d = ntohl(p[3]);
+ if (a == 0 && b == 0 && c == 0 && d == 1) {
+ return 0; /* "::1" style address. */
+ }
+ if (a == 0 && b == 0 && c == 0xFFFF && (d >> 24) == 0x7F) {
+ return 0; /* "::ffff:127.x.x.x" style address. */
+ }
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/3rdparty/libuv/samples/socks5-proxy/util.c b/3rdparty/libuv/samples/socks5-proxy/util.c
new file mode 100644
index 00000000000..af34f055936
--- /dev/null
+++ b/3rdparty/libuv/samples/socks5-proxy/util.c
@@ -0,0 +1,72 @@
+/* Copyright StrongLoop, Inc. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "defs.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static void pr_do(FILE *stream,
+ const char *label,
+ const char *fmt,
+ va_list ap);
+
+void *xmalloc(size_t size) {
+ void *ptr;
+
+ ptr = malloc(size);
+ if (ptr == NULL) {
+ pr_err("out of memory, need %lu bytes", (unsigned long) size);
+ exit(1);
+ }
+
+ return ptr;
+}
+
+void pr_info(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ pr_do(stdout, "info", fmt, ap);
+ va_end(ap);
+}
+
+void pr_warn(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ pr_do(stderr, "warn", fmt, ap);
+ va_end(ap);
+}
+
+void pr_err(const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ pr_do(stderr, "error", fmt, ap);
+ va_end(ap);
+}
+
+static void pr_do(FILE *stream,
+ const char *label,
+ const char *fmt,
+ va_list ap) {
+ char fmtbuf[1024];
+ vsnprintf(fmtbuf, sizeof(fmtbuf), fmt, ap);
+ fprintf(stream, "%s:%s: %s\n", _getprogname(), label, fmtbuf);
+}
diff --git a/3rdparty/libuv/src/fs-poll.c b/3rdparty/libuv/src/fs-poll.c
new file mode 100644
index 00000000000..44d47b88ed2
--- /dev/null
+++ b/3rdparty/libuv/src/fs-poll.c
@@ -0,0 +1,255 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "uv-common.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct poll_ctx {
+ uv_fs_poll_t* parent_handle; /* NULL if parent has been stopped or closed */
+ int busy_polling;
+ unsigned int interval;
+ uint64_t start_time;
+ uv_loop_t* loop;
+ uv_fs_poll_cb poll_cb;
+ uv_timer_t timer_handle;
+ uv_fs_t fs_req; /* TODO(bnoordhuis) mark fs_req internal */
+ uv_stat_t statbuf;
+ char path[1]; /* variable length */
+};
+
+static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b);
+static void poll_cb(uv_fs_t* req);
+static void timer_cb(uv_timer_t* timer);
+static void timer_close_cb(uv_handle_t* handle);
+
+static uv_stat_t zero_statbuf;
+
+
+int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_POLL);
+ return 0;
+}
+
+
+int uv_fs_poll_start(uv_fs_poll_t* handle,
+ uv_fs_poll_cb cb,
+ const char* path,
+ unsigned int interval) {
+ struct poll_ctx* ctx;
+ uv_loop_t* loop;
+ size_t len;
+ int err;
+
+ if (uv__is_active(handle))
+ return 0;
+
+ loop = handle->loop;
+ len = strlen(path);
+ ctx = uv__calloc(1, sizeof(*ctx) + len);
+
+ if (ctx == NULL)
+ return UV_ENOMEM;
+
+ ctx->loop = loop;
+ ctx->poll_cb = cb;
+ ctx->interval = interval ? interval : 1;
+ ctx->start_time = uv_now(loop);
+ ctx->parent_handle = handle;
+ memcpy(ctx->path, path, len + 1);
+
+ err = uv_timer_init(loop, &ctx->timer_handle);
+ if (err < 0)
+ goto error;
+
+ ctx->timer_handle.flags |= UV__HANDLE_INTERNAL;
+ uv__handle_unref(&ctx->timer_handle);
+
+ err = uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb);
+ if (err < 0)
+ goto error;
+
+ handle->poll_ctx = ctx;
+ uv__handle_start(handle);
+
+ return 0;
+
+error:
+ uv__free(ctx);
+ return err;
+}
+
+
+int uv_fs_poll_stop(uv_fs_poll_t* handle) {
+ struct poll_ctx* ctx;
+
+ if (!uv__is_active(handle))
+ return 0;
+
+ ctx = handle->poll_ctx;
+ assert(ctx != NULL);
+ assert(ctx->parent_handle != NULL);
+ ctx->parent_handle = NULL;
+ handle->poll_ctx = NULL;
+
+ /* Close the timer if it's active. If it's inactive, there's a stat request
+ * in progress and poll_cb will take care of the cleanup.
+ */
+ if (uv__is_active(&ctx->timer_handle))
+ uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
+
+ uv__handle_stop(handle);
+
+ return 0;
+}
+
+
+int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) {
+ struct poll_ctx* ctx;
+ size_t required_len;
+
+ if (!uv__is_active(handle)) {
+ *size = 0;
+ return UV_EINVAL;
+ }
+
+ ctx = handle->poll_ctx;
+ assert(ctx != NULL);
+
+ required_len = strlen(ctx->path);
+ if (required_len > *size) {
+ *size = required_len;
+ return UV_ENOBUFS;
+ }
+
+ memcpy(buffer, ctx->path, required_len);
+ *size = required_len;
+
+ return 0;
+}
+
+
+void uv__fs_poll_close(uv_fs_poll_t* handle) {
+ uv_fs_poll_stop(handle);
+}
+
+
+static void timer_cb(uv_timer_t* timer) {
+ struct poll_ctx* ctx;
+
+ ctx = container_of(timer, struct poll_ctx, timer_handle);
+ assert(ctx->parent_handle != NULL);
+ assert(ctx->parent_handle->poll_ctx == ctx);
+ ctx->start_time = uv_now(ctx->loop);
+
+ if (uv_fs_stat(ctx->loop, &ctx->fs_req, ctx->path, poll_cb))
+ abort();
+}
+
+
+static void poll_cb(uv_fs_t* req) {
+ uv_stat_t* statbuf;
+ struct poll_ctx* ctx;
+ uint64_t interval;
+
+ ctx = container_of(req, struct poll_ctx, fs_req);
+
+ if (ctx->parent_handle == NULL) { /* handle has been stopped or closed */
+ uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
+ uv_fs_req_cleanup(req);
+ return;
+ }
+
+ if (req->result != 0) {
+ if (ctx->busy_polling != req->result) {
+ ctx->poll_cb(ctx->parent_handle,
+ req->result,
+ &ctx->statbuf,
+ &zero_statbuf);
+ ctx->busy_polling = req->result;
+ }
+ goto out;
+ }
+
+ statbuf = &req->statbuf;
+
+ if (ctx->busy_polling != 0)
+ if (ctx->busy_polling < 0 || !statbuf_eq(&ctx->statbuf, statbuf))
+ ctx->poll_cb(ctx->parent_handle, 0, &ctx->statbuf, statbuf);
+
+ ctx->statbuf = *statbuf;
+ ctx->busy_polling = 1;
+
+out:
+ uv_fs_req_cleanup(req);
+
+ if (ctx->parent_handle == NULL) { /* handle has been stopped by callback */
+ uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
+ return;
+ }
+
+ /* Reschedule timer, subtract the delay from doing the stat(). */
+ interval = ctx->interval;
+ interval -= (uv_now(ctx->loop) - ctx->start_time) % interval;
+
+ if (uv_timer_start(&ctx->timer_handle, timer_cb, interval, 0))
+ abort();
+}
+
+
+static void timer_close_cb(uv_handle_t* handle) {
+ uv__free(container_of(handle, struct poll_ctx, timer_handle));
+}
+
+
+static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b) {
+ return a->st_ctim.tv_nsec == b->st_ctim.tv_nsec
+ && a->st_mtim.tv_nsec == b->st_mtim.tv_nsec
+ && a->st_birthtim.tv_nsec == b->st_birthtim.tv_nsec
+ && a->st_ctim.tv_sec == b->st_ctim.tv_sec
+ && a->st_mtim.tv_sec == b->st_mtim.tv_sec
+ && a->st_birthtim.tv_sec == b->st_birthtim.tv_sec
+ && a->st_size == b->st_size
+ && a->st_mode == b->st_mode
+ && a->st_uid == b->st_uid
+ && a->st_gid == b->st_gid
+ && a->st_ino == b->st_ino
+ && a->st_dev == b->st_dev
+ && a->st_flags == b->st_flags
+ && a->st_gen == b->st_gen;
+}
+
+
+#if defined(_WIN32)
+
+#include "win/internal.h"
+#include "win/handle-inl.h"
+
+void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle) {
+ assert(handle->flags & UV__HANDLE_CLOSING);
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ uv__handle_close(handle);
+}
+
+#endif /* _WIN32 */
diff --git a/3rdparty/libuv/src/heap-inl.h b/3rdparty/libuv/src/heap-inl.h
new file mode 100644
index 00000000000..1e2ed60e094
--- /dev/null
+++ b/3rdparty/libuv/src/heap-inl.h
@@ -0,0 +1,245 @@
+/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef UV_SRC_HEAP_H_
+#define UV_SRC_HEAP_H_
+
+#include <stddef.h> /* NULL */
+
+#if defined(__GNUC__)
+# define HEAP_EXPORT(declaration) __attribute__((unused)) static declaration
+#else
+# define HEAP_EXPORT(declaration) static declaration
+#endif
+
+struct heap_node {
+ struct heap_node* left;
+ struct heap_node* right;
+ struct heap_node* parent;
+};
+
+/* A binary min heap. The usual properties hold: the root is the lowest
+ * element in the set, the height of the tree is at most log2(nodes) and
+ * it's always a complete binary tree.
+ *
+ * The heap function try hard to detect corrupted tree nodes at the cost
+ * of a minor reduction in performance. Compile with -DNDEBUG to disable.
+ */
+struct heap {
+ struct heap_node* min;
+ unsigned int nelts;
+};
+
+/* Return non-zero if a < b. */
+typedef int (*heap_compare_fn)(const struct heap_node* a,
+ const struct heap_node* b);
+
+/* Public functions. */
+HEAP_EXPORT(void heap_init(struct heap* heap));
+HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap));
+HEAP_EXPORT(void heap_insert(struct heap* heap,
+ struct heap_node* newnode,
+ heap_compare_fn less_than));
+HEAP_EXPORT(void heap_remove(struct heap* heap,
+ struct heap_node* node,
+ heap_compare_fn less_than));
+HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than));
+
+/* Implementation follows. */
+
+HEAP_EXPORT(void heap_init(struct heap* heap)) {
+ heap->min = NULL;
+ heap->nelts = 0;
+}
+
+HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap)) {
+ return heap->min;
+}
+
+/* Swap parent with child. Child moves closer to the root, parent moves away. */
+static void heap_node_swap(struct heap* heap,
+ struct heap_node* parent,
+ struct heap_node* child) {
+ struct heap_node* sibling;
+ struct heap_node t;
+
+ t = *parent;
+ *parent = *child;
+ *child = t;
+
+ parent->parent = child;
+ if (child->left == child) {
+ child->left = parent;
+ sibling = child->right;
+ } else {
+ child->right = parent;
+ sibling = child->left;
+ }
+ if (sibling != NULL)
+ sibling->parent = child;
+
+ if (parent->left != NULL)
+ parent->left->parent = parent;
+ if (parent->right != NULL)
+ parent->right->parent = parent;
+
+ if (child->parent == NULL)
+ heap->min = child;
+ else if (child->parent->left == parent)
+ child->parent->left = child;
+ else
+ child->parent->right = child;
+}
+
+HEAP_EXPORT(void heap_insert(struct heap* heap,
+ struct heap_node* newnode,
+ heap_compare_fn less_than)) {
+ struct heap_node** parent;
+ struct heap_node** child;
+ unsigned int path;
+ unsigned int n;
+ unsigned int k;
+
+ newnode->left = NULL;
+ newnode->right = NULL;
+ newnode->parent = NULL;
+
+ /* Calculate the path from the root to the insertion point. This is a min
+ * heap so we always insert at the left-most free node of the bottom row.
+ */
+ path = 0;
+ for (k = 0, n = 1 + heap->nelts; n >= 2; k += 1, n /= 2)
+ path = (path << 1) | (n & 1);
+
+ /* Now traverse the heap using the path we calculated in the previous step. */
+ parent = child = &heap->min;
+ while (k > 0) {
+ parent = child;
+ if (path & 1)
+ child = &(*child)->right;
+ else
+ child = &(*child)->left;
+ path >>= 1;
+ k -= 1;
+ }
+
+ /* Insert the new node. */
+ newnode->parent = *parent;
+ *child = newnode;
+ heap->nelts += 1;
+
+ /* Walk up the tree and check at each node if the heap property holds.
+ * It's a min heap so parent < child must be true.
+ */
+ while (newnode->parent != NULL && less_than(newnode, newnode->parent))
+ heap_node_swap(heap, newnode->parent, newnode);
+}
+
+HEAP_EXPORT(void heap_remove(struct heap* heap,
+ struct heap_node* node,
+ heap_compare_fn less_than)) {
+ struct heap_node* smallest;
+ struct heap_node** max;
+ struct heap_node* child;
+ unsigned int path;
+ unsigned int k;
+ unsigned int n;
+
+ if (heap->nelts == 0)
+ return;
+
+ /* Calculate the path from the min (the root) to the max, the left-most node
+ * of the bottom row.
+ */
+ path = 0;
+ for (k = 0, n = heap->nelts; n >= 2; k += 1, n /= 2)
+ path = (path << 1) | (n & 1);
+
+ /* Now traverse the heap using the path we calculated in the previous step. */
+ max = &heap->min;
+ while (k > 0) {
+ if (path & 1)
+ max = &(*max)->right;
+ else
+ max = &(*max)->left;
+ path >>= 1;
+ k -= 1;
+ }
+
+ heap->nelts -= 1;
+
+ /* Unlink the max node. */
+ child = *max;
+ *max = NULL;
+
+ if (child == node) {
+ /* We're removing either the max or the last node in the tree. */
+ if (child == heap->min) {
+ heap->min = NULL;
+ }
+ return;
+ }
+
+ /* Replace the to be deleted node with the max node. */
+ child->left = node->left;
+ child->right = node->right;
+ child->parent = node->parent;
+
+ if (child->left != NULL) {
+ child->left->parent = child;
+ }
+
+ if (child->right != NULL) {
+ child->right->parent = child;
+ }
+
+ if (node->parent == NULL) {
+ heap->min = child;
+ } else if (node->parent->left == node) {
+ node->parent->left = child;
+ } else {
+ node->parent->right = child;
+ }
+
+ /* Walk down the subtree and check at each node if the heap property holds.
+ * It's a min heap so parent < child must be true. If the parent is bigger,
+ * swap it with the smallest child.
+ */
+ for (;;) {
+ smallest = child;
+ if (child->left != NULL && less_than(child->left, smallest))
+ smallest = child->left;
+ if (child->right != NULL && less_than(child->right, smallest))
+ smallest = child->right;
+ if (smallest == child)
+ break;
+ heap_node_swap(heap, child, smallest);
+ }
+
+ /* Walk up the subtree and check that each parent is less than the node
+ * this is required, because `max` node is not guaranteed to be the
+ * actual maximum in tree
+ */
+ while (child->parent != NULL && less_than(child, child->parent))
+ heap_node_swap(heap, child->parent, child);
+}
+
+HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than)) {
+ heap_remove(heap, heap->min, less_than);
+}
+
+#undef HEAP_EXPORT
+
+#endif /* UV_SRC_HEAP_H_ */
diff --git a/3rdparty/libuv/src/inet.c b/3rdparty/libuv/src/inet.c
new file mode 100644
index 00000000000..da63a688c4e
--- /dev/null
+++ b/3rdparty/libuv/src/inet.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+# include "stdint-msvc2008.h"
+#else
+# include <stdint.h>
+#endif
+
+#include "uv.h"
+#include "uv-common.h"
+
+#define UV__INET_ADDRSTRLEN 16
+#define UV__INET6_ADDRSTRLEN 46
+
+
+static int inet_ntop4(const unsigned char *src, char *dst, size_t size);
+static int inet_ntop6(const unsigned char *src, char *dst, size_t size);
+static int inet_pton4(const char *src, unsigned char *dst);
+static int inet_pton6(const char *src, unsigned char *dst);
+
+
+int uv_inet_ntop(int af, const void* src, char* dst, size_t size) {
+ switch (af) {
+ case AF_INET:
+ return (inet_ntop4(src, dst, size));
+ case AF_INET6:
+ return (inet_ntop6(src, dst, size));
+ default:
+ return UV_EAFNOSUPPORT;
+ }
+ /* NOTREACHED */
+}
+
+
+static int inet_ntop4(const unsigned char *src, char *dst, size_t size) {
+ static const char fmt[] = "%u.%u.%u.%u";
+ char tmp[UV__INET_ADDRSTRLEN];
+ int l;
+
+ l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
+ if (l <= 0 || (size_t) l >= size) {
+ return UV_ENOSPC;
+ }
+ strncpy(dst, tmp, size);
+ dst[size - 1] = '\0';
+ return 0;
+}
+
+
+static int inet_ntop6(const unsigned char *src, char *dst, size_t size) {
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[UV__INET6_ADDRSTRLEN], *tp;
+ struct { int base, len; } best, cur;
+ unsigned int words[sizeof(struct in6_addr) / sizeof(uint16_t)];
+ int i;
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, '\0', sizeof words);
+ for (i = 0; i < (int) sizeof(struct in6_addr); i++)
+ words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+ best.base = -1;
+ best.len = 0;
+ cur.base = -1;
+ cur.len = 0;
+ for (i = 0; i < (int) ARRAY_SIZE(words); i++) {
+ if (words[i] == 0) {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ } else {
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ }
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ for (i = 0; i < (int) ARRAY_SIZE(words); i++) {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len)) {
+ if (i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0)
+ *tp++ = ':';
+ /* Is this address an encapsulated IPv4? */
+ if (i == 6 && best.base == 0 && (best.len == 6 ||
+ (best.len == 7 && words[7] != 0x0001) ||
+ (best.len == 5 && words[5] == 0xffff))) {
+ int err = inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp));
+ if (err)
+ return err;
+ tp += strlen(tp);
+ break;
+ }
+ tp += sprintf(tp, "%x", words[i]);
+ }
+ /* Was it a trailing run of 0x00's? */
+ if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words))
+ *tp++ = ':';
+ *tp++ = '\0';
+
+ /*
+ * Check for overflow, copy, and we're done.
+ */
+ if ((size_t)(tp - tmp) > size) {
+ return UV_ENOSPC;
+ }
+ strcpy(dst, tmp);
+ return 0;
+}
+
+
+int uv_inet_pton(int af, const char* src, void* dst) {
+ if (src == NULL || dst == NULL)
+ return UV_EINVAL;
+
+ switch (af) {
+ case AF_INET:
+ return (inet_pton4(src, dst));
+ case AF_INET6: {
+ int len;
+ char tmp[UV__INET6_ADDRSTRLEN], *s, *p;
+ s = (char*) src;
+ p = strchr(src, '%');
+ if (p != NULL) {
+ s = tmp;
+ len = p - src;
+ if (len > UV__INET6_ADDRSTRLEN-1)
+ return UV_EINVAL;
+ memcpy(s, src, len);
+ s[len] = '\0';
+ }
+ return inet_pton6(s, dst);
+ }
+ default:
+ return UV_EAFNOSUPPORT;
+ }
+ /* NOTREACHED */
+}
+
+
+static int inet_pton4(const char *src, unsigned char *dst) {
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ unsigned char tmp[sizeof(struct in_addr)], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ *(tp = tmp) = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr(digits, ch)) != NULL) {
+ unsigned int nw = *tp * 10 + (pch - digits);
+
+ if (saw_digit && *tp == 0)
+ return UV_EINVAL;
+ if (nw > 255)
+ return UV_EINVAL;
+ *tp = nw;
+ if (!saw_digit) {
+ if (++octets > 4)
+ return UV_EINVAL;
+ saw_digit = 1;
+ }
+ } else if (ch == '.' && saw_digit) {
+ if (octets == 4)
+ return UV_EINVAL;
+ *++tp = 0;
+ saw_digit = 0;
+ } else
+ return UV_EINVAL;
+ }
+ if (octets < 4)
+ return UV_EINVAL;
+ memcpy(dst, tmp, sizeof(struct in_addr));
+ return 0;
+}
+
+
+static int inet_pton6(const char *src, unsigned char *dst) {
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ unsigned char tmp[sizeof(struct in6_addr)], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, seen_xdigits;
+ unsigned int val;
+
+ memset((tp = tmp), '\0', sizeof tmp);
+ endp = tp + sizeof tmp;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return UV_EINVAL;
+ curtok = src;
+ seen_xdigits = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (++seen_xdigits > 4)
+ return UV_EINVAL;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!seen_xdigits) {
+ if (colonp)
+ return UV_EINVAL;
+ colonp = tp;
+ continue;
+ } else if (*src == '\0') {
+ return UV_EINVAL;
+ }
+ if (tp + sizeof(uint16_t) > endp)
+ return UV_EINVAL;
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ seen_xdigits = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + sizeof(struct in_addr)) <= endp)) {
+ int err = inet_pton4(curtok, tp);
+ if (err == 0) {
+ tp += sizeof(struct in_addr);
+ seen_xdigits = 0;
+ break; /*%< '\\0' was seen by inet_pton4(). */
+ }
+ }
+ return UV_EINVAL;
+ }
+ if (seen_xdigits) {
+ if (tp + sizeof(uint16_t) > endp)
+ return UV_EINVAL;
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ if (tp == endp)
+ return UV_EINVAL;
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ return UV_EINVAL;
+ memcpy(dst, tmp, sizeof tmp);
+ return 0;
+}
diff --git a/3rdparty/libuv/src/queue.h b/3rdparty/libuv/src/queue.h
new file mode 100644
index 00000000000..ff3540a0a51
--- /dev/null
+++ b/3rdparty/libuv/src/queue.h
@@ -0,0 +1,108 @@
+/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef QUEUE_H_
+#define QUEUE_H_
+
+#include <stddef.h>
+
+typedef void *QUEUE[2];
+
+/* Private macros. */
+#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0]))
+#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1]))
+#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q)))
+#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q)))
+
+/* Public macros. */
+#define QUEUE_DATA(ptr, type, field) \
+ ((type *) ((char *) (ptr) - offsetof(type, field)))
+
+/* Important note: mutating the list while QUEUE_FOREACH is
+ * iterating over its elements results in undefined behavior.
+ */
+#define QUEUE_FOREACH(q, h) \
+ for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q))
+
+#define QUEUE_EMPTY(q) \
+ ((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q))
+
+#define QUEUE_HEAD(q) \
+ (QUEUE_NEXT(q))
+
+#define QUEUE_INIT(q) \
+ do { \
+ QUEUE_NEXT(q) = (q); \
+ QUEUE_PREV(q) = (q); \
+ } \
+ while (0)
+
+#define QUEUE_ADD(h, n) \
+ do { \
+ QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \
+ QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \
+ QUEUE_PREV(h) = QUEUE_PREV(n); \
+ QUEUE_PREV_NEXT(h) = (h); \
+ } \
+ while (0)
+
+#define QUEUE_SPLIT(h, q, n) \
+ do { \
+ QUEUE_PREV(n) = QUEUE_PREV(h); \
+ QUEUE_PREV_NEXT(n) = (n); \
+ QUEUE_NEXT(n) = (q); \
+ QUEUE_PREV(h) = QUEUE_PREV(q); \
+ QUEUE_PREV_NEXT(h) = (h); \
+ QUEUE_PREV(q) = (n); \
+ } \
+ while (0)
+
+#define QUEUE_MOVE(h, n) \
+ do { \
+ if (QUEUE_EMPTY(h)) \
+ QUEUE_INIT(n); \
+ else { \
+ QUEUE* q = QUEUE_HEAD(h); \
+ QUEUE_SPLIT(h, q, n); \
+ } \
+ } \
+ while (0)
+
+#define QUEUE_INSERT_HEAD(h, q) \
+ do { \
+ QUEUE_NEXT(q) = QUEUE_NEXT(h); \
+ QUEUE_PREV(q) = (h); \
+ QUEUE_NEXT_PREV(q) = (q); \
+ QUEUE_NEXT(h) = (q); \
+ } \
+ while (0)
+
+#define QUEUE_INSERT_TAIL(h, q) \
+ do { \
+ QUEUE_NEXT(q) = (h); \
+ QUEUE_PREV(q) = QUEUE_PREV(h); \
+ QUEUE_PREV_NEXT(q) = (q); \
+ QUEUE_PREV(h) = (q); \
+ } \
+ while (0)
+
+#define QUEUE_REMOVE(q) \
+ do { \
+ QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \
+ QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \
+ } \
+ while (0)
+
+#endif /* QUEUE_H_ */
diff --git a/3rdparty/libuv/src/threadpool.c b/3rdparty/libuv/src/threadpool.c
new file mode 100644
index 00000000000..2c5152b4200
--- /dev/null
+++ b/3rdparty/libuv/src/threadpool.c
@@ -0,0 +1,303 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv-common.h"
+
+#if !defined(_WIN32)
+# include "unix/internal.h"
+#else
+# include "win/req-inl.h"
+/* TODO(saghul): unify internal req functions */
+static void uv__req_init(uv_loop_t* loop,
+ uv_req_t* req,
+ uv_req_type type) {
+ uv_req_init(loop, req);
+ req->type = type;
+ uv__req_register(loop, req);
+}
+# define uv__req_init(loop, req, type) \
+ uv__req_init((loop), (uv_req_t*)(req), (type))
+#endif
+
+#include <stdlib.h>
+
+#define MAX_THREADPOOL_SIZE 128
+
+static uv_once_t once = UV_ONCE_INIT;
+static uv_cond_t cond;
+static uv_mutex_t mutex;
+static unsigned int idle_threads;
+static unsigned int nthreads;
+static uv_thread_t* threads;
+static uv_thread_t default_threads[4];
+static QUEUE exit_message;
+static QUEUE wq;
+static volatile int initialized;
+
+
+static void uv__cancelled(struct uv__work* w) {
+ abort();
+}
+
+
+/* To avoid deadlock with uv_cancel() it's crucial that the worker
+ * never holds the global mutex and the loop-local mutex at the same time.
+ */
+static void worker(void* arg) {
+ struct uv__work* w;
+ QUEUE* q;
+
+ (void) arg;
+
+ for (;;) {
+ uv_mutex_lock(&mutex);
+
+ while (QUEUE_EMPTY(&wq)) {
+ idle_threads += 1;
+ uv_cond_wait(&cond, &mutex);
+ idle_threads -= 1;
+ }
+
+ q = QUEUE_HEAD(&wq);
+
+ if (q == &exit_message)
+ uv_cond_signal(&cond);
+ else {
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q); /* Signal uv_cancel() that the work req is
+ executing. */
+ }
+
+ uv_mutex_unlock(&mutex);
+
+ if (q == &exit_message)
+ break;
+
+ w = QUEUE_DATA(q, struct uv__work, wq);
+ w->work(w);
+
+ uv_mutex_lock(&w->loop->wq_mutex);
+ w->work = NULL; /* Signal uv_cancel() that the work req is done
+ executing. */
+ QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq);
+ uv_async_send(&w->loop->wq_async);
+ uv_mutex_unlock(&w->loop->wq_mutex);
+ }
+}
+
+
+static void post(QUEUE* q) {
+ uv_mutex_lock(&mutex);
+ QUEUE_INSERT_TAIL(&wq, q);
+ if (idle_threads > 0)
+ uv_cond_signal(&cond);
+ uv_mutex_unlock(&mutex);
+}
+
+
+#ifndef _WIN32
+UV_DESTRUCTOR(static void cleanup(void)) {
+ unsigned int i;
+
+ if (initialized == 0)
+ return;
+
+ post(&exit_message);
+
+ for (i = 0; i < nthreads; i++)
+ if (uv_thread_join(threads + i))
+ abort();
+
+ if (threads != default_threads)
+ uv__free(threads);
+
+ uv_mutex_destroy(&mutex);
+ uv_cond_destroy(&cond);
+
+ threads = NULL;
+ nthreads = 0;
+ initialized = 0;
+}
+#endif
+
+
+static void init_once(void) {
+ unsigned int i;
+ const char* val;
+
+ nthreads = ARRAY_SIZE(default_threads);
+ val = getenv("UV_THREADPOOL_SIZE");
+ if (val != NULL)
+ nthreads = atoi(val);
+ if (nthreads == 0)
+ nthreads = 1;
+ if (nthreads > MAX_THREADPOOL_SIZE)
+ nthreads = MAX_THREADPOOL_SIZE;
+
+ threads = default_threads;
+ if (nthreads > ARRAY_SIZE(default_threads)) {
+ threads = uv__malloc(nthreads * sizeof(threads[0]));
+ if (threads == NULL) {
+ nthreads = ARRAY_SIZE(default_threads);
+ threads = default_threads;
+ }
+ }
+
+ if (uv_cond_init(&cond))
+ abort();
+
+ if (uv_mutex_init(&mutex))
+ abort();
+
+ QUEUE_INIT(&wq);
+
+ for (i = 0; i < nthreads; i++)
+ if (uv_thread_create(threads + i, worker, NULL))
+ abort();
+
+ initialized = 1;
+}
+
+
+void uv__work_submit(uv_loop_t* loop,
+ struct uv__work* w,
+ void (*work)(struct uv__work* w),
+ void (*done)(struct uv__work* w, int status)) {
+ uv_once(&once, init_once);
+ w->loop = loop;
+ w->work = work;
+ w->done = done;
+ post(&w->wq);
+}
+
+
+static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
+ int cancelled;
+
+ uv_mutex_lock(&mutex);
+ uv_mutex_lock(&w->loop->wq_mutex);
+
+ cancelled = !QUEUE_EMPTY(&w->wq) && w->work != NULL;
+ if (cancelled)
+ QUEUE_REMOVE(&w->wq);
+
+ uv_mutex_unlock(&w->loop->wq_mutex);
+ uv_mutex_unlock(&mutex);
+
+ if (!cancelled)
+ return UV_EBUSY;
+
+ w->work = uv__cancelled;
+ uv_mutex_lock(&loop->wq_mutex);
+ QUEUE_INSERT_TAIL(&loop->wq, &w->wq);
+ uv_async_send(&loop->wq_async);
+ uv_mutex_unlock(&loop->wq_mutex);
+
+ return 0;
+}
+
+
+void uv__work_done(uv_async_t* handle) {
+ struct uv__work* w;
+ uv_loop_t* loop;
+ QUEUE* q;
+ QUEUE wq;
+ int err;
+
+ loop = container_of(handle, uv_loop_t, wq_async);
+ uv_mutex_lock(&loop->wq_mutex);
+ QUEUE_MOVE(&loop->wq, &wq);
+ uv_mutex_unlock(&loop->wq_mutex);
+
+ while (!QUEUE_EMPTY(&wq)) {
+ q = QUEUE_HEAD(&wq);
+ QUEUE_REMOVE(q);
+
+ w = container_of(q, struct uv__work, wq);
+ err = (w->work == uv__cancelled) ? UV_ECANCELED : 0;
+ w->done(w, err);
+ }
+}
+
+
+static void uv__queue_work(struct uv__work* w) {
+ uv_work_t* req = container_of(w, uv_work_t, work_req);
+
+ req->work_cb(req);
+}
+
+
+static void uv__queue_done(struct uv__work* w, int err) {
+ uv_work_t* req;
+
+ req = container_of(w, uv_work_t, work_req);
+ uv__req_unregister(req->loop, req);
+
+ if (req->after_work_cb == NULL)
+ return;
+
+ req->after_work_cb(req, err);
+}
+
+
+int uv_queue_work(uv_loop_t* loop,
+ uv_work_t* req,
+ uv_work_cb work_cb,
+ uv_after_work_cb after_work_cb) {
+ if (work_cb == NULL)
+ return UV_EINVAL;
+
+ uv__req_init(loop, req, UV_WORK);
+ req->loop = loop;
+ req->work_cb = work_cb;
+ req->after_work_cb = after_work_cb;
+ uv__work_submit(loop, &req->work_req, uv__queue_work, uv__queue_done);
+ return 0;
+}
+
+
+int uv_cancel(uv_req_t* req) {
+ struct uv__work* wreq;
+ uv_loop_t* loop;
+
+ switch (req->type) {
+ case UV_FS:
+ loop = ((uv_fs_t*) req)->loop;
+ wreq = &((uv_fs_t*) req)->work_req;
+ break;
+ case UV_GETADDRINFO:
+ loop = ((uv_getaddrinfo_t*) req)->loop;
+ wreq = &((uv_getaddrinfo_t*) req)->work_req;
+ break;
+ case UV_GETNAMEINFO:
+ loop = ((uv_getnameinfo_t*) req)->loop;
+ wreq = &((uv_getnameinfo_t*) req)->work_req;
+ break;
+ case UV_WORK:
+ loop = ((uv_work_t*) req)->loop;
+ wreq = &((uv_work_t*) req)->work_req;
+ break;
+ default:
+ return UV_EINVAL;
+ }
+
+ return uv__work_cancel(loop, req, wreq);
+}
diff --git a/3rdparty/libuv/src/unix/aix.c b/3rdparty/libuv/src/unix/aix.c
new file mode 100644
index 00000000000..c90b7e5cb9b
--- /dev/null
+++ b/3rdparty/libuv/src/unix/aix.c
@@ -0,0 +1,1158 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utmp.h>
+#include <libgen.h>
+
+#include <sys/protosw.h>
+#include <libperfstat.h>
+#include <procinfo.h>
+#include <sys/proc.h>
+#include <sys/procfs.h>
+
+#include <sys/poll.h>
+
+#include <sys/pollset.h>
+#include <ctype.h>
+#ifdef HAVE_SYS_AHAFS_EVPRODS_H
+#include <sys/ahafs_evProds.h>
+#endif
+
+#include <sys/mntctl.h>
+#include <sys/vmount.h>
+#include <limits.h>
+#include <strings.h>
+#include <sys/vnode.h>
+
+#define RDWR_BUF_SIZE 4096
+#define EQ(a,b) (strcmp(a,b) == 0)
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ loop->fs_fd = -1;
+
+ /* Passing maxfd of -1 should mean the limit is determined
+ * by the user's ulimit or the global limit as per the doc */
+ loop->backend_fd = pollset_create(-1);
+
+ if (loop->backend_fd == -1)
+ return -1;
+
+ return 0;
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+ if (loop->fs_fd != -1) {
+ uv__close(loop->fs_fd);
+ loop->fs_fd = -1;
+ }
+
+ if (loop->backend_fd != -1) {
+ pollset_destroy(loop->backend_fd);
+ loop->backend_fd = -1;
+ }
+}
+
+
+void uv__io_poll(uv_loop_t* loop, int timeout) {
+ struct pollfd events[1024];
+ struct pollfd pqry;
+ struct pollfd* pe;
+ struct poll_ctl pc;
+ QUEUE* q;
+ uv__io_t* w;
+ uint64_t base;
+ uint64_t diff;
+ int nevents;
+ int count;
+ int nfds;
+ int i;
+ int rc;
+ int add_failed;
+
+ if (loop->nfds == 0) {
+ assert(QUEUE_EMPTY(&loop->watcher_queue));
+ return;
+ }
+
+ while (!QUEUE_EMPTY(&loop->watcher_queue)) {
+ q = QUEUE_HEAD(&loop->watcher_queue);
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q);
+
+ w = QUEUE_DATA(q, uv__io_t, watcher_queue);
+ assert(w->pevents != 0);
+ assert(w->fd >= 0);
+ assert(w->fd < (int) loop->nwatchers);
+
+ pc.events = w->pevents;
+ pc.fd = w->fd;
+
+ add_failed = 0;
+ if (w->events == 0) {
+ pc.cmd = PS_ADD;
+ if (pollset_ctl(loop->backend_fd, &pc, 1)) {
+ if (errno != EINVAL) {
+ assert(0 && "Failed to add file descriptor (pc.fd) to pollset");
+ abort();
+ }
+ /* Check if the fd is already in the pollset */
+ pqry.fd = pc.fd;
+ rc = pollset_query(loop->backend_fd, &pqry);
+ switch (rc) {
+ case -1:
+ assert(0 && "Failed to query pollset for file descriptor");
+ abort();
+ case 0:
+ assert(0 && "Pollset does not contain file descriptor");
+ abort();
+ }
+ /* If we got here then the pollset already contained the file descriptor even though
+ * we didn't think it should. This probably shouldn't happen, but we can continue. */
+ add_failed = 1;
+ }
+ }
+ if (w->events != 0 || add_failed) {
+ /* Modify, potentially removing events -- need to delete then add.
+ * Could maybe mod if we knew for sure no events are removed, but
+ * content of w->events is handled above as not reliable (falls back)
+ * so may require a pollset_query() which would have to be pretty cheap
+ * compared to a PS_DELETE to be worth optimizing. Alternatively, could
+ * lazily remove events, squelching them in the mean time. */
+ pc.cmd = PS_DELETE;
+ if (pollset_ctl(loop->backend_fd, &pc, 1)) {
+ assert(0 && "Failed to delete file descriptor (pc.fd) from pollset");
+ abort();
+ }
+ pc.cmd = PS_ADD;
+ if (pollset_ctl(loop->backend_fd, &pc, 1)) {
+ assert(0 && "Failed to add file descriptor (pc.fd) to pollset");
+ abort();
+ }
+ }
+
+ w->events = w->pevents;
+ }
+
+ assert(timeout >= -1);
+ base = loop->time;
+ count = 48; /* Benchmarks suggest this gives the best throughput. */
+
+ for (;;) {
+ nfds = pollset_poll(loop->backend_fd,
+ events,
+ ARRAY_SIZE(events),
+ timeout);
+
+ /* Update loop->time unconditionally. It's tempting to skip the update when
+ * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
+ * operating system didn't reschedule our process while in the syscall.
+ */
+ SAVE_ERRNO(uv__update_time(loop));
+
+ if (nfds == 0) {
+ assert(timeout != -1);
+ return;
+ }
+
+ if (nfds == -1) {
+ if (errno != EINTR) {
+ abort();
+ }
+
+ if (timeout == -1)
+ continue;
+
+ if (timeout == 0)
+ return;
+
+ /* Interrupted by a signal. Update timeout and poll again. */
+ goto update_timeout;
+ }
+
+ nevents = 0;
+
+ assert(loop->watchers != NULL);
+ loop->watchers[loop->nwatchers] = (void*) events;
+ loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
+
+ for (i = 0; i < nfds; i++) {
+ pe = events + i;
+ pc.cmd = PS_DELETE;
+ pc.fd = pe->fd;
+
+ /* Skip invalidated events, see uv__platform_invalidate_fd */
+ if (pc.fd == -1)
+ continue;
+
+ assert(pc.fd >= 0);
+ assert((unsigned) pc.fd < loop->nwatchers);
+
+ w = loop->watchers[pc.fd];
+
+ if (w == NULL) {
+ /* File descriptor that we've stopped watching, disarm it.
+ *
+ * Ignore all errors because we may be racing with another thread
+ * when the file descriptor is closed.
+ */
+ pollset_ctl(loop->backend_fd, &pc, 1);
+ continue;
+ }
+
+ w->cb(loop, w, pe->revents);
+ nevents++;
+ }
+
+ loop->watchers[loop->nwatchers] = NULL;
+ loop->watchers[loop->nwatchers + 1] = NULL;
+
+ if (nevents != 0) {
+ if (nfds == ARRAY_SIZE(events) && --count != 0) {
+ /* Poll for more events but don't block this time. */
+ timeout = 0;
+ continue;
+ }
+ return;
+ }
+
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+update_timeout:
+ assert(timeout > 0);
+
+ diff = loop->time - base;
+ if (diff >= (uint64_t) timeout)
+ return;
+
+ timeout -= diff;
+ }
+}
+
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ uint64_t G = 1000000000;
+ timebasestruct_t t;
+ read_wall_time(&t, TIMEBASE_SZ);
+ time_base_to_time(&t, TIMEBASE_SZ);
+ return (uint64_t) t.tb_high * G + t.tb_low;
+}
+
+
+/*
+ * We could use a static buffer for the path manipulations that we need outside
+ * of the function, but this function could be called by multiple consumers and
+ * we don't want to potentially create a race condition in the use of snprintf.
+ * There is no direct way of getting the exe path in AIX - either through /procfs
+ * or through some libc APIs. The below approach is to parse the argv[0]'s pattern
+ * and use it in conjunction with PATH environment variable to craft one.
+ */
+int uv_exepath(char* buffer, size_t* size) {
+ int res;
+ char args[PATH_MAX];
+ char abspath[PATH_MAX];
+ size_t abspath_size;
+ struct procsinfo pi;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ pi.pi_pid = getpid();
+ res = getargs(&pi, sizeof(pi), args, sizeof(args));
+ if (res < 0)
+ return -EINVAL;
+
+ /*
+ * Possibilities for args:
+ * i) an absolute path such as: /home/user/myprojects/nodejs/node
+ * ii) a relative path such as: ./node or ../myprojects/nodejs/node
+ * iii) a bare filename such as "node", after exporting PATH variable
+ * to its location.
+ */
+
+ /* Case i) and ii) absolute or relative paths */
+ if (strchr(args, '/') != NULL) {
+ if (realpath(args, abspath) != abspath)
+ return -errno;
+
+ abspath_size = strlen(abspath);
+
+ *size -= 1;
+ if (*size > abspath_size)
+ *size = abspath_size;
+
+ memcpy(buffer, abspath, *size);
+ buffer[*size] = '\0';
+
+ return 0;
+ } else {
+ /* Case iii). Search PATH environment variable */
+ char trypath[PATH_MAX];
+ char *clonedpath = NULL;
+ char *token = NULL;
+ char *path = getenv("PATH");
+
+ if (path == NULL)
+ return -EINVAL;
+
+ clonedpath = uv__strdup(path);
+ if (clonedpath == NULL)
+ return -ENOMEM;
+
+ token = strtok(clonedpath, ":");
+ while (token != NULL) {
+ snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args);
+ if (realpath(trypath, abspath) == abspath) {
+ /* Check the match is executable */
+ if (access(abspath, X_OK) == 0) {
+ abspath_size = strlen(abspath);
+
+ *size -= 1;
+ if (*size > abspath_size)
+ *size = abspath_size;
+
+ memcpy(buffer, abspath, *size);
+ buffer[*size] = '\0';
+
+ uv__free(clonedpath);
+ return 0;
+ }
+ }
+ token = strtok(NULL, ":");
+ }
+ uv__free(clonedpath);
+
+ /* Out of tokens (path entries), and no match found */
+ return -EINVAL;
+ }
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ perfstat_memory_total_t mem_total;
+ int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1);
+ if (result == -1) {
+ return 0;
+ }
+ return mem_total.real_free * 4096;
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ perfstat_memory_total_t mem_total;
+ int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1);
+ if (result == -1) {
+ return 0;
+ }
+ return mem_total.real_total * 4096;
+}
+
+
+void uv_loadavg(double avg[3]) {
+ perfstat_cpu_total_t ps_total;
+ int result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1);
+ if (result == -1) {
+ avg[0] = 0.; avg[1] = 0.; avg[2] = 0.;
+ return;
+ }
+ avg[0] = ps_total.loadavg[0] / (double)(1 << SBITS);
+ avg[1] = ps_total.loadavg[1] / (double)(1 << SBITS);
+ avg[2] = ps_total.loadavg[2] / (double)(1 << SBITS);
+}
+
+
+#ifdef HAVE_SYS_AHAFS_EVPRODS_H
+static char *uv__rawname(char *cp) {
+ static char rawbuf[FILENAME_MAX+1];
+ char *dp = rindex(cp, '/');
+
+ if (dp == 0)
+ return 0;
+
+ *dp = 0;
+ strcpy(rawbuf, cp);
+ *dp = '/';
+ strcat(rawbuf, "/r");
+ strcat(rawbuf, dp+1);
+ return rawbuf;
+}
+
+
+/*
+ * Determine whether given pathname is a directory
+ * Returns 0 if the path is a directory, -1 if not
+ *
+ * Note: Opportunity here for more detailed error information but
+ * that requires changing callers of this function as well
+ */
+static int uv__path_is_a_directory(char* filename) {
+ struct stat statbuf;
+
+ if (stat(filename, &statbuf) < 0)
+ return -1; /* failed: not a directory, assume it is a file */
+
+ if (statbuf.st_type == VDIR)
+ return 0;
+
+ return -1;
+}
+
+
+/*
+ * Check whether AHAFS is mounted.
+ * Returns 0 if AHAFS is mounted, or an error code < 0 on failure
+ */
+static int uv__is_ahafs_mounted(void){
+ int rv, i = 2;
+ struct vmount *p;
+ int size_multiplier = 10;
+ size_t siz = sizeof(struct vmount)*size_multiplier;
+ struct vmount *vmt;
+ const char *dev = "/aha";
+ char *obj, *stub;
+
+ p = uv__malloc(siz);
+ if (p == NULL)
+ return -errno;
+
+ /* Retrieve all mounted filesystems */
+ rv = mntctl(MCTL_QUERY, siz, (char*)p);
+ if (rv < 0)
+ return -errno;
+ if (rv == 0) {
+ /* buffer was not large enough, reallocate to correct size */
+ siz = *(int*)p;
+ uv__free(p);
+ p = uv__malloc(siz);
+ if (p == NULL)
+ return -errno;
+ rv = mntctl(MCTL_QUERY, siz, (char*)p);
+ if (rv < 0)
+ return -errno;
+ }
+
+ /* Look for dev in filesystems mount info */
+ for(vmt = p, i = 0; i < rv; i++) {
+ obj = vmt2dataptr(vmt, VMT_OBJECT); /* device */
+ stub = vmt2dataptr(vmt, VMT_STUB); /* mount point */
+
+ if (EQ(obj, dev) || EQ(uv__rawname(obj), dev) || EQ(stub, dev)) {
+ uv__free(p); /* Found a match */
+ return 0;
+ }
+ vmt = (struct vmount *) ((char *) vmt + vmt->vmt_length);
+ }
+
+ /* /aha is required for monitoring filesystem changes */
+ return -1;
+}
+
+/*
+ * Recursive call to mkdir() to create intermediate folders, if any
+ * Returns code from mkdir call
+ */
+static int uv__makedir_p(const char *dir) {
+ char tmp[256];
+ char *p = NULL;
+ size_t len;
+ int err;
+
+ snprintf(tmp, sizeof(tmp),"%s",dir);
+ len = strlen(tmp);
+ if (tmp[len - 1] == '/')
+ tmp[len - 1] = 0;
+ for (p = tmp + 1; *p; p++) {
+ if (*p == '/') {
+ *p = 0;
+ err = mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+ if(err != 0)
+ return err;
+ *p = '/';
+ }
+ }
+ return mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+}
+
+/*
+ * Creates necessary subdirectories in the AIX Event Infrastructure
+ * file system for monitoring the object specified.
+ * Returns code from mkdir call
+ */
+static int uv__make_subdirs_p(const char *filename) {
+ char cmd[2048];
+ char *p;
+ int rc = 0;
+
+ /* Strip off the monitor file name */
+ p = strrchr(filename, '/');
+
+ if (p == NULL)
+ return 0;
+
+ if (uv__path_is_a_directory((char*)filename) == 0) {
+ sprintf(cmd, "/aha/fs/modDir.monFactory");
+ } else {
+ sprintf(cmd, "/aha/fs/modFile.monFactory");
+ }
+
+ strncat(cmd, filename, (p - filename));
+ rc = uv__makedir_p(cmd);
+
+ if (rc == -1 && errno != EEXIST){
+ return -errno;
+ }
+
+ return rc;
+}
+
+
+/*
+ * Checks if /aha is mounted, then proceeds to set up the monitoring
+ * objects for the specified file.
+ * Returns 0 on success, or an error code < 0 on failure
+ */
+static int uv__setup_ahafs(const char* filename, int *fd) {
+ int rc = 0;
+ char mon_file_write_string[RDWR_BUF_SIZE];
+ char mon_file[PATH_MAX];
+ int file_is_directory = 0; /* -1 == NO, 0 == YES */
+
+ /* Create monitor file name for object */
+ file_is_directory = uv__path_is_a_directory((char*)filename);
+
+ if (file_is_directory == 0)
+ sprintf(mon_file, "/aha/fs/modDir.monFactory");
+ else
+ sprintf(mon_file, "/aha/fs/modFile.monFactory");
+
+ if ((strlen(mon_file) + strlen(filename) + 5) > PATH_MAX)
+ return -ENAMETOOLONG;
+
+ /* Make the necessary subdirectories for the monitor file */
+ rc = uv__make_subdirs_p(filename);
+ if (rc == -1 && errno != EEXIST)
+ return rc;
+
+ strcat(mon_file, filename);
+ strcat(mon_file, ".mon");
+
+ *fd = 0; errno = 0;
+
+ /* Open the monitor file, creating it if necessary */
+ *fd = open(mon_file, O_CREAT|O_RDWR);
+ if (*fd < 0)
+ return -errno;
+
+ /* Write out the monitoring specifications.
+ * In this case, we are monitoring for a state change event type
+ * CHANGED=YES
+ * We will be waiting in select call, rather than a read:
+ * WAIT_TYPE=WAIT_IN_SELECT
+ * We only want minimal information for files:
+ * INFO_LVL=1
+ * For directories, we want more information to track what file
+ * caused the change
+ * INFO_LVL=2
+ */
+
+ if (file_is_directory == 0)
+ sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=2");
+ else
+ sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1");
+
+ rc = write(*fd, mon_file_write_string, strlen(mon_file_write_string)+1);
+ if (rc < 0)
+ return -errno;
+
+ return 0;
+}
+
+/*
+ * Skips a specified number of lines in the buffer passed in.
+ * Walks the buffer pointed to by p and attempts to skip n lines.
+ * Returns the total number of lines skipped
+ */
+static int uv__skip_lines(char **p, int n) {
+ int lines = 0;
+
+ while(n > 0) {
+ *p = strchr(*p, '\n');
+ if (!p)
+ return lines;
+
+ (*p)++;
+ n--;
+ lines++;
+ }
+ return lines;
+}
+
+
+/*
+ * Parse the event occurrence data to figure out what event just occurred
+ * and take proper action.
+ *
+ * The buf is a pointer to the buffer containing the event occurrence data
+ * Returns 0 on success, -1 if unrecoverable error in parsing
+ *
+ */
+static int uv__parse_data(char *buf, int *events, uv_fs_event_t* handle) {
+ int evp_rc, i;
+ char *p;
+ char filename[PATH_MAX]; /* To be used when handling directories */
+
+ p = buf;
+ *events = 0;
+
+ /* Clean the filename buffer*/
+ for(i = 0; i < PATH_MAX; i++) {
+ filename[i] = 0;
+ }
+ i = 0;
+
+ /* Check for BUF_WRAP */
+ if (strncmp(buf, "BUF_WRAP", strlen("BUF_WRAP")) == 0) {
+ assert(0 && "Buffer wrap detected, Some event occurrences lost!");
+ return 0;
+ }
+
+ /* Since we are using the default buffer size (4K), and have specified
+ * INFO_LVL=1, we won't see any EVENT_OVERFLOW conditions. Applications
+ * should check for this keyword if they are using an INFO_LVL of 2 or
+ * higher, and have a buffer size of <= 4K
+ */
+
+ /* Skip to RC_FROM_EVPROD */
+ if (uv__skip_lines(&p, 9) != 9)
+ return -1;
+
+ if (sscanf(p, "RC_FROM_EVPROD=%d\nEND_EVENT_DATA", &evp_rc) == 1) {
+ if (uv__path_is_a_directory(handle->path) == 0) { /* Directory */
+ if (evp_rc == AHAFS_MODDIR_UNMOUNT || evp_rc == AHAFS_MODDIR_REMOVE_SELF) {
+ /* The directory is no longer available for monitoring */
+ *events = UV_RENAME;
+ handle->dir_filename = NULL;
+ } else {
+ /* A file was added/removed inside the directory */
+ *events = UV_CHANGE;
+
+ /* Get the EVPROD_INFO */
+ if (uv__skip_lines(&p, 1) != 1)
+ return -1;
+
+ /* Scan out the name of the file that triggered the event*/
+ if (sscanf(p, "BEGIN_EVPROD_INFO\n%sEND_EVPROD_INFO", filename) == 1) {
+ handle->dir_filename = uv__strdup((const char*)&filename);
+ } else
+ return -1;
+ }
+ } else { /* Regular File */
+ if (evp_rc == AHAFS_MODFILE_RENAME)
+ *events = UV_RENAME;
+ else
+ *events = UV_CHANGE;
+ }
+ }
+ else
+ return -1;
+
+ return 0;
+}
+
+
+/* This is the internal callback */
+static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int fflags) {
+ char result_data[RDWR_BUF_SIZE];
+ int bytes, rc = 0;
+ uv_fs_event_t* handle;
+ int events = 0;
+ int i = 0;
+ char fname[PATH_MAX];
+ char *p;
+
+ handle = container_of(event_watch, uv_fs_event_t, event_watcher);
+
+ /* Clean all the buffers*/
+ for(i = 0; i < PATH_MAX; i++) {
+ fname[i] = 0;
+ }
+ i = 0;
+
+ /* At this point, we assume that polling has been done on the
+ * file descriptor, so we can just read the AHAFS event occurrence
+ * data and parse its results without having to block anything
+ */
+ bytes = pread(event_watch->fd, result_data, RDWR_BUF_SIZE, 0);
+
+ assert((bytes <= 0) && "uv__ahafs_event - Error reading monitor file");
+
+ /* Parse the data */
+ if(bytes > 0)
+ rc = uv__parse_data(result_data, &events, handle);
+
+ /* For directory changes, the name of the files that triggered the change
+ * are never absolute pathnames
+ */
+ if (uv__path_is_a_directory(handle->path) == 0) {
+ p = handle->dir_filename;
+ while(*p != NULL){
+ fname[i]= *p;
+ i++;
+ p++;
+ }
+ } else {
+ /* For file changes, figure out whether filename is absolute or not */
+ if (handle->path[0] == '/') {
+ p = strrchr(handle->path, '/');
+ p++;
+
+ while(*p != NULL) {
+ fname[i]= *p;
+ i++;
+ p++;
+ }
+ }
+ }
+
+ /* Unrecoverable error */
+ if (rc == -1)
+ return;
+ else /* Call the actual JavaScript callback function */
+ handle->cb(handle, (const char*)&fname, events, 0);
+}
+#endif
+
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+#ifdef HAVE_SYS_AHAFS_EVPRODS_H
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
+ return 0;
+#else
+ return -ENOSYS;
+#endif
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* filename,
+ unsigned int flags) {
+#ifdef HAVE_SYS_AHAFS_EVPRODS_H
+ int fd, rc, i = 0, res = 0;
+ char cwd[PATH_MAX];
+ char absolute_path[PATH_MAX];
+ char fname[PATH_MAX];
+ char *p;
+
+ /* Clean all the buffers*/
+ for(i = 0; i < PATH_MAX; i++) {
+ cwd[i] = 0;
+ absolute_path[i] = 0;
+ fname[i] = 0;
+ }
+ i = 0;
+
+ /* Figure out whether filename is absolute or not */
+ if (filename[0] == '/') {
+ /* We have absolute pathname, create the relative pathname*/
+ sprintf(absolute_path, filename);
+ p = strrchr(filename, '/');
+ p++;
+ } else {
+ if (filename[0] == '.' && filename[1] == '/') {
+ /* We have a relative pathname, compose the absolute pathname */
+ sprintf(fname, filename);
+ snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
+ res = readlink(cwd, absolute_path, sizeof(absolute_path) - 1);
+ if (res < 0)
+ return res;
+ p = strrchr(absolute_path, '/');
+ p++;
+ p++;
+ } else {
+ /* We have a relative pathname, compose the absolute pathname */
+ sprintf(fname, filename);
+ snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid());
+ res = readlink(cwd, absolute_path, sizeof(absolute_path) - 1);
+ if (res < 0)
+ return res;
+ p = strrchr(absolute_path, '/');
+ p++;
+ }
+ /* Copy to filename buffer */
+ while(filename[i] != NULL) {
+ *p = filename[i];
+ i++;
+ p++;
+ }
+ }
+
+ if (uv__is_ahafs_mounted() < 0) /* /aha checks failed */
+ return UV_ENOSYS;
+
+ /* Setup ahafs */
+ rc = uv__setup_ahafs((const char *)absolute_path, &fd);
+ if (rc != 0)
+ return rc;
+
+ /* Setup/Initialize all the libuv routines */
+ uv__handle_start(handle);
+ uv__io_init(&handle->event_watcher, uv__ahafs_event, fd);
+ handle->path = uv__strdup((const char*)&absolute_path);
+ handle->cb = cb;
+
+ uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN);
+
+ return 0;
+#else
+ return -ENOSYS;
+#endif
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+#ifdef HAVE_SYS_AHAFS_EVPRODS_H
+ if (!uv__is_active(handle))
+ return 0;
+
+ uv__io_close(handle->loop, &handle->event_watcher);
+ uv__handle_stop(handle);
+
+ if (uv__path_is_a_directory(handle->path) == 0) {
+ uv__free(handle->dir_filename);
+ handle->dir_filename = NULL;
+ }
+
+ uv__free(handle->path);
+ handle->path = NULL;
+ uv__close(handle->event_watcher.fd);
+ handle->event_watcher.fd = -1;
+
+ return 0;
+#else
+ return -ENOSYS;
+#endif
+}
+
+
+void uv__fs_event_close(uv_fs_event_t* handle) {
+#ifdef HAVE_SYS_AHAFS_EVPRODS_H
+ uv_fs_event_stop(handle);
+#else
+ UNREACHABLE();
+#endif
+}
+
+
+char** uv_setup_args(int argc, char** argv) {
+ return argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ if (size > 0) {
+ buffer[0] = '\0';
+ }
+ return 0;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ char pp[64];
+ psinfo_t psinfo;
+ int err;
+ int fd;
+
+ snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid());
+
+ fd = open(pp, O_RDONLY);
+ if (fd == -1)
+ return -errno;
+
+ /* FIXME(bnoordhuis) Handle EINTR. */
+ err = -EINVAL;
+ if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) {
+ *rss = (size_t)psinfo.pr_rssize * 1024;
+ err = 0;
+ }
+ uv__close(fd);
+
+ return err;
+}
+
+
+int uv_uptime(double* uptime) {
+ struct utmp *utmp_buf;
+ size_t entries = 0;
+ time_t boot_time;
+
+ utmpname(UTMP_FILE);
+
+ setutent();
+
+ while ((utmp_buf = getutent()) != NULL) {
+ if (utmp_buf->ut_user[0] && utmp_buf->ut_type == USER_PROCESS)
+ ++entries;
+ if (utmp_buf->ut_type == BOOT_TIME)
+ boot_time = utmp_buf->ut_time;
+ }
+
+ endutent();
+
+ if (boot_time == 0)
+ return -ENOSYS;
+
+ *uptime = time(NULL) - boot_time;
+ return 0;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ uv_cpu_info_t* cpu_info;
+ perfstat_cpu_total_t ps_total;
+ perfstat_cpu_t* ps_cpus;
+ perfstat_id_t cpu_id;
+ int result, ncpus, idx = 0;
+
+ result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1);
+ if (result == -1) {
+ return -ENOSYS;
+ }
+
+ ncpus = result = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0);
+ if (result == -1) {
+ return -ENOSYS;
+ }
+
+ ps_cpus = (perfstat_cpu_t*) uv__malloc(ncpus * sizeof(perfstat_cpu_t));
+ if (!ps_cpus) {
+ return -ENOMEM;
+ }
+
+ strcpy(cpu_id.name, FIRST_CPU);
+ result = perfstat_cpu(&cpu_id, ps_cpus, sizeof(perfstat_cpu_t), ncpus);
+ if (result == -1) {
+ uv__free(ps_cpus);
+ return -ENOSYS;
+ }
+
+ *cpu_infos = (uv_cpu_info_t*) uv__malloc(ncpus * sizeof(uv_cpu_info_t));
+ if (!*cpu_infos) {
+ uv__free(ps_cpus);
+ return -ENOMEM;
+ }
+
+ *count = ncpus;
+
+ cpu_info = *cpu_infos;
+ while (idx < ncpus) {
+ cpu_info->speed = (int)(ps_total.processorHZ / 1000000);
+ cpu_info->model = uv__strdup(ps_total.description);
+ cpu_info->cpu_times.user = ps_cpus[idx].user;
+ cpu_info->cpu_times.sys = ps_cpus[idx].sys;
+ cpu_info->cpu_times.idle = ps_cpus[idx].idle;
+ cpu_info->cpu_times.irq = ps_cpus[idx].wait;
+ cpu_info->cpu_times.nice = 0;
+ cpu_info++;
+ idx++;
+ }
+
+ uv__free(ps_cpus);
+ return 0;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; ++i) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses,
+ int* count) {
+ uv_interface_address_t* address;
+ int sockfd, size = 1;
+ struct ifconf ifc;
+ struct ifreq *ifr, *p, flg;
+
+ *count = 0;
+
+ if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
+ return -errno;
+ }
+
+ if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) {
+ SAVE_ERRNO(uv__close(sockfd));
+ return -errno;
+ }
+
+ ifc.ifc_req = (struct ifreq*)uv__malloc(size);
+ ifc.ifc_len = size;
+ if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
+ SAVE_ERRNO(uv__close(sockfd));
+ return -errno;
+ }
+
+#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
+
+ /* Count all up and running ipv4/ipv6 addresses */
+ ifr = ifc.ifc_req;
+ while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
+ p = ifr;
+ ifr = (struct ifreq*)
+ ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
+
+ if (!(p->ifr_addr.sa_family == AF_INET6 ||
+ p->ifr_addr.sa_family == AF_INET))
+ continue;
+
+ memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
+ if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
+ SAVE_ERRNO(uv__close(sockfd));
+ return -errno;
+ }
+
+ if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
+ continue;
+
+ (*count)++;
+ }
+
+ /* Alloc the return interface structs */
+ *addresses = (uv_interface_address_t*)
+ uv__malloc(*count * sizeof(uv_interface_address_t));
+ if (!(*addresses)) {
+ uv__close(sockfd);
+ return -ENOMEM;
+ }
+ address = *addresses;
+
+ ifr = ifc.ifc_req;
+ while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
+ p = ifr;
+ ifr = (struct ifreq*)
+ ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
+
+ if (!(p->ifr_addr.sa_family == AF_INET6 ||
+ p->ifr_addr.sa_family == AF_INET))
+ continue;
+
+ memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
+ if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
+ uv__close(sockfd);
+ return -ENOSYS;
+ }
+
+ if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
+ continue;
+
+ /* All conditions above must match count loop */
+
+ address->name = uv__strdup(p->ifr_name);
+
+ if (p->ifr_addr.sa_family == AF_INET6) {
+ address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
+ } else {
+ address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
+ }
+
+ /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
+
+ address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
+
+ address++;
+ }
+
+#undef ADDR_SIZE
+
+ uv__close(sockfd);
+ return 0;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ int i;
+
+ for (i = 0; i < count; ++i) {
+ uv__free(addresses[i].name);
+ }
+
+ uv__free(addresses);
+}
+
+void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
+ struct pollfd* events;
+ uintptr_t i;
+ uintptr_t nfds;
+ struct poll_ctl pc;
+
+ assert(loop->watchers != NULL);
+
+ events = (struct pollfd*) loop->watchers[loop->nwatchers];
+ nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
+
+ if (events != NULL)
+ /* Invalidate events with same file descriptor */
+ for (i = 0; i < nfds; i++)
+ if ((int) events[i].fd == fd)
+ events[i].fd = -1;
+
+ /* Remove the file descriptor from the poll set */
+ pc.events = 0;
+ pc.cmd = PS_DELETE;
+ pc.fd = fd;
+ if(loop->backend_fd >= 0)
+ pollset_ctl(loop->backend_fd, &pc, 1);
+}
diff --git a/3rdparty/libuv/src/unix/android-ifaddrs.c b/3rdparty/libuv/src/unix/android-ifaddrs.c
new file mode 100644
index 00000000000..30f681b7d04
--- /dev/null
+++ b/3rdparty/libuv/src/unix/android-ifaddrs.c
@@ -0,0 +1,703 @@
+/*
+Copyright (c) 2013, Kenneth MacKay
+Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement #289016)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "android-ifaddrs.h"
+#include "uv-common.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+typedef struct NetlinkList
+{
+ struct NetlinkList *m_next;
+ struct nlmsghdr *m_data;
+ unsigned int m_size;
+} NetlinkList;
+
+static int netlink_socket(void)
+{
+ struct sockaddr_nl l_addr;
+
+ int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if(l_socket < 0)
+ {
+ return -1;
+ }
+
+ memset(&l_addr, 0, sizeof(l_addr));
+ l_addr.nl_family = AF_NETLINK;
+ if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
+ {
+ close(l_socket);
+ return -1;
+ }
+
+ return l_socket;
+}
+
+static int netlink_send(int p_socket, int p_request)
+{
+ char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
+
+ struct nlmsghdr *l_hdr;
+ struct rtgenmsg *l_msg;
+ struct sockaddr_nl l_addr;
+
+ memset(l_buffer, 0, sizeof(l_buffer));
+
+ l_hdr = (struct nlmsghdr *)l_buffer;
+ l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr);
+
+ l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg));
+ l_hdr->nlmsg_type = p_request;
+ l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
+ l_hdr->nlmsg_pid = 0;
+ l_hdr->nlmsg_seq = p_socket;
+ l_msg->rtgen_family = AF_UNSPEC;
+
+ memset(&l_addr, 0, sizeof(l_addr));
+ l_addr.nl_family = AF_NETLINK;
+ return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
+}
+
+static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
+{
+ struct sockaddr_nl l_addr;
+ struct msghdr l_msg;
+
+ struct iovec l_iov;
+ l_iov.iov_base = p_buffer;
+ l_iov.iov_len = p_len;
+
+ for(;;)
+ {
+ int l_result;
+ l_msg.msg_name = (void *)&l_addr;
+ l_msg.msg_namelen = sizeof(l_addr);
+ l_msg.msg_iov = &l_iov;
+ l_msg.msg_iovlen = 1;
+ l_msg.msg_control = NULL;
+ l_msg.msg_controllen = 0;
+ l_msg.msg_flags = 0;
+ l_result = recvmsg(p_socket, &l_msg, 0);
+
+ if(l_result < 0)
+ {
+ if(errno == EINTR)
+ {
+ continue;
+ }
+ return -2;
+ }
+
+ /* Buffer was too small */
+ if(l_msg.msg_flags & MSG_TRUNC)
+ {
+ return -1;
+ }
+ return l_result;
+ }
+}
+
+static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
+{
+ size_t l_size = 4096;
+ void *l_buffer = NULL;
+
+ for(;;)
+ {
+ int l_read;
+
+ uv__free(l_buffer);
+ l_buffer = uv__malloc(l_size);
+ if (l_buffer == NULL)
+ {
+ return NULL;
+ }
+
+ l_read = netlink_recv(p_socket, l_buffer, l_size);
+ *p_size = l_read;
+ if(l_read == -2)
+ {
+ uv__free(l_buffer);
+ return NULL;
+ }
+ if(l_read >= 0)
+ {
+ pid_t l_pid = getpid();
+ struct nlmsghdr *l_hdr;
+ for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
+ {
+ if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+ {
+ continue;
+ }
+
+ if(l_hdr->nlmsg_type == NLMSG_DONE)
+ {
+ *p_done = 1;
+ break;
+ }
+
+ if(l_hdr->nlmsg_type == NLMSG_ERROR)
+ {
+ uv__free(l_buffer);
+ return NULL;
+ }
+ }
+ return l_buffer;
+ }
+
+ l_size *= 2;
+ }
+}
+
+static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
+{
+ NetlinkList *l_item = uv__malloc(sizeof(NetlinkList));
+ if (l_item == NULL)
+ {
+ return NULL;
+ }
+
+ l_item->m_next = NULL;
+ l_item->m_data = p_data;
+ l_item->m_size = p_size;
+ return l_item;
+}
+
+static void freeResultList(NetlinkList *p_list)
+{
+ NetlinkList *l_cur;
+ while(p_list)
+ {
+ l_cur = p_list;
+ p_list = p_list->m_next;
+ uv__free(l_cur->m_data);
+ uv__free(l_cur);
+ }
+}
+
+static NetlinkList *getResultList(int p_socket, int p_request)
+{
+ int l_size;
+ int l_done;
+ NetlinkList *l_list;
+ NetlinkList *l_end;
+
+ if(netlink_send(p_socket, p_request) < 0)
+ {
+ return NULL;
+ }
+
+ l_list = NULL;
+ l_end = NULL;
+
+ l_done = 0;
+ while(!l_done)
+ {
+ NetlinkList *l_item;
+
+ struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
+ /* Error */
+ if(!l_hdr)
+ {
+ freeResultList(l_list);
+ return NULL;
+ }
+
+ l_item = newListItem(l_hdr, l_size);
+ if (!l_item)
+ {
+ freeResultList(l_list);
+ return NULL;
+ }
+ if(!l_list)
+ {
+ l_list = l_item;
+ }
+ else
+ {
+ l_end->m_next = l_item;
+ }
+ l_end = l_item;
+ }
+ return l_list;
+}
+
+static size_t maxSize(size_t a, size_t b)
+{
+ return (a > b ? a : b);
+}
+
+static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
+{
+ switch(p_family)
+ {
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+ case AF_PACKET:
+ return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
+ default:
+ return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
+ }
+}
+
+static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
+{
+ switch(p_family)
+ {
+ case AF_INET:
+ memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
+ break;
+ case AF_INET6:
+ memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
+ break;
+ case AF_PACKET:
+ memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
+ ((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
+ break;
+ default:
+ memcpy(p_dest->sa_data, p_data, p_size);
+ break;
+ }
+ p_dest->sa_family = p_family;
+}
+
+static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
+{
+ if(!*p_resultList)
+ {
+ *p_resultList = p_entry;
+ }
+ else
+ {
+ struct ifaddrs *l_cur = *p_resultList;
+ while(l_cur->ifa_next)
+ {
+ l_cur = l_cur->ifa_next;
+ }
+ l_cur->ifa_next = p_entry;
+ }
+}
+
+static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
+{
+ struct ifaddrs *l_entry;
+
+ char *l_index;
+ char *l_name;
+ char *l_addr;
+ char *l_data;
+
+ struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
+
+ size_t l_nameSize = 0;
+ size_t l_addrSize = 0;
+ size_t l_dataSize = 0;
+
+ size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
+ struct rtattr *l_rta;
+ for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+ {
+ size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
+ switch(l_rta->rta_type)
+ {
+ case IFLA_ADDRESS:
+ case IFLA_BROADCAST:
+ l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
+ break;
+ case IFLA_IFNAME:
+ l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
+ break;
+ case IFLA_STATS:
+ l_dataSize += NLMSG_ALIGN(l_rtaSize);
+ break;
+ default:
+ break;
+ }
+ }
+
+ l_entry = uv__malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
+ if (l_entry == NULL)
+ {
+ return -1;
+ }
+ memset(l_entry, 0, sizeof(struct ifaddrs));
+ l_entry->ifa_name = "";
+
+ l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
+ l_name = l_index + sizeof(int);
+ l_addr = l_name + l_nameSize;
+ l_data = l_addr + l_addrSize;
+
+ /* Save the interface index so we can look it up when handling the
+ * addresses.
+ */
+ memcpy(l_index, &l_info->ifi_index, sizeof(int));
+
+ l_entry->ifa_flags = l_info->ifi_flags;
+
+ l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
+ for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+ {
+ void *l_rtaData = RTA_DATA(l_rta);
+ size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
+ switch(l_rta->rta_type)
+ {
+ case IFLA_ADDRESS:
+ case IFLA_BROADCAST:
+ {
+ size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
+ makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
+ ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
+ ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
+ if(l_rta->rta_type == IFLA_ADDRESS)
+ {
+ l_entry->ifa_addr = (struct sockaddr *)l_addr;
+ }
+ else
+ {
+ l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
+ }
+ l_addr += NLMSG_ALIGN(l_addrLen);
+ break;
+ }
+ case IFLA_IFNAME:
+ strncpy(l_name, l_rtaData, l_rtaDataSize);
+ l_name[l_rtaDataSize] = '\0';
+ l_entry->ifa_name = l_name;
+ break;
+ case IFLA_STATS:
+ memcpy(l_data, l_rtaData, l_rtaDataSize);
+ l_entry->ifa_data = l_data;
+ break;
+ default:
+ break;
+ }
+ }
+
+ addToEnd(p_resultList, l_entry);
+ return 0;
+}
+
+static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks)
+{
+ int l_num = 0;
+ struct ifaddrs *l_cur = *p_links;
+ while(l_cur && l_num < p_numLinks)
+ {
+ char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
+ int l_index;
+ memcpy(&l_index, l_indexPtr, sizeof(int));
+ if(l_index == p_index)
+ {
+ return l_cur;
+ }
+
+ l_cur = l_cur->ifa_next;
+ ++l_num;
+ }
+ return NULL;
+}
+
+static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks)
+{
+ struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
+ struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
+
+ size_t l_nameSize = 0;
+ size_t l_addrSize = 0;
+
+ int l_addedNetmask = 0;
+
+ size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
+ struct rtattr *l_rta;
+ struct ifaddrs *l_entry;
+
+ char *l_name;
+ char *l_addr;
+
+ for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+ {
+ size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
+ if(l_info->ifa_family == AF_PACKET)
+ {
+ continue;
+ }
+
+ switch(l_rta->rta_type)
+ {
+ case IFA_ADDRESS:
+ case IFA_LOCAL:
+ if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
+ {
+ /* Make room for netmask */
+ l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
+ l_addedNetmask = 1;
+ }
+ case IFA_BROADCAST:
+ l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
+ break;
+ case IFA_LABEL:
+ l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
+ break;
+ default:
+ break;
+ }
+ }
+
+ l_entry = uv__malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
+ if (l_entry == NULL)
+ {
+ return -1;
+ }
+ memset(l_entry, 0, sizeof(struct ifaddrs));
+ l_entry->ifa_name = (l_interface ? l_interface->ifa_name : "");
+
+ l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
+ l_addr = l_name + l_nameSize;
+
+ l_entry->ifa_flags = l_info->ifa_flags;
+ if(l_interface)
+ {
+ l_entry->ifa_flags |= l_interface->ifa_flags;
+ }
+
+ l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
+ for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+ {
+ void *l_rtaData = RTA_DATA(l_rta);
+ size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
+ switch(l_rta->rta_type)
+ {
+ case IFA_ADDRESS:
+ case IFA_BROADCAST:
+ case IFA_LOCAL:
+ {
+ size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
+ makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
+ if(l_info->ifa_family == AF_INET6)
+ {
+ if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
+ {
+ ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
+ }
+ }
+
+ /* Apparently in a point-to-point network IFA_ADDRESS contains
+ * the dest address and IFA_LOCAL contains the local address
+ */
+ if(l_rta->rta_type == IFA_ADDRESS)
+ {
+ if(l_entry->ifa_addr)
+ {
+ l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
+ }
+ else
+ {
+ l_entry->ifa_addr = (struct sockaddr *)l_addr;
+ }
+ }
+ else if(l_rta->rta_type == IFA_LOCAL)
+ {
+ if(l_entry->ifa_addr)
+ {
+ l_entry->ifa_dstaddr = l_entry->ifa_addr;
+ }
+ l_entry->ifa_addr = (struct sockaddr *)l_addr;
+ }
+ else
+ {
+ l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
+ }
+ l_addr += NLMSG_ALIGN(l_addrLen);
+ break;
+ }
+ case IFA_LABEL:
+ strncpy(l_name, l_rtaData, l_rtaDataSize);
+ l_name[l_rtaDataSize] = '\0';
+ l_entry->ifa_name = l_name;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
+ {
+ unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
+ unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
+ char l_mask[16] = {0};
+ unsigned i;
+ for(i=0; i<(l_prefix/8); ++i)
+ {
+ l_mask[i] = 0xff;
+ }
+ if(l_prefix % 8)
+ {
+ l_mask[i] = 0xff << (8 - (l_prefix % 8));
+ }
+
+ makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
+ l_entry->ifa_netmask = (struct sockaddr *)l_addr;
+ }
+
+ addToEnd(p_resultList, l_entry);
+ return 0;
+}
+
+static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
+{
+
+ int l_numLinks = 0;
+ pid_t l_pid = getpid();
+ for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
+ {
+ unsigned int l_nlsize = p_netlinkList->m_size;
+ struct nlmsghdr *l_hdr;
+ for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
+ {
+ if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+ {
+ continue;
+ }
+
+ if(l_hdr->nlmsg_type == NLMSG_DONE)
+ {
+ break;
+ }
+
+ if(l_hdr->nlmsg_type == RTM_NEWLINK)
+ {
+ if(interpretLink(l_hdr, p_resultList) == -1)
+ {
+ return -1;
+ }
+ ++l_numLinks;
+ }
+ }
+ }
+ return l_numLinks;
+}
+
+static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
+{
+ pid_t l_pid = getpid();
+ for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
+ {
+ unsigned int l_nlsize = p_netlinkList->m_size;
+ struct nlmsghdr *l_hdr;
+ for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
+ {
+ if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+ {
+ continue;
+ }
+
+ if(l_hdr->nlmsg_type == NLMSG_DONE)
+ {
+ break;
+ }
+
+ if(l_hdr->nlmsg_type == RTM_NEWADDR)
+ {
+ if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
+ {
+ return -1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+int getifaddrs(struct ifaddrs **ifap)
+{
+ int l_socket;
+ int l_result;
+ int l_numLinks;
+ NetlinkList *l_linkResults;
+ NetlinkList *l_addrResults;
+
+ if(!ifap)
+ {
+ return -1;
+ }
+ *ifap = NULL;
+
+ l_socket = netlink_socket();
+ if(l_socket < 0)
+ {
+ return -1;
+ }
+
+ l_linkResults = getResultList(l_socket, RTM_GETLINK);
+ if(!l_linkResults)
+ {
+ close(l_socket);
+ return -1;
+ }
+
+ l_addrResults = getResultList(l_socket, RTM_GETADDR);
+ if(!l_addrResults)
+ {
+ close(l_socket);
+ freeResultList(l_linkResults);
+ return -1;
+ }
+
+ l_result = 0;
+ l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);
+ if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1)
+ {
+ l_result = -1;
+ }
+
+ freeResultList(l_linkResults);
+ freeResultList(l_addrResults);
+ close(l_socket);
+ return l_result;
+}
+
+void freeifaddrs(struct ifaddrs *ifa)
+{
+ struct ifaddrs *l_cur;
+ while(ifa)
+ {
+ l_cur = ifa;
+ ifa = ifa->ifa_next;
+ uv__free(l_cur);
+ }
+}
diff --git a/3rdparty/libuv/src/unix/async.c b/3rdparty/libuv/src/unix/async.c
new file mode 100644
index 00000000000..184b598126e
--- /dev/null
+++ b/3rdparty/libuv/src/unix/async.c
@@ -0,0 +1,290 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* This file contains both the uv__async internal infrastructure and the
+ * user-facing uv_async_t functions.
+ */
+
+#include "uv.h"
+#include "internal.h"
+#include "atomic-ops.h"
+
+#include <errno.h>
+#include <stdio.h> /* snprintf() */
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void uv__async_event(uv_loop_t* loop,
+ struct uv__async* w,
+ unsigned int nevents);
+static int uv__async_eventfd(void);
+
+
+int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
+ int err;
+
+ err = uv__async_start(loop, &loop->async_watcher, uv__async_event);
+ if (err)
+ return err;
+
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC);
+ handle->async_cb = async_cb;
+ handle->pending = 0;
+
+ QUEUE_INSERT_TAIL(&loop->async_handles, &handle->queue);
+ uv__handle_start(handle);
+
+ return 0;
+}
+
+
+int uv_async_send(uv_async_t* handle) {
+ /* Do a cheap read first. */
+ if (ACCESS_ONCE(int, handle->pending) != 0)
+ return 0;
+
+ if (cmpxchgi(&handle->pending, 0, 1) == 0)
+ uv__async_send(&handle->loop->async_watcher);
+
+ return 0;
+}
+
+
+void uv__async_close(uv_async_t* handle) {
+ QUEUE_REMOVE(&handle->queue);
+ uv__handle_stop(handle);
+}
+
+
+static void uv__async_event(uv_loop_t* loop,
+ struct uv__async* w,
+ unsigned int nevents) {
+ QUEUE queue;
+ QUEUE* q;
+ uv_async_t* h;
+
+ QUEUE_MOVE(&loop->async_handles, &queue);
+ while (!QUEUE_EMPTY(&queue)) {
+ q = QUEUE_HEAD(&queue);
+ h = QUEUE_DATA(q, uv_async_t, queue);
+
+ QUEUE_REMOVE(q);
+ QUEUE_INSERT_TAIL(&loop->async_handles, q);
+
+ if (cmpxchgi(&h->pending, 1, 0) == 0)
+ continue;
+
+ if (h->async_cb == NULL)
+ continue;
+ h->async_cb(h);
+ }
+}
+
+
+static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+ struct uv__async* wa;
+ char buf[1024];
+ unsigned n;
+ ssize_t r;
+
+ n = 0;
+ for (;;) {
+ r = read(w->fd, buf, sizeof(buf));
+
+ if (r > 0)
+ n += r;
+
+ if (r == sizeof(buf))
+ continue;
+
+ if (r != -1)
+ break;
+
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ break;
+
+ if (errno == EINTR)
+ continue;
+
+ abort();
+ }
+
+ wa = container_of(w, struct uv__async, io_watcher);
+
+#if defined(__linux__)
+ if (wa->wfd == -1) {
+ uint64_t val;
+ assert(n == sizeof(val));
+ memcpy(&val, buf, sizeof(val)); /* Avoid alignment issues. */
+ wa->cb(loop, wa, val);
+ return;
+ }
+#endif
+
+ wa->cb(loop, wa, n);
+}
+
+
+void uv__async_send(struct uv__async* wa) {
+ const void* buf;
+ ssize_t len;
+ int fd;
+ int r;
+
+ buf = "";
+ len = 1;
+ fd = wa->wfd;
+
+#if defined(__linux__)
+ if (fd == -1) {
+ static const uint64_t val = 1;
+ buf = &val;
+ len = sizeof(val);
+ fd = wa->io_watcher.fd; /* eventfd */
+ }
+#endif
+
+ do
+ r = write(fd, buf, len);
+ while (r == -1 && errno == EINTR);
+
+ if (r == len)
+ return;
+
+ if (r == -1)
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ return;
+
+ abort();
+}
+
+
+void uv__async_init(struct uv__async* wa) {
+ wa->io_watcher.fd = -1;
+ wa->wfd = -1;
+}
+
+
+int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb) {
+ int pipefd[2];
+ int err;
+
+ if (wa->io_watcher.fd != -1)
+ return 0;
+
+ err = uv__async_eventfd();
+ if (err >= 0) {
+ pipefd[0] = err;
+ pipefd[1] = -1;
+ }
+ else if (err == -ENOSYS) {
+ err = uv__make_pipe(pipefd, UV__F_NONBLOCK);
+#if defined(__linux__)
+ /* Save a file descriptor by opening one of the pipe descriptors as
+ * read/write through the procfs. That file descriptor can then
+ * function as both ends of the pipe.
+ */
+ if (err == 0) {
+ char buf[32];
+ int fd;
+
+ snprintf(buf, sizeof(buf), "/proc/self/fd/%d", pipefd[0]);
+ fd = uv__open_cloexec(buf, O_RDWR);
+ if (fd >= 0) {
+ uv__close(pipefd[0]);
+ uv__close(pipefd[1]);
+ pipefd[0] = fd;
+ pipefd[1] = fd;
+ }
+ }
+#endif
+ }
+
+ if (err < 0)
+ return err;
+
+ uv__io_init(&wa->io_watcher, uv__async_io, pipefd[0]);
+ uv__io_start(loop, &wa->io_watcher, UV__POLLIN);
+ wa->wfd = pipefd[1];
+ wa->cb = cb;
+
+ return 0;
+}
+
+
+void uv__async_stop(uv_loop_t* loop, struct uv__async* wa) {
+ if (wa->io_watcher.fd == -1)
+ return;
+
+ if (wa->wfd != -1) {
+ if (wa->wfd != wa->io_watcher.fd)
+ uv__close(wa->wfd);
+ wa->wfd = -1;
+ }
+
+ uv__io_stop(loop, &wa->io_watcher, UV__POLLIN);
+ uv__close(wa->io_watcher.fd);
+ wa->io_watcher.fd = -1;
+}
+
+
+static int uv__async_eventfd() {
+#if defined(__linux__)
+ static int no_eventfd2;
+ static int no_eventfd;
+ int fd;
+
+ if (no_eventfd2)
+ goto skip_eventfd2;
+
+ fd = uv__eventfd2(0, UV__EFD_CLOEXEC | UV__EFD_NONBLOCK);
+ if (fd != -1)
+ return fd;
+
+ if (errno != ENOSYS)
+ return -errno;
+
+ no_eventfd2 = 1;
+
+skip_eventfd2:
+
+ if (no_eventfd)
+ goto skip_eventfd;
+
+ fd = uv__eventfd(0);
+ if (fd != -1) {
+ uv__cloexec(fd, 1);
+ uv__nonblock(fd, 1);
+ return fd;
+ }
+
+ if (errno != ENOSYS)
+ return -errno;
+
+ no_eventfd = 1;
+
+skip_eventfd:
+
+#endif
+
+ return -ENOSYS;
+}
diff --git a/3rdparty/libuv/src/unix/atomic-ops.h b/3rdparty/libuv/src/unix/atomic-ops.h
new file mode 100644
index 00000000000..84e471838be
--- /dev/null
+++ b/3rdparty/libuv/src/unix/atomic-ops.h
@@ -0,0 +1,77 @@
+/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef UV_ATOMIC_OPS_H_
+#define UV_ATOMIC_OPS_H_
+
+#include "internal.h" /* UV_UNUSED */
+
+#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+#include <atomic.h>
+#define __sync_val_compare_and_swap(p, o, n) atomic_cas_ptr(p, o, n)
+#endif
+
+UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval));
+UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval));
+UV_UNUSED(static void cpu_relax(void));
+
+/* Prefer hand-rolled assembly over the gcc builtins because the latter also
+ * issue full memory barriers.
+ */
+UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
+#if defined(__i386__) || defined(__x86_64__)
+ int out;
+ __asm__ __volatile__ ("lock; cmpxchg %2, %1;"
+ : "=a" (out), "+m" (*(volatile int*) ptr)
+ : "r" (newval), "0" (oldval)
+ : "memory");
+ return out;
+#elif defined(_AIX) && defined(__xlC__)
+ const int out = (*(volatile int*) ptr);
+ __compare_and_swap(ptr, &oldval, newval);
+ return out;
+#else
+ return __sync_val_compare_and_swap(ptr, oldval, newval);
+#endif
+}
+
+UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) {
+#if defined(__i386__) || defined(__x86_64__)
+ long out;
+ __asm__ __volatile__ ("lock; cmpxchg %2, %1;"
+ : "=a" (out), "+m" (*(volatile long*) ptr)
+ : "r" (newval), "0" (oldval)
+ : "memory");
+ return out;
+#elif defined(_AIX) && defined(__xlC__)
+ const long out = (*(volatile int*) ptr);
+# if defined(__64BIT__)
+ __compare_and_swaplp(ptr, &oldval, newval);
+# else
+ __compare_and_swap(ptr, &oldval, newval);
+# endif /* if defined(__64BIT__) */
+ return out;
+#else
+ return __sync_val_compare_and_swap(ptr, oldval, newval);
+#endif
+}
+
+UV_UNUSED(static void cpu_relax(void)) {
+#if defined(__i386__) || defined(__x86_64__)
+ __asm__ __volatile__ ("rep; nop"); /* a.k.a. PAUSE */
+#endif
+}
+
+#endif /* UV_ATOMIC_OPS_H_ */
diff --git a/3rdparty/libuv/src/unix/core.c b/3rdparty/libuv/src/unix/core.c
new file mode 100644
index 00000000000..cedd86ed34a
--- /dev/null
+++ b/3rdparty/libuv/src/unix/core.c
@@ -0,0 +1,1104 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stddef.h> /* NULL */
+#include <stdio.h> /* printf */
+#include <stdlib.h>
+#include <string.h> /* strerror */
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <limits.h> /* INT_MAX, PATH_MAX, IOV_MAX */
+#include <sys/uio.h> /* writev */
+#include <sys/resource.h> /* getrusage */
+#include <pwd.h>
+
+#ifdef __linux__
+# include <sys/ioctl.h>
+#endif
+
+#ifdef __sun
+# include <sys/types.h>
+# include <sys/wait.h>
+#endif
+
+#ifdef __APPLE__
+# include <mach-o/dyld.h> /* _NSGetExecutablePath */
+# include <sys/filio.h>
+# include <sys/ioctl.h>
+#endif
+
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+# include <sys/sysctl.h>
+# include <sys/filio.h>
+# include <sys/ioctl.h>
+# include <sys/wait.h>
+# define UV__O_CLOEXEC O_CLOEXEC
+# if defined(__FreeBSD__) && __FreeBSD__ >= 10
+# define uv__accept4 accept4
+# define UV__SOCK_NONBLOCK SOCK_NONBLOCK
+# define UV__SOCK_CLOEXEC SOCK_CLOEXEC
+# endif
+# if !defined(F_DUP2FD_CLOEXEC) && defined(_F_DUP2FD_CLOEXEC)
+# define F_DUP2FD_CLOEXEC _F_DUP2FD_CLOEXEC
+# endif
+#endif
+
+#ifdef _AIX
+#include <sys/ioctl.h>
+#endif
+
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
+# include <dlfcn.h> /* for dlsym */
+#endif
+
+static int uv__run_pending(uv_loop_t* loop);
+
+/* Verify that uv_buf_t is ABI-compatible with struct iovec. */
+STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec));
+STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->base) ==
+ sizeof(((struct iovec*) 0)->iov_base));
+STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->len) ==
+ sizeof(((struct iovec*) 0)->iov_len));
+STATIC_ASSERT(offsetof(uv_buf_t, base) == offsetof(struct iovec, iov_base));
+STATIC_ASSERT(offsetof(uv_buf_t, len) == offsetof(struct iovec, iov_len));
+
+
+uint64_t uv_hrtime(void) {
+ return uv__hrtime(UV_CLOCK_PRECISE);
+}
+
+
+void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
+ assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
+
+ handle->flags |= UV_CLOSING;
+ handle->close_cb = close_cb;
+
+ switch (handle->type) {
+ case UV_NAMED_PIPE:
+ uv__pipe_close((uv_pipe_t*)handle);
+ break;
+
+ case UV_TTY:
+ uv__stream_close((uv_stream_t*)handle);
+ break;
+
+ case UV_TCP:
+ uv__tcp_close((uv_tcp_t*)handle);
+ break;
+
+ case UV_UDP:
+ uv__udp_close((uv_udp_t*)handle);
+ break;
+
+ case UV_PREPARE:
+ uv__prepare_close((uv_prepare_t*)handle);
+ break;
+
+ case UV_CHECK:
+ uv__check_close((uv_check_t*)handle);
+ break;
+
+ case UV_IDLE:
+ uv__idle_close((uv_idle_t*)handle);
+ break;
+
+ case UV_ASYNC:
+ uv__async_close((uv_async_t*)handle);
+ break;
+
+ case UV_TIMER:
+ uv__timer_close((uv_timer_t*)handle);
+ break;
+
+ case UV_PROCESS:
+ uv__process_close((uv_process_t*)handle);
+ break;
+
+ case UV_FS_EVENT:
+ uv__fs_event_close((uv_fs_event_t*)handle);
+ break;
+
+ case UV_POLL:
+ uv__poll_close((uv_poll_t*)handle);
+ break;
+
+ case UV_FS_POLL:
+ uv__fs_poll_close((uv_fs_poll_t*)handle);
+ break;
+
+ case UV_SIGNAL:
+ uv__signal_close((uv_signal_t*) handle);
+ /* Signal handles may not be closed immediately. The signal code will */
+ /* itself close uv__make_close_pending whenever appropriate. */
+ return;
+
+ default:
+ assert(0);
+ }
+
+ uv__make_close_pending(handle);
+}
+
+int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
+ int r;
+ int fd;
+ socklen_t len;
+
+ if (handle == NULL || value == NULL)
+ return -EINVAL;
+
+ if (handle->type == UV_TCP || handle->type == UV_NAMED_PIPE)
+ fd = uv__stream_fd((uv_stream_t*) handle);
+ else if (handle->type == UV_UDP)
+ fd = ((uv_udp_t *) handle)->io_watcher.fd;
+ else
+ return -ENOTSUP;
+
+ len = sizeof(*value);
+
+ if (*value == 0)
+ r = getsockopt(fd, SOL_SOCKET, optname, value, &len);
+ else
+ r = setsockopt(fd, SOL_SOCKET, optname, (const void*) value, len);
+
+ if (r < 0)
+ return -errno;
+
+ return 0;
+}
+
+void uv__make_close_pending(uv_handle_t* handle) {
+ assert(handle->flags & UV_CLOSING);
+ assert(!(handle->flags & UV_CLOSED));
+ handle->next_closing = handle->loop->closing_handles;
+ handle->loop->closing_handles = handle;
+}
+
+int uv__getiovmax(void) {
+#if defined(IOV_MAX)
+ return IOV_MAX;
+#elif defined(_SC_IOV_MAX)
+ static int iovmax = -1;
+ if (iovmax == -1) {
+ iovmax = sysconf(_SC_IOV_MAX);
+ /* On some embedded devices (arm-linux-uclibc based ip camera),
+ * sysconf(_SC_IOV_MAX) can not get the correct value. The return
+ * value is -1 and the errno is EINPROGRESS. Degrade the value to 1.
+ */
+ if (iovmax == -1) iovmax = 1;
+ }
+ return iovmax;
+#else
+ return 1024;
+#endif
+}
+
+
+static void uv__finish_close(uv_handle_t* handle) {
+ /* Note: while the handle is in the UV_CLOSING state now, it's still possible
+ * for it to be active in the sense that uv__is_active() returns true.
+ * A good example is when the user calls uv_shutdown(), immediately followed
+ * by uv_close(). The handle is considered active at this point because the
+ * completion of the shutdown req is still pending.
+ */
+ assert(handle->flags & UV_CLOSING);
+ assert(!(handle->flags & UV_CLOSED));
+ handle->flags |= UV_CLOSED;
+
+ switch (handle->type) {
+ case UV_PREPARE:
+ case UV_CHECK:
+ case UV_IDLE:
+ case UV_ASYNC:
+ case UV_TIMER:
+ case UV_PROCESS:
+ case UV_FS_EVENT:
+ case UV_FS_POLL:
+ case UV_POLL:
+ case UV_SIGNAL:
+ break;
+
+ case UV_NAMED_PIPE:
+ case UV_TCP:
+ case UV_TTY:
+ uv__stream_destroy((uv_stream_t*)handle);
+ break;
+
+ case UV_UDP:
+ uv__udp_finish_close((uv_udp_t*)handle);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+
+ uv__handle_unref(handle);
+ QUEUE_REMOVE(&handle->handle_queue);
+
+ if (handle->close_cb) {
+ handle->close_cb(handle);
+ }
+}
+
+
+static void uv__run_closing_handles(uv_loop_t* loop) {
+ uv_handle_t* p;
+ uv_handle_t* q;
+
+ p = loop->closing_handles;
+ loop->closing_handles = NULL;
+
+ while (p) {
+ q = p->next_closing;
+ uv__finish_close(p);
+ p = q;
+ }
+}
+
+
+int uv_is_closing(const uv_handle_t* handle) {
+ return uv__is_closing(handle);
+}
+
+
+int uv_backend_fd(const uv_loop_t* loop) {
+ return loop->backend_fd;
+}
+
+
+int uv_backend_timeout(const uv_loop_t* loop) {
+ if (loop->stop_flag != 0)
+ return 0;
+
+ if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
+ return 0;
+
+ if (!QUEUE_EMPTY(&loop->idle_handles))
+ return 0;
+
+ if (!QUEUE_EMPTY(&loop->pending_queue))
+ return 0;
+
+ if (loop->closing_handles)
+ return 0;
+
+ return uv__next_timeout(loop);
+}
+
+
+static int uv__loop_alive(const uv_loop_t* loop) {
+ return uv__has_active_handles(loop) ||
+ uv__has_active_reqs(loop) ||
+ loop->closing_handles != NULL;
+}
+
+
+int uv_loop_alive(const uv_loop_t* loop) {
+ return uv__loop_alive(loop);
+}
+
+
+int uv_run(uv_loop_t* loop, uv_run_mode mode) {
+ int timeout;
+ int r;
+ int ran_pending;
+
+ r = uv__loop_alive(loop);
+ if (!r)
+ uv__update_time(loop);
+
+ while (r != 0 && loop->stop_flag == 0) {
+ uv__update_time(loop);
+ uv__run_timers(loop);
+ ran_pending = uv__run_pending(loop);
+ uv__run_idle(loop);
+ uv__run_prepare(loop);
+
+ timeout = 0;
+ if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
+ timeout = uv_backend_timeout(loop);
+
+ uv__io_poll(loop, timeout);
+ uv__run_check(loop);
+ uv__run_closing_handles(loop);
+
+ if (mode == UV_RUN_ONCE) {
+ /* UV_RUN_ONCE implies forward progress: at least one callback must have
+ * been invoked when it returns. uv__io_poll() can return without doing
+ * I/O (meaning: no callbacks) when its timeout expires - which means we
+ * have pending timers that satisfy the forward progress constraint.
+ *
+ * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
+ * the check.
+ */
+ uv__update_time(loop);
+ uv__run_timers(loop);
+ }
+
+ r = uv__loop_alive(loop);
+ if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
+ break;
+ }
+
+ /* The if statement lets gcc compile it to a conditional store. Avoids
+ * dirtying a cache line.
+ */
+ if (loop->stop_flag != 0)
+ loop->stop_flag = 0;
+
+ return r;
+}
+
+
+void uv_update_time(uv_loop_t* loop) {
+ uv__update_time(loop);
+}
+
+
+int uv_is_active(const uv_handle_t* handle) {
+ return uv__is_active(handle);
+}
+
+
+/* Open a socket in non-blocking close-on-exec mode, atomically if possible. */
+int uv__socket(int domain, int type, int protocol) {
+ int sockfd;
+ int err;
+
+#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
+ sockfd = socket(domain, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
+ if (sockfd != -1)
+ return sockfd;
+
+ if (errno != EINVAL)
+ return -errno;
+#endif
+
+ sockfd = socket(domain, type, protocol);
+ if (sockfd == -1)
+ return -errno;
+
+ err = uv__nonblock(sockfd, 1);
+ if (err == 0)
+ err = uv__cloexec(sockfd, 1);
+
+ if (err) {
+ uv__close(sockfd);
+ return err;
+ }
+
+#if defined(SO_NOSIGPIPE)
+ {
+ int on = 1;
+ setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
+ }
+#endif
+
+ return sockfd;
+}
+
+
+int uv__accept(int sockfd) {
+ int peerfd;
+ int err;
+
+ assert(sockfd >= 0);
+
+ while (1) {
+#if defined(__linux__) || __FreeBSD__ >= 10
+ static int no_accept4;
+
+ if (no_accept4)
+ goto skip;
+
+ peerfd = uv__accept4(sockfd,
+ NULL,
+ NULL,
+ UV__SOCK_NONBLOCK|UV__SOCK_CLOEXEC);
+ if (peerfd != -1)
+ return peerfd;
+
+ if (errno == EINTR)
+ continue;
+
+ if (errno != ENOSYS)
+ return -errno;
+
+ no_accept4 = 1;
+skip:
+#endif
+
+ peerfd = accept(sockfd, NULL, NULL);
+ if (peerfd == -1) {
+ if (errno == EINTR)
+ continue;
+ return -errno;
+ }
+
+ err = uv__cloexec(peerfd, 1);
+ if (err == 0)
+ err = uv__nonblock(peerfd, 1);
+
+ if (err) {
+ uv__close(peerfd);
+ return err;
+ }
+
+ return peerfd;
+ }
+}
+
+
+int uv__close(int fd) {
+ int saved_errno;
+ int rc;
+
+ assert(fd > -1); /* Catch uninitialized io_watcher.fd bugs. */
+ assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */
+
+ saved_errno = errno;
+ rc = close(fd);
+ if (rc == -1) {
+ rc = -errno;
+ if (rc == -EINTR)
+ rc = -EINPROGRESS; /* For platform/libc consistency. */
+ errno = saved_errno;
+ }
+
+ return rc;
+}
+
+
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
+ defined(_AIX) || defined(__DragonFly__)
+
+int uv__nonblock(int fd, int set) {
+ int r;
+
+ do
+ r = ioctl(fd, FIONBIO, &set);
+ while (r == -1 && errno == EINTR);
+
+ if (r)
+ return -errno;
+
+ return 0;
+}
+
+
+int uv__cloexec(int fd, int set) {
+ int r;
+
+ do
+ r = ioctl(fd, set ? FIOCLEX : FIONCLEX);
+ while (r == -1 && errno == EINTR);
+
+ if (r)
+ return -errno;
+
+ return 0;
+}
+
+#else /* !(defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
+ defined(_AIX) || defined(__DragonFly__)) */
+
+int uv__nonblock(int fd, int set) {
+ int flags;
+ int r;
+
+ do
+ r = fcntl(fd, F_GETFL);
+ while (r == -1 && errno == EINTR);
+
+ if (r == -1)
+ return -errno;
+
+ /* Bail out now if already set/clear. */
+ if (!!(r & O_NONBLOCK) == !!set)
+ return 0;
+
+ if (set)
+ flags = r | O_NONBLOCK;
+ else
+ flags = r & ~O_NONBLOCK;
+
+ do
+ r = fcntl(fd, F_SETFL, flags);
+ while (r == -1 && errno == EINTR);
+
+ if (r)
+ return -errno;
+
+ return 0;
+}
+
+
+int uv__cloexec(int fd, int set) {
+ int flags;
+ int r;
+
+ do
+ r = fcntl(fd, F_GETFD);
+ while (r == -1 && errno == EINTR);
+
+ if (r == -1)
+ return -errno;
+
+ /* Bail out now if already set/clear. */
+ if (!!(r & FD_CLOEXEC) == !!set)
+ return 0;
+
+ if (set)
+ flags = r | FD_CLOEXEC;
+ else
+ flags = r & ~FD_CLOEXEC;
+
+ do
+ r = fcntl(fd, F_SETFD, flags);
+ while (r == -1 && errno == EINTR);
+
+ if (r)
+ return -errno;
+
+ return 0;
+}
+
+#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
+ defined(_AIX) || defined(__DragonFly__) */
+
+
+/* This function is not execve-safe, there is a race window
+ * between the call to dup() and fcntl(FD_CLOEXEC).
+ */
+int uv__dup(int fd) {
+ int err;
+
+ fd = dup(fd);
+
+ if (fd == -1)
+ return -errno;
+
+ err = uv__cloexec(fd, 1);
+ if (err) {
+ uv__close(fd);
+ return err;
+ }
+
+ return fd;
+}
+
+
+ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
+ struct cmsghdr* cmsg;
+ ssize_t rc;
+ int* pfd;
+ int* end;
+#if defined(__linux__)
+ static int no_msg_cmsg_cloexec;
+ if (no_msg_cmsg_cloexec == 0) {
+ rc = recvmsg(fd, msg, flags | 0x40000000); /* MSG_CMSG_CLOEXEC */
+ if (rc != -1)
+ return rc;
+ if (errno != EINVAL)
+ return -errno;
+ rc = recvmsg(fd, msg, flags);
+ if (rc == -1)
+ return -errno;
+ no_msg_cmsg_cloexec = 1;
+ } else {
+ rc = recvmsg(fd, msg, flags);
+ }
+#else
+ rc = recvmsg(fd, msg, flags);
+#endif
+ if (rc == -1)
+ return -errno;
+ if (msg->msg_controllen == 0)
+ return rc;
+ for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg))
+ if (cmsg->cmsg_type == SCM_RIGHTS)
+ for (pfd = (int*) CMSG_DATA(cmsg),
+ end = (int*) ((char*) cmsg + cmsg->cmsg_len);
+ pfd < end;
+ pfd += 1)
+ uv__cloexec(*pfd, 1);
+ return rc;
+}
+
+
+int uv_cwd(char* buffer, size_t* size) {
+ if (buffer == NULL || size == NULL)
+ return -EINVAL;
+
+ if (getcwd(buffer, *size) == NULL)
+ return -errno;
+
+ *size = strlen(buffer);
+ if (*size > 1 && buffer[*size - 1] == '/') {
+ buffer[*size-1] = '\0';
+ (*size)--;
+ }
+
+ return 0;
+}
+
+
+int uv_chdir(const char* dir) {
+ if (chdir(dir))
+ return -errno;
+
+ return 0;
+}
+
+
+void uv_disable_stdio_inheritance(void) {
+ int fd;
+
+ /* Set the CLOEXEC flag on all open descriptors. Unconditionally try the
+ * first 16 file descriptors. After that, bail out after the first error.
+ */
+ for (fd = 0; ; fd++)
+ if (uv__cloexec(fd, 1) && fd > 15)
+ break;
+}
+
+
+int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
+ int fd_out;
+
+ switch (handle->type) {
+ case UV_TCP:
+ case UV_NAMED_PIPE:
+ case UV_TTY:
+ fd_out = uv__stream_fd((uv_stream_t*) handle);
+ break;
+
+ case UV_UDP:
+ fd_out = ((uv_udp_t *) handle)->io_watcher.fd;
+ break;
+
+ case UV_POLL:
+ fd_out = ((uv_poll_t *) handle)->io_watcher.fd;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (uv__is_closing(handle) || fd_out == -1)
+ return -EBADF;
+
+ *fd = fd_out;
+ return 0;
+}
+
+
+static int uv__run_pending(uv_loop_t* loop) {
+ QUEUE* q;
+ QUEUE pq;
+ uv__io_t* w;
+
+ if (QUEUE_EMPTY(&loop->pending_queue))
+ return 0;
+
+ QUEUE_MOVE(&loop->pending_queue, &pq);
+
+ while (!QUEUE_EMPTY(&pq)) {
+ q = QUEUE_HEAD(&pq);
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q);
+ w = QUEUE_DATA(q, uv__io_t, pending_queue);
+ w->cb(loop, w, UV__POLLOUT);
+ }
+
+ return 1;
+}
+
+
+static unsigned int next_power_of_two(unsigned int val) {
+ val -= 1;
+ val |= val >> 1;
+ val |= val >> 2;
+ val |= val >> 4;
+ val |= val >> 8;
+ val |= val >> 16;
+ val += 1;
+ return val;
+}
+
+static void maybe_resize(uv_loop_t* loop, unsigned int len) {
+ uv__io_t** watchers;
+ void* fake_watcher_list;
+ void* fake_watcher_count;
+ unsigned int nwatchers;
+ unsigned int i;
+
+ if (len <= loop->nwatchers)
+ return;
+
+ /* Preserve fake watcher list and count at the end of the watchers */
+ if (loop->watchers != NULL) {
+ fake_watcher_list = loop->watchers[loop->nwatchers];
+ fake_watcher_count = loop->watchers[loop->nwatchers + 1];
+ } else {
+ fake_watcher_list = NULL;
+ fake_watcher_count = NULL;
+ }
+
+ nwatchers = next_power_of_two(len + 2) - 2;
+ watchers = uv__realloc(loop->watchers,
+ (nwatchers + 2) * sizeof(loop->watchers[0]));
+
+ if (watchers == NULL)
+ abort();
+ for (i = loop->nwatchers; i < nwatchers; i++)
+ watchers[i] = NULL;
+ watchers[nwatchers] = fake_watcher_list;
+ watchers[nwatchers + 1] = fake_watcher_count;
+
+ loop->watchers = watchers;
+ loop->nwatchers = nwatchers;
+}
+
+
+void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) {
+ assert(cb != NULL);
+ assert(fd >= -1);
+ QUEUE_INIT(&w->pending_queue);
+ QUEUE_INIT(&w->watcher_queue);
+ w->cb = cb;
+ w->fd = fd;
+ w->events = 0;
+ w->pevents = 0;
+
+#if defined(UV_HAVE_KQUEUE)
+ w->rcount = 0;
+ w->wcount = 0;
+#endif /* defined(UV_HAVE_KQUEUE) */
+}
+
+
+void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+ assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT)));
+ assert(0 != events);
+ assert(w->fd >= 0);
+ assert(w->fd < INT_MAX);
+
+ w->pevents |= events;
+ maybe_resize(loop, w->fd + 1);
+
+#if !defined(__sun)
+ /* The event ports backend needs to rearm all file descriptors on each and
+ * every tick of the event loop but the other backends allow us to
+ * short-circuit here if the event mask is unchanged.
+ */
+ if (w->events == w->pevents) {
+ if (w->events == 0 && !QUEUE_EMPTY(&w->watcher_queue)) {
+ QUEUE_REMOVE(&w->watcher_queue);
+ QUEUE_INIT(&w->watcher_queue);
+ }
+ return;
+ }
+#endif
+
+ if (QUEUE_EMPTY(&w->watcher_queue))
+ QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
+
+ if (loop->watchers[w->fd] == NULL) {
+ loop->watchers[w->fd] = w;
+ loop->nfds++;
+ }
+}
+
+
+void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+ assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT)));
+ assert(0 != events);
+
+ if (w->fd == -1)
+ return;
+
+ assert(w->fd >= 0);
+
+ /* Happens when uv__io_stop() is called on a handle that was never started. */
+ if ((unsigned) w->fd >= loop->nwatchers)
+ return;
+
+ w->pevents &= ~events;
+
+ if (w->pevents == 0) {
+ QUEUE_REMOVE(&w->watcher_queue);
+ QUEUE_INIT(&w->watcher_queue);
+
+ if (loop->watchers[w->fd] != NULL) {
+ assert(loop->watchers[w->fd] == w);
+ assert(loop->nfds > 0);
+ loop->watchers[w->fd] = NULL;
+ loop->nfds--;
+ w->events = 0;
+ }
+ }
+ else if (QUEUE_EMPTY(&w->watcher_queue))
+ QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
+}
+
+
+void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
+ uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT);
+ QUEUE_REMOVE(&w->pending_queue);
+
+ /* Remove stale events for this file descriptor */
+ uv__platform_invalidate_fd(loop, w->fd);
+}
+
+
+void uv__io_feed(uv_loop_t* loop, uv__io_t* w) {
+ if (QUEUE_EMPTY(&w->pending_queue))
+ QUEUE_INSERT_TAIL(&loop->pending_queue, &w->pending_queue);
+}
+
+
+int uv__io_active(const uv__io_t* w, unsigned int events) {
+ assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT)));
+ assert(0 != events);
+ return 0 != (w->pevents & events);
+}
+
+
+int uv_getrusage(uv_rusage_t* rusage) {
+ struct rusage usage;
+
+ if (getrusage(RUSAGE_SELF, &usage))
+ return -errno;
+
+ rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec;
+ rusage->ru_utime.tv_usec = usage.ru_utime.tv_usec;
+
+ rusage->ru_stime.tv_sec = usage.ru_stime.tv_sec;
+ rusage->ru_stime.tv_usec = usage.ru_stime.tv_usec;
+
+ rusage->ru_maxrss = usage.ru_maxrss;
+ rusage->ru_ixrss = usage.ru_ixrss;
+ rusage->ru_idrss = usage.ru_idrss;
+ rusage->ru_isrss = usage.ru_isrss;
+ rusage->ru_minflt = usage.ru_minflt;
+ rusage->ru_majflt = usage.ru_majflt;
+ rusage->ru_nswap = usage.ru_nswap;
+ rusage->ru_inblock = usage.ru_inblock;
+ rusage->ru_oublock = usage.ru_oublock;
+ rusage->ru_msgsnd = usage.ru_msgsnd;
+ rusage->ru_msgrcv = usage.ru_msgrcv;
+ rusage->ru_nsignals = usage.ru_nsignals;
+ rusage->ru_nvcsw = usage.ru_nvcsw;
+ rusage->ru_nivcsw = usage.ru_nivcsw;
+
+ return 0;
+}
+
+
+int uv__open_cloexec(const char* path, int flags) {
+ int err;
+ int fd;
+
+#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 9) || \
+ defined(__DragonFly__)
+ static int no_cloexec;
+
+ if (!no_cloexec) {
+ fd = open(path, flags | UV__O_CLOEXEC);
+ if (fd != -1)
+ return fd;
+
+ if (errno != EINVAL)
+ return -errno;
+
+ /* O_CLOEXEC not supported. */
+ no_cloexec = 1;
+ }
+#endif
+
+ fd = open(path, flags);
+ if (fd == -1)
+ return -errno;
+
+ err = uv__cloexec(fd, 1);
+ if (err) {
+ uv__close(fd);
+ return err;
+ }
+
+ return fd;
+}
+
+
+int uv__dup2_cloexec(int oldfd, int newfd) {
+ int r;
+#if defined(__FreeBSD__) && __FreeBSD__ >= 10
+ r = dup3(oldfd, newfd, O_CLOEXEC);
+ if (r == -1)
+ return -errno;
+ return r;
+#elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC)
+ r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd);
+ if (r != -1)
+ return r;
+ if (errno != EINVAL)
+ return -errno;
+ /* Fall through. */
+#elif defined(__linux__)
+ static int no_dup3;
+ if (!no_dup3) {
+ do
+ r = uv__dup3(oldfd, newfd, UV__O_CLOEXEC);
+ while (r == -1 && errno == EBUSY);
+ if (r != -1)
+ return r;
+ if (errno != ENOSYS)
+ return -errno;
+ /* Fall through. */
+ no_dup3 = 1;
+ }
+#endif
+ {
+ int err;
+ do
+ r = dup2(oldfd, newfd);
+#if defined(__linux__)
+ while (r == -1 && errno == EBUSY);
+#else
+ while (0); /* Never retry. */
+#endif
+
+ if (r == -1)
+ return -errno;
+
+ err = uv__cloexec(newfd, 1);
+ if (err) {
+ uv__close(newfd);
+ return err;
+ }
+
+ return r;
+ }
+}
+
+
+int uv_os_homedir(char* buffer, size_t* size) {
+ struct passwd pw;
+ struct passwd* result;
+ char* buf;
+ uid_t uid;
+ size_t bufsize;
+ size_t len;
+ long initsize;
+ int r;
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
+ int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**);
+#endif
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ /* Check if the HOME environment variable is set first */
+ buf = getenv("HOME");
+
+ if (buf != NULL) {
+ len = strlen(buf);
+
+ if (len >= *size) {
+ *size = len;
+ return -ENOBUFS;
+ }
+
+ memcpy(buffer, buf, len + 1);
+ *size = len;
+
+ return 0;
+ }
+
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
+ getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r");
+ if (getpwuid_r == NULL)
+ return -ENOSYS;
+#endif
+
+ /* HOME is not set, so call getpwuid() */
+ initsize = sysconf(_SC_GETPW_R_SIZE_MAX);
+
+ if (initsize <= 0)
+ bufsize = 4096;
+ else
+ bufsize = (size_t) initsize;
+
+ uid = getuid();
+ buf = NULL;
+
+ for (;;) {
+ uv__free(buf);
+ buf = uv__malloc(bufsize);
+
+ if (buf == NULL)
+ return -ENOMEM;
+
+ r = getpwuid_r(uid, &pw, buf, bufsize, &result);
+
+ if (r != ERANGE)
+ break;
+
+ bufsize *= 2;
+ }
+
+ if (r != 0) {
+ uv__free(buf);
+ return -r;
+ }
+
+ if (result == NULL) {
+ uv__free(buf);
+ return -ENOENT;
+ }
+
+ len = strlen(pw.pw_dir);
+
+ if (len >= *size) {
+ *size = len;
+ uv__free(buf);
+ return -ENOBUFS;
+ }
+
+ memcpy(buffer, pw.pw_dir, len + 1);
+ *size = len;
+ uv__free(buf);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/src/unix/darwin-proctitle.c b/3rdparty/libuv/src/unix/darwin-proctitle.c
new file mode 100644
index 00000000000..1142311609f
--- /dev/null
+++ b/3rdparty/libuv/src/unix/darwin-proctitle.c
@@ -0,0 +1,206 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <TargetConditionals.h>
+
+#if !TARGET_OS_IPHONE
+# include <CoreFoundation/CoreFoundation.h>
+# include <ApplicationServices/ApplicationServices.h>
+#endif
+
+
+static int uv__pthread_setname_np(const char* name) {
+ int (*dynamic_pthread_setname_np)(const char* name);
+ char namebuf[64]; /* MAXTHREADNAMESIZE */
+ int err;
+
+ /* pthread_setname_np() first appeared in OS X 10.6 and iOS 3.2. */
+ *(void **)(&dynamic_pthread_setname_np) =
+ dlsym(RTLD_DEFAULT, "pthread_setname_np");
+
+ if (dynamic_pthread_setname_np == NULL)
+ return -ENOSYS;
+
+ strncpy(namebuf, name, sizeof(namebuf) - 1);
+ namebuf[sizeof(namebuf) - 1] = '\0';
+
+ err = dynamic_pthread_setname_np(namebuf);
+ if (err)
+ return -err;
+
+ return 0;
+}
+
+
+int uv__set_process_title(const char* title) {
+#if TARGET_OS_IPHONE
+ return uv__pthread_setname_np(title);
+#else
+ CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
+ const char*,
+ CFStringEncoding);
+ CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef);
+ void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef);
+ void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef);
+ CFTypeRef (*pLSGetCurrentApplicationASN)(void);
+ OSStatus (*pLSSetApplicationInformationItem)(int,
+ CFTypeRef,
+ CFStringRef,
+ CFStringRef,
+ CFDictionaryRef*);
+ void* application_services_handle;
+ void* core_foundation_handle;
+ CFBundleRef launch_services_bundle;
+ CFStringRef* display_name_key;
+ CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef);
+ CFBundleRef (*pCFBundleGetMainBundle)(void);
+ CFBundleRef hi_services_bundle;
+ OSStatus (*pSetApplicationIsDaemon)(int);
+ CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef);
+ void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
+ void*);
+ CFTypeRef asn;
+ int err;
+
+ err = -ENOENT;
+ application_services_handle = dlopen("/System/Library/Frameworks/"
+ "ApplicationServices.framework/"
+ "Versions/A/ApplicationServices",
+ RTLD_LAZY | RTLD_LOCAL);
+ core_foundation_handle = dlopen("/System/Library/Frameworks/"
+ "CoreFoundation.framework/"
+ "Versions/A/CoreFoundation",
+ RTLD_LAZY | RTLD_LOCAL);
+
+ if (application_services_handle == NULL || core_foundation_handle == NULL)
+ goto out;
+
+ *(void **)(&pCFStringCreateWithCString) =
+ dlsym(core_foundation_handle, "CFStringCreateWithCString");
+ *(void **)(&pCFBundleGetBundleWithIdentifier) =
+ dlsym(core_foundation_handle, "CFBundleGetBundleWithIdentifier");
+ *(void **)(&pCFBundleGetDataPointerForName) =
+ dlsym(core_foundation_handle, "CFBundleGetDataPointerForName");
+ *(void **)(&pCFBundleGetFunctionPointerForName) =
+ dlsym(core_foundation_handle, "CFBundleGetFunctionPointerForName");
+
+ if (pCFStringCreateWithCString == NULL ||
+ pCFBundleGetBundleWithIdentifier == NULL ||
+ pCFBundleGetDataPointerForName == NULL ||
+ pCFBundleGetFunctionPointerForName == NULL) {
+ goto out;
+ }
+
+#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
+
+ launch_services_bundle =
+ pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices"));
+
+ if (launch_services_bundle == NULL)
+ goto out;
+
+ *(void **)(&pLSGetCurrentApplicationASN) =
+ pCFBundleGetFunctionPointerForName(launch_services_bundle,
+ S("_LSGetCurrentApplicationASN"));
+
+ if (pLSGetCurrentApplicationASN == NULL)
+ goto out;
+
+ *(void **)(&pLSSetApplicationInformationItem) =
+ pCFBundleGetFunctionPointerForName(launch_services_bundle,
+ S("_LSSetApplicationInformationItem"));
+
+ if (pLSSetApplicationInformationItem == NULL)
+ goto out;
+
+ display_name_key = pCFBundleGetDataPointerForName(launch_services_bundle,
+ S("_kLSDisplayNameKey"));
+
+ if (display_name_key == NULL || *display_name_key == NULL)
+ goto out;
+
+ *(void **)(&pCFBundleGetInfoDictionary) = dlsym(core_foundation_handle,
+ "CFBundleGetInfoDictionary");
+ *(void **)(&pCFBundleGetMainBundle) = dlsym(core_foundation_handle,
+ "CFBundleGetMainBundle");
+ if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL)
+ goto out;
+
+ /* Black 10.9 magic, to remove (Not responding) mark in Activity Monitor */
+ hi_services_bundle =
+ pCFBundleGetBundleWithIdentifier(S("com.apple.HIServices"));
+ err = -ENOENT;
+ if (hi_services_bundle == NULL)
+ goto out;
+
+ *(void **)(&pSetApplicationIsDaemon) = pCFBundleGetFunctionPointerForName(
+ hi_services_bundle,
+ S("SetApplicationIsDaemon"));
+ *(void **)(&pLSApplicationCheckIn) = pCFBundleGetFunctionPointerForName(
+ launch_services_bundle,
+ S("_LSApplicationCheckIn"));
+ *(void **)(&pLSSetApplicationLaunchServicesServerConnectionStatus) =
+ pCFBundleGetFunctionPointerForName(
+ launch_services_bundle,
+ S("_LSSetApplicationLaunchServicesServerConnectionStatus"));
+ if (pSetApplicationIsDaemon == NULL ||
+ pLSApplicationCheckIn == NULL ||
+ pLSSetApplicationLaunchServicesServerConnectionStatus == NULL) {
+ goto out;
+ }
+
+ if (pSetApplicationIsDaemon(1) != noErr)
+ goto out;
+
+ pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL);
+
+ /* Check into process manager?! */
+ pLSApplicationCheckIn(-2,
+ pCFBundleGetInfoDictionary(pCFBundleGetMainBundle()));
+
+ asn = pLSGetCurrentApplicationASN();
+
+ err = -EINVAL;
+ if (pLSSetApplicationInformationItem(-2, /* Magic value. */
+ asn,
+ *display_name_key,
+ S(title),
+ NULL) != noErr) {
+ goto out;
+ }
+
+ uv__pthread_setname_np(title); /* Don't care if it fails. */
+ err = 0;
+
+out:
+ if (core_foundation_handle != NULL)
+ dlclose(core_foundation_handle);
+
+ if (application_services_handle != NULL)
+ dlclose(application_services_handle);
+
+ return err;
+#endif /* !TARGET_OS_IPHONE */
+}
diff --git a/3rdparty/libuv/src/unix/darwin.c b/3rdparty/libuv/src/unix/darwin.c
new file mode 100644
index 00000000000..cf95da21693
--- /dev/null
+++ b/3rdparty/libuv/src/unix/darwin.c
@@ -0,0 +1,335 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <mach-o/dyld.h> /* _NSGetExecutablePath */
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <unistd.h> /* sysconf */
+
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ loop->cf_state = NULL;
+
+ if (uv__kqueue_init(loop))
+ return -errno;
+
+ return 0;
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+ uv__fsevents_loop_delete(loop);
+}
+
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ static mach_timebase_info_data_t info;
+
+ if ((ACCESS_ONCE(uint32_t, info.numer) == 0 ||
+ ACCESS_ONCE(uint32_t, info.denom) == 0) &&
+ mach_timebase_info(&info) != KERN_SUCCESS)
+ abort();
+
+ return mach_absolute_time() * info.numer / info.denom;
+}
+
+
+int uv_exepath(char* buffer, size_t* size) {
+ /* realpath(exepath) may be > PATH_MAX so double it to be on the safe side. */
+ char abspath[PATH_MAX * 2 + 1];
+ char exepath[PATH_MAX + 1];
+ uint32_t exepath_size;
+ size_t abspath_size;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ exepath_size = sizeof(exepath);
+ if (_NSGetExecutablePath(exepath, &exepath_size))
+ return -EIO;
+
+ if (realpath(exepath, abspath) != abspath)
+ return -errno;
+
+ abspath_size = strlen(abspath);
+ if (abspath_size == 0)
+ return -EIO;
+
+ *size -= 1;
+ if (*size > abspath_size)
+ *size = abspath_size;
+
+ memcpy(buffer, abspath, *size);
+ buffer[*size] = '\0';
+
+ return 0;
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ vm_statistics_data_t info;
+ mach_msg_type_number_t count = sizeof(info) / sizeof(integer_t);
+
+ if (host_statistics(mach_host_self(), HOST_VM_INFO,
+ (host_info_t)&info, &count) != KERN_SUCCESS) {
+ return -EINVAL; /* FIXME(bnoordhuis) Translate error. */
+ }
+
+ return (uint64_t) info.free_count * sysconf(_SC_PAGESIZE);
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ uint64_t info;
+ int which[] = {CTL_HW, HW_MEMSIZE};
+ size_t size = sizeof(info);
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) info;
+}
+
+
+void uv_loadavg(double avg[3]) {
+ struct loadavg info;
+ size_t size = sizeof(info);
+ int which[] = {CTL_VM, VM_LOADAVG};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
+
+ avg[0] = (double) info.ldavg[0] / info.fscale;
+ avg[1] = (double) info.ldavg[1] / info.fscale;
+ avg[2] = (double) info.ldavg[2] / info.fscale;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ mach_msg_type_number_t count;
+ task_basic_info_data_t info;
+ kern_return_t err;
+
+ count = TASK_BASIC_INFO_COUNT;
+ err = task_info(mach_task_self(),
+ TASK_BASIC_INFO,
+ (task_info_t) &info,
+ &count);
+ (void) &err;
+ /* task_info(TASK_BASIC_INFO) cannot really fail. Anything other than
+ * KERN_SUCCESS implies a libuv bug.
+ */
+ assert(err == KERN_SUCCESS);
+ *rss = info.resident_size;
+
+ return 0;
+}
+
+
+int uv_uptime(double* uptime) {
+ time_t now;
+ struct timeval info;
+ size_t size = sizeof(info);
+ static int which[] = {CTL_KERN, KERN_BOOTTIME};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ now = time(NULL);
+ *uptime = now - info.tv_sec;
+
+ return 0;
+}
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
+ multiplier = ((uint64_t)1000L / ticks);
+ char model[512];
+ uint64_t cpuspeed;
+ size_t size;
+ unsigned int i;
+ natural_t numcpus;
+ mach_msg_type_number_t msg_type;
+ processor_cpu_load_info_data_t *info;
+ uv_cpu_info_t* cpu_info;
+
+ size = sizeof(model);
+ if (sysctlbyname("machdep.cpu.brand_string", &model, &size, NULL, 0) &&
+ sysctlbyname("hw.model", &model, &size, NULL, 0)) {
+ return -errno;
+ }
+
+ size = sizeof(cpuspeed);
+ if (sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0))
+ return -errno;
+
+ if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus,
+ (processor_info_array_t*)&info,
+ &msg_type) != KERN_SUCCESS) {
+ return -EINVAL; /* FIXME(bnoordhuis) Translate error. */
+ }
+
+ *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
+ if (!(*cpu_infos)) {
+ vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);
+ return -ENOMEM;
+ }
+
+ *count = numcpus;
+
+ for (i = 0; i < numcpus; i++) {
+ cpu_info = &(*cpu_infos)[i];
+
+ cpu_info->cpu_times.user = (uint64_t)(info[i].cpu_ticks[0]) * multiplier;
+ cpu_info->cpu_times.nice = (uint64_t)(info[i].cpu_ticks[3]) * multiplier;
+ cpu_info->cpu_times.sys = (uint64_t)(info[i].cpu_ticks[1]) * multiplier;
+ cpu_info->cpu_times.idle = (uint64_t)(info[i].cpu_ticks[2]) * multiplier;
+ cpu_info->cpu_times.irq = 0;
+
+ cpu_info->model = uv__strdup(model);
+ cpu_info->speed = cpuspeed/1000000;
+ }
+ vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);
+
+ return 0;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
+ struct ifaddrs *addrs, *ent;
+ uv_interface_address_t* address;
+ int i;
+ struct sockaddr_dl *sa_addr;
+
+ if (getifaddrs(&addrs))
+ return -errno;
+
+ *count = 0;
+
+ /* Count the number of interfaces */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family == AF_LINK)) {
+ continue;
+ }
+
+ (*count)++;
+ }
+
+ *addresses = uv__malloc(*count * sizeof(**addresses));
+ if (!(*addresses)) {
+ freeifaddrs(addrs);
+ return -ENOMEM;
+ }
+
+ address = *addresses;
+
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
+ continue;
+
+ if (ent->ifa_addr == NULL)
+ continue;
+
+ /*
+ * On Mac OS X getifaddrs returns information related to Mac Addresses for
+ * various devices, such as firewire, etc. These are not relevant here.
+ */
+ if (ent->ifa_addr->sa_family == AF_LINK)
+ continue;
+
+ address->name = uv__strdup(ent->ifa_name);
+
+ if (ent->ifa_addr->sa_family == AF_INET6) {
+ address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
+ } else {
+ address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
+ }
+
+ if (ent->ifa_netmask->sa_family == AF_INET6) {
+ address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
+ } else {
+ address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
+ }
+
+ address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
+
+ address++;
+ }
+
+ /* Fill in physical addresses for each interface */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family != AF_LINK)) {
+ continue;
+ }
+
+ address = *addresses;
+
+ for (i = 0; i < (*count); i++) {
+ if (strcmp(address->name, ent->ifa_name) == 0) {
+ sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
+ memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
+ }
+ address++;
+ }
+ }
+
+ freeifaddrs(addrs);
+
+ return 0;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(addresses[i].name);
+ }
+
+ uv__free(addresses);
+}
diff --git a/3rdparty/libuv/src/unix/dl.c b/3rdparty/libuv/src/unix/dl.c
new file mode 100644
index 00000000000..fc1c052bb81
--- /dev/null
+++ b/3rdparty/libuv/src/unix/dl.c
@@ -0,0 +1,80 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+#include <locale.h>
+
+static int uv__dlerror(uv_lib_t* lib);
+
+
+int uv_dlopen(const char* filename, uv_lib_t* lib) {
+ dlerror(); /* Reset error status. */
+ lib->errmsg = NULL;
+ lib->handle = dlopen(filename, RTLD_LAZY);
+ return lib->handle ? 0 : uv__dlerror(lib);
+}
+
+
+void uv_dlclose(uv_lib_t* lib) {
+ uv__free(lib->errmsg);
+ lib->errmsg = NULL;
+
+ if (lib->handle) {
+ /* Ignore errors. No good way to signal them without leaking memory. */
+ dlclose(lib->handle);
+ lib->handle = NULL;
+ }
+}
+
+
+int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
+ dlerror(); /* Reset error status. */
+ *ptr = dlsym(lib->handle, name);
+ return uv__dlerror(lib);
+}
+
+
+const char* uv_dlerror(const uv_lib_t* lib) {
+ return lib->errmsg ? lib->errmsg : "no error";
+}
+
+
+static int uv__dlerror(uv_lib_t* lib) {
+ const char* errmsg;
+
+ uv__free(lib->errmsg);
+
+ errmsg = dlerror();
+
+ if (errmsg) {
+ lib->errmsg = uv__strdup(errmsg);
+ return -1;
+ }
+ else {
+ lib->errmsg = NULL;
+ return 0;
+ }
+}
diff --git a/3rdparty/libuv/src/unix/freebsd.c b/3rdparty/libuv/src/unix/freebsd.c
new file mode 100644
index 00000000000..b747abdf5bc
--- /dev/null
+++ b/3rdparty/libuv/src/unix/freebsd.c
@@ -0,0 +1,450 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+
+#include <kvm.h>
+#include <paths.h>
+#include <sys/user.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <vm/vm_param.h> /* VM_LOADAVG */
+#include <time.h>
+#include <stdlib.h>
+#include <unistd.h> /* sysconf */
+#include <fcntl.h>
+
+#undef NANOSEC
+#define NANOSEC ((uint64_t) 1e9)
+
+#ifndef CPUSTATES
+# define CPUSTATES 5U
+#endif
+#ifndef CP_USER
+# define CP_USER 0
+# define CP_NICE 1
+# define CP_SYS 2
+# define CP_IDLE 3
+# define CP_INTR 4
+#endif
+
+static char *process_title;
+
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ return uv__kqueue_init(loop);
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+}
+
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
+}
+
+
+#ifdef __DragonFly__
+int uv_exepath(char* buffer, size_t* size) {
+ char abspath[PATH_MAX * 2 + 1];
+ ssize_t abspath_size;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ abspath_size = readlink("/proc/curproc/file", abspath, sizeof(abspath));
+ if (abspath_size < 0)
+ return -errno;
+
+ assert(abspath_size > 0);
+ *size -= 1;
+
+ if (*size > abspath_size)
+ *size = abspath_size;
+
+ memcpy(buffer, abspath, *size);
+ buffer[*size] = '\0';
+
+ return 0;
+}
+#else
+int uv_exepath(char* buffer, size_t* size) {
+ char abspath[PATH_MAX * 2 + 1];
+ int mib[4];
+ size_t abspath_size;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PATHNAME;
+ mib[3] = -1;
+
+ abspath_size = sizeof abspath;
+ if (sysctl(mib, 4, abspath, &abspath_size, NULL, 0))
+ return -errno;
+
+ assert(abspath_size > 0);
+ abspath_size -= 1;
+ *size -= 1;
+
+ if (*size > abspath_size)
+ *size = abspath_size;
+
+ memcpy(buffer, abspath, *size);
+ buffer[*size] = '\0';
+
+ return 0;
+}
+#endif
+
+uint64_t uv_get_free_memory(void) {
+ int freecount;
+ size_t size = sizeof(freecount);
+
+ if (sysctlbyname("vm.stats.vm.v_free_count", &freecount, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) freecount * sysconf(_SC_PAGESIZE);
+
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ unsigned long info;
+ int which[] = {CTL_HW, HW_PHYSMEM};
+
+ size_t size = sizeof(info);
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) info;
+}
+
+
+void uv_loadavg(double avg[3]) {
+ struct loadavg info;
+ size_t size = sizeof(info);
+ int which[] = {CTL_VM, VM_LOADAVG};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
+
+ avg[0] = (double) info.ldavg[0] / info.fscale;
+ avg[1] = (double) info.ldavg[1] / info.fscale;
+ avg[2] = (double) info.ldavg[2] / info.fscale;
+}
+
+
+char** uv_setup_args(int argc, char** argv) {
+ process_title = argc ? uv__strdup(argv[0]) : NULL;
+ return argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ int oid[4];
+
+ uv__free(process_title);
+ process_title = uv__strdup(title);
+
+ oid[0] = CTL_KERN;
+ oid[1] = KERN_PROC;
+ oid[2] = KERN_PROC_ARGS;
+ oid[3] = getpid();
+
+ sysctl(oid,
+ ARRAY_SIZE(oid),
+ NULL,
+ NULL,
+ process_title,
+ strlen(process_title) + 1);
+
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ if (process_title) {
+ strncpy(buffer, process_title, size);
+ } else {
+ if (size > 0) {
+ buffer[0] = '\0';
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ kvm_t *kd = NULL;
+ struct kinfo_proc *kinfo = NULL;
+ pid_t pid;
+ int nprocs;
+ size_t page_size = getpagesize();
+
+ pid = getpid();
+
+ kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
+ if (kd == NULL) goto error;
+
+ kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, &nprocs);
+ if (kinfo == NULL) goto error;
+
+#ifdef __DragonFly__
+ *rss = kinfo->kp_vm_rssize * page_size;
+#else
+ *rss = kinfo->ki_rssize * page_size;
+#endif
+
+ kvm_close(kd);
+
+ return 0;
+
+error:
+ if (kd) kvm_close(kd);
+ return -EPERM;
+}
+
+
+int uv_uptime(double* uptime) {
+ int r;
+ struct timespec sp;
+ r = clock_gettime(CLOCK_MONOTONIC, &sp);
+ if (r)
+ return -errno;
+
+ *uptime = sp.tv_sec;
+ return 0;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
+ multiplier = ((uint64_t)1000L / ticks), cpuspeed, maxcpus,
+ cur = 0;
+ uv_cpu_info_t* cpu_info;
+ const char* maxcpus_key;
+ const char* cptimes_key;
+ char model[512];
+ long* cp_times;
+ int numcpus;
+ size_t size;
+ int i;
+
+#if defined(__DragonFly__)
+ /* This is not quite correct but DragonFlyBSD doesn't seem to have anything
+ * comparable to kern.smp.maxcpus or kern.cp_times (kern.cp_time is a total,
+ * not per CPU). At least this stops uv_cpu_info() from failing completely.
+ */
+ maxcpus_key = "hw.ncpu";
+ cptimes_key = "kern.cp_time";
+#else
+ maxcpus_key = "kern.smp.maxcpus";
+ cptimes_key = "kern.cp_times";
+#endif
+
+ size = sizeof(model);
+ if (sysctlbyname("hw.model", &model, &size, NULL, 0))
+ return -errno;
+
+ size = sizeof(numcpus);
+ if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0))
+ return -errno;
+
+ *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
+ if (!(*cpu_infos))
+ return -ENOMEM;
+
+ *count = numcpus;
+
+ size = sizeof(cpuspeed);
+ if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) {
+ SAVE_ERRNO(uv__free(*cpu_infos));
+ return -errno;
+ }
+
+ /* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of
+ * ncpu.
+ */
+ size = sizeof(maxcpus);
+ if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) {
+ SAVE_ERRNO(uv__free(*cpu_infos));
+ return -errno;
+ }
+
+ size = maxcpus * CPUSTATES * sizeof(long);
+
+ cp_times = uv__malloc(size);
+ if (cp_times == NULL) {
+ uv__free(*cpu_infos);
+ return -ENOMEM;
+ }
+
+ if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) {
+ SAVE_ERRNO(uv__free(cp_times));
+ SAVE_ERRNO(uv__free(*cpu_infos));
+ return -errno;
+ }
+
+ for (i = 0; i < numcpus; i++) {
+ cpu_info = &(*cpu_infos)[i];
+
+ cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier;
+ cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier;
+ cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier;
+ cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier;
+ cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier;
+
+ cpu_info->model = uv__strdup(model);
+ cpu_info->speed = cpuspeed;
+
+ cur+=CPUSTATES;
+ }
+
+ uv__free(cp_times);
+ return 0;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
+ struct ifaddrs *addrs, *ent;
+ uv_interface_address_t* address;
+ int i;
+ struct sockaddr_dl *sa_addr;
+
+ if (getifaddrs(&addrs))
+ return -errno;
+
+ *count = 0;
+
+ /* Count the number of interfaces */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family == AF_LINK)) {
+ continue;
+ }
+
+ (*count)++;
+ }
+
+ *addresses = uv__malloc(*count * sizeof(**addresses));
+ if (!(*addresses)) {
+ freeifaddrs(addrs);
+ return -ENOMEM;
+ }
+
+ address = *addresses;
+
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
+ continue;
+
+ if (ent->ifa_addr == NULL)
+ continue;
+
+ /*
+ * On FreeBSD getifaddrs returns information related to the raw underlying
+ * devices. We're not interested in this information yet.
+ */
+ if (ent->ifa_addr->sa_family == AF_LINK)
+ continue;
+
+ address->name = uv__strdup(ent->ifa_name);
+
+ if (ent->ifa_addr->sa_family == AF_INET6) {
+ address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
+ } else {
+ address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
+ }
+
+ if (ent->ifa_netmask->sa_family == AF_INET6) {
+ address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
+ } else {
+ address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
+ }
+
+ address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
+
+ address++;
+ }
+
+ /* Fill in physical addresses for each interface */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family != AF_LINK)) {
+ continue;
+ }
+
+ address = *addresses;
+
+ for (i = 0; i < (*count); i++) {
+ if (strcmp(address->name, ent->ifa_name) == 0) {
+ sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
+ memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
+ }
+ address++;
+ }
+ }
+
+ freeifaddrs(addrs);
+
+ return 0;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(addresses[i].name);
+ }
+
+ uv__free(addresses);
+}
diff --git a/3rdparty/libuv/src/unix/fs.c b/3rdparty/libuv/src/unix/fs.c
new file mode 100644
index 00000000000..57b65be25a8
--- /dev/null
+++ b/3rdparty/libuv/src/unix/fs.c
@@ -0,0 +1,1310 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* Caveat emptor: this file deviates from the libuv convention of returning
+ * negated errno codes. Most uv_fs_*() functions map directly to the system
+ * call of the same name. For more complex wrappers, it's easier to just
+ * return -1 with errno set. The dispatcher in uv__fs_work() takes care of
+ * getting the errno to the right place (req->result or as the return value.)
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utime.h>
+#include <poll.h>
+
+#if defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__)
+# define HAVE_PREADV 1
+#else
+# define HAVE_PREADV 0
+#endif
+
+#if defined(__linux__) || defined(__sun)
+# include <sys/sendfile.h>
+#endif
+
+#define INIT(subtype) \
+ do { \
+ req->type = UV_FS; \
+ if (cb != NULL) \
+ uv__req_init(loop, req, UV_FS); \
+ req->fs_type = UV_FS_ ## subtype; \
+ req->result = 0; \
+ req->ptr = NULL; \
+ req->loop = loop; \
+ req->path = NULL; \
+ req->new_path = NULL; \
+ req->cb = cb; \
+ } \
+ while (0)
+
+#define PATH \
+ do { \
+ assert(path != NULL); \
+ if (cb == NULL) { \
+ req->path = path; \
+ } else { \
+ req->path = uv__strdup(path); \
+ if (req->path == NULL) { \
+ uv__req_unregister(loop, req); \
+ return -ENOMEM; \
+ } \
+ } \
+ } \
+ while (0)
+
+#define PATH2 \
+ do { \
+ if (cb == NULL) { \
+ req->path = path; \
+ req->new_path = new_path; \
+ } else { \
+ size_t path_len; \
+ size_t new_path_len; \
+ path_len = strlen(path) + 1; \
+ new_path_len = strlen(new_path) + 1; \
+ req->path = uv__malloc(path_len + new_path_len); \
+ if (req->path == NULL) { \
+ uv__req_unregister(loop, req); \
+ return -ENOMEM; \
+ } \
+ req->new_path = req->path + path_len; \
+ memcpy((void*) req->path, path, path_len); \
+ memcpy((void*) req->new_path, new_path, new_path_len); \
+ } \
+ } \
+ while (0)
+
+#define POST \
+ do { \
+ if (cb != NULL) { \
+ uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \
+ return 0; \
+ } \
+ else { \
+ uv__fs_work(&req->work_req); \
+ return req->result; \
+ } \
+ } \
+ while (0)
+
+
+static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
+#if defined(__linux__) || defined(__sun) || defined(__NetBSD__)
+ return fdatasync(req->file);
+#elif defined(__APPLE__) && defined(F_FULLFSYNC)
+ return fcntl(req->file, F_FULLFSYNC);
+#else
+ return fsync(req->file);
+#endif
+}
+
+
+static ssize_t uv__fs_futime(uv_fs_t* req) {
+#if defined(__linux__)
+ /* utimesat() has nanosecond resolution but we stick to microseconds
+ * for the sake of consistency with other platforms.
+ */
+ static int no_utimesat;
+ struct timespec ts[2];
+ struct timeval tv[2];
+ char path[sizeof("/proc/self/fd/") + 3 * sizeof(int)];
+ int r;
+
+ if (no_utimesat)
+ goto skip;
+
+ ts[0].tv_sec = req->atime;
+ ts[0].tv_nsec = (unsigned long)(req->atime * 1000000) % 1000000 * 1000;
+ ts[1].tv_sec = req->mtime;
+ ts[1].tv_nsec = (unsigned long)(req->mtime * 1000000) % 1000000 * 1000;
+
+ r = uv__utimesat(req->file, NULL, ts, 0);
+ if (r == 0)
+ return r;
+
+ if (errno != ENOSYS)
+ return r;
+
+ no_utimesat = 1;
+
+skip:
+
+ tv[0].tv_sec = req->atime;
+ tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000;
+ tv[1].tv_sec = req->mtime;
+ tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000;
+ snprintf(path, sizeof(path), "/proc/self/fd/%d", (int) req->file);
+
+ r = utimes(path, tv);
+ if (r == 0)
+ return r;
+
+ switch (errno) {
+ case ENOENT:
+ if (fcntl(req->file, F_GETFL) == -1 && errno == EBADF)
+ break;
+ /* Fall through. */
+
+ case EACCES:
+ case ENOTDIR:
+ errno = ENOSYS;
+ break;
+ }
+
+ return r;
+
+#elif defined(__APPLE__) \
+ || defined(__DragonFly__) \
+ || defined(__FreeBSD__) \
+ || defined(__NetBSD__) \
+ || defined(__OpenBSD__) \
+ || defined(__sun)
+ struct timeval tv[2];
+ tv[0].tv_sec = req->atime;
+ tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000;
+ tv[1].tv_sec = req->mtime;
+ tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000;
+# if defined(__sun)
+ return futimesat(req->file, NULL, tv);
+# else
+ return futimes(req->file, tv);
+# endif
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+
+static ssize_t uv__fs_mkdtemp(uv_fs_t* req) {
+ return mkdtemp((char*) req->path) ? 0 : -1;
+}
+
+
+static ssize_t uv__fs_open(uv_fs_t* req) {
+ static int no_cloexec_support;
+ int r;
+
+ /* Try O_CLOEXEC before entering locks */
+ if (no_cloexec_support == 0) {
+#ifdef O_CLOEXEC
+ r = open(req->path, req->flags | O_CLOEXEC, req->mode);
+ if (r >= 0)
+ return r;
+ if (errno != EINVAL)
+ return r;
+ no_cloexec_support = 1;
+#endif /* O_CLOEXEC */
+ }
+
+ if (req->cb != NULL)
+ uv_rwlock_rdlock(&req->loop->cloexec_lock);
+
+ r = open(req->path, req->flags, req->mode);
+
+ /* In case of failure `uv__cloexec` will leave error in `errno`,
+ * so it is enough to just set `r` to `-1`.
+ */
+ if (r >= 0 && uv__cloexec(r, 1) != 0) {
+ r = uv__close(r);
+ if (r != 0 && r != -EINPROGRESS)
+ abort();
+ r = -1;
+ }
+
+ if (req->cb != NULL)
+ uv_rwlock_rdunlock(&req->loop->cloexec_lock);
+
+ return r;
+}
+
+
+static ssize_t uv__fs_read(uv_fs_t* req) {
+#if defined(__linux__)
+ static int no_preadv;
+#endif
+ ssize_t result;
+
+#if defined(_AIX)
+ struct stat buf;
+ if(fstat(req->file, &buf))
+ return -1;
+ if(S_ISDIR(buf.st_mode)) {
+ errno = EISDIR;
+ return -1;
+ }
+#endif /* defined(_AIX) */
+ if (req->off < 0) {
+ if (req->nbufs == 1)
+ result = read(req->file, req->bufs[0].base, req->bufs[0].len);
+ else
+ result = readv(req->file, (struct iovec*) req->bufs, req->nbufs);
+ } else {
+ if (req->nbufs == 1) {
+ result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
+ goto done;
+ }
+
+#if HAVE_PREADV
+ result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
+#else
+# if defined(__linux__)
+ if (no_preadv) retry:
+# endif
+ {
+ off_t nread;
+ size_t index;
+
+ nread = 0;
+ index = 0;
+ result = 1;
+ do {
+ if (req->bufs[index].len > 0) {
+ result = pread(req->file,
+ req->bufs[index].base,
+ req->bufs[index].len,
+ req->off + nread);
+ if (result > 0)
+ nread += result;
+ }
+ index++;
+ } while (index < req->nbufs && result > 0);
+ if (nread > 0)
+ result = nread;
+ }
+# if defined(__linux__)
+ else {
+ result = uv__preadv(req->file,
+ (struct iovec*)req->bufs,
+ req->nbufs,
+ req->off);
+ if (result == -1 && errno == ENOSYS) {
+ no_preadv = 1;
+ goto retry;
+ }
+ }
+# endif
+#endif
+ }
+
+done:
+ return result;
+}
+
+
+#if defined(__OpenBSD__) || (defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8))
+static int uv__fs_scandir_filter(uv__dirent_t* dent) {
+#else
+static int uv__fs_scandir_filter(const uv__dirent_t* dent) {
+#endif
+ return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0;
+}
+
+
+static ssize_t uv__fs_scandir(uv_fs_t* req) {
+ uv__dirent_t **dents;
+ int saved_errno;
+ int n;
+
+ dents = NULL;
+ n = scandir(req->path, &dents, uv__fs_scandir_filter, alphasort);
+
+ /* NOTE: We will use nbufs as an index field */
+ req->nbufs = 0;
+
+ if (n == 0)
+ goto out; /* osx still needs to deallocate some memory */
+ else if (n == -1)
+ return n;
+
+ req->ptr = dents;
+
+ return n;
+
+out:
+ saved_errno = errno;
+ if (dents != NULL) {
+ int i;
+
+ for (i = 0; i < n; i++)
+ uv__free(dents[i]);
+ uv__free(dents);
+ }
+ errno = saved_errno;
+
+ req->ptr = NULL;
+
+ return n;
+}
+
+
+static ssize_t uv__fs_pathmax_size(const char* path) {
+ ssize_t pathmax;
+
+ pathmax = pathconf(path, _PC_PATH_MAX);
+
+ if (pathmax == -1) {
+#if defined(PATH_MAX)
+ return PATH_MAX;
+#else
+ return 4096;
+#endif
+ }
+
+ return pathmax;
+}
+
+static ssize_t uv__fs_readlink(uv_fs_t* req) {
+ ssize_t len;
+ char* buf;
+
+ len = uv__fs_pathmax_size(req->path);
+ buf = uv__malloc(len + 1);
+
+ if (buf == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ len = readlink(req->path, buf, len);
+
+ if (len == -1) {
+ uv__free(buf);
+ return -1;
+ }
+
+ buf[len] = '\0';
+ req->ptr = buf;
+
+ return 0;
+}
+
+static ssize_t uv__fs_realpath(uv_fs_t* req) {
+ ssize_t len;
+ char* buf;
+
+ len = uv__fs_pathmax_size(req->path);
+ buf = uv__malloc(len + 1);
+
+ if (buf == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (realpath(req->path, buf) == NULL) {
+ uv__free(buf);
+ return -1;
+ }
+
+ req->ptr = buf;
+
+ return 0;
+}
+
+static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) {
+ struct pollfd pfd;
+ int use_pread;
+ off_t offset;
+ ssize_t nsent;
+ ssize_t nread;
+ ssize_t nwritten;
+ size_t buflen;
+ size_t len;
+ ssize_t n;
+ int in_fd;
+ int out_fd;
+ char buf[8192];
+
+ len = req->bufsml[0].len;
+ in_fd = req->flags;
+ out_fd = req->file;
+ offset = req->off;
+ use_pread = 1;
+
+ /* Here are the rules regarding errors:
+ *
+ * 1. Read errors are reported only if nsent==0, otherwise we return nsent.
+ * The user needs to know that some data has already been sent, to stop
+ * them from sending it twice.
+ *
+ * 2. Write errors are always reported. Write errors are bad because they
+ * mean data loss: we've read data but now we can't write it out.
+ *
+ * We try to use pread() and fall back to regular read() if the source fd
+ * doesn't support positional reads, for example when it's a pipe fd.
+ *
+ * If we get EAGAIN when writing to the target fd, we poll() on it until
+ * it becomes writable again.
+ *
+ * FIXME: If we get a write error when use_pread==1, it should be safe to
+ * return the number of sent bytes instead of an error because pread()
+ * is, in theory, idempotent. However, special files in /dev or /proc
+ * may support pread() but not necessarily return the same data on
+ * successive reads.
+ *
+ * FIXME: There is no way now to signal that we managed to send *some* data
+ * before a write error.
+ */
+ for (nsent = 0; (size_t) nsent < len; ) {
+ buflen = len - nsent;
+
+ if (buflen > sizeof(buf))
+ buflen = sizeof(buf);
+
+ do
+ if (use_pread)
+ nread = pread(in_fd, buf, buflen, offset);
+ else
+ nread = read(in_fd, buf, buflen);
+ while (nread == -1 && errno == EINTR);
+
+ if (nread == 0)
+ goto out;
+
+ if (nread == -1) {
+ if (use_pread && nsent == 0 && (errno == EIO || errno == ESPIPE)) {
+ use_pread = 0;
+ continue;
+ }
+
+ if (nsent == 0)
+ nsent = -1;
+
+ goto out;
+ }
+
+ for (nwritten = 0; nwritten < nread; ) {
+ do
+ n = write(out_fd, buf + nwritten, nread - nwritten);
+ while (n == -1 && errno == EINTR);
+
+ if (n != -1) {
+ nwritten += n;
+ continue;
+ }
+
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ nsent = -1;
+ goto out;
+ }
+
+ pfd.fd = out_fd;
+ pfd.events = POLLOUT;
+ pfd.revents = 0;
+
+ do
+ n = poll(&pfd, 1, -1);
+ while (n == -1 && errno == EINTR);
+
+ if (n == -1 || (pfd.revents & ~POLLOUT) != 0) {
+ errno = EIO;
+ nsent = -1;
+ goto out;
+ }
+ }
+
+ offset += nread;
+ nsent += nread;
+ }
+
+out:
+ if (nsent != -1)
+ req->off = offset;
+
+ return nsent;
+}
+
+
+static ssize_t uv__fs_sendfile(uv_fs_t* req) {
+ int in_fd;
+ int out_fd;
+
+ in_fd = req->flags;
+ out_fd = req->file;
+
+#if defined(__linux__) || defined(__sun)
+ {
+ off_t off;
+ ssize_t r;
+
+ off = req->off;
+ r = sendfile(out_fd, in_fd, &off, req->bufsml[0].len);
+
+ /* sendfile() on SunOS returns EINVAL if the target fd is not a socket but
+ * it still writes out data. Fortunately, we can detect it by checking if
+ * the offset has been updated.
+ */
+ if (r != -1 || off > req->off) {
+ r = off - req->off;
+ req->off = off;
+ return r;
+ }
+
+ if (errno == EINVAL ||
+ errno == EIO ||
+ errno == ENOTSOCK ||
+ errno == EXDEV) {
+ errno = 0;
+ return uv__fs_sendfile_emul(req);
+ }
+
+ return -1;
+ }
+#elif defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__)
+ {
+ off_t len;
+ ssize_t r;
+
+ /* sendfile() on FreeBSD and Darwin returns EAGAIN if the target fd is in
+ * non-blocking mode and not all data could be written. If a non-zero
+ * number of bytes have been sent, we don't consider it an error.
+ */
+
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+ len = 0;
+ r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0);
+#else
+ /* The darwin sendfile takes len as an input for the length to send,
+ * so make sure to initialize it with the caller's value. */
+ len = req->bufsml[0].len;
+ r = sendfile(in_fd, out_fd, req->off, &len, NULL, 0);
+#endif
+
+ /*
+ * The man page for sendfile(2) on DragonFly states that `len` contains
+ * a meaningful value ONLY in case of EAGAIN and EINTR.
+ * Nothing is said about it's value in case of other errors, so better
+ * not depend on the potential wrong assumption that is was not modified
+ * by the syscall.
+ */
+ if (r == 0 || ((errno == EAGAIN || errno == EINTR) && len != 0)) {
+ req->off += len;
+ return (ssize_t) len;
+ }
+
+ if (errno == EINVAL ||
+ errno == EIO ||
+ errno == ENOTSOCK ||
+ errno == EXDEV) {
+ errno = 0;
+ return uv__fs_sendfile_emul(req);
+ }
+
+ return -1;
+ }
+#else
+ /* Squelch compiler warnings. */
+ (void) &in_fd;
+ (void) &out_fd;
+
+ return uv__fs_sendfile_emul(req);
+#endif
+}
+
+
+static ssize_t uv__fs_utime(uv_fs_t* req) {
+ struct utimbuf buf;
+ buf.actime = req->atime;
+ buf.modtime = req->mtime;
+ return utime(req->path, &buf); /* TODO use utimes() where available */
+}
+
+
+static ssize_t uv__fs_write(uv_fs_t* req) {
+#if defined(__linux__)
+ static int no_pwritev;
+#endif
+ ssize_t r;
+
+ /* Serialize writes on OS X, concurrent write() and pwrite() calls result in
+ * data loss. We can't use a per-file descriptor lock, the descriptor may be
+ * a dup().
+ */
+#if defined(__APPLE__)
+ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+ if (pthread_mutex_lock(&lock))
+ abort();
+#endif
+
+ if (req->off < 0) {
+ if (req->nbufs == 1)
+ r = write(req->file, req->bufs[0].base, req->bufs[0].len);
+ else
+ r = writev(req->file, (struct iovec*) req->bufs, req->nbufs);
+ } else {
+ if (req->nbufs == 1) {
+ r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
+ goto done;
+ }
+#if HAVE_PREADV
+ r = pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
+#else
+# if defined(__linux__)
+ if (no_pwritev) retry:
+# endif
+ {
+ off_t written;
+ size_t index;
+
+ written = 0;
+ index = 0;
+ r = 0;
+ do {
+ if (req->bufs[index].len > 0) {
+ r = pwrite(req->file,
+ req->bufs[index].base,
+ req->bufs[index].len,
+ req->off + written);
+ if (r > 0)
+ written += r;
+ }
+ index++;
+ } while (index < req->nbufs && r >= 0);
+ if (written > 0)
+ r = written;
+ }
+# if defined(__linux__)
+ else {
+ r = uv__pwritev(req->file,
+ (struct iovec*) req->bufs,
+ req->nbufs,
+ req->off);
+ if (r == -1 && errno == ENOSYS) {
+ no_pwritev = 1;
+ goto retry;
+ }
+ }
+# endif
+#endif
+ }
+
+done:
+#if defined(__APPLE__)
+ if (pthread_mutex_unlock(&lock))
+ abort();
+#endif
+
+ return r;
+}
+
+static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
+ dst->st_dev = src->st_dev;
+ dst->st_mode = src->st_mode;
+ dst->st_nlink = src->st_nlink;
+ dst->st_uid = src->st_uid;
+ dst->st_gid = src->st_gid;
+ dst->st_rdev = src->st_rdev;
+ dst->st_ino = src->st_ino;
+ dst->st_size = src->st_size;
+ dst->st_blksize = src->st_blksize;
+ dst->st_blocks = src->st_blocks;
+
+#if defined(__APPLE__)
+ dst->st_atim.tv_sec = src->st_atimespec.tv_sec;
+ dst->st_atim.tv_nsec = src->st_atimespec.tv_nsec;
+ dst->st_mtim.tv_sec = src->st_mtimespec.tv_sec;
+ dst->st_mtim.tv_nsec = src->st_mtimespec.tv_nsec;
+ dst->st_ctim.tv_sec = src->st_ctimespec.tv_sec;
+ dst->st_ctim.tv_nsec = src->st_ctimespec.tv_nsec;
+ dst->st_birthtim.tv_sec = src->st_birthtimespec.tv_sec;
+ dst->st_birthtim.tv_nsec = src->st_birthtimespec.tv_nsec;
+ dst->st_flags = src->st_flags;
+ dst->st_gen = src->st_gen;
+#elif defined(__ANDROID__)
+ dst->st_atim.tv_sec = src->st_atime;
+ dst->st_atim.tv_nsec = src->st_atime_nsec;
+ dst->st_mtim.tv_sec = src->st_mtime;
+ dst->st_mtim.tv_nsec = src->st_mtime_nsec;
+ dst->st_ctim.tv_sec = src->st_ctime;
+ dst->st_ctim.tv_nsec = src->st_ctime_nsec;
+ dst->st_birthtim.tv_sec = src->st_ctime;
+ dst->st_birthtim.tv_nsec = src->st_ctime_nsec;
+ dst->st_flags = 0;
+ dst->st_gen = 0;
+#elif !defined(_AIX) && ( \
+ defined(_BSD_SOURCE) || \
+ defined(_SVID_SOURCE) || \
+ defined(_XOPEN_SOURCE) || \
+ defined(_DEFAULT_SOURCE))
+ dst->st_atim.tv_sec = src->st_atim.tv_sec;
+ dst->st_atim.tv_nsec = src->st_atim.tv_nsec;
+ dst->st_mtim.tv_sec = src->st_mtim.tv_sec;
+ dst->st_mtim.tv_nsec = src->st_mtim.tv_nsec;
+ dst->st_ctim.tv_sec = src->st_ctim.tv_sec;
+ dst->st_ctim.tv_nsec = src->st_ctim.tv_nsec;
+# if defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__)
+ dst->st_birthtim.tv_sec = src->st_birthtim.tv_sec;
+ dst->st_birthtim.tv_nsec = src->st_birthtim.tv_nsec;
+ dst->st_flags = src->st_flags;
+ dst->st_gen = src->st_gen;
+# else
+ dst->st_birthtim.tv_sec = src->st_ctim.tv_sec;
+ dst->st_birthtim.tv_nsec = src->st_ctim.tv_nsec;
+ dst->st_flags = 0;
+ dst->st_gen = 0;
+# endif
+#else
+ dst->st_atim.tv_sec = src->st_atime;
+ dst->st_atim.tv_nsec = 0;
+ dst->st_mtim.tv_sec = src->st_mtime;
+ dst->st_mtim.tv_nsec = 0;
+ dst->st_ctim.tv_sec = src->st_ctime;
+ dst->st_ctim.tv_nsec = 0;
+ dst->st_birthtim.tv_sec = src->st_ctime;
+ dst->st_birthtim.tv_nsec = 0;
+ dst->st_flags = 0;
+ dst->st_gen = 0;
+#endif
+}
+
+
+static int uv__fs_stat(const char *path, uv_stat_t *buf) {
+ struct stat pbuf;
+ int ret;
+ ret = stat(path, &pbuf);
+ uv__to_stat(&pbuf, buf);
+ return ret;
+}
+
+
+static int uv__fs_lstat(const char *path, uv_stat_t *buf) {
+ struct stat pbuf;
+ int ret;
+ ret = lstat(path, &pbuf);
+ uv__to_stat(&pbuf, buf);
+ return ret;
+}
+
+
+static int uv__fs_fstat(int fd, uv_stat_t *buf) {
+ struct stat pbuf;
+ int ret;
+ ret = fstat(fd, &pbuf);
+ uv__to_stat(&pbuf, buf);
+ return ret;
+}
+
+
+typedef ssize_t (*uv__fs_buf_iter_processor)(uv_fs_t* req);
+static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) {
+ unsigned int iovmax;
+ unsigned int nbufs;
+ uv_buf_t* bufs;
+ ssize_t total;
+ ssize_t result;
+
+ iovmax = uv__getiovmax();
+ nbufs = req->nbufs;
+ bufs = req->bufs;
+ total = 0;
+
+ while (nbufs > 0) {
+ req->nbufs = nbufs;
+ if (req->nbufs > iovmax)
+ req->nbufs = iovmax;
+
+ result = process(req);
+ if (result <= 0) {
+ if (total == 0)
+ total = result;
+ break;
+ }
+
+ if (req->off >= 0)
+ req->off += result;
+
+ req->bufs += req->nbufs;
+ nbufs -= req->nbufs;
+ total += result;
+ }
+
+ if (bufs != req->bufsml)
+ uv__free(bufs);
+ req->bufs = NULL;
+
+ return total;
+}
+
+
+static void uv__fs_work(struct uv__work* w) {
+ int retry_on_eintr;
+ uv_fs_t* req;
+ ssize_t r;
+
+ req = container_of(w, uv_fs_t, work_req);
+ retry_on_eintr = !(req->fs_type == UV_FS_CLOSE);
+
+ do {
+ errno = 0;
+
+#define X(type, action) \
+ case UV_FS_ ## type: \
+ r = action; \
+ break;
+
+ switch (req->fs_type) {
+ X(ACCESS, access(req->path, req->flags));
+ X(CHMOD, chmod(req->path, req->mode));
+ X(CHOWN, chown(req->path, req->uid, req->gid));
+ X(CLOSE, close(req->file));
+ X(FCHMOD, fchmod(req->file, req->mode));
+ X(FCHOWN, fchown(req->file, req->uid, req->gid));
+ X(FDATASYNC, uv__fs_fdatasync(req));
+ X(FSTAT, uv__fs_fstat(req->file, &req->statbuf));
+ X(FSYNC, fsync(req->file));
+ X(FTRUNCATE, ftruncate(req->file, req->off));
+ X(FUTIME, uv__fs_futime(req));
+ X(LSTAT, uv__fs_lstat(req->path, &req->statbuf));
+ X(LINK, link(req->path, req->new_path));
+ X(MKDIR, mkdir(req->path, req->mode));
+ X(MKDTEMP, uv__fs_mkdtemp(req));
+ X(OPEN, uv__fs_open(req));
+ X(READ, uv__fs_buf_iter(req, uv__fs_read));
+ X(SCANDIR, uv__fs_scandir(req));
+ X(READLINK, uv__fs_readlink(req));
+ X(REALPATH, uv__fs_realpath(req));
+ X(RENAME, rename(req->path, req->new_path));
+ X(RMDIR, rmdir(req->path));
+ X(SENDFILE, uv__fs_sendfile(req));
+ X(STAT, uv__fs_stat(req->path, &req->statbuf));
+ X(SYMLINK, symlink(req->path, req->new_path));
+ X(UNLINK, unlink(req->path));
+ X(UTIME, uv__fs_utime(req));
+ X(WRITE, uv__fs_buf_iter(req, uv__fs_write));
+ default: abort();
+ }
+#undef X
+ } while (r == -1 && errno == EINTR && retry_on_eintr);
+
+ if (r == -1)
+ req->result = -errno;
+ else
+ req->result = r;
+
+ if (r == 0 && (req->fs_type == UV_FS_STAT ||
+ req->fs_type == UV_FS_FSTAT ||
+ req->fs_type == UV_FS_LSTAT)) {
+ req->ptr = &req->statbuf;
+ }
+}
+
+
+static void uv__fs_done(struct uv__work* w, int status) {
+ uv_fs_t* req;
+
+ req = container_of(w, uv_fs_t, work_req);
+ uv__req_unregister(req->loop, req);
+
+ if (status == -ECANCELED) {
+ assert(req->result == 0);
+ req->result = -ECANCELED;
+ }
+
+ req->cb(req);
+}
+
+
+int uv_fs_access(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int flags,
+ uv_fs_cb cb) {
+ INIT(ACCESS);
+ PATH;
+ req->flags = flags;
+ POST;
+}
+
+
+int uv_fs_chmod(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int mode,
+ uv_fs_cb cb) {
+ INIT(CHMOD);
+ PATH;
+ req->mode = mode;
+ POST;
+}
+
+
+int uv_fs_chown(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_uid_t uid,
+ uv_gid_t gid,
+ uv_fs_cb cb) {
+ INIT(CHOWN);
+ PATH;
+ req->uid = uid;
+ req->gid = gid;
+ POST;
+}
+
+
+int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
+ INIT(CLOSE);
+ req->file = file;
+ POST;
+}
+
+
+int uv_fs_fchmod(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ int mode,
+ uv_fs_cb cb) {
+ INIT(FCHMOD);
+ req->file = file;
+ req->mode = mode;
+ POST;
+}
+
+
+int uv_fs_fchown(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ uv_uid_t uid,
+ uv_gid_t gid,
+ uv_fs_cb cb) {
+ INIT(FCHOWN);
+ req->file = file;
+ req->uid = uid;
+ req->gid = gid;
+ POST;
+}
+
+
+int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
+ INIT(FDATASYNC);
+ req->file = file;
+ POST;
+}
+
+
+int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
+ INIT(FSTAT);
+ req->file = file;
+ POST;
+}
+
+
+int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
+ INIT(FSYNC);
+ req->file = file;
+ POST;
+}
+
+
+int uv_fs_ftruncate(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ int64_t off,
+ uv_fs_cb cb) {
+ INIT(FTRUNCATE);
+ req->file = file;
+ req->off = off;
+ POST;
+}
+
+
+int uv_fs_futime(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ double atime,
+ double mtime,
+ uv_fs_cb cb) {
+ INIT(FUTIME);
+ req->file = file;
+ req->atime = atime;
+ req->mtime = mtime;
+ POST;
+}
+
+
+int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ INIT(LSTAT);
+ PATH;
+ POST;
+}
+
+
+int uv_fs_link(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ uv_fs_cb cb) {
+ INIT(LINK);
+ PATH2;
+ POST;
+}
+
+
+int uv_fs_mkdir(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int mode,
+ uv_fs_cb cb) {
+ INIT(MKDIR);
+ PATH;
+ req->mode = mode;
+ POST;
+}
+
+
+int uv_fs_mkdtemp(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* tpl,
+ uv_fs_cb cb) {
+ INIT(MKDTEMP);
+ req->path = uv__strdup(tpl);
+ if (req->path == NULL) {
+ if (cb != NULL)
+ uv__req_unregister(loop, req);
+ return -ENOMEM;
+ }
+ POST;
+}
+
+
+int uv_fs_open(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int flags,
+ int mode,
+ uv_fs_cb cb) {
+ INIT(OPEN);
+ PATH;
+ req->flags = flags;
+ req->mode = mode;
+ POST;
+}
+
+
+int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
+ uv_file file,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ int64_t off,
+ uv_fs_cb cb) {
+ if (bufs == NULL || nbufs == 0)
+ return -EINVAL;
+
+ INIT(READ);
+ req->file = file;
+
+ req->nbufs = nbufs;
+ req->bufs = req->bufsml;
+ if (nbufs > ARRAY_SIZE(req->bufsml))
+ req->bufs = uv__malloc(nbufs * sizeof(*bufs));
+
+ if (req->bufs == NULL) {
+ if (cb != NULL)
+ uv__req_unregister(loop, req);
+ return -ENOMEM;
+ }
+
+ memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
+
+ req->off = off;
+ POST;
+}
+
+
+int uv_fs_scandir(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int flags,
+ uv_fs_cb cb) {
+ INIT(SCANDIR);
+ PATH;
+ req->flags = flags;
+ POST;
+}
+
+
+int uv_fs_readlink(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb) {
+ INIT(READLINK);
+ PATH;
+ POST;
+}
+
+
+int uv_fs_realpath(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char * path,
+ uv_fs_cb cb) {
+ INIT(REALPATH);
+ PATH;
+ POST;
+}
+
+
+int uv_fs_rename(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ uv_fs_cb cb) {
+ INIT(RENAME);
+ PATH2;
+ POST;
+}
+
+
+int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ INIT(RMDIR);
+ PATH;
+ POST;
+}
+
+
+int uv_fs_sendfile(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file out_fd,
+ uv_file in_fd,
+ int64_t off,
+ size_t len,
+ uv_fs_cb cb) {
+ INIT(SENDFILE);
+ req->flags = in_fd; /* hack */
+ req->file = out_fd;
+ req->off = off;
+ req->bufsml[0].len = len;
+ POST;
+}
+
+
+int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ INIT(STAT);
+ PATH;
+ POST;
+}
+
+
+int uv_fs_symlink(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ int flags,
+ uv_fs_cb cb) {
+ INIT(SYMLINK);
+ PATH2;
+ req->flags = flags;
+ POST;
+}
+
+
+int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ INIT(UNLINK);
+ PATH;
+ POST;
+}
+
+
+int uv_fs_utime(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ double atime,
+ double mtime,
+ uv_fs_cb cb) {
+ INIT(UTIME);
+ PATH;
+ req->atime = atime;
+ req->mtime = mtime;
+ POST;
+}
+
+
+int uv_fs_write(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ int64_t off,
+ uv_fs_cb cb) {
+ if (bufs == NULL || nbufs == 0)
+ return -EINVAL;
+
+ INIT(WRITE);
+ req->file = file;
+
+ req->nbufs = nbufs;
+ req->bufs = req->bufsml;
+ if (nbufs > ARRAY_SIZE(req->bufsml))
+ req->bufs = uv__malloc(nbufs * sizeof(*bufs));
+
+ if (req->bufs == NULL) {
+ if (cb != NULL)
+ uv__req_unregister(loop, req);
+ return -ENOMEM;
+ }
+
+ memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
+
+ req->off = off;
+ POST;
+}
+
+
+void uv_fs_req_cleanup(uv_fs_t* req) {
+ /* Only necessary for asychronous requests, i.e., requests with a callback.
+ * Synchronous ones don't copy their arguments and have req->path and
+ * req->new_path pointing to user-owned memory. UV_FS_MKDTEMP is the
+ * exception to the rule, it always allocates memory.
+ */
+ if (req->path != NULL && (req->cb != NULL || req->fs_type == UV_FS_MKDTEMP))
+ uv__free((void*) req->path); /* Memory is shared with req->new_path. */
+
+ req->path = NULL;
+ req->new_path = NULL;
+
+ if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL)
+ uv__fs_scandir_cleanup(req);
+
+ if (req->ptr != &req->statbuf)
+ uv__free(req->ptr);
+ req->ptr = NULL;
+}
diff --git a/3rdparty/libuv/src/unix/fsevents.c b/3rdparty/libuv/src/unix/fsevents.c
new file mode 100644
index 00000000000..d331a131726
--- /dev/null
+++ b/3rdparty/libuv/src/unix/fsevents.c
@@ -0,0 +1,904 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#if TARGET_OS_IPHONE
+
+/* iOS (currently) doesn't provide the FSEvents-API (nor CoreServices) */
+
+int uv__fsevents_init(uv_fs_event_t* handle) {
+ return 0;
+}
+
+
+int uv__fsevents_close(uv_fs_event_t* handle) {
+ return 0;
+}
+
+
+void uv__fsevents_loop_delete(uv_loop_t* loop) {
+}
+
+#else /* TARGET_OS_IPHONE */
+
+#include <dlfcn.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#include <CoreFoundation/CFRunLoop.h>
+#include <CoreServices/CoreServices.h>
+
+/* These are macros to avoid "initializer element is not constant" errors
+ * with old versions of gcc.
+ */
+#define kFSEventsModified (kFSEventStreamEventFlagItemFinderInfoMod | \
+ kFSEventStreamEventFlagItemModified | \
+ kFSEventStreamEventFlagItemInodeMetaMod | \
+ kFSEventStreamEventFlagItemChangeOwner | \
+ kFSEventStreamEventFlagItemXattrMod)
+
+#define kFSEventsRenamed (kFSEventStreamEventFlagItemCreated | \
+ kFSEventStreamEventFlagItemRemoved | \
+ kFSEventStreamEventFlagItemRenamed)
+
+#define kFSEventsSystem (kFSEventStreamEventFlagUserDropped | \
+ kFSEventStreamEventFlagKernelDropped | \
+ kFSEventStreamEventFlagEventIdsWrapped | \
+ kFSEventStreamEventFlagHistoryDone | \
+ kFSEventStreamEventFlagMount | \
+ kFSEventStreamEventFlagUnmount | \
+ kFSEventStreamEventFlagRootChanged)
+
+typedef struct uv__fsevents_event_s uv__fsevents_event_t;
+typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t;
+typedef struct uv__cf_loop_state_s uv__cf_loop_state_t;
+
+enum uv__cf_loop_signal_type_e {
+ kUVCFLoopSignalRegular,
+ kUVCFLoopSignalClosing
+};
+typedef enum uv__cf_loop_signal_type_e uv__cf_loop_signal_type_t;
+
+struct uv__cf_loop_signal_s {
+ QUEUE member;
+ uv_fs_event_t* handle;
+ uv__cf_loop_signal_type_t type;
+};
+
+struct uv__fsevents_event_s {
+ QUEUE member;
+ int events;
+ char path[1];
+};
+
+struct uv__cf_loop_state_s {
+ CFRunLoopRef loop;
+ CFRunLoopSourceRef signal_source;
+ int fsevent_need_reschedule;
+ FSEventStreamRef fsevent_stream;
+ uv_sem_t fsevent_sem;
+ uv_mutex_t fsevent_mutex;
+ void* fsevent_handles[2];
+ unsigned int fsevent_handle_count;
+};
+
+/* Forward declarations */
+static void uv__cf_loop_cb(void* arg);
+static void* uv__cf_loop_runner(void* arg);
+static int uv__cf_loop_signal(uv_loop_t* loop,
+ uv_fs_event_t* handle,
+ uv__cf_loop_signal_type_t type);
+
+/* Lazy-loaded by uv__fsevents_global_init(). */
+static CFArrayRef (*pCFArrayCreate)(CFAllocatorRef,
+ const void**,
+ CFIndex,
+ const CFArrayCallBacks*);
+static void (*pCFRelease)(CFTypeRef);
+static void (*pCFRunLoopAddSource)(CFRunLoopRef,
+ CFRunLoopSourceRef,
+ CFStringRef);
+static CFRunLoopRef (*pCFRunLoopGetCurrent)(void);
+static void (*pCFRunLoopRemoveSource)(CFRunLoopRef,
+ CFRunLoopSourceRef,
+ CFStringRef);
+static void (*pCFRunLoopRun)(void);
+static CFRunLoopSourceRef (*pCFRunLoopSourceCreate)(CFAllocatorRef,
+ CFIndex,
+ CFRunLoopSourceContext*);
+static void (*pCFRunLoopSourceSignal)(CFRunLoopSourceRef);
+static void (*pCFRunLoopStop)(CFRunLoopRef);
+static void (*pCFRunLoopWakeUp)(CFRunLoopRef);
+static CFStringRef (*pCFStringCreateWithFileSystemRepresentation)(
+ CFAllocatorRef,
+ const char*);
+static CFStringEncoding (*pCFStringGetSystemEncoding)(void);
+static CFStringRef (*pkCFRunLoopDefaultMode);
+static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef,
+ FSEventStreamCallback,
+ FSEventStreamContext*,
+ CFArrayRef,
+ FSEventStreamEventId,
+ CFTimeInterval,
+ FSEventStreamCreateFlags);
+static void (*pFSEventStreamFlushSync)(FSEventStreamRef);
+static void (*pFSEventStreamInvalidate)(FSEventStreamRef);
+static void (*pFSEventStreamRelease)(FSEventStreamRef);
+static void (*pFSEventStreamScheduleWithRunLoop)(FSEventStreamRef,
+ CFRunLoopRef,
+ CFStringRef);
+static Boolean (*pFSEventStreamStart)(FSEventStreamRef);
+static void (*pFSEventStreamStop)(FSEventStreamRef);
+
+#define UV__FSEVENTS_PROCESS(handle, block) \
+ do { \
+ QUEUE events; \
+ QUEUE* q; \
+ uv__fsevents_event_t* event; \
+ int err; \
+ uv_mutex_lock(&(handle)->cf_mutex); \
+ /* Split-off all events and empty original queue */ \
+ QUEUE_MOVE(&(handle)->cf_events, &events); \
+ /* Get error (if any) and zero original one */ \
+ err = (handle)->cf_error; \
+ (handle)->cf_error = 0; \
+ uv_mutex_unlock(&(handle)->cf_mutex); \
+ /* Loop through events, deallocating each after processing */ \
+ while (!QUEUE_EMPTY(&events)) { \
+ q = QUEUE_HEAD(&events); \
+ event = QUEUE_DATA(q, uv__fsevents_event_t, member); \
+ QUEUE_REMOVE(q); \
+ /* NOTE: Checking uv__is_active() is required here, because handle \
+ * callback may close handle and invoking it after it will lead to \
+ * incorrect behaviour */ \
+ if (!uv__is_closing((handle)) && uv__is_active((handle))) \
+ block \
+ /* Free allocated data */ \
+ uv__free(event); \
+ } \
+ if (err != 0 && !uv__is_closing((handle)) && uv__is_active((handle))) \
+ (handle)->cb((handle), NULL, 0, err); \
+ } while (0)
+
+
+/* Runs in UV loop's thread, when there're events to report to handle */
+static void uv__fsevents_cb(uv_async_t* cb) {
+ uv_fs_event_t* handle;
+
+ handle = cb->data;
+
+ UV__FSEVENTS_PROCESS(handle, {
+ handle->cb(handle, event->path[0] ? event->path : NULL, event->events, 0);
+ });
+}
+
+
+/* Runs in CF thread, pushed event into handle's event list */
+static void uv__fsevents_push_event(uv_fs_event_t* handle,
+ QUEUE* events,
+ int err) {
+ assert(events != NULL || err != 0);
+ uv_mutex_lock(&handle->cf_mutex);
+
+ /* Concatenate two queues */
+ if (events != NULL)
+ QUEUE_ADD(&handle->cf_events, events);
+
+ /* Propagate error */
+ if (err != 0)
+ handle->cf_error = err;
+ uv_mutex_unlock(&handle->cf_mutex);
+
+ uv_async_send(handle->cf_cb);
+}
+
+
+/* Runs in CF thread, when there're events in FSEventStream */
+static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
+ void* info,
+ size_t numEvents,
+ void* eventPaths,
+ const FSEventStreamEventFlags eventFlags[],
+ const FSEventStreamEventId eventIds[]) {
+ size_t i;
+ int len;
+ char** paths;
+ char* path;
+ char* pos;
+ uv_fs_event_t* handle;
+ QUEUE* q;
+ uv_loop_t* loop;
+ uv__cf_loop_state_t* state;
+ uv__fsevents_event_t* event;
+ QUEUE head;
+
+ loop = info;
+ state = loop->cf_state;
+ assert(state != NULL);
+ paths = eventPaths;
+
+ /* For each handle */
+ uv_mutex_lock(&state->fsevent_mutex);
+ QUEUE_FOREACH(q, &state->fsevent_handles) {
+ handle = QUEUE_DATA(q, uv_fs_event_t, cf_member);
+ QUEUE_INIT(&head);
+
+ /* Process and filter out events */
+ for (i = 0; i < numEvents; i++) {
+ /* Ignore system events */
+ if (eventFlags[i] & kFSEventsSystem)
+ continue;
+
+ path = paths[i];
+ len = strlen(path);
+
+ /* Filter out paths that are outside handle's request */
+ if (strncmp(path, handle->realpath, handle->realpath_len) != 0)
+ continue;
+
+ if (handle->realpath_len > 1 || *handle->realpath != '/') {
+ path += handle->realpath_len;
+ len -= handle->realpath_len;
+
+ /* Skip forward slash */
+ if (*path != '\0') {
+ path++;
+ len--;
+ }
+ }
+
+#ifdef MAC_OS_X_VERSION_10_7
+ /* Ignore events with path equal to directory itself */
+ if (len == 0)
+ continue;
+#endif /* MAC_OS_X_VERSION_10_7 */
+
+ /* Do not emit events from subdirectories (without option set) */
+ if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != 0) {
+ pos = strchr(path + 1, '/');
+ if (pos != NULL)
+ continue;
+ }
+
+#ifndef MAC_OS_X_VERSION_10_7
+ path = "";
+ len = 0;
+#endif /* MAC_OS_X_VERSION_10_7 */
+
+ event = uv__malloc(sizeof(*event) + len);
+ if (event == NULL)
+ break;
+
+ memset(event, 0, sizeof(*event));
+ memcpy(event->path, path, len + 1);
+
+ if ((eventFlags[i] & kFSEventsModified) != 0 &&
+ (eventFlags[i] & kFSEventsRenamed) == 0)
+ event->events = UV_CHANGE;
+ else
+ event->events = UV_RENAME;
+
+ QUEUE_INSERT_TAIL(&head, &event->member);
+ }
+
+ if (!QUEUE_EMPTY(&head))
+ uv__fsevents_push_event(handle, &head, 0);
+ }
+ uv_mutex_unlock(&state->fsevent_mutex);
+}
+
+
+/* Runs in CF thread */
+static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
+ uv__cf_loop_state_t* state;
+ FSEventStreamContext ctx;
+ FSEventStreamRef ref;
+ CFAbsoluteTime latency;
+ FSEventStreamCreateFlags flags;
+
+ /* Initialize context */
+ ctx.version = 0;
+ ctx.info = loop;
+ ctx.retain = NULL;
+ ctx.release = NULL;
+ ctx.copyDescription = NULL;
+
+ latency = 0.05;
+
+ /* Explanation of selected flags:
+ * 1. NoDefer - without this flag, events that are happening continuously
+ * (i.e. each event is happening after time interval less than `latency`,
+ * counted from previous event), will be deferred and passed to callback
+ * once they'll either fill whole OS buffer, or when this continuous stream
+ * will stop (i.e. there'll be delay between events, bigger than
+ * `latency`).
+ * Specifying this flag will invoke callback after `latency` time passed
+ * since event.
+ * 2. FileEvents - fire callback for file changes too (by default it is firing
+ * it only for directory changes).
+ */
+ flags = kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents;
+
+ /*
+ * NOTE: It might sound like a good idea to remember last seen StreamEventId,
+ * but in reality one dir might have last StreamEventId less than, the other,
+ * that is being watched now. Which will cause FSEventStream API to report
+ * changes to files from the past.
+ */
+ ref = pFSEventStreamCreate(NULL,
+ &uv__fsevents_event_cb,
+ &ctx,
+ paths,
+ kFSEventStreamEventIdSinceNow,
+ latency,
+ flags);
+ assert(ref != NULL);
+
+ state = loop->cf_state;
+ pFSEventStreamScheduleWithRunLoop(ref,
+ state->loop,
+ *pkCFRunLoopDefaultMode);
+ if (!pFSEventStreamStart(ref)) {
+ pFSEventStreamInvalidate(ref);
+ pFSEventStreamRelease(ref);
+ return -EMFILE;
+ }
+
+ state->fsevent_stream = ref;
+ return 0;
+}
+
+
+/* Runs in CF thread */
+static void uv__fsevents_destroy_stream(uv_loop_t* loop) {
+ uv__cf_loop_state_t* state;
+
+ state = loop->cf_state;
+
+ if (state->fsevent_stream == NULL)
+ return;
+
+ /* Flush all accumulated events */
+ pFSEventStreamFlushSync(state->fsevent_stream);
+
+ /* Stop emitting events */
+ pFSEventStreamStop(state->fsevent_stream);
+
+ /* Release stream */
+ pFSEventStreamInvalidate(state->fsevent_stream);
+ pFSEventStreamRelease(state->fsevent_stream);
+ state->fsevent_stream = NULL;
+}
+
+
+/* Runs in CF thread, when there're new fsevent handles to add to stream */
+static void uv__fsevents_reschedule(uv_fs_event_t* handle,
+ uv__cf_loop_signal_type_t type) {
+ uv__cf_loop_state_t* state;
+ QUEUE* q;
+ uv_fs_event_t* curr;
+ CFArrayRef cf_paths;
+ CFStringRef* paths;
+ unsigned int i;
+ int err;
+ unsigned int path_count;
+
+ state = handle->loop->cf_state;
+ paths = NULL;
+ cf_paths = NULL;
+ err = 0;
+ /* NOTE: `i` is used in deallocation loop below */
+ i = 0;
+
+ /* Optimization to prevent O(n^2) time spent when starting to watch
+ * many files simultaneously
+ */
+ uv_mutex_lock(&state->fsevent_mutex);
+ if (state->fsevent_need_reschedule == 0) {
+ uv_mutex_unlock(&state->fsevent_mutex);
+ goto final;
+ }
+ state->fsevent_need_reschedule = 0;
+ uv_mutex_unlock(&state->fsevent_mutex);
+
+ /* Destroy previous FSEventStream */
+ uv__fsevents_destroy_stream(handle->loop);
+
+ /* Any failure below will be a memory failure */
+ err = -ENOMEM;
+
+ /* Create list of all watched paths */
+ uv_mutex_lock(&state->fsevent_mutex);
+ path_count = state->fsevent_handle_count;
+ if (path_count != 0) {
+ paths = uv__malloc(sizeof(*paths) * path_count);
+ if (paths == NULL) {
+ uv_mutex_unlock(&state->fsevent_mutex);
+ goto final;
+ }
+
+ q = &state->fsevent_handles;
+ for (; i < path_count; i++) {
+ q = QUEUE_NEXT(q);
+ assert(q != &state->fsevent_handles);
+ curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
+
+ assert(curr->realpath != NULL);
+ paths[i] =
+ pCFStringCreateWithFileSystemRepresentation(NULL, curr->realpath);
+ if (paths[i] == NULL) {
+ uv_mutex_unlock(&state->fsevent_mutex);
+ goto final;
+ }
+ }
+ }
+ uv_mutex_unlock(&state->fsevent_mutex);
+ err = 0;
+
+ if (path_count != 0) {
+ /* Create new FSEventStream */
+ cf_paths = pCFArrayCreate(NULL, (const void**) paths, path_count, NULL);
+ if (cf_paths == NULL) {
+ err = -ENOMEM;
+ goto final;
+ }
+ err = uv__fsevents_create_stream(handle->loop, cf_paths);
+ }
+
+final:
+ /* Deallocate all paths in case of failure */
+ if (err != 0) {
+ if (cf_paths == NULL) {
+ while (i != 0)
+ pCFRelease(paths[--i]);
+ uv__free(paths);
+ } else {
+ /* CFArray takes ownership of both strings and original C-array */
+ pCFRelease(cf_paths);
+ }
+
+ /* Broadcast error to all handles */
+ uv_mutex_lock(&state->fsevent_mutex);
+ QUEUE_FOREACH(q, &state->fsevent_handles) {
+ curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
+ uv__fsevents_push_event(curr, NULL, err);
+ }
+ uv_mutex_unlock(&state->fsevent_mutex);
+ }
+
+ /*
+ * Main thread will block until the removal of handle from the list,
+ * we must tell it when we're ready.
+ *
+ * NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close`
+ */
+ if (type == kUVCFLoopSignalClosing)
+ uv_sem_post(&state->fsevent_sem);
+}
+
+
+static int uv__fsevents_global_init(void) {
+ static pthread_mutex_t global_init_mutex = PTHREAD_MUTEX_INITIALIZER;
+ static void* core_foundation_handle;
+ static void* core_services_handle;
+ int err;
+
+ err = 0;
+ pthread_mutex_lock(&global_init_mutex);
+ if (core_foundation_handle != NULL)
+ goto out;
+
+ /* The libraries are never unloaded because we currently don't have a good
+ * mechanism for keeping a reference count. It's unlikely to be an issue
+ * but if it ever becomes one, we can turn the dynamic library handles into
+ * per-event loop properties and have the dynamic linker keep track for us.
+ */
+ err = -ENOSYS;
+ core_foundation_handle = dlopen("/System/Library/Frameworks/"
+ "CoreFoundation.framework/"
+ "Versions/A/CoreFoundation",
+ RTLD_LAZY | RTLD_LOCAL);
+ if (core_foundation_handle == NULL)
+ goto out;
+
+ core_services_handle = dlopen("/System/Library/Frameworks/"
+ "CoreServices.framework/"
+ "Versions/A/CoreServices",
+ RTLD_LAZY | RTLD_LOCAL);
+ if (core_services_handle == NULL)
+ goto out;
+
+ err = -ENOENT;
+#define V(handle, symbol) \
+ do { \
+ *(void **)(&p ## symbol) = dlsym((handle), #symbol); \
+ if (p ## symbol == NULL) \
+ goto out; \
+ } \
+ while (0)
+ V(core_foundation_handle, CFArrayCreate);
+ V(core_foundation_handle, CFRelease);
+ V(core_foundation_handle, CFRunLoopAddSource);
+ V(core_foundation_handle, CFRunLoopGetCurrent);
+ V(core_foundation_handle, CFRunLoopRemoveSource);
+ V(core_foundation_handle, CFRunLoopRun);
+ V(core_foundation_handle, CFRunLoopSourceCreate);
+ V(core_foundation_handle, CFRunLoopSourceSignal);
+ V(core_foundation_handle, CFRunLoopStop);
+ V(core_foundation_handle, CFRunLoopWakeUp);
+ V(core_foundation_handle, CFStringCreateWithFileSystemRepresentation);
+ V(core_foundation_handle, CFStringGetSystemEncoding);
+ V(core_foundation_handle, kCFRunLoopDefaultMode);
+ V(core_services_handle, FSEventStreamCreate);
+ V(core_services_handle, FSEventStreamFlushSync);
+ V(core_services_handle, FSEventStreamInvalidate);
+ V(core_services_handle, FSEventStreamRelease);
+ V(core_services_handle, FSEventStreamScheduleWithRunLoop);
+ V(core_services_handle, FSEventStreamStart);
+ V(core_services_handle, FSEventStreamStop);
+#undef V
+ err = 0;
+
+out:
+ if (err && core_services_handle != NULL) {
+ dlclose(core_services_handle);
+ core_services_handle = NULL;
+ }
+
+ if (err && core_foundation_handle != NULL) {
+ dlclose(core_foundation_handle);
+ core_foundation_handle = NULL;
+ }
+
+ pthread_mutex_unlock(&global_init_mutex);
+ return err;
+}
+
+
+/* Runs in UV loop */
+static int uv__fsevents_loop_init(uv_loop_t* loop) {
+ CFRunLoopSourceContext ctx;
+ uv__cf_loop_state_t* state;
+ pthread_attr_t attr_storage;
+ pthread_attr_t* attr;
+ int err;
+
+ if (loop->cf_state != NULL)
+ return 0;
+
+ err = uv__fsevents_global_init();
+ if (err)
+ return err;
+
+ state = uv__calloc(1, sizeof(*state));
+ if (state == NULL)
+ return -ENOMEM;
+
+ err = uv_mutex_init(&loop->cf_mutex);
+ if (err)
+ goto fail_mutex_init;
+
+ err = uv_sem_init(&loop->cf_sem, 0);
+ if (err)
+ goto fail_sem_init;
+
+ QUEUE_INIT(&loop->cf_signals);
+
+ err = uv_sem_init(&state->fsevent_sem, 0);
+ if (err)
+ goto fail_fsevent_sem_init;
+
+ err = uv_mutex_init(&state->fsevent_mutex);
+ if (err)
+ goto fail_fsevent_mutex_init;
+
+ QUEUE_INIT(&state->fsevent_handles);
+ state->fsevent_need_reschedule = 0;
+ state->fsevent_handle_count = 0;
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.info = loop;
+ ctx.perform = uv__cf_loop_cb;
+ state->signal_source = pCFRunLoopSourceCreate(NULL, 0, &ctx);
+ if (state->signal_source == NULL) {
+ err = -ENOMEM;
+ goto fail_signal_source_create;
+ }
+
+ /* In the unlikely event that pthread_attr_init() fails, create the thread
+ * with the default stack size. We'll use a little more address space but
+ * that in itself is not a fatal error.
+ */
+ attr = &attr_storage;
+ if (pthread_attr_init(attr))
+ attr = NULL;
+
+ if (attr != NULL)
+ if (pthread_attr_setstacksize(attr, 4 * PTHREAD_STACK_MIN))
+ abort();
+
+ loop->cf_state = state;
+
+ /* uv_thread_t is an alias for pthread_t. */
+ err = -pthread_create(&loop->cf_thread, attr, uv__cf_loop_runner, loop);
+
+ if (attr != NULL)
+ pthread_attr_destroy(attr);
+
+ if (err)
+ goto fail_thread_create;
+
+ /* Synchronize threads */
+ uv_sem_wait(&loop->cf_sem);
+ return 0;
+
+fail_thread_create:
+ loop->cf_state = NULL;
+
+fail_signal_source_create:
+ uv_mutex_destroy(&state->fsevent_mutex);
+
+fail_fsevent_mutex_init:
+ uv_sem_destroy(&state->fsevent_sem);
+
+fail_fsevent_sem_init:
+ uv_sem_destroy(&loop->cf_sem);
+
+fail_sem_init:
+ uv_mutex_destroy(&loop->cf_mutex);
+
+fail_mutex_init:
+ uv__free(state);
+ return err;
+}
+
+
+/* Runs in UV loop */
+void uv__fsevents_loop_delete(uv_loop_t* loop) {
+ uv__cf_loop_signal_t* s;
+ uv__cf_loop_state_t* state;
+ QUEUE* q;
+
+ if (loop->cf_state == NULL)
+ return;
+
+ if (uv__cf_loop_signal(loop, NULL, kUVCFLoopSignalRegular) != 0)
+ abort();
+
+ uv_thread_join(&loop->cf_thread);
+ uv_sem_destroy(&loop->cf_sem);
+ uv_mutex_destroy(&loop->cf_mutex);
+
+ /* Free any remaining data */
+ while (!QUEUE_EMPTY(&loop->cf_signals)) {
+ q = QUEUE_HEAD(&loop->cf_signals);
+ s = QUEUE_DATA(q, uv__cf_loop_signal_t, member);
+ QUEUE_REMOVE(q);
+ uv__free(s);
+ }
+
+ /* Destroy state */
+ state = loop->cf_state;
+ uv_sem_destroy(&state->fsevent_sem);
+ uv_mutex_destroy(&state->fsevent_mutex);
+ pCFRelease(state->signal_source);
+ uv__free(state);
+ loop->cf_state = NULL;
+}
+
+
+/* Runs in CF thread. This is the CF loop's body */
+static void* uv__cf_loop_runner(void* arg) {
+ uv_loop_t* loop;
+ uv__cf_loop_state_t* state;
+
+ loop = arg;
+ state = loop->cf_state;
+ state->loop = pCFRunLoopGetCurrent();
+
+ pCFRunLoopAddSource(state->loop,
+ state->signal_source,
+ *pkCFRunLoopDefaultMode);
+
+ uv_sem_post(&loop->cf_sem);
+
+ pCFRunLoopRun();
+ pCFRunLoopRemoveSource(state->loop,
+ state->signal_source,
+ *pkCFRunLoopDefaultMode);
+
+ return NULL;
+}
+
+
+/* Runs in CF thread, executed after `uv__cf_loop_signal()` */
+static void uv__cf_loop_cb(void* arg) {
+ uv_loop_t* loop;
+ uv__cf_loop_state_t* state;
+ QUEUE* item;
+ QUEUE split_head;
+ uv__cf_loop_signal_t* s;
+
+ loop = arg;
+ state = loop->cf_state;
+
+ uv_mutex_lock(&loop->cf_mutex);
+ QUEUE_MOVE(&loop->cf_signals, &split_head);
+ uv_mutex_unlock(&loop->cf_mutex);
+
+ while (!QUEUE_EMPTY(&split_head)) {
+ item = QUEUE_HEAD(&split_head);
+ QUEUE_REMOVE(item);
+
+ s = QUEUE_DATA(item, uv__cf_loop_signal_t, member);
+
+ /* This was a termination signal */
+ if (s->handle == NULL)
+ pCFRunLoopStop(state->loop);
+ else
+ uv__fsevents_reschedule(s->handle, s->type);
+
+ uv__free(s);
+ }
+}
+
+
+/* Runs in UV loop to notify CF thread */
+int uv__cf_loop_signal(uv_loop_t* loop,
+ uv_fs_event_t* handle,
+ uv__cf_loop_signal_type_t type) {
+ uv__cf_loop_signal_t* item;
+ uv__cf_loop_state_t* state;
+
+ item = uv__malloc(sizeof(*item));
+ if (item == NULL)
+ return -ENOMEM;
+
+ item->handle = handle;
+ item->type = type;
+
+ uv_mutex_lock(&loop->cf_mutex);
+ QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member);
+ uv_mutex_unlock(&loop->cf_mutex);
+
+ state = loop->cf_state;
+ assert(state != NULL);
+ pCFRunLoopSourceSignal(state->signal_source);
+ pCFRunLoopWakeUp(state->loop);
+
+ return 0;
+}
+
+
+/* Runs in UV loop to initialize handle */
+int uv__fsevents_init(uv_fs_event_t* handle) {
+ int err;
+ uv__cf_loop_state_t* state;
+
+ err = uv__fsevents_loop_init(handle->loop);
+ if (err)
+ return err;
+
+ /* Get absolute path to file */
+ handle->realpath = realpath(handle->path, NULL);
+ if (handle->realpath == NULL)
+ return -errno;
+ handle->realpath_len = strlen(handle->realpath);
+
+ /* Initialize event queue */
+ QUEUE_INIT(&handle->cf_events);
+ handle->cf_error = 0;
+
+ /*
+ * Events will occur in other thread.
+ * Initialize callback for getting them back into event loop's thread
+ */
+ handle->cf_cb = uv__malloc(sizeof(*handle->cf_cb));
+ if (handle->cf_cb == NULL) {
+ err = -ENOMEM;
+ goto fail_cf_cb_malloc;
+ }
+
+ handle->cf_cb->data = handle;
+ uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb);
+ handle->cf_cb->flags |= UV__HANDLE_INTERNAL;
+ uv_unref((uv_handle_t*) handle->cf_cb);
+
+ err = uv_mutex_init(&handle->cf_mutex);
+ if (err)
+ goto fail_cf_mutex_init;
+
+ /* Insert handle into the list */
+ state = handle->loop->cf_state;
+ uv_mutex_lock(&state->fsevent_mutex);
+ QUEUE_INSERT_TAIL(&state->fsevent_handles, &handle->cf_member);
+ state->fsevent_handle_count++;
+ state->fsevent_need_reschedule = 1;
+ uv_mutex_unlock(&state->fsevent_mutex);
+
+ /* Reschedule FSEventStream */
+ assert(handle != NULL);
+ err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalRegular);
+ if (err)
+ goto fail_loop_signal;
+
+ return 0;
+
+fail_loop_signal:
+ uv_mutex_destroy(&handle->cf_mutex);
+
+fail_cf_mutex_init:
+ uv__free(handle->cf_cb);
+ handle->cf_cb = NULL;
+
+fail_cf_cb_malloc:
+ uv__free(handle->realpath);
+ handle->realpath = NULL;
+ handle->realpath_len = 0;
+
+ return err;
+}
+
+
+/* Runs in UV loop to de-initialize handle */
+int uv__fsevents_close(uv_fs_event_t* handle) {
+ int err;
+ uv__cf_loop_state_t* state;
+
+ if (handle->cf_cb == NULL)
+ return -EINVAL;
+
+ /* Remove handle from the list */
+ state = handle->loop->cf_state;
+ uv_mutex_lock(&state->fsevent_mutex);
+ QUEUE_REMOVE(&handle->cf_member);
+ state->fsevent_handle_count--;
+ state->fsevent_need_reschedule = 1;
+ uv_mutex_unlock(&state->fsevent_mutex);
+
+ /* Reschedule FSEventStream */
+ assert(handle != NULL);
+ err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalClosing);
+ if (err)
+ return -err;
+
+ /* Wait for deinitialization */
+ uv_sem_wait(&state->fsevent_sem);
+
+ uv_close((uv_handle_t*) handle->cf_cb, (uv_close_cb) uv__free);
+ handle->cf_cb = NULL;
+
+ /* Free data in queue */
+ UV__FSEVENTS_PROCESS(handle, {
+ /* NOP */
+ });
+
+ uv_mutex_destroy(&handle->cf_mutex);
+ uv__free(handle->realpath);
+ handle->realpath = NULL;
+ handle->realpath_len = 0;
+
+ return 0;
+}
+
+#endif /* TARGET_OS_IPHONE */
diff --git a/3rdparty/libuv/src/unix/getaddrinfo.c b/3rdparty/libuv/src/unix/getaddrinfo.c
new file mode 100644
index 00000000000..2049aea2f38
--- /dev/null
+++ b/3rdparty/libuv/src/unix/getaddrinfo.c
@@ -0,0 +1,202 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* Expose glibc-specific EAI_* error codes. Needs to be defined before we
+ * include any headers.
+ */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+
+#include "uv.h"
+#include "internal.h"
+
+#include <errno.h>
+#include <stddef.h> /* NULL */
+#include <stdlib.h>
+#include <string.h>
+
+/* EAI_* constants. */
+#include <netdb.h>
+
+
+int uv__getaddrinfo_translate_error(int sys_err) {
+ switch (sys_err) {
+ case 0: return 0;
+#if defined(EAI_ADDRFAMILY)
+ case EAI_ADDRFAMILY: return UV_EAI_ADDRFAMILY;
+#endif
+#if defined(EAI_AGAIN)
+ case EAI_AGAIN: return UV_EAI_AGAIN;
+#endif
+#if defined(EAI_BADFLAGS)
+ case EAI_BADFLAGS: return UV_EAI_BADFLAGS;
+#endif
+#if defined(EAI_BADHINTS)
+ case EAI_BADHINTS: return UV_EAI_BADHINTS;
+#endif
+#if defined(EAI_CANCELED)
+ case EAI_CANCELED: return UV_EAI_CANCELED;
+#endif
+#if defined(EAI_FAIL)
+ case EAI_FAIL: return UV_EAI_FAIL;
+#endif
+#if defined(EAI_FAMILY)
+ case EAI_FAMILY: return UV_EAI_FAMILY;
+#endif
+#if defined(EAI_MEMORY)
+ case EAI_MEMORY: return UV_EAI_MEMORY;
+#endif
+#if defined(EAI_NODATA)
+ case EAI_NODATA: return UV_EAI_NODATA;
+#endif
+#if defined(EAI_NONAME)
+# if !defined(EAI_NODATA) || EAI_NODATA != EAI_NONAME
+ case EAI_NONAME: return UV_EAI_NONAME;
+# endif
+#endif
+#if defined(EAI_OVERFLOW)
+ case EAI_OVERFLOW: return UV_EAI_OVERFLOW;
+#endif
+#if defined(EAI_PROTOCOL)
+ case EAI_PROTOCOL: return UV_EAI_PROTOCOL;
+#endif
+#if defined(EAI_SERVICE)
+ case EAI_SERVICE: return UV_EAI_SERVICE;
+#endif
+#if defined(EAI_SOCKTYPE)
+ case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE;
+#endif
+#if defined(EAI_SYSTEM)
+ case EAI_SYSTEM: return -errno;
+#endif
+ }
+ assert(!"unknown EAI_* error code");
+ abort();
+ return 0; /* Pacify compiler. */
+}
+
+
+static void uv__getaddrinfo_work(struct uv__work* w) {
+ uv_getaddrinfo_t* req;
+ int err;
+
+ req = container_of(w, uv_getaddrinfo_t, work_req);
+ err = getaddrinfo(req->hostname, req->service, req->hints, &req->addrinfo);
+ req->retcode = uv__getaddrinfo_translate_error(err);
+}
+
+
+static void uv__getaddrinfo_done(struct uv__work* w, int status) {
+ uv_getaddrinfo_t* req;
+
+ req = container_of(w, uv_getaddrinfo_t, work_req);
+ uv__req_unregister(req->loop, req);
+
+ /* See initialization in uv_getaddrinfo(). */
+ if (req->hints)
+ uv__free(req->hints);
+ else if (req->service)
+ uv__free(req->service);
+ else if (req->hostname)
+ uv__free(req->hostname);
+ else
+ assert(0);
+
+ req->hints = NULL;
+ req->service = NULL;
+ req->hostname = NULL;
+
+ if (status == -ECANCELED) {
+ assert(req->retcode == 0);
+ req->retcode = UV_EAI_CANCELED;
+ }
+
+ if (req->cb)
+ req->cb(req, req->retcode, req->addrinfo);
+}
+
+
+int uv_getaddrinfo(uv_loop_t* loop,
+ uv_getaddrinfo_t* req,
+ uv_getaddrinfo_cb cb,
+ const char* hostname,
+ const char* service,
+ const struct addrinfo* hints) {
+ size_t hostname_len;
+ size_t service_len;
+ size_t hints_len;
+ size_t len;
+ char* buf;
+
+ if (req == NULL || (hostname == NULL && service == NULL))
+ return -EINVAL;
+
+ hostname_len = hostname ? strlen(hostname) + 1 : 0;
+ service_len = service ? strlen(service) + 1 : 0;
+ hints_len = hints ? sizeof(*hints) : 0;
+ buf = uv__malloc(hostname_len + service_len + hints_len);
+
+ if (buf == NULL)
+ return -ENOMEM;
+
+ uv__req_init(loop, req, UV_GETADDRINFO);
+ req->loop = loop;
+ req->cb = cb;
+ req->addrinfo = NULL;
+ req->hints = NULL;
+ req->service = NULL;
+ req->hostname = NULL;
+ req->retcode = 0;
+
+ /* order matters, see uv_getaddrinfo_done() */
+ len = 0;
+
+ if (hints) {
+ req->hints = memcpy(buf + len, hints, sizeof(*hints));
+ len += sizeof(*hints);
+ }
+
+ if (service) {
+ req->service = memcpy(buf + len, service, service_len);
+ len += service_len;
+ }
+
+ if (hostname)
+ req->hostname = memcpy(buf + len, hostname, hostname_len);
+
+ if (cb) {
+ uv__work_submit(loop,
+ &req->work_req,
+ uv__getaddrinfo_work,
+ uv__getaddrinfo_done);
+ return 0;
+ } else {
+ uv__getaddrinfo_work(&req->work_req);
+ uv__getaddrinfo_done(&req->work_req, 0);
+ return req->retcode;
+ }
+}
+
+
+void uv_freeaddrinfo(struct addrinfo* ai) {
+ if (ai)
+ freeaddrinfo(ai);
+}
diff --git a/3rdparty/libuv/src/unix/getnameinfo.c b/3rdparty/libuv/src/unix/getnameinfo.c
new file mode 100644
index 00000000000..daa798a450e
--- /dev/null
+++ b/3rdparty/libuv/src/unix/getnameinfo.c
@@ -0,0 +1,120 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to
+* deal in the Software without restriction, including without limitation the
+* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+* sell copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+* IN THE SOFTWARE.
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+static void uv__getnameinfo_work(struct uv__work* w) {
+ uv_getnameinfo_t* req;
+ int err;
+ socklen_t salen;
+
+ req = container_of(w, uv_getnameinfo_t, work_req);
+
+ if (req->storage.ss_family == AF_INET)
+ salen = sizeof(struct sockaddr_in);
+ else if (req->storage.ss_family == AF_INET6)
+ salen = sizeof(struct sockaddr_in6);
+ else
+ abort();
+
+ err = getnameinfo((struct sockaddr*) &req->storage,
+ salen,
+ req->host,
+ sizeof(req->host),
+ req->service,
+ sizeof(req->service),
+ req->flags);
+ req->retcode = uv__getaddrinfo_translate_error(err);
+}
+
+static void uv__getnameinfo_done(struct uv__work* w, int status) {
+ uv_getnameinfo_t* req;
+ char* host;
+ char* service;
+
+ req = container_of(w, uv_getnameinfo_t, work_req);
+ uv__req_unregister(req->loop, req);
+ host = service = NULL;
+
+ if (status == -ECANCELED) {
+ assert(req->retcode == 0);
+ req->retcode = UV_EAI_CANCELED;
+ } else if (req->retcode == 0) {
+ host = req->host;
+ service = req->service;
+ }
+
+ if (req->getnameinfo_cb)
+ req->getnameinfo_cb(req, req->retcode, host, service);
+}
+
+/*
+* Entry point for getnameinfo
+* return 0 if a callback will be made
+* return error code if validation fails
+*/
+int uv_getnameinfo(uv_loop_t* loop,
+ uv_getnameinfo_t* req,
+ uv_getnameinfo_cb getnameinfo_cb,
+ const struct sockaddr* addr,
+ int flags) {
+ if (req == NULL || addr == NULL)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in));
+ } else if (addr->sa_family == AF_INET6) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in6));
+ } else {
+ return UV_EINVAL;
+ }
+
+ uv__req_init(loop, (uv_req_t*)req, UV_GETNAMEINFO);
+
+ req->getnameinfo_cb = getnameinfo_cb;
+ req->flags = flags;
+ req->type = UV_GETNAMEINFO;
+ req->loop = loop;
+ req->retcode = 0;
+
+ if (getnameinfo_cb) {
+ uv__work_submit(loop,
+ &req->work_req,
+ uv__getnameinfo_work,
+ uv__getnameinfo_done);
+ return 0;
+ } else {
+ uv__getnameinfo_work(&req->work_req);
+ uv__getnameinfo_done(&req->work_req, 0);
+ return req->retcode;
+ }
+}
diff --git a/3rdparty/libuv/src/unix/internal.h b/3rdparty/libuv/src/unix/internal.h
new file mode 100644
index 00000000000..741fa57d69c
--- /dev/null
+++ b/3rdparty/libuv/src/unix/internal.h
@@ -0,0 +1,316 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_UNIX_INTERNAL_H_
+#define UV_UNIX_INTERNAL_H_
+
+#include "uv-common.h"
+
+#include <assert.h>
+#include <stdlib.h> /* abort */
+#include <string.h> /* strrchr */
+#include <fcntl.h> /* O_CLOEXEC, may be */
+
+#if defined(__STRICT_ANSI__)
+# define inline __inline
+#endif
+
+#if defined(__linux__)
+# include "linux-syscalls.h"
+#endif /* __linux__ */
+
+#if defined(__sun)
+# include <sys/port.h>
+# include <port.h>
+#endif /* __sun */
+
+#if defined(_AIX)
+#define reqevents events
+#define rtnevents revents
+#include <sys/poll.h>
+#endif /* _AIX */
+
+#if defined(__APPLE__) && !TARGET_OS_IPHONE
+# include <CoreServices/CoreServices.h>
+#endif
+
+#define ACCESS_ONCE(type, var) \
+ (*(volatile type*) &(var))
+
+#define ROUND_UP(a, b) \
+ ((a) % (b) ? ((a) + (b)) - ((a) % (b)) : (a))
+
+#define UNREACHABLE() \
+ do { \
+ assert(0 && "unreachable code"); \
+ abort(); \
+ } \
+ while (0)
+
+#define SAVE_ERRNO(block) \
+ do { \
+ int _saved_errno = errno; \
+ do { block; } while (0); \
+ errno = _saved_errno; \
+ } \
+ while (0)
+
+/* The __clang__ and __INTEL_COMPILER checks are superfluous because they
+ * define __GNUC__. They are here to convey to you, dear reader, that these
+ * macros are enabled when compiling with clang or icc.
+ */
+#if defined(__clang__) || \
+ defined(__GNUC__) || \
+ defined(__INTEL_COMPILER) || \
+ defined(__SUNPRO_C)
+# define UV_DESTRUCTOR(declaration) __attribute__((destructor)) declaration
+# define UV_UNUSED(declaration) __attribute__((unused)) declaration
+#else
+# define UV_DESTRUCTOR(declaration) declaration
+# define UV_UNUSED(declaration) declaration
+#endif
+
+#if defined(__linux__)
+# define UV__POLLIN UV__EPOLLIN
+# define UV__POLLOUT UV__EPOLLOUT
+# define UV__POLLERR UV__EPOLLERR
+# define UV__POLLHUP UV__EPOLLHUP
+#endif
+
+#if defined(__sun) || defined(_AIX)
+# define UV__POLLIN POLLIN
+# define UV__POLLOUT POLLOUT
+# define UV__POLLERR POLLERR
+# define UV__POLLHUP POLLHUP
+#endif
+
+#ifndef UV__POLLIN
+# define UV__POLLIN 1
+#endif
+
+#ifndef UV__POLLOUT
+# define UV__POLLOUT 2
+#endif
+
+#ifndef UV__POLLERR
+# define UV__POLLERR 4
+#endif
+
+#ifndef UV__POLLHUP
+# define UV__POLLHUP 8
+#endif
+
+#if !defined(O_CLOEXEC) && defined(__FreeBSD__)
+/*
+ * It may be that we are just missing `__POSIX_VISIBLE >= 200809`.
+ * Try using fixed value const and give up, if it doesn't work
+ */
+# define O_CLOEXEC 0x00100000
+#endif
+
+typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t;
+
+/* handle flags */
+enum {
+ UV_CLOSING = 0x01, /* uv_close() called but not finished. */
+ UV_CLOSED = 0x02, /* close(2) finished. */
+ UV_STREAM_READING = 0x04, /* uv_read_start() called. */
+ UV_STREAM_SHUTTING = 0x08, /* uv_shutdown() called but not complete. */
+ UV_STREAM_SHUT = 0x10, /* Write side closed. */
+ UV_STREAM_READABLE = 0x20, /* The stream is readable */
+ UV_STREAM_WRITABLE = 0x40, /* The stream is writable */
+ UV_STREAM_BLOCKING = 0x80, /* Synchronous writes. */
+ UV_STREAM_READ_PARTIAL = 0x100, /* read(2) read less than requested. */
+ UV_STREAM_READ_EOF = 0x200, /* read(2) read EOF. */
+ UV_TCP_NODELAY = 0x400, /* Disable Nagle. */
+ UV_TCP_KEEPALIVE = 0x800, /* Turn on keep-alive. */
+ UV_TCP_SINGLE_ACCEPT = 0x1000, /* Only accept() when idle. */
+ UV_HANDLE_IPV6 = 0x10000, /* Handle is bound to a IPv6 socket. */
+ UV_UDP_PROCESSING = 0x20000 /* Handle is running the send callback queue. */
+};
+
+/* loop flags */
+enum {
+ UV_LOOP_BLOCK_SIGPROF = 1
+};
+
+typedef enum {
+ UV_CLOCK_PRECISE = 0, /* Use the highest resolution clock available. */
+ UV_CLOCK_FAST = 1 /* Use the fastest clock with <= 1ms granularity. */
+} uv_clocktype_t;
+
+struct uv__stream_queued_fds_s {
+ unsigned int size;
+ unsigned int offset;
+ int fds[1];
+};
+
+
+/* core */
+int uv__nonblock(int fd, int set);
+int uv__close(int fd);
+int uv__cloexec(int fd, int set);
+int uv__socket(int domain, int type, int protocol);
+int uv__dup(int fd);
+ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);
+void uv__make_close_pending(uv_handle_t* handle);
+int uv__getiovmax(void);
+
+void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd);
+void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events);
+void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events);
+void uv__io_close(uv_loop_t* loop, uv__io_t* w);
+void uv__io_feed(uv_loop_t* loop, uv__io_t* w);
+int uv__io_active(const uv__io_t* w, unsigned int events);
+void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */
+
+/* async */
+void uv__async_send(struct uv__async* wa);
+void uv__async_init(struct uv__async* wa);
+int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb);
+void uv__async_stop(uv_loop_t* loop, struct uv__async* wa);
+
+/* loop */
+void uv__run_idle(uv_loop_t* loop);
+void uv__run_check(uv_loop_t* loop);
+void uv__run_prepare(uv_loop_t* loop);
+
+/* stream */
+void uv__stream_init(uv_loop_t* loop, uv_stream_t* stream,
+ uv_handle_type type);
+int uv__stream_open(uv_stream_t*, int fd, int flags);
+void uv__stream_destroy(uv_stream_t* stream);
+#if defined(__APPLE__)
+int uv__stream_try_select(uv_stream_t* stream, int* fd);
+#endif /* defined(__APPLE__) */
+void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
+int uv__accept(int sockfd);
+int uv__dup2_cloexec(int oldfd, int newfd);
+int uv__open_cloexec(const char* path, int flags);
+
+/* tcp */
+int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb);
+int uv__tcp_nodelay(int fd, int on);
+int uv__tcp_keepalive(int fd, int on, unsigned int delay);
+
+/* pipe */
+int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
+
+/* timer */
+void uv__run_timers(uv_loop_t* loop);
+int uv__next_timeout(const uv_loop_t* loop);
+
+/* signal */
+void uv__signal_close(uv_signal_t* handle);
+void uv__signal_global_once_init(void);
+void uv__signal_loop_cleanup(uv_loop_t* loop);
+
+/* platform specific */
+uint64_t uv__hrtime(uv_clocktype_t type);
+int uv__kqueue_init(uv_loop_t* loop);
+int uv__platform_loop_init(uv_loop_t* loop);
+void uv__platform_loop_delete(uv_loop_t* loop);
+void uv__platform_invalidate_fd(uv_loop_t* loop, int fd);
+
+/* various */
+void uv__async_close(uv_async_t* handle);
+void uv__check_close(uv_check_t* handle);
+void uv__fs_event_close(uv_fs_event_t* handle);
+void uv__idle_close(uv_idle_t* handle);
+void uv__pipe_close(uv_pipe_t* handle);
+void uv__poll_close(uv_poll_t* handle);
+void uv__prepare_close(uv_prepare_t* handle);
+void uv__process_close(uv_process_t* handle);
+void uv__stream_close(uv_stream_t* handle);
+void uv__tcp_close(uv_tcp_t* handle);
+void uv__timer_close(uv_timer_t* handle);
+void uv__udp_close(uv_udp_t* handle);
+void uv__udp_finish_close(uv_udp_t* handle);
+uv_handle_type uv__handle_type(int fd);
+
+#if defined(__APPLE__)
+int uv___stream_fd(const uv_stream_t* handle);
+#define uv__stream_fd(handle) (uv___stream_fd((const uv_stream_t*) (handle)))
+#else
+#define uv__stream_fd(handle) ((handle)->io_watcher.fd)
+#endif /* defined(__APPLE__) */
+
+#ifdef UV__O_NONBLOCK
+# define UV__F_NONBLOCK UV__O_NONBLOCK
+#else
+# define UV__F_NONBLOCK 1
+#endif
+
+int uv__make_socketpair(int fds[2], int flags);
+int uv__make_pipe(int fds[2], int flags);
+
+#if defined(__APPLE__)
+
+int uv__fsevents_init(uv_fs_event_t* handle);
+int uv__fsevents_close(uv_fs_event_t* handle);
+void uv__fsevents_loop_delete(uv_loop_t* loop);
+
+/* OSX < 10.7 has no file events, polyfill them */
+#ifndef MAC_OS_X_VERSION_10_7
+
+static const int kFSEventStreamCreateFlagFileEvents = 0x00000010;
+static const int kFSEventStreamEventFlagItemCreated = 0x00000100;
+static const int kFSEventStreamEventFlagItemRemoved = 0x00000200;
+static const int kFSEventStreamEventFlagItemInodeMetaMod = 0x00000400;
+static const int kFSEventStreamEventFlagItemRenamed = 0x00000800;
+static const int kFSEventStreamEventFlagItemModified = 0x00001000;
+static const int kFSEventStreamEventFlagItemFinderInfoMod = 0x00002000;
+static const int kFSEventStreamEventFlagItemChangeOwner = 0x00004000;
+static const int kFSEventStreamEventFlagItemXattrMod = 0x00008000;
+static const int kFSEventStreamEventFlagItemIsFile = 0x00010000;
+static const int kFSEventStreamEventFlagItemIsDir = 0x00020000;
+static const int kFSEventStreamEventFlagItemIsSymlink = 0x00040000;
+
+#endif /* __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 */
+
+#endif /* defined(__APPLE__) */
+
+UV_UNUSED(static void uv__req_init(uv_loop_t* loop,
+ uv_req_t* req,
+ uv_req_type type)) {
+ req->type = type;
+ uv__req_register(loop, req);
+}
+#define uv__req_init(loop, req, type) \
+ uv__req_init((loop), (uv_req_t*)(req), (type))
+
+UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) {
+ /* Use a fast time source if available. We only need millisecond precision.
+ */
+ loop->time = uv__hrtime(UV_CLOCK_FAST) / 1000000;
+}
+
+UV_UNUSED(static char* uv__basename_r(const char* path)) {
+ char* s;
+
+ s = strrchr(path, '/');
+ if (s == NULL)
+ return (char*) path;
+
+ return s + 1;
+}
+
+#endif /* UV_UNIX_INTERNAL_H_ */
diff --git a/3rdparty/libuv/src/unix/kqueue.c b/3rdparty/libuv/src/unix/kqueue.c
new file mode 100644
index 00000000000..495f20d285f
--- /dev/null
+++ b/3rdparty/libuv/src/unix/kqueue.c
@@ -0,0 +1,426 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+
+static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags);
+
+
+int uv__kqueue_init(uv_loop_t* loop) {
+ loop->backend_fd = kqueue();
+ if (loop->backend_fd == -1)
+ return -errno;
+
+ uv__cloexec(loop->backend_fd, 1);
+
+ return 0;
+}
+
+
+void uv__io_poll(uv_loop_t* loop, int timeout) {
+ struct kevent events[1024];
+ struct kevent* ev;
+ struct timespec spec;
+ unsigned int nevents;
+ unsigned int revents;
+ QUEUE* q;
+ uv__io_t* w;
+ sigset_t* pset;
+ sigset_t set;
+ uint64_t base;
+ uint64_t diff;
+ int filter;
+ int fflags;
+ int count;
+ int nfds;
+ int fd;
+ int op;
+ int i;
+
+ if (loop->nfds == 0) {
+ assert(QUEUE_EMPTY(&loop->watcher_queue));
+ return;
+ }
+
+ nevents = 0;
+
+ while (!QUEUE_EMPTY(&loop->watcher_queue)) {
+ q = QUEUE_HEAD(&loop->watcher_queue);
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q);
+
+ w = QUEUE_DATA(q, uv__io_t, watcher_queue);
+ assert(w->pevents != 0);
+ assert(w->fd >= 0);
+ assert(w->fd < (int) loop->nwatchers);
+
+ if ((w->events & UV__POLLIN) == 0 && (w->pevents & UV__POLLIN) != 0) {
+ filter = EVFILT_READ;
+ fflags = 0;
+ op = EV_ADD;
+
+ if (w->cb == uv__fs_event) {
+ filter = EVFILT_VNODE;
+ fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME
+ | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
+ op = EV_ADD | EV_ONESHOT; /* Stop the event from firing repeatedly. */
+ }
+
+ EV_SET(events + nevents, w->fd, filter, op, fflags, 0, 0);
+
+ if (++nevents == ARRAY_SIZE(events)) {
+ if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
+ abort();
+ nevents = 0;
+ }
+ }
+
+ if ((w->events & UV__POLLOUT) == 0 && (w->pevents & UV__POLLOUT) != 0) {
+ EV_SET(events + nevents, w->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
+
+ if (++nevents == ARRAY_SIZE(events)) {
+ if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
+ abort();
+ nevents = 0;
+ }
+ }
+
+ w->events = w->pevents;
+ }
+
+ pset = NULL;
+ if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
+ pset = &set;
+ sigemptyset(pset);
+ sigaddset(pset, SIGPROF);
+ }
+
+ assert(timeout >= -1);
+ base = loop->time;
+ count = 48; /* Benchmarks suggest this gives the best throughput. */
+
+ for (;; nevents = 0) {
+ if (timeout != -1) {
+ spec.tv_sec = timeout / 1000;
+ spec.tv_nsec = (timeout % 1000) * 1000000;
+ }
+
+ if (pset != NULL)
+ pthread_sigmask(SIG_BLOCK, pset, NULL);
+
+ nfds = kevent(loop->backend_fd,
+ events,
+ nevents,
+ events,
+ ARRAY_SIZE(events),
+ timeout == -1 ? NULL : &spec);
+
+ if (pset != NULL)
+ pthread_sigmask(SIG_UNBLOCK, pset, NULL);
+
+ /* Update loop->time unconditionally. It's tempting to skip the update when
+ * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
+ * operating system didn't reschedule our process while in the syscall.
+ */
+ SAVE_ERRNO(uv__update_time(loop));
+
+ if (nfds == 0) {
+ assert(timeout != -1);
+ return;
+ }
+
+ if (nfds == -1) {
+ if (errno != EINTR)
+ abort();
+
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+ /* Interrupted by a signal. Update timeout and poll again. */
+ goto update_timeout;
+ }
+
+ nevents = 0;
+
+ assert(loop->watchers != NULL);
+ loop->watchers[loop->nwatchers] = (void*) events;
+ loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
+ for (i = 0; i < nfds; i++) {
+ ev = events + i;
+ fd = ev->ident;
+ /* Skip invalidated events, see uv__platform_invalidate_fd */
+ if (fd == -1)
+ continue;
+ w = loop->watchers[fd];
+
+ if (w == NULL) {
+ /* File descriptor that we've stopped watching, disarm it. */
+ /* TODO batch up */
+ struct kevent events[1];
+
+ EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
+ if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
+ if (errno != EBADF && errno != ENOENT)
+ abort();
+
+ continue;
+ }
+
+ if (ev->filter == EVFILT_VNODE) {
+ assert(w->events == UV__POLLIN);
+ assert(w->pevents == UV__POLLIN);
+ w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */
+ nevents++;
+ continue;
+ }
+
+ revents = 0;
+
+ if (ev->filter == EVFILT_READ) {
+ if (w->pevents & UV__POLLIN) {
+ revents |= UV__POLLIN;
+ w->rcount = ev->data;
+ } else {
+ /* TODO batch up */
+ struct kevent events[1];
+ EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
+ if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
+ if (errno != ENOENT)
+ abort();
+ }
+ }
+
+ if (ev->filter == EVFILT_WRITE) {
+ if (w->pevents & UV__POLLOUT) {
+ revents |= UV__POLLOUT;
+ w->wcount = ev->data;
+ } else {
+ /* TODO batch up */
+ struct kevent events[1];
+ EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
+ if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
+ if (errno != ENOENT)
+ abort();
+ }
+ }
+
+ if (ev->flags & EV_ERROR)
+ revents |= UV__POLLERR;
+
+ if (revents == 0)
+ continue;
+
+ w->cb(loop, w, revents);
+ nevents++;
+ }
+ loop->watchers[loop->nwatchers] = NULL;
+ loop->watchers[loop->nwatchers + 1] = NULL;
+
+ if (nevents != 0) {
+ if (nfds == ARRAY_SIZE(events) && --count != 0) {
+ /* Poll for more events but don't block this time. */
+ timeout = 0;
+ continue;
+ }
+ return;
+ }
+
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+update_timeout:
+ assert(timeout > 0);
+
+ diff = loop->time - base;
+ if (diff >= (uint64_t) timeout)
+ return;
+
+ timeout -= diff;
+ }
+}
+
+
+void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
+ struct kevent* events;
+ uintptr_t i;
+ uintptr_t nfds;
+
+ assert(loop->watchers != NULL);
+
+ events = (struct kevent*) loop->watchers[loop->nwatchers];
+ nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
+ if (events == NULL)
+ return;
+
+ /* Invalidate events with same file descriptor */
+ for (i = 0; i < nfds; i++)
+ if ((int) events[i].ident == fd)
+ events[i].ident = -1;
+}
+
+
+static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) {
+ uv_fs_event_t* handle;
+ struct kevent ev;
+ int events;
+ const char* path;
+#if defined(F_GETPATH)
+ /* MAXPATHLEN == PATH_MAX but the former is what XNU calls it internally. */
+ char pathbuf[MAXPATHLEN];
+#endif
+
+ handle = container_of(w, uv_fs_event_t, event_watcher);
+
+ if (fflags & (NOTE_ATTRIB | NOTE_EXTEND))
+ events = UV_CHANGE;
+ else
+ events = UV_RENAME;
+
+ path = NULL;
+#if defined(F_GETPATH)
+ /* Also works when the file has been unlinked from the file system. Passing
+ * in the path when the file has been deleted is arguably a little strange
+ * but it's consistent with what the inotify backend does.
+ */
+ if (fcntl(handle->event_watcher.fd, F_GETPATH, pathbuf) == 0)
+ path = uv__basename_r(pathbuf);
+#endif
+ handle->cb(handle, path, events, 0);
+
+ if (handle->event_watcher.fd == -1)
+ return;
+
+ /* Watcher operates in one-shot mode, re-arm it. */
+ fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME
+ | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
+
+ EV_SET(&ev, w->fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, fflags, 0, 0);
+
+ if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
+ abort();
+}
+
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
+ return 0;
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* path,
+ unsigned int flags) {
+#if defined(__APPLE__)
+ struct stat statbuf;
+#endif /* defined(__APPLE__) */
+ int fd;
+
+ if (uv__is_active(handle))
+ return -EINVAL;
+
+ /* TODO open asynchronously - but how do we report back errors? */
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return -errno;
+
+ uv__handle_start(handle);
+ uv__io_init(&handle->event_watcher, uv__fs_event, fd);
+ handle->path = uv__strdup(path);
+ handle->cb = cb;
+
+#if defined(__APPLE__)
+ /* Nullify field to perform checks later */
+ handle->cf_cb = NULL;
+ handle->realpath = NULL;
+ handle->realpath_len = 0;
+ handle->cf_flags = flags;
+
+ if (fstat(fd, &statbuf))
+ goto fallback;
+ /* FSEvents works only with directories */
+ if (!(statbuf.st_mode & S_IFDIR))
+ goto fallback;
+
+ /* The fallback fd is no longer needed */
+ uv__close(fd);
+ handle->event_watcher.fd = -1;
+
+ return uv__fsevents_init(handle);
+
+fallback:
+#endif /* defined(__APPLE__) */
+
+ uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN);
+
+ return 0;
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+ if (!uv__is_active(handle))
+ return 0;
+
+ uv__handle_stop(handle);
+
+#if defined(__APPLE__)
+ if (uv__fsevents_close(handle))
+#endif /* defined(__APPLE__) */
+ {
+ uv__io_close(handle->loop, &handle->event_watcher);
+ }
+
+ uv__free(handle->path);
+ handle->path = NULL;
+
+ if (handle->event_watcher.fd != -1) {
+ /* When FSEvents is used, we don't use the event_watcher's fd under certain
+ * confitions. (see uv_fs_event_start) */
+ uv__close(handle->event_watcher.fd);
+ handle->event_watcher.fd = -1;
+ }
+
+ return 0;
+}
+
+
+void uv__fs_event_close(uv_fs_event_t* handle) {
+ uv_fs_event_stop(handle);
+}
diff --git a/3rdparty/libuv/src/unix/linux-core.c b/3rdparty/libuv/src/unix/linux-core.c
new file mode 100644
index 00000000000..3ff6fb15e93
--- /dev/null
+++ b/3rdparty/libuv/src/unix/linux-core.c
@@ -0,0 +1,899 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <net/if.h>
+#include <sys/param.h>
+#include <sys/prctl.h>
+#include <sys/sysinfo.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+
+#define HAVE_IFADDRS_H 1
+
+#ifdef __UCLIBC__
+# if __UCLIBC_MAJOR__ < 0 || __UCLIBC_MINOR__ < 9 || __UCLIBC_SUBLEVEL__ < 32
+# undef HAVE_IFADDRS_H
+# endif
+#endif
+
+#ifdef HAVE_IFADDRS_H
+# if defined(__ANDROID__)
+# include "android-ifaddrs.h"
+# else
+# include <ifaddrs.h>
+# endif
+# include <sys/socket.h>
+# include <net/ethernet.h>
+# include <linux/if_packet.h>
+#endif /* HAVE_IFADDRS_H */
+
+/* Available from 2.6.32 onwards. */
+#ifndef CLOCK_MONOTONIC_COARSE
+# define CLOCK_MONOTONIC_COARSE 6
+#endif
+
+/* This is rather annoying: CLOCK_BOOTTIME lives in <linux/time.h> but we can't
+ * include that file because it conflicts with <time.h>. We'll just have to
+ * define it ourselves.
+ */
+#ifndef CLOCK_BOOTTIME
+# define CLOCK_BOOTTIME 7
+#endif
+
+static int read_models(unsigned int numcpus, uv_cpu_info_t* ci);
+static int read_times(unsigned int numcpus, uv_cpu_info_t* ci);
+static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci);
+static unsigned long read_cpufreq(unsigned int cpunum);
+
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ int fd;
+
+ fd = uv__epoll_create1(UV__EPOLL_CLOEXEC);
+
+ /* epoll_create1() can fail either because it's not implemented (old kernel)
+ * or because it doesn't understand the EPOLL_CLOEXEC flag.
+ */
+ if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) {
+ fd = uv__epoll_create(256);
+
+ if (fd != -1)
+ uv__cloexec(fd, 1);
+ }
+
+ loop->backend_fd = fd;
+ loop->inotify_fd = -1;
+ loop->inotify_watchers = NULL;
+
+ if (fd == -1)
+ return -errno;
+
+ return 0;
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+ if (loop->inotify_fd == -1) return;
+ uv__io_stop(loop, &loop->inotify_read_watcher, UV__POLLIN);
+ uv__close(loop->inotify_fd);
+ loop->inotify_fd = -1;
+}
+
+
+void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
+ struct uv__epoll_event* events;
+ struct uv__epoll_event dummy;
+ uintptr_t i;
+ uintptr_t nfds;
+
+ assert(loop->watchers != NULL);
+
+ events = (struct uv__epoll_event*) loop->watchers[loop->nwatchers];
+ nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
+ if (events != NULL)
+ /* Invalidate events with same file descriptor */
+ for (i = 0; i < nfds; i++)
+ if ((int) events[i].data == fd)
+ events[i].data = -1;
+
+ /* Remove the file descriptor from the epoll.
+ * This avoids a problem where the same file description remains open
+ * in another process, causing repeated junk epoll events.
+ *
+ * We pass in a dummy epoll_event, to work around a bug in old kernels.
+ */
+ if (loop->backend_fd >= 0) {
+ /* Work around a bug in kernels 3.10 to 3.19 where passing a struct that
+ * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings.
+ */
+ memset(&dummy, 0, sizeof(dummy));
+ uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &dummy);
+ }
+}
+
+
+void uv__io_poll(uv_loop_t* loop, int timeout) {
+ /* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes
+ * effectively infinite on 32 bits architectures. To avoid blocking
+ * indefinitely, we cap the timeout and poll again if necessary.
+ *
+ * Note that "30 minutes" is a simplification because it depends on
+ * the value of CONFIG_HZ. The magic constant assumes CONFIG_HZ=1200,
+ * that being the largest value I have seen in the wild (and only once.)
+ */
+ static const int max_safe_timeout = 1789569;
+ static int no_epoll_pwait;
+ static int no_epoll_wait;
+ struct uv__epoll_event events[1024];
+ struct uv__epoll_event* pe;
+ struct uv__epoll_event e;
+ int real_timeout;
+ QUEUE* q;
+ uv__io_t* w;
+ sigset_t sigset;
+ uint64_t sigmask;
+ uint64_t base;
+ int nevents;
+ int count;
+ int nfds;
+ int fd;
+ int op;
+ int i;
+
+ if (loop->nfds == 0) {
+ assert(QUEUE_EMPTY(&loop->watcher_queue));
+ return;
+ }
+
+ while (!QUEUE_EMPTY(&loop->watcher_queue)) {
+ q = QUEUE_HEAD(&loop->watcher_queue);
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q);
+
+ w = QUEUE_DATA(q, uv__io_t, watcher_queue);
+ assert(w->pevents != 0);
+ assert(w->fd >= 0);
+ assert(w->fd < (int) loop->nwatchers);
+
+ e.events = w->pevents;
+ e.data = w->fd;
+
+ if (w->events == 0)
+ op = UV__EPOLL_CTL_ADD;
+ else
+ op = UV__EPOLL_CTL_MOD;
+
+ /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
+ * events, skip the syscall and squelch the events after epoll_wait().
+ */
+ if (uv__epoll_ctl(loop->backend_fd, op, w->fd, &e)) {
+ if (errno != EEXIST)
+ abort();
+
+ assert(op == UV__EPOLL_CTL_ADD);
+
+ /* We've reactivated a file descriptor that's been watched before. */
+ if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_MOD, w->fd, &e))
+ abort();
+ }
+
+ w->events = w->pevents;
+ }
+
+ sigmask = 0;
+ if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGPROF);
+ sigmask |= 1 << (SIGPROF - 1);
+ }
+
+ assert(timeout >= -1);
+ base = loop->time;
+ count = 48; /* Benchmarks suggest this gives the best throughput. */
+ real_timeout = timeout;
+
+ for (;;) {
+ /* See the comment for max_safe_timeout for an explanation of why
+ * this is necessary. Executive summary: kernel bug workaround.
+ */
+ if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
+ timeout = max_safe_timeout;
+
+ if (sigmask != 0 && no_epoll_pwait != 0)
+ if (pthread_sigmask(SIG_BLOCK, &sigset, NULL))
+ abort();
+
+ if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) {
+ nfds = uv__epoll_pwait(loop->backend_fd,
+ events,
+ ARRAY_SIZE(events),
+ timeout,
+ sigmask);
+ if (nfds == -1 && errno == ENOSYS)
+ no_epoll_pwait = 1;
+ } else {
+ nfds = uv__epoll_wait(loop->backend_fd,
+ events,
+ ARRAY_SIZE(events),
+ timeout);
+ if (nfds == -1 && errno == ENOSYS)
+ no_epoll_wait = 1;
+ }
+
+ if (sigmask != 0 && no_epoll_pwait != 0)
+ if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL))
+ abort();
+
+ /* Update loop->time unconditionally. It's tempting to skip the update when
+ * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
+ * operating system didn't reschedule our process while in the syscall.
+ */
+ SAVE_ERRNO(uv__update_time(loop));
+
+ if (nfds == 0) {
+ assert(timeout != -1);
+
+ timeout = real_timeout - timeout;
+ if (timeout > 0)
+ continue;
+
+ return;
+ }
+
+ if (nfds == -1) {
+ if (errno == ENOSYS) {
+ /* epoll_wait() or epoll_pwait() failed, try the other system call. */
+ assert(no_epoll_wait == 0 || no_epoll_pwait == 0);
+ continue;
+ }
+
+ if (errno != EINTR)
+ abort();
+
+ if (timeout == -1)
+ continue;
+
+ if (timeout == 0)
+ return;
+
+ /* Interrupted by a signal. Update timeout and poll again. */
+ goto update_timeout;
+ }
+
+ nevents = 0;
+
+ assert(loop->watchers != NULL);
+ loop->watchers[loop->nwatchers] = (void*) events;
+ loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
+ for (i = 0; i < nfds; i++) {
+ pe = events + i;
+ fd = pe->data;
+
+ /* Skip invalidated events, see uv__platform_invalidate_fd */
+ if (fd == -1)
+ continue;
+
+ assert(fd >= 0);
+ assert((unsigned) fd < loop->nwatchers);
+
+ w = loop->watchers[fd];
+
+ if (w == NULL) {
+ /* File descriptor that we've stopped watching, disarm it.
+ *
+ * Ignore all errors because we may be racing with another thread
+ * when the file descriptor is closed.
+ */
+ uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, pe);
+ continue;
+ }
+
+ /* Give users only events they're interested in. Prevents spurious
+ * callbacks when previous callback invocation in this loop has stopped
+ * the current watcher. Also, filters out events that users has not
+ * requested us to watch.
+ */
+ pe->events &= w->pevents | UV__POLLERR | UV__POLLHUP;
+
+ /* Work around an epoll quirk where it sometimes reports just the
+ * EPOLLERR or EPOLLHUP event. In order to force the event loop to
+ * move forward, we merge in the read/write events that the watcher
+ * is interested in; uv__read() and uv__write() will then deal with
+ * the error or hangup in the usual fashion.
+ *
+ * Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user
+ * reads the available data, calls uv_read_stop(), then sometime later
+ * calls uv_read_start() again. By then, libuv has forgotten about the
+ * hangup and the kernel won't report EPOLLIN again because there's
+ * nothing left to read. If anything, libuv is to blame here. The
+ * current hack is just a quick bandaid; to properly fix it, libuv
+ * needs to remember the error/hangup event. We should get that for
+ * free when we switch over to edge-triggered I/O.
+ */
+ if (pe->events == UV__EPOLLERR || pe->events == UV__EPOLLHUP)
+ pe->events |= w->pevents & (UV__EPOLLIN | UV__EPOLLOUT);
+
+ if (pe->events != 0) {
+ w->cb(loop, w, pe->events);
+ nevents++;
+ }
+ }
+ loop->watchers[loop->nwatchers] = NULL;
+ loop->watchers[loop->nwatchers + 1] = NULL;
+
+ if (nevents != 0) {
+ if (nfds == ARRAY_SIZE(events) && --count != 0) {
+ /* Poll for more events but don't block this time. */
+ timeout = 0;
+ continue;
+ }
+ return;
+ }
+
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+update_timeout:
+ assert(timeout > 0);
+
+ real_timeout -= (loop->time - base);
+ if (real_timeout <= 0)
+ return;
+
+ timeout = real_timeout;
+ }
+}
+
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ static clock_t fast_clock_id = -1;
+ struct timespec t;
+ clock_t clock_id;
+
+ /* Prefer CLOCK_MONOTONIC_COARSE if available but only when it has
+ * millisecond granularity or better. CLOCK_MONOTONIC_COARSE is
+ * serviced entirely from the vDSO, whereas CLOCK_MONOTONIC may
+ * decide to make a costly system call.
+ */
+ /* TODO(bnoordhuis) Use CLOCK_MONOTONIC_COARSE for UV_CLOCK_PRECISE
+ * when it has microsecond granularity or better (unlikely).
+ */
+ if (type == UV_CLOCK_FAST && fast_clock_id == -1) {
+ if (clock_getres(CLOCK_MONOTONIC_COARSE, &t) == 0 &&
+ t.tv_nsec <= 1 * 1000 * 1000) {
+ fast_clock_id = CLOCK_MONOTONIC_COARSE;
+ } else {
+ fast_clock_id = CLOCK_MONOTONIC;
+ }
+ }
+
+ clock_id = CLOCK_MONOTONIC;
+ if (type == UV_CLOCK_FAST)
+ clock_id = fast_clock_id;
+
+ if (clock_gettime(clock_id, &t))
+ return 0; /* Not really possible. */
+
+ return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec;
+}
+
+
+void uv_loadavg(double avg[3]) {
+ struct sysinfo info;
+
+ if (sysinfo(&info) < 0) return;
+
+ avg[0] = (double) info.loads[0] / 65536.0;
+ avg[1] = (double) info.loads[1] / 65536.0;
+ avg[2] = (double) info.loads[2] / 65536.0;
+}
+
+
+int uv_exepath(char* buffer, size_t* size) {
+ ssize_t n;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ n = *size - 1;
+ if (n > 0)
+ n = readlink("/proc/self/exe", buffer, n);
+
+ if (n == -1)
+ return -errno;
+
+ buffer[n] = '\0';
+ *size = n;
+
+ return 0;
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES);
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ char buf[1024];
+ const char* s;
+ ssize_t n;
+ long val;
+ int fd;
+ int i;
+
+ do
+ fd = open("/proc/self/stat", O_RDONLY);
+ while (fd == -1 && errno == EINTR);
+
+ if (fd == -1)
+ return -errno;
+
+ do
+ n = read(fd, buf, sizeof(buf) - 1);
+ while (n == -1 && errno == EINTR);
+
+ uv__close(fd);
+ if (n == -1)
+ return -errno;
+ buf[n] = '\0';
+
+ s = strchr(buf, ' ');
+ if (s == NULL)
+ goto err;
+
+ s += 1;
+ if (*s != '(')
+ goto err;
+
+ s = strchr(s, ')');
+ if (s == NULL)
+ goto err;
+
+ for (i = 1; i <= 22; i++) {
+ s = strchr(s + 1, ' ');
+ if (s == NULL)
+ goto err;
+ }
+
+ errno = 0;
+ val = strtol(s, NULL, 10);
+ if (errno != 0)
+ goto err;
+ if (val < 0)
+ goto err;
+
+ *rss = val * getpagesize();
+ return 0;
+
+err:
+ return -EINVAL;
+}
+
+
+int uv_uptime(double* uptime) {
+ static volatile int no_clock_boottime;
+ struct timespec now;
+ int r;
+
+ /* Try CLOCK_BOOTTIME first, fall back to CLOCK_MONOTONIC if not available
+ * (pre-2.6.39 kernels). CLOCK_MONOTONIC doesn't increase when the system
+ * is suspended.
+ */
+ if (no_clock_boottime) {
+ retry: r = clock_gettime(CLOCK_MONOTONIC, &now);
+ }
+ else if ((r = clock_gettime(CLOCK_BOOTTIME, &now)) && errno == EINVAL) {
+ no_clock_boottime = 1;
+ goto retry;
+ }
+
+ if (r)
+ return -errno;
+
+ *uptime = now.tv_sec;
+ return 0;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ unsigned int numcpus;
+ uv_cpu_info_t* ci;
+ int err;
+
+ *cpu_infos = NULL;
+ *count = 0;
+
+ numcpus = sysconf(_SC_NPROCESSORS_ONLN);
+ assert(numcpus != (unsigned int) -1);
+ assert(numcpus != 0);
+
+ ci = uv__calloc(numcpus, sizeof(*ci));
+ if (ci == NULL)
+ return -ENOMEM;
+
+ err = read_models(numcpus, ci);
+ if (err == 0)
+ err = read_times(numcpus, ci);
+
+ if (err) {
+ uv_free_cpu_info(ci, numcpus);
+ return err;
+ }
+
+ /* read_models() on x86 also reads the CPU speed from /proc/cpuinfo.
+ * We don't check for errors here. Worst case, the field is left zero.
+ */
+ if (ci[0].speed == 0)
+ read_speeds(numcpus, ci);
+
+ *cpu_infos = ci;
+ *count = numcpus;
+
+ return 0;
+}
+
+
+static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) {
+ unsigned int num;
+
+ for (num = 0; num < numcpus; num++)
+ ci[num].speed = read_cpufreq(num) / 1000;
+}
+
+
+/* Also reads the CPU frequency on x86. The other architectures only have
+ * a BogoMIPS field, which may not be very accurate.
+ *
+ * Note: Simply returns on error, uv_cpu_info() takes care of the cleanup.
+ */
+static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
+ static const char model_marker[] = "model name\t: ";
+ static const char speed_marker[] = "cpu MHz\t\t: ";
+ const char* inferred_model;
+ unsigned int model_idx;
+ unsigned int speed_idx;
+ char buf[1024];
+ char* model;
+ FILE* fp;
+
+ /* Most are unused on non-ARM, non-MIPS and non-x86 architectures. */
+ (void) &model_marker;
+ (void) &speed_marker;
+ (void) &speed_idx;
+ (void) &model;
+ (void) &buf;
+ (void) &fp;
+
+ model_idx = 0;
+ speed_idx = 0;
+
+#if defined(__arm__) || \
+ defined(__i386__) || \
+ defined(__mips__) || \
+ defined(__x86_64__)
+ fp = fopen("/proc/cpuinfo", "r");
+ if (fp == NULL)
+ return -errno;
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (model_idx < numcpus) {
+ if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) {
+ model = buf + sizeof(model_marker) - 1;
+ model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */
+ if (model == NULL) {
+ fclose(fp);
+ return -ENOMEM;
+ }
+ ci[model_idx++].model = model;
+ continue;
+ }
+ }
+#if defined(__arm__) || defined(__mips__)
+ if (model_idx < numcpus) {
+#if defined(__arm__)
+ /* Fallback for pre-3.8 kernels. */
+ static const char model_marker[] = "Processor\t: ";
+#else /* defined(__mips__) */
+ static const char model_marker[] = "cpu model\t\t: ";
+#endif
+ if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) {
+ model = buf + sizeof(model_marker) - 1;
+ model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */
+ if (model == NULL) {
+ fclose(fp);
+ return -ENOMEM;
+ }
+ ci[model_idx++].model = model;
+ continue;
+ }
+ }
+#else /* !__arm__ && !__mips__ */
+ if (speed_idx < numcpus) {
+ if (strncmp(buf, speed_marker, sizeof(speed_marker) - 1) == 0) {
+ ci[speed_idx++].speed = atoi(buf + sizeof(speed_marker) - 1);
+ continue;
+ }
+ }
+#endif /* __arm__ || __mips__ */
+ }
+
+ fclose(fp);
+#endif /* __arm__ || __i386__ || __mips__ || __x86_64__ */
+
+ /* Now we want to make sure that all the models contain *something* because
+ * it's not safe to leave them as null. Copy the last entry unless there
+ * isn't one, in that case we simply put "unknown" into everything.
+ */
+ inferred_model = "unknown";
+ if (model_idx > 0)
+ inferred_model = ci[model_idx - 1].model;
+
+ while (model_idx < numcpus) {
+ model = uv__strndup(inferred_model, strlen(inferred_model));
+ if (model == NULL)
+ return -ENOMEM;
+ ci[model_idx++].model = model;
+ }
+
+ return 0;
+}
+
+
+static int read_times(unsigned int numcpus, uv_cpu_info_t* ci) {
+ unsigned long clock_ticks;
+ struct uv_cpu_times_s ts;
+ unsigned long user;
+ unsigned long nice;
+ unsigned long sys;
+ unsigned long idle;
+ unsigned long dummy;
+ unsigned long irq;
+ unsigned int num;
+ unsigned int len;
+ char buf[1024];
+ FILE* fp;
+
+ clock_ticks = sysconf(_SC_CLK_TCK);
+ assert(clock_ticks != (unsigned long) -1);
+ assert(clock_ticks != 0);
+
+ fp = fopen("/proc/stat", "r");
+ if (fp == NULL)
+ return -errno;
+
+ if (!fgets(buf, sizeof(buf), fp))
+ abort();
+
+ num = 0;
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (num >= numcpus)
+ break;
+
+ if (strncmp(buf, "cpu", 3))
+ break;
+
+ /* skip "cpu<num> " marker */
+ {
+ unsigned int n;
+ int r = sscanf(buf, "cpu%u ", &n);
+ assert(r == 1);
+ (void) r; /* silence build warning */
+ for (len = sizeof("cpu0"); n /= 10; len++);
+ }
+
+ /* Line contains user, nice, system, idle, iowait, irq, softirq, steal,
+ * guest, guest_nice but we're only interested in the first four + irq.
+ *
+ * Don't use %*s to skip fields or %ll to read straight into the uint64_t
+ * fields, they're not allowed in C89 mode.
+ */
+ if (6 != sscanf(buf + len,
+ "%lu %lu %lu %lu %lu %lu",
+ &user,
+ &nice,
+ &sys,
+ &idle,
+ &dummy,
+ &irq))
+ abort();
+
+ ts.user = clock_ticks * user;
+ ts.nice = clock_ticks * nice;
+ ts.sys = clock_ticks * sys;
+ ts.idle = clock_ticks * idle;
+ ts.irq = clock_ticks * irq;
+ ci[num++].cpu_times = ts;
+ }
+ fclose(fp);
+ assert(num == numcpus);
+
+ return 0;
+}
+
+
+static unsigned long read_cpufreq(unsigned int cpunum) {
+ unsigned long val;
+ char buf[1024];
+ FILE* fp;
+
+ snprintf(buf,
+ sizeof(buf),
+ "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq",
+ cpunum);
+
+ fp = fopen(buf, "r");
+ if (fp == NULL)
+ return 0;
+
+ if (fscanf(fp, "%lu", &val) != 1)
+ val = 0;
+
+ fclose(fp);
+
+ return val;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses,
+ int* count) {
+#ifndef HAVE_IFADDRS_H
+ return -ENOSYS;
+#else
+ struct ifaddrs *addrs, *ent;
+ uv_interface_address_t* address;
+ int i;
+ struct sockaddr_ll *sll;
+
+ if (getifaddrs(&addrs))
+ return -errno;
+
+ *count = 0;
+ *addresses = NULL;
+
+ /* Count the number of interfaces */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family == PF_PACKET)) {
+ continue;
+ }
+
+ (*count)++;
+ }
+
+ if (*count == 0)
+ return 0;
+
+ *addresses = uv__malloc(*count * sizeof(**addresses));
+ if (!(*addresses)) {
+ freeifaddrs(addrs);
+ return -ENOMEM;
+ }
+
+ address = *addresses;
+
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
+ continue;
+
+ if (ent->ifa_addr == NULL)
+ continue;
+
+ /*
+ * On Linux getifaddrs returns information related to the raw underlying
+ * devices. We're not interested in this information yet.
+ */
+ if (ent->ifa_addr->sa_family == PF_PACKET)
+ continue;
+
+ address->name = uv__strdup(ent->ifa_name);
+
+ if (ent->ifa_addr->sa_family == AF_INET6) {
+ address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
+ } else {
+ address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
+ }
+
+ if (ent->ifa_netmask->sa_family == AF_INET6) {
+ address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
+ } else {
+ address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
+ }
+
+ address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
+
+ address++;
+ }
+
+ /* Fill in physical addresses for each interface */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family != PF_PACKET)) {
+ continue;
+ }
+
+ address = *addresses;
+
+ for (i = 0; i < (*count); i++) {
+ if (strcmp(address->name, ent->ifa_name) == 0) {
+ sll = (struct sockaddr_ll*)ent->ifa_addr;
+ memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr));
+ }
+ address++;
+ }
+ }
+
+ freeifaddrs(addrs);
+
+ return 0;
+#endif
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(addresses[i].name);
+ }
+
+ uv__free(addresses);
+}
+
+
+void uv__set_process_title(const char* title) {
+#if defined(PR_SET_NAME)
+ prctl(PR_SET_NAME, title); /* Only copies first 16 characters. */
+#endif
+}
diff --git a/3rdparty/libuv/src/unix/linux-inotify.c b/3rdparty/libuv/src/unix/linux-inotify.c
new file mode 100644
index 00000000000..282912115d8
--- /dev/null
+++ b/3rdparty/libuv/src/unix/linux-inotify.c
@@ -0,0 +1,285 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "tree.h"
+#include "internal.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <unistd.h>
+
+struct watcher_list {
+ RB_ENTRY(watcher_list) entry;
+ QUEUE watchers;
+ int iterating;
+ char* path;
+ int wd;
+};
+
+struct watcher_root {
+ struct watcher_list* rbh_root;
+};
+#define CAST(p) ((struct watcher_root*)(p))
+
+
+static int compare_watchers(const struct watcher_list* a,
+ const struct watcher_list* b) {
+ if (a->wd < b->wd) return -1;
+ if (a->wd > b->wd) return 1;
+ return 0;
+}
+
+
+RB_GENERATE_STATIC(watcher_root, watcher_list, entry, compare_watchers)
+
+
+static void uv__inotify_read(uv_loop_t* loop,
+ uv__io_t* w,
+ unsigned int revents);
+
+
+static int new_inotify_fd(void) {
+ int err;
+ int fd;
+
+ fd = uv__inotify_init1(UV__IN_NONBLOCK | UV__IN_CLOEXEC);
+ if (fd != -1)
+ return fd;
+
+ if (errno != ENOSYS)
+ return -errno;
+
+ fd = uv__inotify_init();
+ if (fd == -1)
+ return -errno;
+
+ err = uv__cloexec(fd, 1);
+ if (err == 0)
+ err = uv__nonblock(fd, 1);
+
+ if (err) {
+ uv__close(fd);
+ return err;
+ }
+
+ return fd;
+}
+
+
+static int init_inotify(uv_loop_t* loop) {
+ int err;
+
+ if (loop->inotify_fd != -1)
+ return 0;
+
+ err = new_inotify_fd();
+ if (err < 0)
+ return err;
+
+ loop->inotify_fd = err;
+ uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd);
+ uv__io_start(loop, &loop->inotify_read_watcher, UV__POLLIN);
+
+ return 0;
+}
+
+
+static struct watcher_list* find_watcher(uv_loop_t* loop, int wd) {
+ struct watcher_list w;
+ w.wd = wd;
+ return RB_FIND(watcher_root, CAST(&loop->inotify_watchers), &w);
+}
+
+static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) {
+ /* if the watcher_list->watchers is being iterated over, we can't free it. */
+ if ((!w->iterating) && QUEUE_EMPTY(&w->watchers)) {
+ /* No watchers left for this path. Clean up. */
+ RB_REMOVE(watcher_root, CAST(&loop->inotify_watchers), w);
+ uv__inotify_rm_watch(loop->inotify_fd, w->wd);
+ uv__free(w);
+ }
+}
+
+static void uv__inotify_read(uv_loop_t* loop,
+ uv__io_t* dummy,
+ unsigned int events) {
+ const struct uv__inotify_event* e;
+ struct watcher_list* w;
+ uv_fs_event_t* h;
+ QUEUE queue;
+ QUEUE* q;
+ const char* path;
+ ssize_t size;
+ const char *p;
+ /* needs to be large enough for sizeof(inotify_event) + strlen(path) */
+ char buf[4096];
+
+ while (1) {
+ do
+ size = read(loop->inotify_fd, buf, sizeof(buf));
+ while (size == -1 && errno == EINTR);
+
+ if (size == -1) {
+ assert(errno == EAGAIN || errno == EWOULDBLOCK);
+ break;
+ }
+
+ assert(size > 0); /* pre-2.6.21 thing, size=0 == read buffer too small */
+
+ /* Now we have one or more inotify_event structs. */
+ for (p = buf; p < buf + size; p += sizeof(*e) + e->len) {
+ e = (const struct uv__inotify_event*)p;
+
+ events = 0;
+ if (e->mask & (UV__IN_ATTRIB|UV__IN_MODIFY))
+ events |= UV_CHANGE;
+ if (e->mask & ~(UV__IN_ATTRIB|UV__IN_MODIFY))
+ events |= UV_RENAME;
+
+ w = find_watcher(loop, e->wd);
+ if (w == NULL)
+ continue; /* Stale event, no watchers left. */
+
+ /* inotify does not return the filename when monitoring a single file
+ * for modifications. Repurpose the filename for API compatibility.
+ * I'm not convinced this is a good thing, maybe it should go.
+ */
+ path = e->len ? (const char*) (e + 1) : uv__basename_r(w->path);
+
+ /* We're about to iterate over the queue and call user's callbacks.
+ * What can go wrong?
+ * A callback could call uv_fs_event_stop()
+ * and the queue can change under our feet.
+ * So, we use QUEUE_MOVE() trick to safely iterate over the queue.
+ * And we don't free the watcher_list until we're done iterating.
+ *
+ * First,
+ * tell uv_fs_event_stop() (that could be called from a user's callback)
+ * not to free watcher_list.
+ */
+ w->iterating = 1;
+ QUEUE_MOVE(&w->watchers, &queue);
+ while (!QUEUE_EMPTY(&queue)) {
+ q = QUEUE_HEAD(&queue);
+ h = QUEUE_DATA(q, uv_fs_event_t, watchers);
+
+ QUEUE_REMOVE(q);
+ QUEUE_INSERT_TAIL(&w->watchers, q);
+
+ h->cb(h, path, events, 0);
+ }
+ /* done iterating, time to (maybe) free empty watcher_list */
+ w->iterating = 0;
+ maybe_free_watcher_list(w, loop);
+ }
+ }
+}
+
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
+ return 0;
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* path,
+ unsigned int flags) {
+ struct watcher_list* w;
+ int events;
+ int err;
+ int wd;
+
+ if (uv__is_active(handle))
+ return -EINVAL;
+
+ err = init_inotify(handle->loop);
+ if (err)
+ return err;
+
+ events = UV__IN_ATTRIB
+ | UV__IN_CREATE
+ | UV__IN_MODIFY
+ | UV__IN_DELETE
+ | UV__IN_DELETE_SELF
+ | UV__IN_MOVE_SELF
+ | UV__IN_MOVED_FROM
+ | UV__IN_MOVED_TO;
+
+ wd = uv__inotify_add_watch(handle->loop->inotify_fd, path, events);
+ if (wd == -1)
+ return -errno;
+
+ w = find_watcher(handle->loop, wd);
+ if (w)
+ goto no_insert;
+
+ w = uv__malloc(sizeof(*w) + strlen(path) + 1);
+ if (w == NULL)
+ return -ENOMEM;
+
+ w->wd = wd;
+ w->path = strcpy((char*)(w + 1), path);
+ QUEUE_INIT(&w->watchers);
+ w->iterating = 0;
+ RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w);
+
+no_insert:
+ uv__handle_start(handle);
+ QUEUE_INSERT_TAIL(&w->watchers, &handle->watchers);
+ handle->path = w->path;
+ handle->cb = cb;
+ handle->wd = wd;
+
+ return 0;
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+ struct watcher_list* w;
+
+ if (!uv__is_active(handle))
+ return 0;
+
+ w = find_watcher(handle->loop, handle->wd);
+ assert(w != NULL);
+
+ handle->wd = -1;
+ handle->path = NULL;
+ uv__handle_stop(handle);
+ QUEUE_REMOVE(&handle->watchers);
+
+ maybe_free_watcher_list(w, handle->loop);
+
+ return 0;
+}
+
+
+void uv__fs_event_close(uv_fs_event_t* handle) {
+ uv_fs_event_stop(handle);
+}
diff --git a/3rdparty/libuv/src/unix/linux-syscalls.c b/3rdparty/libuv/src/unix/linux-syscalls.c
new file mode 100644
index 00000000000..89998ded26b
--- /dev/null
+++ b/3rdparty/libuv/src/unix/linux-syscalls.c
@@ -0,0 +1,471 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "linux-syscalls.h"
+#include <unistd.h>
+#include <signal.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#if defined(__has_feature)
+# if __has_feature(memory_sanitizer)
+# define MSAN_ACTIVE 1
+# include <sanitizer/msan_interface.h>
+# endif
+#endif
+
+#if defined(__i386__)
+# ifndef __NR_socketcall
+# define __NR_socketcall 102
+# endif
+#endif
+
+#if defined(__arm__)
+# if defined(__thumb__) || defined(__ARM_EABI__)
+# define UV_SYSCALL_BASE 0
+# else
+# define UV_SYSCALL_BASE 0x900000
+# endif
+#endif /* __arm__ */
+
+#ifndef __NR_accept4
+# if defined(__x86_64__)
+# define __NR_accept4 288
+# elif defined(__i386__)
+ /* Nothing. Handled through socketcall(). */
+# elif defined(__arm__)
+# define __NR_accept4 (UV_SYSCALL_BASE + 366)
+# endif
+#endif /* __NR_accept4 */
+
+#ifndef __NR_eventfd
+# if defined(__x86_64__)
+# define __NR_eventfd 284
+# elif defined(__i386__)
+# define __NR_eventfd 323
+# elif defined(__arm__)
+# define __NR_eventfd (UV_SYSCALL_BASE + 351)
+# endif
+#endif /* __NR_eventfd */
+
+#ifndef __NR_eventfd2
+# if defined(__x86_64__)
+# define __NR_eventfd2 290
+# elif defined(__i386__)
+# define __NR_eventfd2 328
+# elif defined(__arm__)
+# define __NR_eventfd2 (UV_SYSCALL_BASE + 356)
+# endif
+#endif /* __NR_eventfd2 */
+
+#ifndef __NR_epoll_create
+# if defined(__x86_64__)
+# define __NR_epoll_create 213
+# elif defined(__i386__)
+# define __NR_epoll_create 254
+# elif defined(__arm__)
+# define __NR_epoll_create (UV_SYSCALL_BASE + 250)
+# endif
+#endif /* __NR_epoll_create */
+
+#ifndef __NR_epoll_create1
+# if defined(__x86_64__)
+# define __NR_epoll_create1 291
+# elif defined(__i386__)
+# define __NR_epoll_create1 329
+# elif defined(__arm__)
+# define __NR_epoll_create1 (UV_SYSCALL_BASE + 357)
+# endif
+#endif /* __NR_epoll_create1 */
+
+#ifndef __NR_epoll_ctl
+# if defined(__x86_64__)
+# define __NR_epoll_ctl 233 /* used to be 214 */
+# elif defined(__i386__)
+# define __NR_epoll_ctl 255
+# elif defined(__arm__)
+# define __NR_epoll_ctl (UV_SYSCALL_BASE + 251)
+# endif
+#endif /* __NR_epoll_ctl */
+
+#ifndef __NR_epoll_wait
+# if defined(__x86_64__)
+# define __NR_epoll_wait 232 /* used to be 215 */
+# elif defined(__i386__)
+# define __NR_epoll_wait 256
+# elif defined(__arm__)
+# define __NR_epoll_wait (UV_SYSCALL_BASE + 252)
+# endif
+#endif /* __NR_epoll_wait */
+
+#ifndef __NR_epoll_pwait
+# if defined(__x86_64__)
+# define __NR_epoll_pwait 281
+# elif defined(__i386__)
+# define __NR_epoll_pwait 319
+# elif defined(__arm__)
+# define __NR_epoll_pwait (UV_SYSCALL_BASE + 346)
+# endif
+#endif /* __NR_epoll_pwait */
+
+#ifndef __NR_inotify_init
+# if defined(__x86_64__)
+# define __NR_inotify_init 253
+# elif defined(__i386__)
+# define __NR_inotify_init 291
+# elif defined(__arm__)
+# define __NR_inotify_init (UV_SYSCALL_BASE + 316)
+# endif
+#endif /* __NR_inotify_init */
+
+#ifndef __NR_inotify_init1
+# if defined(__x86_64__)
+# define __NR_inotify_init1 294
+# elif defined(__i386__)
+# define __NR_inotify_init1 332
+# elif defined(__arm__)
+# define __NR_inotify_init1 (UV_SYSCALL_BASE + 360)
+# endif
+#endif /* __NR_inotify_init1 */
+
+#ifndef __NR_inotify_add_watch
+# if defined(__x86_64__)
+# define __NR_inotify_add_watch 254
+# elif defined(__i386__)
+# define __NR_inotify_add_watch 292
+# elif defined(__arm__)
+# define __NR_inotify_add_watch (UV_SYSCALL_BASE + 317)
+# endif
+#endif /* __NR_inotify_add_watch */
+
+#ifndef __NR_inotify_rm_watch
+# if defined(__x86_64__)
+# define __NR_inotify_rm_watch 255
+# elif defined(__i386__)
+# define __NR_inotify_rm_watch 293
+# elif defined(__arm__)
+# define __NR_inotify_rm_watch (UV_SYSCALL_BASE + 318)
+# endif
+#endif /* __NR_inotify_rm_watch */
+
+#ifndef __NR_pipe2
+# if defined(__x86_64__)
+# define __NR_pipe2 293
+# elif defined(__i386__)
+# define __NR_pipe2 331
+# elif defined(__arm__)
+# define __NR_pipe2 (UV_SYSCALL_BASE + 359)
+# endif
+#endif /* __NR_pipe2 */
+
+#ifndef __NR_recvmmsg
+# if defined(__x86_64__)
+# define __NR_recvmmsg 299
+# elif defined(__i386__)
+# define __NR_recvmmsg 337
+# elif defined(__arm__)
+# define __NR_recvmmsg (UV_SYSCALL_BASE + 365)
+# endif
+#endif /* __NR_recvmsg */
+
+#ifndef __NR_sendmmsg
+# if defined(__x86_64__)
+# define __NR_sendmmsg 307
+# elif defined(__i386__)
+# define __NR_sendmmsg 345
+# elif defined(__arm__)
+# define __NR_sendmmsg (UV_SYSCALL_BASE + 374)
+# endif
+#endif /* __NR_sendmmsg */
+
+#ifndef __NR_utimensat
+# if defined(__x86_64__)
+# define __NR_utimensat 280
+# elif defined(__i386__)
+# define __NR_utimensat 320
+# elif defined(__arm__)
+# define __NR_utimensat (UV_SYSCALL_BASE + 348)
+# endif
+#endif /* __NR_utimensat */
+
+#ifndef __NR_preadv
+# if defined(__x86_64__)
+# define __NR_preadv 295
+# elif defined(__i386__)
+# define __NR_preadv 333
+# elif defined(__arm__)
+# define __NR_preadv (UV_SYSCALL_BASE + 361)
+# endif
+#endif /* __NR_preadv */
+
+#ifndef __NR_pwritev
+# if defined(__x86_64__)
+# define __NR_pwritev 296
+# elif defined(__i386__)
+# define __NR_pwritev 334
+# elif defined(__arm__)
+# define __NR_pwritev (UV_SYSCALL_BASE + 362)
+# endif
+#endif /* __NR_pwritev */
+
+#ifndef __NR_dup3
+# if defined(__x86_64__)
+# define __NR_dup3 292
+# elif defined(__i386__)
+# define __NR_dup3 330
+# elif defined(__arm__)
+# define __NR_dup3 (UV_SYSCALL_BASE + 358)
+# endif
+#endif /* __NR_pwritev */
+
+
+int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) {
+#if defined(__i386__)
+ unsigned long args[4];
+ int r;
+
+ args[0] = (unsigned long) fd;
+ args[1] = (unsigned long) addr;
+ args[2] = (unsigned long) addrlen;
+ args[3] = (unsigned long) flags;
+
+ r = syscall(__NR_socketcall, 18 /* SYS_ACCEPT4 */, args);
+
+ /* socketcall() raises EINVAL when SYS_ACCEPT4 is not supported but so does
+ * a bad flags argument. Try to distinguish between the two cases.
+ */
+ if (r == -1)
+ if (errno == EINVAL)
+ if ((flags & ~(UV__SOCK_CLOEXEC|UV__SOCK_NONBLOCK)) == 0)
+ errno = ENOSYS;
+
+ return r;
+#elif defined(__NR_accept4)
+ return syscall(__NR_accept4, fd, addr, addrlen, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__eventfd(unsigned int count) {
+#if defined(__NR_eventfd)
+ return syscall(__NR_eventfd, count);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__eventfd2(unsigned int count, int flags) {
+#if defined(__NR_eventfd2)
+ return syscall(__NR_eventfd2, count, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__epoll_create(int size) {
+#if defined(__NR_epoll_create)
+ return syscall(__NR_epoll_create, size);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__epoll_create1(int flags) {
+#if defined(__NR_epoll_create1)
+ return syscall(__NR_epoll_create1, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event* events) {
+#if defined(__NR_epoll_ctl)
+ return syscall(__NR_epoll_ctl, epfd, op, fd, events);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__epoll_wait(int epfd,
+ struct uv__epoll_event* events,
+ int nevents,
+ int timeout) {
+#if defined(__NR_epoll_wait)
+ int result;
+ result = syscall(__NR_epoll_wait, epfd, events, nevents, timeout);
+#if MSAN_ACTIVE
+ if (result > 0)
+ __msan_unpoison(events, sizeof(events[0]) * result);
+#endif
+ return result;
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__epoll_pwait(int epfd,
+ struct uv__epoll_event* events,
+ int nevents,
+ int timeout,
+ uint64_t sigmask) {
+#if defined(__NR_epoll_pwait)
+ int result;
+ result = syscall(__NR_epoll_pwait,
+ epfd,
+ events,
+ nevents,
+ timeout,
+ &sigmask,
+ sizeof(sigmask));
+#if MSAN_ACTIVE
+ if (result > 0)
+ __msan_unpoison(events, sizeof(events[0]) * result);
+#endif
+ return result;
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__inotify_init(void) {
+#if defined(__NR_inotify_init)
+ return syscall(__NR_inotify_init);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__inotify_init1(int flags) {
+#if defined(__NR_inotify_init1)
+ return syscall(__NR_inotify_init1, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__inotify_add_watch(int fd, const char* path, uint32_t mask) {
+#if defined(__NR_inotify_add_watch)
+ return syscall(__NR_inotify_add_watch, fd, path, mask);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__inotify_rm_watch(int fd, int32_t wd) {
+#if defined(__NR_inotify_rm_watch)
+ return syscall(__NR_inotify_rm_watch, fd, wd);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__pipe2(int pipefd[2], int flags) {
+#if defined(__NR_pipe2)
+ int result;
+ result = syscall(__NR_pipe2, pipefd, flags);
+#if MSAN_ACTIVE
+ if (!result)
+ __msan_unpoison(pipefd, sizeof(int[2]));
+#endif
+ return result;
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__sendmmsg(int fd,
+ struct uv__mmsghdr* mmsg,
+ unsigned int vlen,
+ unsigned int flags) {
+#if defined(__NR_sendmmsg)
+ return syscall(__NR_sendmmsg, fd, mmsg, vlen, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__recvmmsg(int fd,
+ struct uv__mmsghdr* mmsg,
+ unsigned int vlen,
+ unsigned int flags,
+ struct timespec* timeout) {
+#if defined(__NR_recvmmsg)
+ return syscall(__NR_recvmmsg, fd, mmsg, vlen, flags, timeout);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__utimesat(int dirfd,
+ const char* path,
+ const struct timespec times[2],
+ int flags)
+{
+#if defined(__NR_utimensat)
+ return syscall(__NR_utimensat, dirfd, path, times, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
+#if defined(__NR_preadv)
+ return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
+#if defined(__NR_pwritev)
+ return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__dup3(int oldfd, int newfd, int flags) {
+#if defined(__NR_dup3)
+ return syscall(__NR_dup3, oldfd, newfd, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
diff --git a/3rdparty/libuv/src/unix/linux-syscalls.h b/3rdparty/libuv/src/unix/linux-syscalls.h
new file mode 100644
index 00000000000..96e79439cf0
--- /dev/null
+++ b/3rdparty/libuv/src/unix/linux-syscalls.h
@@ -0,0 +1,158 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_LINUX_SYSCALL_H_
+#define UV_LINUX_SYSCALL_H_
+
+#undef _GNU_SOURCE
+#define _GNU_SOURCE
+
+#include <stdint.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#if defined(__alpha__)
+# define UV__O_CLOEXEC 0x200000
+#elif defined(__hppa__)
+# define UV__O_CLOEXEC 0x200000
+#elif defined(__sparc__)
+# define UV__O_CLOEXEC 0x400000
+#else
+# define UV__O_CLOEXEC 0x80000
+#endif
+
+#if defined(__alpha__)
+# define UV__O_NONBLOCK 0x4
+#elif defined(__hppa__)
+# define UV__O_NONBLOCK O_NONBLOCK
+#elif defined(__mips__)
+# define UV__O_NONBLOCK 0x80
+#elif defined(__sparc__)
+# define UV__O_NONBLOCK 0x4000
+#else
+# define UV__O_NONBLOCK 0x800
+#endif
+
+#define UV__EFD_CLOEXEC UV__O_CLOEXEC
+#define UV__EFD_NONBLOCK UV__O_NONBLOCK
+
+#define UV__IN_CLOEXEC UV__O_CLOEXEC
+#define UV__IN_NONBLOCK UV__O_NONBLOCK
+
+#define UV__SOCK_CLOEXEC UV__O_CLOEXEC
+#if defined(SOCK_NONBLOCK)
+# define UV__SOCK_NONBLOCK SOCK_NONBLOCK
+#else
+# define UV__SOCK_NONBLOCK UV__O_NONBLOCK
+#endif
+
+/* epoll flags */
+#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC
+#define UV__EPOLL_CTL_ADD 1
+#define UV__EPOLL_CTL_DEL 2
+#define UV__EPOLL_CTL_MOD 3
+
+#define UV__EPOLLIN 1
+#define UV__EPOLLOUT 4
+#define UV__EPOLLERR 8
+#define UV__EPOLLHUP 16
+#define UV__EPOLLONESHOT 0x40000000
+#define UV__EPOLLET 0x80000000
+
+/* inotify flags */
+#define UV__IN_ACCESS 0x001
+#define UV__IN_MODIFY 0x002
+#define UV__IN_ATTRIB 0x004
+#define UV__IN_CLOSE_WRITE 0x008
+#define UV__IN_CLOSE_NOWRITE 0x010
+#define UV__IN_OPEN 0x020
+#define UV__IN_MOVED_FROM 0x040
+#define UV__IN_MOVED_TO 0x080
+#define UV__IN_CREATE 0x100
+#define UV__IN_DELETE 0x200
+#define UV__IN_DELETE_SELF 0x400
+#define UV__IN_MOVE_SELF 0x800
+
+#if defined(__x86_64__)
+struct uv__epoll_event {
+ uint32_t events;
+ uint64_t data;
+} __attribute__((packed));
+#else
+struct uv__epoll_event {
+ uint32_t events;
+ uint64_t data;
+};
+#endif
+
+struct uv__inotify_event {
+ int32_t wd;
+ uint32_t mask;
+ uint32_t cookie;
+ uint32_t len;
+ /* char name[0]; */
+};
+
+struct uv__mmsghdr {
+ struct msghdr msg_hdr;
+ unsigned int msg_len;
+};
+
+int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags);
+int uv__eventfd(unsigned int count);
+int uv__epoll_create(int size);
+int uv__epoll_create1(int flags);
+int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event *ev);
+int uv__epoll_wait(int epfd,
+ struct uv__epoll_event* events,
+ int nevents,
+ int timeout);
+int uv__epoll_pwait(int epfd,
+ struct uv__epoll_event* events,
+ int nevents,
+ int timeout,
+ uint64_t sigmask);
+int uv__eventfd2(unsigned int count, int flags);
+int uv__inotify_init(void);
+int uv__inotify_init1(int flags);
+int uv__inotify_add_watch(int fd, const char* path, uint32_t mask);
+int uv__inotify_rm_watch(int fd, int32_t wd);
+int uv__pipe2(int pipefd[2], int flags);
+int uv__recvmmsg(int fd,
+ struct uv__mmsghdr* mmsg,
+ unsigned int vlen,
+ unsigned int flags,
+ struct timespec* timeout);
+int uv__sendmmsg(int fd,
+ struct uv__mmsghdr* mmsg,
+ unsigned int vlen,
+ unsigned int flags);
+int uv__utimesat(int dirfd,
+ const char* path,
+ const struct timespec times[2],
+ int flags);
+ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
+ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
+int uv__dup3(int oldfd, int newfd, int flags);
+
+#endif /* UV_LINUX_SYSCALL_H_ */
diff --git a/3rdparty/libuv/src/unix/loop-watcher.c b/3rdparty/libuv/src/unix/loop-watcher.c
new file mode 100644
index 00000000000..340bb0dfa11
--- /dev/null
+++ b/3rdparty/libuv/src/unix/loop-watcher.c
@@ -0,0 +1,68 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#define UV_LOOP_WATCHER_DEFINE(name, type) \
+ int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_##type); \
+ handle->name##_cb = NULL; \
+ return 0; \
+ } \
+ \
+ int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
+ if (uv__is_active(handle)) return 0; \
+ if (cb == NULL) return -EINVAL; \
+ QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue); \
+ handle->name##_cb = cb; \
+ uv__handle_start(handle); \
+ return 0; \
+ } \
+ \
+ int uv_##name##_stop(uv_##name##_t* handle) { \
+ if (!uv__is_active(handle)) return 0; \
+ QUEUE_REMOVE(&handle->queue); \
+ uv__handle_stop(handle); \
+ return 0; \
+ } \
+ \
+ void uv__run_##name(uv_loop_t* loop) { \
+ uv_##name##_t* h; \
+ QUEUE queue; \
+ QUEUE* q; \
+ QUEUE_MOVE(&loop->name##_handles, &queue); \
+ while (!QUEUE_EMPTY(&queue)) { \
+ q = QUEUE_HEAD(&queue); \
+ h = QUEUE_DATA(q, uv_##name##_t, queue); \
+ QUEUE_REMOVE(q); \
+ QUEUE_INSERT_TAIL(&loop->name##_handles, q); \
+ h->name##_cb(h); \
+ } \
+ } \
+ \
+ void uv__##name##_close(uv_##name##_t* handle) { \
+ uv_##name##_stop(handle); \
+ }
+
+UV_LOOP_WATCHER_DEFINE(prepare, PREPARE)
+UV_LOOP_WATCHER_DEFINE(check, CHECK)
+UV_LOOP_WATCHER_DEFINE(idle, IDLE)
diff --git a/3rdparty/libuv/src/unix/loop.c b/3rdparty/libuv/src/unix/loop.c
new file mode 100644
index 00000000000..92e96f09ed0
--- /dev/null
+++ b/3rdparty/libuv/src/unix/loop.c
@@ -0,0 +1,155 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "tree.h"
+#include "internal.h"
+#include "heap-inl.h"
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int uv_loop_init(uv_loop_t* loop) {
+ int err;
+
+ uv__signal_global_once_init();
+
+ memset(loop, 0, sizeof(*loop));
+ heap_init((struct heap*) &loop->timer_heap);
+ QUEUE_INIT(&loop->wq);
+ QUEUE_INIT(&loop->active_reqs);
+ QUEUE_INIT(&loop->idle_handles);
+ QUEUE_INIT(&loop->async_handles);
+ QUEUE_INIT(&loop->check_handles);
+ QUEUE_INIT(&loop->prepare_handles);
+ QUEUE_INIT(&loop->handle_queue);
+
+ loop->nfds = 0;
+ loop->watchers = NULL;
+ loop->nwatchers = 0;
+ QUEUE_INIT(&loop->pending_queue);
+ QUEUE_INIT(&loop->watcher_queue);
+
+ loop->closing_handles = NULL;
+ uv__update_time(loop);
+ uv__async_init(&loop->async_watcher);
+ loop->signal_pipefd[0] = -1;
+ loop->signal_pipefd[1] = -1;
+ loop->backend_fd = -1;
+ loop->emfile_fd = -1;
+
+ loop->timer_counter = 0;
+ loop->stop_flag = 0;
+
+ err = uv__platform_loop_init(loop);
+ if (err)
+ return err;
+
+ err = uv_signal_init(loop, &loop->child_watcher);
+ if (err)
+ goto fail_signal_init;
+
+ uv__handle_unref(&loop->child_watcher);
+ loop->child_watcher.flags |= UV__HANDLE_INTERNAL;
+ QUEUE_INIT(&loop->process_handles);
+
+ err = uv_rwlock_init(&loop->cloexec_lock);
+ if (err)
+ goto fail_rwlock_init;
+
+ err = uv_mutex_init(&loop->wq_mutex);
+ if (err)
+ goto fail_mutex_init;
+
+ err = uv_async_init(loop, &loop->wq_async, uv__work_done);
+ if (err)
+ goto fail_async_init;
+
+ uv__handle_unref(&loop->wq_async);
+ loop->wq_async.flags |= UV__HANDLE_INTERNAL;
+
+ return 0;
+
+fail_async_init:
+ uv_mutex_destroy(&loop->wq_mutex);
+
+fail_mutex_init:
+ uv_rwlock_destroy(&loop->cloexec_lock);
+
+fail_rwlock_init:
+ uv__signal_loop_cleanup(loop);
+
+fail_signal_init:
+ uv__platform_loop_delete(loop);
+
+ return err;
+}
+
+
+void uv__loop_close(uv_loop_t* loop) {
+ uv__signal_loop_cleanup(loop);
+ uv__platform_loop_delete(loop);
+ uv__async_stop(loop, &loop->async_watcher);
+
+ if (loop->emfile_fd != -1) {
+ uv__close(loop->emfile_fd);
+ loop->emfile_fd = -1;
+ }
+
+ if (loop->backend_fd != -1) {
+ uv__close(loop->backend_fd);
+ loop->backend_fd = -1;
+ }
+
+ uv_mutex_lock(&loop->wq_mutex);
+ assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
+ assert(!uv__has_active_reqs(loop));
+ uv_mutex_unlock(&loop->wq_mutex);
+ uv_mutex_destroy(&loop->wq_mutex);
+
+ /*
+ * Note that all thread pool stuff is finished at this point and
+ * it is safe to just destroy rw lock
+ */
+ uv_rwlock_destroy(&loop->cloexec_lock);
+
+#if 0
+ assert(QUEUE_EMPTY(&loop->pending_queue));
+ assert(QUEUE_EMPTY(&loop->watcher_queue));
+ assert(loop->nfds == 0);
+#endif
+
+ uv__free(loop->watchers);
+ loop->watchers = NULL;
+ loop->nwatchers = 0;
+}
+
+
+int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
+ if (option != UV_LOOP_BLOCK_SIGNAL)
+ return UV_ENOSYS;
+
+ if (va_arg(ap, int) != SIGPROF)
+ return UV_EINVAL;
+
+ loop->flags |= UV_LOOP_BLOCK_SIGPROF;
+ return 0;
+}
diff --git a/3rdparty/libuv/src/unix/netbsd.c b/3rdparty/libuv/src/unix/netbsd.c
new file mode 100644
index 00000000000..ca48550f9d9
--- /dev/null
+++ b/3rdparty/libuv/src/unix/netbsd.c
@@ -0,0 +1,370 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+
+#include <kvm.h>
+#include <paths.h>
+#include <ifaddrs.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <uvm/uvm_extern.h>
+
+#include <unistd.h>
+#include <time.h>
+
+#undef NANOSEC
+#define NANOSEC ((uint64_t) 1e9)
+
+static char *process_title;
+
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ return uv__kqueue_init(loop);
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+}
+
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
+}
+
+
+void uv_loadavg(double avg[3]) {
+ struct loadavg info;
+ size_t size = sizeof(info);
+ int which[] = {CTL_VM, VM_LOADAVG};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0) == -1) return;
+
+ avg[0] = (double) info.ldavg[0] / info.fscale;
+ avg[1] = (double) info.ldavg[1] / info.fscale;
+ avg[2] = (double) info.ldavg[2] / info.fscale;
+}
+
+
+int uv_exepath(char* buffer, size_t* size) {
+ int mib[4];
+ size_t cb;
+ pid_t mypid;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ mypid = getpid();
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC_ARGS;
+ mib[2] = mypid;
+ mib[3] = KERN_PROC_ARGV;
+
+ cb = *size;
+ if (sysctl(mib, 4, buffer, &cb, NULL, 0))
+ return -errno;
+ *size = strlen(buffer);
+
+ return 0;
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ struct uvmexp info;
+ size_t size = sizeof(info);
+ int which[] = {CTL_VM, VM_UVMEXP};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
+}
+
+
+uint64_t uv_get_total_memory(void) {
+#if defined(HW_PHYSMEM64)
+ uint64_t info;
+ int which[] = {CTL_HW, HW_PHYSMEM64};
+#else
+ unsigned int info;
+ int which[] = {CTL_HW, HW_PHYSMEM};
+#endif
+ size_t size = sizeof(info);
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) info;
+}
+
+
+char** uv_setup_args(int argc, char** argv) {
+ process_title = argc ? uv__strdup(argv[0]) : NULL;
+ return argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ if (process_title) uv__free(process_title);
+
+ process_title = uv__strdup(title);
+ setproctitle("%s", title);
+
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ if (process_title) {
+ strncpy(buffer, process_title, size);
+ } else {
+ if (size > 0) {
+ buffer[0] = '\0';
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ kvm_t *kd = NULL;
+ struct kinfo_proc2 *kinfo = NULL;
+ pid_t pid;
+ int nprocs;
+ int max_size = sizeof(struct kinfo_proc2);
+ int page_size;
+
+ page_size = getpagesize();
+ pid = getpid();
+
+ kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open");
+
+ if (kd == NULL) goto error;
+
+ kinfo = kvm_getproc2(kd, KERN_PROC_PID, pid, max_size, &nprocs);
+ if (kinfo == NULL) goto error;
+
+ *rss = kinfo->p_vm_rssize * page_size;
+
+ kvm_close(kd);
+
+ return 0;
+
+error:
+ if (kd) kvm_close(kd);
+ return -EPERM;
+}
+
+
+int uv_uptime(double* uptime) {
+ time_t now;
+ struct timeval info;
+ size_t size = sizeof(info);
+ static int which[] = {CTL_KERN, KERN_BOOTTIME};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ now = time(NULL);
+
+ *uptime = (double)(now - info.tv_sec);
+ return 0;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK);
+ unsigned int multiplier = ((uint64_t)1000L / ticks);
+ unsigned int cur = 0;
+ uv_cpu_info_t* cpu_info;
+ u_int64_t* cp_times;
+ char model[512];
+ u_int64_t cpuspeed;
+ int numcpus;
+ size_t size;
+ int i;
+
+ size = sizeof(model);
+ if (sysctlbyname("machdep.cpu_brand", &model, &size, NULL, 0) &&
+ sysctlbyname("hw.model", &model, &size, NULL, 0)) {
+ return -errno;
+ }
+
+ size = sizeof(numcpus);
+ if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0))
+ return -errno;
+ *count = numcpus;
+
+ /* Only i386 and amd64 have machdep.tsc_freq */
+ size = sizeof(cpuspeed);
+ if (sysctlbyname("machdep.tsc_freq", &cpuspeed, &size, NULL, 0))
+ cpuspeed = 0;
+
+ size = numcpus * CPUSTATES * sizeof(*cp_times);
+ cp_times = uv__malloc(size);
+ if (cp_times == NULL)
+ return -ENOMEM;
+
+ if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0))
+ return -errno;
+
+ *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
+ if (!(*cpu_infos)) {
+ uv__free(cp_times);
+ uv__free(*cpu_infos);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < numcpus; i++) {
+ cpu_info = &(*cpu_infos)[i];
+ cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier;
+ cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier;
+ cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier;
+ cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier;
+ cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier;
+ cpu_info->model = uv__strdup(model);
+ cpu_info->speed = (int)(cpuspeed/(uint64_t) 1e6);
+ cur += CPUSTATES;
+ }
+ uv__free(cp_times);
+ return 0;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
+ struct ifaddrs *addrs, *ent;
+ uv_interface_address_t* address;
+ int i;
+ struct sockaddr_dl *sa_addr;
+
+ if (getifaddrs(&addrs))
+ return -errno;
+
+ *count = 0;
+
+ /* Count the number of interfaces */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family != PF_INET)) {
+ continue;
+ }
+ (*count)++;
+ }
+
+ *addresses = uv__malloc(*count * sizeof(**addresses));
+
+ if (!(*addresses)) {
+ freeifaddrs(addrs);
+ return -ENOMEM;
+ }
+
+ address = *addresses;
+
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
+ continue;
+
+ if (ent->ifa_addr == NULL)
+ continue;
+
+ if (ent->ifa_addr->sa_family != PF_INET)
+ continue;
+
+ address->name = uv__strdup(ent->ifa_name);
+
+ if (ent->ifa_addr->sa_family == AF_INET6) {
+ address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
+ } else {
+ address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
+ }
+
+ if (ent->ifa_netmask->sa_family == AF_INET6) {
+ address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
+ } else {
+ address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
+ }
+
+ address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
+
+ address++;
+ }
+
+ /* Fill in physical addresses for each interface */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family != AF_LINK)) {
+ continue;
+ }
+
+ address = *addresses;
+
+ for (i = 0; i < (*count); i++) {
+ if (strcmp(address->name, ent->ifa_name) == 0) {
+ sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
+ memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
+ }
+ address++;
+ }
+ }
+
+ freeifaddrs(addrs);
+
+ return 0;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(addresses[i].name);
+ }
+
+ uv__free(addresses);
+}
diff --git a/3rdparty/libuv/src/unix/openbsd.c b/3rdparty/libuv/src/unix/openbsd.c
new file mode 100644
index 00000000000..6a3909a666c
--- /dev/null
+++ b/3rdparty/libuv/src/unix/openbsd.c
@@ -0,0 +1,386 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/sched.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#undef NANOSEC
+#define NANOSEC ((uint64_t) 1e9)
+
+
+static char *process_title;
+
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ return uv__kqueue_init(loop);
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+}
+
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
+}
+
+
+void uv_loadavg(double avg[3]) {
+ struct loadavg info;
+ size_t size = sizeof(info);
+ int which[] = {CTL_VM, VM_LOADAVG};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
+
+ avg[0] = (double) info.ldavg[0] / info.fscale;
+ avg[1] = (double) info.ldavg[1] / info.fscale;
+ avg[2] = (double) info.ldavg[2] / info.fscale;
+}
+
+
+int uv_exepath(char* buffer, size_t* size) {
+ int mib[4];
+ char **argsbuf = NULL;
+ char **argsbuf_tmp;
+ size_t argsbuf_size = 100U;
+ size_t exepath_size;
+ pid_t mypid;
+ int err;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ mypid = getpid();
+ for (;;) {
+ err = -ENOMEM;
+ argsbuf_tmp = uv__realloc(argsbuf, argsbuf_size);
+ if (argsbuf_tmp == NULL)
+ goto out;
+ argsbuf = argsbuf_tmp;
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC_ARGS;
+ mib[2] = mypid;
+ mib[3] = KERN_PROC_ARGV;
+ if (sysctl(mib, 4, argsbuf, &argsbuf_size, NULL, 0) == 0) {
+ break;
+ }
+ if (errno != ENOMEM) {
+ err = -errno;
+ goto out;
+ }
+ argsbuf_size *= 2U;
+ }
+
+ if (argsbuf[0] == NULL) {
+ err = -EINVAL; /* FIXME(bnoordhuis) More appropriate error. */
+ goto out;
+ }
+
+ *size -= 1;
+ exepath_size = strlen(argsbuf[0]);
+ if (*size > exepath_size)
+ *size = exepath_size;
+
+ memcpy(buffer, argsbuf[0], *size);
+ buffer[*size] = '\0';
+ err = 0;
+
+out:
+ uv__free(argsbuf);
+
+ return err;
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ struct uvmexp info;
+ size_t size = sizeof(info);
+ int which[] = {CTL_VM, VM_UVMEXP};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ uint64_t info;
+ int which[] = {CTL_HW, HW_PHYSMEM64};
+ size_t size = sizeof(info);
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) info;
+}
+
+
+char** uv_setup_args(int argc, char** argv) {
+ process_title = argc ? uv__strdup(argv[0]) : NULL;
+ return argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ uv__free(process_title);
+ process_title = uv__strdup(title);
+ setproctitle(title);
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ if (process_title) {
+ strncpy(buffer, process_title, size);
+ } else {
+ if (size > 0) {
+ buffer[0] = '\0';
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ struct kinfo_proc kinfo;
+ size_t page_size = getpagesize();
+ size_t size = sizeof(struct kinfo_proc);
+ int mib[6];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = getpid();
+ mib[4] = sizeof(struct kinfo_proc);
+ mib[5] = 1;
+
+ if (sysctl(mib, 6, &kinfo, &size, NULL, 0) < 0)
+ return -errno;
+
+ *rss = kinfo.p_vm_rssize * page_size;
+ return 0;
+}
+
+
+int uv_uptime(double* uptime) {
+ time_t now;
+ struct timeval info;
+ size_t size = sizeof(info);
+ static int which[] = {CTL_KERN, KERN_BOOTTIME};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ now = time(NULL);
+
+ *uptime = (double)(now - info.tv_sec);
+ return 0;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
+ multiplier = ((uint64_t)1000L / ticks), cpuspeed;
+ uint64_t info[CPUSTATES];
+ char model[512];
+ int numcpus = 1;
+ int which[] = {CTL_HW,HW_MODEL,0};
+ size_t size;
+ int i;
+ uv_cpu_info_t* cpu_info;
+
+ size = sizeof(model);
+ if (sysctl(which, 2, &model, &size, NULL, 0))
+ return -errno;
+
+ which[1] = HW_NCPU;
+ size = sizeof(numcpus);
+ if (sysctl(which, 2, &numcpus, &size, NULL, 0))
+ return -errno;
+
+ *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
+ if (!(*cpu_infos))
+ return -ENOMEM;
+
+ *count = numcpus;
+
+ which[1] = HW_CPUSPEED;
+ size = sizeof(cpuspeed);
+ if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) {
+ SAVE_ERRNO(uv__free(*cpu_infos));
+ return -errno;
+ }
+
+ size = sizeof(info);
+ which[0] = CTL_KERN;
+ which[1] = KERN_CPTIME2;
+ for (i = 0; i < numcpus; i++) {
+ which[2] = i;
+ size = sizeof(info);
+ if (sysctl(which, 3, &info, &size, NULL, 0)) {
+ SAVE_ERRNO(uv__free(*cpu_infos));
+ return -errno;
+ }
+
+ cpu_info = &(*cpu_infos)[i];
+
+ cpu_info->cpu_times.user = (uint64_t)(info[CP_USER]) * multiplier;
+ cpu_info->cpu_times.nice = (uint64_t)(info[CP_NICE]) * multiplier;
+ cpu_info->cpu_times.sys = (uint64_t)(info[CP_SYS]) * multiplier;
+ cpu_info->cpu_times.idle = (uint64_t)(info[CP_IDLE]) * multiplier;
+ cpu_info->cpu_times.irq = (uint64_t)(info[CP_INTR]) * multiplier;
+
+ cpu_info->model = uv__strdup(model);
+ cpu_info->speed = cpuspeed;
+ }
+
+ return 0;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses,
+ int* count) {
+ struct ifaddrs *addrs, *ent;
+ uv_interface_address_t* address;
+ int i;
+ struct sockaddr_dl *sa_addr;
+
+ if (getifaddrs(&addrs) != 0)
+ return -errno;
+
+ *count = 0;
+
+ /* Count the number of interfaces */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family != PF_INET)) {
+ continue;
+ }
+ (*count)++;
+ }
+
+ *addresses = uv__malloc(*count * sizeof(**addresses));
+
+ if (!(*addresses)) {
+ freeifaddrs(addrs);
+ return -ENOMEM;
+ }
+
+ address = *addresses;
+
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
+ continue;
+
+ if (ent->ifa_addr == NULL)
+ continue;
+
+ if (ent->ifa_addr->sa_family != PF_INET)
+ continue;
+
+ address->name = uv__strdup(ent->ifa_name);
+
+ if (ent->ifa_addr->sa_family == AF_INET6) {
+ address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
+ } else {
+ address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
+ }
+
+ if (ent->ifa_netmask->sa_family == AF_INET6) {
+ address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
+ } else {
+ address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
+ }
+
+ address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
+
+ address++;
+ }
+
+ /* Fill in physical addresses for each interface */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family != AF_LINK)) {
+ continue;
+ }
+
+ address = *addresses;
+
+ for (i = 0; i < (*count); i++) {
+ if (strcmp(address->name, ent->ifa_name) == 0) {
+ sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
+ memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
+ }
+ address++;
+ }
+ }
+
+ freeifaddrs(addrs);
+
+ return 0;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(addresses[i].name);
+ }
+
+ uv__free(addresses);
+}
diff --git a/3rdparty/libuv/src/unix/pipe.c b/3rdparty/libuv/src/unix/pipe.c
new file mode 100644
index 00000000000..7f87a713bf4
--- /dev/null
+++ b/3rdparty/libuv/src/unix/pipe.c
@@ -0,0 +1,288 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+
+int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
+ uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
+ handle->shutdown_req = NULL;
+ handle->connect_req = NULL;
+ handle->pipe_fname = NULL;
+ handle->ipc = ipc;
+ return 0;
+}
+
+
+int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
+ struct sockaddr_un saddr;
+ const char* pipe_fname;
+ int sockfd;
+ int err;
+
+ pipe_fname = NULL;
+ sockfd = -1;
+
+ /* Already bound? */
+ if (uv__stream_fd(handle) >= 0)
+ return -EINVAL;
+
+ /* Make a copy of the file name, it outlives this function's scope. */
+ pipe_fname = uv__strdup(name);
+ if (pipe_fname == NULL)
+ return -ENOMEM;
+
+ /* We've got a copy, don't touch the original any more. */
+ name = NULL;
+
+ err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
+ if (err < 0)
+ goto err_socket;
+ sockfd = err;
+
+ memset(&saddr, 0, sizeof saddr);
+ strncpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path) - 1);
+ saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0';
+ saddr.sun_family = AF_UNIX;
+
+ if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) {
+ err = -errno;
+ /* Convert ENOENT to EACCES for compatibility with Windows. */
+ if (err == -ENOENT)
+ err = -EACCES;
+ goto err_bind;
+ }
+
+ /* Success. */
+ handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */
+ handle->io_watcher.fd = sockfd;
+ return 0;
+
+err_bind:
+ uv__close(sockfd);
+
+err_socket:
+ uv__free((void*)pipe_fname);
+ return err;
+}
+
+
+int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
+ if (uv__stream_fd(handle) == -1)
+ return -EINVAL;
+
+ if (listen(uv__stream_fd(handle), backlog))
+ return -errno;
+
+ handle->connection_cb = cb;
+ handle->io_watcher.cb = uv__server_io;
+ uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN);
+ return 0;
+}
+
+
+void uv__pipe_close(uv_pipe_t* handle) {
+ if (handle->pipe_fname) {
+ /*
+ * Unlink the file system entity before closing the file descriptor.
+ * Doing it the other way around introduces a race where our process
+ * unlinks a socket with the same name that's just been created by
+ * another thread or process.
+ */
+ unlink(handle->pipe_fname);
+ uv__free((void*)handle->pipe_fname);
+ handle->pipe_fname = NULL;
+ }
+
+ uv__stream_close((uv_stream_t*)handle);
+}
+
+
+int uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
+ int err;
+
+ err = uv__nonblock(fd, 1);
+ if (err)
+ return err;
+
+#if defined(__APPLE__)
+ err = uv__stream_try_select((uv_stream_t*) handle, &fd);
+ if (err)
+ return err;
+#endif /* defined(__APPLE__) */
+
+ return uv__stream_open((uv_stream_t*)handle,
+ fd,
+ UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+}
+
+
+void uv_pipe_connect(uv_connect_t* req,
+ uv_pipe_t* handle,
+ const char* name,
+ uv_connect_cb cb) {
+ struct sockaddr_un saddr;
+ int new_sock;
+ int err;
+ int r;
+
+ new_sock = (uv__stream_fd(handle) == -1);
+
+ if (new_sock) {
+ err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
+ if (err < 0)
+ goto out;
+ handle->io_watcher.fd = err;
+ }
+
+ memset(&saddr, 0, sizeof saddr);
+ strncpy(saddr.sun_path, name, sizeof(saddr.sun_path) - 1);
+ saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0';
+ saddr.sun_family = AF_UNIX;
+
+ do {
+ r = connect(uv__stream_fd(handle),
+ (struct sockaddr*)&saddr, sizeof saddr);
+ }
+ while (r == -1 && errno == EINTR);
+
+ if (r == -1 && errno != EINPROGRESS) {
+ err = -errno;
+ goto out;
+ }
+
+ err = 0;
+ if (new_sock) {
+ err = uv__stream_open((uv_stream_t*)handle,
+ uv__stream_fd(handle),
+ UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+ }
+
+ if (err == 0)
+ uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN | UV__POLLOUT);
+
+out:
+ handle->delayed_error = err;
+ handle->connect_req = req;
+
+ uv__req_init(handle->loop, req, UV_CONNECT);
+ req->handle = (uv_stream_t*)handle;
+ req->cb = cb;
+ QUEUE_INIT(&req->queue);
+
+ /* Force callback to run on next tick in case of error. */
+ if (err)
+ uv__io_feed(handle->loop, &handle->io_watcher);
+
+ /* Mimic the Windows pipe implementation, always
+ * return 0 and let the callback handle errors.
+ */
+}
+
+
+typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*);
+
+
+static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
+ uv__peersockfunc func,
+ char* buffer,
+ size_t* size) {
+ struct sockaddr_un sa;
+ socklen_t addrlen;
+ int err;
+
+ addrlen = sizeof(sa);
+ memset(&sa, 0, addrlen);
+ err = func(uv__stream_fd(handle), (struct sockaddr*) &sa, &addrlen);
+ if (err < 0) {
+ *size = 0;
+ return -errno;
+ }
+
+#if defined(__linux__)
+ if (sa.sun_path[0] == 0)
+ /* Linux abstract namespace */
+ addrlen -= offsetof(struct sockaddr_un, sun_path);
+ else
+#endif
+ addrlen = strlen(sa.sun_path);
+
+
+ if (addrlen > *size) {
+ *size = addrlen;
+ return UV_ENOBUFS;
+ }
+
+ memcpy(buffer, sa.sun_path, addrlen);
+ *size = addrlen;
+
+ return 0;
+}
+
+
+int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
+ return uv__pipe_getsockpeername(handle, getsockname, buffer, size);
+}
+
+
+int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
+ return uv__pipe_getsockpeername(handle, getpeername, buffer, size);
+}
+
+
+void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
+}
+
+
+int uv_pipe_pending_count(uv_pipe_t* handle) {
+ uv__stream_queued_fds_t* queued_fds;
+
+ if (!handle->ipc)
+ return 0;
+
+ if (handle->accepted_fd == -1)
+ return 0;
+
+ if (handle->queued_fds == NULL)
+ return 1;
+
+ queued_fds = handle->queued_fds;
+ return queued_fds->offset + 1;
+}
+
+
+uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
+ if (!handle->ipc)
+ return UV_UNKNOWN_HANDLE;
+
+ if (handle->accepted_fd == -1)
+ return UV_UNKNOWN_HANDLE;
+ else
+ return uv__handle_type(handle->accepted_fd);
+}
diff --git a/3rdparty/libuv/src/unix/poll.c b/3rdparty/libuv/src/unix/poll.c
new file mode 100644
index 00000000000..37da3b95851
--- /dev/null
+++ b/3rdparty/libuv/src/unix/poll.c
@@ -0,0 +1,113 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+
+
+static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+ uv_poll_t* handle;
+ int pevents;
+
+ handle = container_of(w, uv_poll_t, io_watcher);
+
+ if (events & UV__POLLERR) {
+ uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT);
+ uv__handle_stop(handle);
+ handle->poll_cb(handle, -EBADF, 0);
+ return;
+ }
+
+ pevents = 0;
+ if (events & UV__POLLIN)
+ pevents |= UV_READABLE;
+ if (events & UV__POLLOUT)
+ pevents |= UV_WRITABLE;
+
+ handle->poll_cb(handle, 0, pevents);
+}
+
+
+int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
+ int err;
+
+ err = uv__nonblock(fd, 1);
+ if (err)
+ return err;
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL);
+ uv__io_init(&handle->io_watcher, uv__poll_io, fd);
+ handle->poll_cb = NULL;
+ return 0;
+}
+
+
+int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
+ uv_os_sock_t socket) {
+ return uv_poll_init(loop, handle, socket);
+}
+
+
+static void uv__poll_stop(uv_poll_t* handle) {
+ uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLIN | UV__POLLOUT);
+ uv__handle_stop(handle);
+}
+
+
+int uv_poll_stop(uv_poll_t* handle) {
+ assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
+ uv__poll_stop(handle);
+ return 0;
+}
+
+
+int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
+ int events;
+
+ assert((pevents & ~(UV_READABLE | UV_WRITABLE)) == 0);
+ assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
+
+ uv__poll_stop(handle);
+
+ if (pevents == 0)
+ return 0;
+
+ events = 0;
+ if (pevents & UV_READABLE)
+ events |= UV__POLLIN;
+ if (pevents & UV_WRITABLE)
+ events |= UV__POLLOUT;
+
+ uv__io_start(handle->loop, &handle->io_watcher, events);
+ uv__handle_start(handle);
+ handle->poll_cb = poll_cb;
+
+ return 0;
+}
+
+
+void uv__poll_close(uv_poll_t* handle) {
+ uv__poll_stop(handle);
+}
diff --git a/3rdparty/libuv/src/unix/process.c b/3rdparty/libuv/src/unix/process.c
new file mode 100644
index 00000000000..571f8cd778c
--- /dev/null
+++ b/3rdparty/libuv/src/unix/process.c
@@ -0,0 +1,563 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+
+#if defined(__APPLE__) && !TARGET_OS_IPHONE
+# include <crt_externs.h>
+# define environ (*_NSGetEnviron())
+#else
+extern char **environ;
+#endif
+
+#ifdef __linux__
+# include <grp.h>
+#endif
+
+
+static void uv__chld(uv_signal_t* handle, int signum) {
+ uv_process_t* process;
+ uv_loop_t* loop;
+ int exit_status;
+ int term_signal;
+ int status;
+ pid_t pid;
+ QUEUE pending;
+ QUEUE* q;
+ QUEUE* h;
+
+ assert(signum == SIGCHLD);
+
+ QUEUE_INIT(&pending);
+ loop = handle->loop;
+
+ h = &loop->process_handles;
+ q = QUEUE_HEAD(h);
+ while (q != h) {
+ process = QUEUE_DATA(q, uv_process_t, queue);
+ q = QUEUE_NEXT(q);
+
+ do
+ pid = waitpid(process->pid, &status, WNOHANG);
+ while (pid == -1 && errno == EINTR);
+
+ if (pid == 0)
+ continue;
+
+ if (pid == -1) {
+ if (errno != ECHILD)
+ abort();
+ continue;
+ }
+
+ process->status = status;
+ QUEUE_REMOVE(&process->queue);
+ QUEUE_INSERT_TAIL(&pending, &process->queue);
+ }
+
+ h = &pending;
+ q = QUEUE_HEAD(h);
+ while (q != h) {
+ process = QUEUE_DATA(q, uv_process_t, queue);
+ q = QUEUE_NEXT(q);
+
+ QUEUE_REMOVE(&process->queue);
+ QUEUE_INIT(&process->queue);
+ uv__handle_stop(process);
+
+ if (process->exit_cb == NULL)
+ continue;
+
+ exit_status = 0;
+ if (WIFEXITED(process->status))
+ exit_status = WEXITSTATUS(process->status);
+
+ term_signal = 0;
+ if (WIFSIGNALED(process->status))
+ term_signal = WTERMSIG(process->status);
+
+ process->exit_cb(process, exit_status, term_signal);
+ }
+ assert(QUEUE_EMPTY(&pending));
+}
+
+
+int uv__make_socketpair(int fds[2], int flags) {
+#if defined(__linux__)
+ static int no_cloexec;
+
+ if (no_cloexec)
+ goto skip;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM | UV__SOCK_CLOEXEC | flags, 0, fds) == 0)
+ return 0;
+
+ /* Retry on EINVAL, it means SOCK_CLOEXEC is not supported.
+ * Anything else is a genuine error.
+ */
+ if (errno != EINVAL)
+ return -errno;
+
+ no_cloexec = 1;
+
+skip:
+#endif
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
+ return -errno;
+
+ uv__cloexec(fds[0], 1);
+ uv__cloexec(fds[1], 1);
+
+ if (flags & UV__F_NONBLOCK) {
+ uv__nonblock(fds[0], 1);
+ uv__nonblock(fds[1], 1);
+ }
+
+ return 0;
+}
+
+
+int uv__make_pipe(int fds[2], int flags) {
+#if defined(__linux__)
+ static int no_pipe2;
+
+ if (no_pipe2)
+ goto skip;
+
+ if (uv__pipe2(fds, flags | UV__O_CLOEXEC) == 0)
+ return 0;
+
+ if (errno != ENOSYS)
+ return -errno;
+
+ no_pipe2 = 1;
+
+skip:
+#endif
+
+ if (pipe(fds))
+ return -errno;
+
+ uv__cloexec(fds[0], 1);
+ uv__cloexec(fds[1], 1);
+
+ if (flags & UV__F_NONBLOCK) {
+ uv__nonblock(fds[0], 1);
+ uv__nonblock(fds[1], 1);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Used for initializing stdio streams like options.stdin_stream. Returns
+ * zero on success. See also the cleanup section in uv_spawn().
+ */
+static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
+ int mask;
+ int fd;
+
+ mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM;
+
+ switch (container->flags & mask) {
+ case UV_IGNORE:
+ return 0;
+
+ case UV_CREATE_PIPE:
+ assert(container->data.stream != NULL);
+ if (container->data.stream->type != UV_NAMED_PIPE)
+ return -EINVAL;
+ else
+ return uv__make_socketpair(fds, 0);
+
+ case UV_INHERIT_FD:
+ case UV_INHERIT_STREAM:
+ if (container->flags & UV_INHERIT_FD)
+ fd = container->data.fd;
+ else
+ fd = uv__stream_fd(container->data.stream);
+
+ if (fd == -1)
+ return -EINVAL;
+
+ fds[1] = fd;
+ return 0;
+
+ default:
+ assert(0 && "Unexpected flags");
+ return -EINVAL;
+ }
+}
+
+
+static int uv__process_open_stream(uv_stdio_container_t* container,
+ int pipefds[2],
+ int writable) {
+ int flags;
+ int err;
+
+ if (!(container->flags & UV_CREATE_PIPE) || pipefds[0] < 0)
+ return 0;
+
+ err = uv__close(pipefds[1]);
+ if (err != 0 && err != -EINPROGRESS)
+ abort();
+
+ pipefds[1] = -1;
+ uv__nonblock(pipefds[0], 1);
+
+ if (container->data.stream->type == UV_NAMED_PIPE &&
+ ((uv_pipe_t*)container->data.stream)->ipc)
+ flags = UV_STREAM_READABLE | UV_STREAM_WRITABLE;
+ else if (writable)
+ flags = UV_STREAM_WRITABLE;
+ else
+ flags = UV_STREAM_READABLE;
+
+ return uv__stream_open(container->data.stream, pipefds[0], flags);
+}
+
+
+static void uv__process_close_stream(uv_stdio_container_t* container) {
+ if (!(container->flags & UV_CREATE_PIPE)) return;
+ uv__stream_close((uv_stream_t*)container->data.stream);
+}
+
+
+static void uv__write_int(int fd, int val) {
+ ssize_t n;
+
+ do
+ n = write(fd, &val, sizeof(val));
+ while (n == -1 && errno == EINTR);
+
+ if (n == -1 && errno == EPIPE)
+ return; /* parent process has quit */
+
+ assert(n == sizeof(val));
+}
+
+
+#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH))
+/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be
+ * avoided. Since this isn't called on those targets, the function
+ * doesn't even need to be defined for them.
+ */
+static void uv__process_child_init(const uv_process_options_t* options,
+ int stdio_count,
+ int (*pipes)[2],
+ int error_fd) {
+ int close_fd;
+ int use_fd;
+ int fd;
+
+ if (options->flags & UV_PROCESS_DETACHED)
+ setsid();
+
+ /* First duplicate low numbered fds, since it's not safe to duplicate them,
+ * they could get replaced. Example: swapping stdout and stderr; without
+ * this fd 2 (stderr) would be duplicated into fd 1, thus making both
+ * stdout and stderr go to the same fd, which was not the intention. */
+ for (fd = 0; fd < stdio_count; fd++) {
+ use_fd = pipes[fd][1];
+ if (use_fd < 0 || use_fd >= fd)
+ continue;
+ pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count);
+ if (pipes[fd][1] == -1) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+ }
+
+ for (fd = 0; fd < stdio_count; fd++) {
+ close_fd = pipes[fd][0];
+ use_fd = pipes[fd][1];
+
+ if (use_fd < 0) {
+ if (fd >= 3)
+ continue;
+ else {
+ /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is
+ * set
+ */
+ use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR);
+ close_fd = use_fd;
+
+ if (use_fd == -1) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+ }
+ }
+
+ if (fd == use_fd)
+ uv__cloexec(use_fd, 0);
+ else
+ fd = dup2(use_fd, fd);
+
+ if (fd == -1) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+
+ if (fd <= 2)
+ uv__nonblock(fd, 0);
+
+ if (close_fd >= stdio_count)
+ uv__close(close_fd);
+ }
+
+ for (fd = 0; fd < stdio_count; fd++) {
+ use_fd = pipes[fd][1];
+
+ if (use_fd >= stdio_count)
+ uv__close(use_fd);
+ }
+
+ if (options->cwd != NULL && chdir(options->cwd)) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+
+ if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) {
+ /* When dropping privileges from root, the `setgroups` call will
+ * remove any extraneous groups. If we don't call this, then
+ * even though our uid has dropped, we may still have groups
+ * that enable us to do super-user things. This will fail if we
+ * aren't root, so don't bother checking the return value, this
+ * is just done as an optimistic privilege dropping function.
+ */
+ SAVE_ERRNO(setgroups(0, NULL));
+ }
+
+ if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+
+ if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+
+ if (options->env != NULL) {
+ environ = options->env;
+ }
+
+ execvp(options->file, options->args);
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+}
+#endif
+
+
+int uv_spawn(uv_loop_t* loop,
+ uv_process_t* process,
+ const uv_process_options_t* options) {
+#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
+ /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */
+ return -ENOSYS;
+#else
+ int signal_pipe[2] = { -1, -1 };
+ int (*pipes)[2];
+ int stdio_count;
+ ssize_t r;
+ pid_t pid;
+ int err;
+ int exec_errorno;
+ int i;
+ int status;
+
+ assert(options->file != NULL);
+ assert(!(options->flags & ~(UV_PROCESS_DETACHED |
+ UV_PROCESS_SETGID |
+ UV_PROCESS_SETUID |
+ UV_PROCESS_WINDOWS_HIDE |
+ UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
+
+ uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
+ QUEUE_INIT(&process->queue);
+
+ stdio_count = options->stdio_count;
+ if (stdio_count < 3)
+ stdio_count = 3;
+
+ err = -ENOMEM;
+ pipes = uv__malloc(stdio_count * sizeof(*pipes));
+ if (pipes == NULL)
+ goto error;
+
+ for (i = 0; i < stdio_count; i++) {
+ pipes[i][0] = -1;
+ pipes[i][1] = -1;
+ }
+
+ for (i = 0; i < options->stdio_count; i++) {
+ err = uv__process_init_stdio(options->stdio + i, pipes[i]);
+ if (err)
+ goto error;
+ }
+
+ /* This pipe is used by the parent to wait until
+ * the child has called `execve()`. We need this
+ * to avoid the following race condition:
+ *
+ * if ((pid = fork()) > 0) {
+ * kill(pid, SIGTERM);
+ * }
+ * else if (pid == 0) {
+ * execve("/bin/cat", argp, envp);
+ * }
+ *
+ * The parent sends a signal immediately after forking.
+ * Since the child may not have called `execve()` yet,
+ * there is no telling what process receives the signal,
+ * our fork or /bin/cat.
+ *
+ * To avoid ambiguity, we create a pipe with both ends
+ * marked close-on-exec. Then, after the call to `fork()`,
+ * the parent polls the read end until it EOFs or errors with EPIPE.
+ */
+ err = uv__make_pipe(signal_pipe, 0);
+ if (err)
+ goto error;
+
+ uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD);
+
+ /* Acquire write lock to prevent opening new fds in worker threads */
+ uv_rwlock_wrlock(&loop->cloexec_lock);
+ pid = fork();
+
+ if (pid == -1) {
+ err = -errno;
+ uv_rwlock_wrunlock(&loop->cloexec_lock);
+ uv__close(signal_pipe[0]);
+ uv__close(signal_pipe[1]);
+ goto error;
+ }
+
+ if (pid == 0) {
+ uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]);
+ abort();
+ }
+
+ /* Release lock in parent process */
+ uv_rwlock_wrunlock(&loop->cloexec_lock);
+ uv__close(signal_pipe[1]);
+
+ process->status = 0;
+ exec_errorno = 0;
+ do
+ r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno));
+ while (r == -1 && errno == EINTR);
+
+ if (r == 0)
+ ; /* okay, EOF */
+ else if (r == sizeof(exec_errorno)) {
+ do
+ err = waitpid(pid, &status, 0); /* okay, read errorno */
+ while (err == -1 && errno == EINTR);
+ assert(err == pid);
+ } else if (r == -1 && errno == EPIPE) {
+ do
+ err = waitpid(pid, &status, 0); /* okay, got EPIPE */
+ while (err == -1 && errno == EINTR);
+ assert(err == pid);
+ } else
+ abort();
+
+ uv__close(signal_pipe[0]);
+
+ for (i = 0; i < options->stdio_count; i++) {
+ err = uv__process_open_stream(options->stdio + i, pipes[i], i == 0);
+ if (err == 0)
+ continue;
+
+ while (i--)
+ uv__process_close_stream(options->stdio + i);
+
+ goto error;
+ }
+
+ /* Only activate this handle if exec() happened successfully */
+ if (exec_errorno == 0) {
+ QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue);
+ uv__handle_start(process);
+ }
+
+ process->pid = pid;
+ process->exit_cb = options->exit_cb;
+
+ uv__free(pipes);
+ return exec_errorno;
+
+error:
+ if (pipes != NULL) {
+ for (i = 0; i < stdio_count; i++) {
+ if (i < options->stdio_count)
+ if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM))
+ continue;
+ if (pipes[i][0] != -1)
+ close(pipes[i][0]);
+ if (pipes[i][1] != -1)
+ close(pipes[i][1]);
+ }
+ uv__free(pipes);
+ }
+
+ return err;
+#endif
+}
+
+
+int uv_process_kill(uv_process_t* process, int signum) {
+ return uv_kill(process->pid, signum);
+}
+
+
+int uv_kill(int pid, int signum) {
+ if (kill(pid, signum))
+ return -errno;
+ else
+ return 0;
+}
+
+
+void uv__process_close(uv_process_t* handle) {
+ QUEUE_REMOVE(&handle->queue);
+ uv__handle_stop(handle);
+ if (QUEUE_EMPTY(&handle->loop->process_handles))
+ uv_signal_stop(&handle->loop->child_watcher);
+}
diff --git a/3rdparty/libuv/src/unix/proctitle.c b/3rdparty/libuv/src/unix/proctitle.c
new file mode 100644
index 00000000000..19214e5ec97
--- /dev/null
+++ b/3rdparty/libuv/src/unix/proctitle.c
@@ -0,0 +1,102 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+extern void uv__set_process_title(const char* title);
+
+static void* args_mem;
+
+static struct {
+ char* str;
+ size_t len;
+} process_title;
+
+
+char** uv_setup_args(int argc, char** argv) {
+ char** new_argv;
+ size_t size;
+ char* s;
+ int i;
+
+ if (argc <= 0)
+ return argv;
+
+ /* Calculate how much memory we need for the argv strings. */
+ size = 0;
+ for (i = 0; i < argc; i++)
+ size += strlen(argv[i]) + 1;
+
+ process_title.str = argv[0];
+ process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0];
+ assert(process_title.len + 1 == size); /* argv memory should be adjacent. */
+
+ /* Add space for the argv pointers. */
+ size += (argc + 1) * sizeof(char*);
+
+ new_argv = uv__malloc(size);
+ if (new_argv == NULL)
+ return argv;
+ args_mem = new_argv;
+
+ /* Copy over the strings and set up the pointer table. */
+ s = (char*) &new_argv[argc + 1];
+ for (i = 0; i < argc; i++) {
+ size = strlen(argv[i]) + 1;
+ memcpy(s, argv[i], size);
+ new_argv[i] = s;
+ s += size;
+ }
+ new_argv[i] = NULL;
+
+ return new_argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ if (process_title.len == 0)
+ return 0;
+
+ /* No need to terminate, byte after is always '\0'. */
+ strncpy(process_title.str, title, process_title.len);
+ uv__set_process_title(title);
+
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ if (process_title.len > 0)
+ strncpy(buffer, process_title.str, size);
+ else if (size > 0)
+ buffer[0] = '\0';
+
+ return 0;
+}
+
+
+UV_DESTRUCTOR(static void free_args_mem(void)) {
+ uv__free(args_mem); /* Keep valgrind happy. */
+ args_mem = NULL;
+}
diff --git a/3rdparty/libuv/src/unix/pthread-fixes.c b/3rdparty/libuv/src/unix/pthread-fixes.c
new file mode 100644
index 00000000000..3a71eb5aae7
--- /dev/null
+++ b/3rdparty/libuv/src/unix/pthread-fixes.c
@@ -0,0 +1,104 @@
+/* Copyright (c) 2013, Sony Mobile Communications AB
+ * Copyright (c) 2012, Google Inc.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Google Inc. nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Android versions < 4.1 have a broken pthread_sigmask.
+ * Note that this block of code must come before any inclusion of
+ * pthread-fixes.h so that the real pthread_sigmask can be referenced.
+ * */
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+
+int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) {
+ static int workaround;
+
+ if (workaround) {
+ return sigprocmask(how, set, oset);
+ } else if (pthread_sigmask(how, set, oset)) {
+ if (errno == EINVAL && sigprocmask(how, set, oset) == 0) {
+ workaround = 1;
+ return 0;
+ } else {
+ return -1;
+ }
+ } else {
+ return 0;
+ }
+}
+
+/*Android doesn't provide pthread_barrier_t for now.*/
+#ifndef PTHREAD_BARRIER_SERIAL_THREAD
+
+#include "pthread-fixes.h"
+
+int pthread_barrier_init(pthread_barrier_t* barrier,
+ const void* barrier_attr,
+ unsigned count) {
+ barrier->count = count;
+ pthread_mutex_init(&barrier->mutex, NULL);
+ pthread_cond_init(&barrier->cond, NULL);
+ return 0;
+}
+
+int pthread_barrier_wait(pthread_barrier_t* barrier) {
+ /* Lock the mutex*/
+ pthread_mutex_lock(&barrier->mutex);
+ /* Decrement the count. If this is the first thread to reach 0, wake up
+ waiters, unlock the mutex, then return PTHREAD_BARRIER_SERIAL_THREAD.*/
+ if (--barrier->count == 0) {
+ /* First thread to reach the barrier */
+ pthread_cond_broadcast(&barrier->cond);
+ pthread_mutex_unlock(&barrier->mutex);
+ return PTHREAD_BARRIER_SERIAL_THREAD;
+ }
+ /* Otherwise, wait for other threads until the count reaches 0, then
+ return 0 to indicate this is not the first thread.*/
+ do {
+ pthread_cond_wait(&barrier->cond, &barrier->mutex);
+ } while (barrier->count > 0);
+
+ pthread_mutex_unlock(&barrier->mutex);
+ return 0;
+}
+
+int pthread_barrier_destroy(pthread_barrier_t *barrier) {
+ barrier->count = 0;
+ pthread_cond_destroy(&barrier->cond);
+ pthread_mutex_destroy(&barrier->mutex);
+ return 0;
+}
+
+#endif /* defined(PTHREAD_BARRIER_SERIAL_THREAD) */
+
+int pthread_yield(void) {
+ sched_yield();
+ return 0;
+}
diff --git a/3rdparty/libuv/src/unix/signal.c b/3rdparty/libuv/src/unix/signal.c
new file mode 100644
index 00000000000..edd9085d3f3
--- /dev/null
+++ b/3rdparty/libuv/src/unix/signal.c
@@ -0,0 +1,467 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+typedef struct {
+ uv_signal_t* handle;
+ int signum;
+} uv__signal_msg_t;
+
+RB_HEAD(uv__signal_tree_s, uv_signal_s);
+
+
+static int uv__signal_unlock(void);
+static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, unsigned int events);
+static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2);
+static void uv__signal_stop(uv_signal_t* handle);
+
+
+static pthread_once_t uv__signal_global_init_guard = PTHREAD_ONCE_INIT;
+static struct uv__signal_tree_s uv__signal_tree =
+ RB_INITIALIZER(uv__signal_tree);
+static int uv__signal_lock_pipefd[2];
+
+
+RB_GENERATE_STATIC(uv__signal_tree_s,
+ uv_signal_s, tree_entry,
+ uv__signal_compare)
+
+
+static void uv__signal_global_init(void) {
+ if (uv__make_pipe(uv__signal_lock_pipefd, 0))
+ abort();
+
+ if (uv__signal_unlock())
+ abort();
+}
+
+
+void uv__signal_global_once_init(void) {
+ pthread_once(&uv__signal_global_init_guard, uv__signal_global_init);
+}
+
+
+
+static int uv__signal_lock(void) {
+ int r;
+ char data;
+
+ do {
+ r = read(uv__signal_lock_pipefd[0], &data, sizeof data);
+ } while (r < 0 && errno == EINTR);
+
+ return (r < 0) ? -1 : 0;
+}
+
+
+static int uv__signal_unlock(void) {
+ int r;
+ char data = 42;
+
+ do {
+ r = write(uv__signal_lock_pipefd[1], &data, sizeof data);
+ } while (r < 0 && errno == EINTR);
+
+ return (r < 0) ? -1 : 0;
+}
+
+
+static void uv__signal_block_and_lock(sigset_t* saved_sigmask) {
+ sigset_t new_mask;
+
+ if (sigfillset(&new_mask))
+ abort();
+
+ if (pthread_sigmask(SIG_SETMASK, &new_mask, saved_sigmask))
+ abort();
+
+ if (uv__signal_lock())
+ abort();
+}
+
+
+static void uv__signal_unlock_and_unblock(sigset_t* saved_sigmask) {
+ if (uv__signal_unlock())
+ abort();
+
+ if (pthread_sigmask(SIG_SETMASK, saved_sigmask, NULL))
+ abort();
+}
+
+
+static uv_signal_t* uv__signal_first_handle(int signum) {
+ /* This function must be called with the signal lock held. */
+ uv_signal_t lookup;
+ uv_signal_t* handle;
+
+ lookup.signum = signum;
+ lookup.loop = NULL;
+
+ handle = RB_NFIND(uv__signal_tree_s, &uv__signal_tree, &lookup);
+
+ if (handle != NULL && handle->signum == signum)
+ return handle;
+
+ return NULL;
+}
+
+
+static void uv__signal_handler(int signum) {
+ uv__signal_msg_t msg;
+ uv_signal_t* handle;
+ int saved_errno;
+
+ saved_errno = errno;
+ memset(&msg, 0, sizeof msg);
+
+ if (uv__signal_lock()) {
+ errno = saved_errno;
+ return;
+ }
+
+ for (handle = uv__signal_first_handle(signum);
+ handle != NULL && handle->signum == signum;
+ handle = RB_NEXT(uv__signal_tree_s, &uv__signal_tree, handle)) {
+ int r;
+
+ msg.signum = signum;
+ msg.handle = handle;
+
+ /* write() should be atomic for small data chunks, so the entire message
+ * should be written at once. In theory the pipe could become full, in
+ * which case the user is out of luck.
+ */
+ do {
+ r = write(handle->loop->signal_pipefd[1], &msg, sizeof msg);
+ } while (r == -1 && errno == EINTR);
+
+ assert(r == sizeof msg ||
+ (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)));
+
+ if (r != -1)
+ handle->caught_signals++;
+ }
+
+ uv__signal_unlock();
+ errno = saved_errno;
+}
+
+
+static int uv__signal_register_handler(int signum) {
+ /* When this function is called, the signal lock must be held. */
+ struct sigaction sa;
+
+ /* XXX use a separate signal stack? */
+ memset(&sa, 0, sizeof(sa));
+ if (sigfillset(&sa.sa_mask))
+ abort();
+ sa.sa_handler = uv__signal_handler;
+
+ /* XXX save old action so we can restore it later on? */
+ if (sigaction(signum, &sa, NULL))
+ return -errno;
+
+ return 0;
+}
+
+
+static void uv__signal_unregister_handler(int signum) {
+ /* When this function is called, the signal lock must be held. */
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_DFL;
+
+ /* sigaction can only fail with EINVAL or EFAULT; an attempt to deregister a
+ * signal implies that it was successfully registered earlier, so EINVAL
+ * should never happen.
+ */
+ if (sigaction(signum, &sa, NULL))
+ abort();
+}
+
+
+static int uv__signal_loop_once_init(uv_loop_t* loop) {
+ int err;
+
+ /* Return if already initialized. */
+ if (loop->signal_pipefd[0] != -1)
+ return 0;
+
+ err = uv__make_pipe(loop->signal_pipefd, UV__F_NONBLOCK);
+ if (err)
+ return err;
+
+ uv__io_init(&loop->signal_io_watcher,
+ uv__signal_event,
+ loop->signal_pipefd[0]);
+ uv__io_start(loop, &loop->signal_io_watcher, UV__POLLIN);
+
+ return 0;
+}
+
+
+void uv__signal_loop_cleanup(uv_loop_t* loop) {
+ QUEUE* q;
+
+ /* Stop all the signal watchers that are still attached to this loop. This
+ * ensures that the (shared) signal tree doesn't contain any invalid entries
+ * entries, and that signal handlers are removed when appropriate.
+ * It's safe to use QUEUE_FOREACH here because the handles and the handle
+ * queue are not modified by uv__signal_stop().
+ */
+ QUEUE_FOREACH(q, &loop->handle_queue) {
+ uv_handle_t* handle = QUEUE_DATA(q, uv_handle_t, handle_queue);
+
+ if (handle->type == UV_SIGNAL)
+ uv__signal_stop((uv_signal_t*) handle);
+ }
+
+ if (loop->signal_pipefd[0] != -1) {
+ uv__close(loop->signal_pipefd[0]);
+ loop->signal_pipefd[0] = -1;
+ }
+
+ if (loop->signal_pipefd[1] != -1) {
+ uv__close(loop->signal_pipefd[1]);
+ loop->signal_pipefd[1] = -1;
+ }
+}
+
+
+int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
+ int err;
+
+ err = uv__signal_loop_once_init(loop);
+ if (err)
+ return err;
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
+ handle->signum = 0;
+ handle->caught_signals = 0;
+ handle->dispatched_signals = 0;
+
+ return 0;
+}
+
+
+void uv__signal_close(uv_signal_t* handle) {
+
+ uv__signal_stop(handle);
+
+ /* If there are any caught signals "trapped" in the signal pipe, we can't
+ * call the close callback yet. Otherwise, add the handle to the finish_close
+ * queue.
+ */
+ if (handle->caught_signals == handle->dispatched_signals) {
+ uv__make_close_pending((uv_handle_t*) handle);
+ }
+}
+
+
+int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
+ sigset_t saved_sigmask;
+ int err;
+
+ assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
+
+ /* If the user supplies signum == 0, then return an error already. If the
+ * signum is otherwise invalid then uv__signal_register will find out
+ * eventually.
+ */
+ if (signum == 0)
+ return -EINVAL;
+
+ /* Short circuit: if the signal watcher is already watching {signum} don't
+ * go through the process of deregistering and registering the handler.
+ * Additionally, this avoids pending signals getting lost in the small time
+ * time frame that handle->signum == 0.
+ */
+ if (signum == handle->signum) {
+ handle->signal_cb = signal_cb;
+ return 0;
+ }
+
+ /* If the signal handler was already active, stop it first. */
+ if (handle->signum != 0) {
+ uv__signal_stop(handle);
+ }
+
+ uv__signal_block_and_lock(&saved_sigmask);
+
+ /* If at this point there are no active signal watchers for this signum (in
+ * any of the loops), it's time to try and register a handler for it here.
+ */
+ if (uv__signal_first_handle(signum) == NULL) {
+ err = uv__signal_register_handler(signum);
+ if (err) {
+ /* Registering the signal handler failed. Must be an invalid signal. */
+ uv__signal_unlock_and_unblock(&saved_sigmask);
+ return err;
+ }
+ }
+
+ handle->signum = signum;
+ RB_INSERT(uv__signal_tree_s, &uv__signal_tree, handle);
+
+ uv__signal_unlock_and_unblock(&saved_sigmask);
+
+ handle->signal_cb = signal_cb;
+ uv__handle_start(handle);
+
+ return 0;
+}
+
+
+static void uv__signal_event(uv_loop_t* loop,
+ uv__io_t* w,
+ unsigned int events) {
+ uv__signal_msg_t* msg;
+ uv_signal_t* handle;
+ char buf[sizeof(uv__signal_msg_t) * 32];
+ size_t bytes, end, i;
+ int r;
+
+ bytes = 0;
+ end = 0;
+
+ do {
+ r = read(loop->signal_pipefd[0], buf + bytes, sizeof(buf) - bytes);
+
+ if (r == -1 && errno == EINTR)
+ continue;
+
+ if (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
+ /* If there are bytes in the buffer already (which really is extremely
+ * unlikely if possible at all) we can't exit the function here. We'll
+ * spin until more bytes are read instead.
+ */
+ if (bytes > 0)
+ continue;
+
+ /* Otherwise, there was nothing there. */
+ return;
+ }
+
+ /* Other errors really should never happen. */
+ if (r == -1)
+ abort();
+
+ bytes += r;
+
+ /* `end` is rounded down to a multiple of sizeof(uv__signal_msg_t). */
+ end = (bytes / sizeof(uv__signal_msg_t)) * sizeof(uv__signal_msg_t);
+
+ for (i = 0; i < end; i += sizeof(uv__signal_msg_t)) {
+ msg = (uv__signal_msg_t*) (buf + i);
+ handle = msg->handle;
+
+ if (msg->signum == handle->signum) {
+ assert(!(handle->flags & UV_CLOSING));
+ handle->signal_cb(handle, handle->signum);
+ }
+
+ handle->dispatched_signals++;
+
+ /* If uv_close was called while there were caught signals that were not
+ * yet dispatched, the uv__finish_close was deferred. Make close pending
+ * now if this has happened.
+ */
+ if ((handle->flags & UV_CLOSING) &&
+ (handle->caught_signals == handle->dispatched_signals)) {
+ uv__make_close_pending((uv_handle_t*) handle);
+ }
+ }
+
+ bytes -= end;
+
+ /* If there are any "partial" messages left, move them to the start of the
+ * the buffer, and spin. This should not happen.
+ */
+ if (bytes) {
+ memmove(buf, buf + end, bytes);
+ continue;
+ }
+ } while (end == sizeof buf);
+}
+
+
+static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
+ /* Compare signums first so all watchers with the same signnum end up
+ * adjacent.
+ */
+ if (w1->signum < w2->signum) return -1;
+ if (w1->signum > w2->signum) return 1;
+
+ /* Sort by loop pointer, so we can easily look up the first item after
+ * { .signum = x, .loop = NULL }.
+ */
+ if (w1->loop < w2->loop) return -1;
+ if (w1->loop > w2->loop) return 1;
+
+ if (w1 < w2) return -1;
+ if (w1 > w2) return 1;
+
+ return 0;
+}
+
+
+int uv_signal_stop(uv_signal_t* handle) {
+ assert(!(handle->flags & (UV_CLOSING | UV_CLOSED)));
+ uv__signal_stop(handle);
+ return 0;
+}
+
+
+static void uv__signal_stop(uv_signal_t* handle) {
+ uv_signal_t* removed_handle;
+ sigset_t saved_sigmask;
+
+ /* If the watcher wasn't started, this is a no-op. */
+ if (handle->signum == 0)
+ return;
+
+ uv__signal_block_and_lock(&saved_sigmask);
+
+ removed_handle = RB_REMOVE(uv__signal_tree_s, &uv__signal_tree, handle);
+ assert(removed_handle == handle);
+ (void) removed_handle;
+
+ /* Check if there are other active signal watchers observing this signal. If
+ * not, unregister the signal handler.
+ */
+ if (uv__signal_first_handle(handle->signum) == NULL)
+ uv__signal_unregister_handler(handle->signum);
+
+ uv__signal_unlock_and_unblock(&saved_sigmask);
+
+ handle->signum = 0;
+ uv__handle_stop(handle);
+}
diff --git a/3rdparty/libuv/src/unix/spinlock.h b/3rdparty/libuv/src/unix/spinlock.h
new file mode 100644
index 00000000000..a20c83cc601
--- /dev/null
+++ b/3rdparty/libuv/src/unix/spinlock.h
@@ -0,0 +1,53 @@
+/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef UV_SPINLOCK_H_
+#define UV_SPINLOCK_H_
+
+#include "internal.h" /* ACCESS_ONCE, UV_UNUSED */
+#include "atomic-ops.h"
+
+#define UV_SPINLOCK_INITIALIZER { 0 }
+
+typedef struct {
+ int lock;
+} uv_spinlock_t;
+
+UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock));
+UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock));
+UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock));
+UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock));
+
+UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock)) {
+ ACCESS_ONCE(int, spinlock->lock) = 0;
+}
+
+UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock)) {
+ while (!uv_spinlock_trylock(spinlock)) cpu_relax();
+}
+
+UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock)) {
+ ACCESS_ONCE(int, spinlock->lock) = 0;
+}
+
+UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock)) {
+ /* TODO(bnoordhuis) Maybe change to a ticket lock to guarantee fair queueing.
+ * Not really critical until we have locks that are (frequently) contended
+ * for by several threads.
+ */
+ return 0 == cmpxchgi(&spinlock->lock, 0, 1);
+}
+
+#endif /* UV_SPINLOCK_H_ */
diff --git a/3rdparty/libuv/src/unix/stream.c b/3rdparty/libuv/src/unix/stream.c
new file mode 100644
index 00000000000..7d7ab2633b6
--- /dev/null
+++ b/3rdparty/libuv/src/unix/stream.c
@@ -0,0 +1,1615 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <limits.h> /* IOV_MAX */
+
+#if defined(__APPLE__)
+# include <sys/event.h>
+# include <sys/time.h>
+# include <sys/select.h>
+
+/* Forward declaration */
+typedef struct uv__stream_select_s uv__stream_select_t;
+
+struct uv__stream_select_s {
+ uv_stream_t* stream;
+ uv_thread_t thread;
+ uv_sem_t close_sem;
+ uv_sem_t async_sem;
+ uv_async_t async;
+ int events;
+ int fake_fd;
+ int int_fd;
+ int fd;
+ fd_set* sread;
+ size_t sread_sz;
+ fd_set* swrite;
+ size_t swrite_sz;
+};
+#endif /* defined(__APPLE__) */
+
+static void uv__stream_connect(uv_stream_t*);
+static void uv__write(uv_stream_t* stream);
+static void uv__read(uv_stream_t* stream);
+static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
+static void uv__write_callbacks(uv_stream_t* stream);
+static size_t uv__write_req_size(uv_write_t* req);
+
+
+void uv__stream_init(uv_loop_t* loop,
+ uv_stream_t* stream,
+ uv_handle_type type) {
+ int err;
+
+ uv__handle_init(loop, (uv_handle_t*)stream, type);
+ stream->read_cb = NULL;
+ stream->alloc_cb = NULL;
+ stream->close_cb = NULL;
+ stream->connection_cb = NULL;
+ stream->connect_req = NULL;
+ stream->shutdown_req = NULL;
+ stream->accepted_fd = -1;
+ stream->queued_fds = NULL;
+ stream->delayed_error = 0;
+ QUEUE_INIT(&stream->write_queue);
+ QUEUE_INIT(&stream->write_completed_queue);
+ stream->write_queue_size = 0;
+
+ if (loop->emfile_fd == -1) {
+ err = uv__open_cloexec("/dev/null", O_RDONLY);
+ if (err < 0)
+ /* In the rare case that "/dev/null" isn't mounted open "/"
+ * instead.
+ */
+ err = uv__open_cloexec("/", O_RDONLY);
+ if (err >= 0)
+ loop->emfile_fd = err;
+ }
+
+#if defined(__APPLE__)
+ stream->select = NULL;
+#endif /* defined(__APPLE_) */
+
+ uv__io_init(&stream->io_watcher, uv__stream_io, -1);
+}
+
+
+static void uv__stream_osx_interrupt_select(uv_stream_t* stream) {
+#if defined(__APPLE__)
+ /* Notify select() thread about state change */
+ uv__stream_select_t* s;
+ int r;
+
+ s = stream->select;
+ if (s == NULL)
+ return;
+
+ /* Interrupt select() loop
+ * NOTE: fake_fd and int_fd are socketpair(), thus writing to one will
+ * emit read event on other side
+ */
+ do
+ r = write(s->fake_fd, "x", 1);
+ while (r == -1 && errno == EINTR);
+
+ assert(r == 1);
+#else /* !defined(__APPLE__) */
+ /* No-op on any other platform */
+#endif /* !defined(__APPLE__) */
+}
+
+
+#if defined(__APPLE__)
+static void uv__stream_osx_select(void* arg) {
+ uv_stream_t* stream;
+ uv__stream_select_t* s;
+ char buf[1024];
+ int events;
+ int fd;
+ int r;
+ int max_fd;
+
+ stream = arg;
+ s = stream->select;
+ fd = s->fd;
+
+ if (fd > s->int_fd)
+ max_fd = fd;
+ else
+ max_fd = s->int_fd;
+
+ while (1) {
+ /* Terminate on semaphore */
+ if (uv_sem_trywait(&s->close_sem) == 0)
+ break;
+
+ /* Watch fd using select(2) */
+ memset(s->sread, 0, s->sread_sz);
+ memset(s->swrite, 0, s->swrite_sz);
+
+ if (uv__io_active(&stream->io_watcher, UV__POLLIN))
+ FD_SET(fd, s->sread);
+ if (uv__io_active(&stream->io_watcher, UV__POLLOUT))
+ FD_SET(fd, s->swrite);
+ FD_SET(s->int_fd, s->sread);
+
+ /* Wait indefinitely for fd events */
+ r = select(max_fd + 1, s->sread, s->swrite, NULL, NULL);
+ if (r == -1) {
+ if (errno == EINTR)
+ continue;
+
+ /* XXX: Possible?! */
+ abort();
+ }
+
+ /* Ignore timeouts */
+ if (r == 0)
+ continue;
+
+ /* Empty socketpair's buffer in case of interruption */
+ if (FD_ISSET(s->int_fd, s->sread))
+ while (1) {
+ r = read(s->int_fd, buf, sizeof(buf));
+
+ if (r == sizeof(buf))
+ continue;
+
+ if (r != -1)
+ break;
+
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ break;
+
+ if (errno == EINTR)
+ continue;
+
+ abort();
+ }
+
+ /* Handle events */
+ events = 0;
+ if (FD_ISSET(fd, s->sread))
+ events |= UV__POLLIN;
+ if (FD_ISSET(fd, s->swrite))
+ events |= UV__POLLOUT;
+
+ assert(events != 0 || FD_ISSET(s->int_fd, s->sread));
+ if (events != 0) {
+ ACCESS_ONCE(int, s->events) = events;
+
+ uv_async_send(&s->async);
+ uv_sem_wait(&s->async_sem);
+
+ /* Should be processed at this stage */
+ assert((s->events == 0) || (stream->flags & UV_CLOSING));
+ }
+ }
+}
+
+
+static void uv__stream_osx_select_cb(uv_async_t* handle) {
+ uv__stream_select_t* s;
+ uv_stream_t* stream;
+ int events;
+
+ s = container_of(handle, uv__stream_select_t, async);
+ stream = s->stream;
+
+ /* Get and reset stream's events */
+ events = s->events;
+ ACCESS_ONCE(int, s->events) = 0;
+
+ assert(events != 0);
+ assert(events == (events & (UV__POLLIN | UV__POLLOUT)));
+
+ /* Invoke callback on event-loop */
+ if ((events & UV__POLLIN) && uv__io_active(&stream->io_watcher, UV__POLLIN))
+ uv__stream_io(stream->loop, &stream->io_watcher, UV__POLLIN);
+
+ if ((events & UV__POLLOUT) && uv__io_active(&stream->io_watcher, UV__POLLOUT))
+ uv__stream_io(stream->loop, &stream->io_watcher, UV__POLLOUT);
+
+ if (stream->flags & UV_CLOSING)
+ return;
+
+ /* NOTE: It is important to do it here, otherwise `select()` might be called
+ * before the actual `uv__read()`, leading to the blocking syscall
+ */
+ uv_sem_post(&s->async_sem);
+}
+
+
+static void uv__stream_osx_cb_close(uv_handle_t* async) {
+ uv__stream_select_t* s;
+
+ s = container_of(async, uv__stream_select_t, async);
+ uv__free(s);
+}
+
+
+int uv__stream_try_select(uv_stream_t* stream, int* fd) {
+ /*
+ * kqueue doesn't work with some files from /dev mount on osx.
+ * select(2) in separate thread for those fds
+ */
+
+ struct kevent filter[1];
+ struct kevent events[1];
+ struct timespec timeout;
+ uv__stream_select_t* s;
+ int fds[2];
+ int err;
+ int ret;
+ int kq;
+ int old_fd;
+ int max_fd;
+ size_t sread_sz;
+ size_t swrite_sz;
+
+ kq = kqueue();
+ if (kq == -1) {
+ perror("(libuv) kqueue()");
+ return -errno;
+ }
+
+ EV_SET(&filter[0], *fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
+
+ /* Use small timeout, because we only want to capture EINVALs */
+ timeout.tv_sec = 0;
+ timeout.tv_nsec = 1;
+
+ ret = kevent(kq, filter, 1, events, 1, &timeout);
+ uv__close(kq);
+
+ if (ret == -1)
+ return -errno;
+
+ if (ret == 0 || (events[0].flags & EV_ERROR) == 0 || events[0].data != EINVAL)
+ return 0;
+
+ /* At this point we definitely know that this fd won't work with kqueue */
+
+ /*
+ * Create fds for io watcher and to interrupt the select() loop.
+ * NOTE: do it ahead of malloc below to allocate enough space for fd_sets
+ */
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
+ return -errno;
+
+ max_fd = *fd;
+ if (fds[1] > max_fd)
+ max_fd = fds[1];
+
+ sread_sz = ROUND_UP(max_fd + 1, sizeof(uint32_t) * NBBY) / NBBY;
+ swrite_sz = sread_sz;
+
+ s = uv__malloc(sizeof(*s) + sread_sz + swrite_sz);
+ if (s == NULL) {
+ err = -ENOMEM;
+ goto failed_malloc;
+ }
+
+ s->events = 0;
+ s->fd = *fd;
+ s->sread = (fd_set*) ((char*) s + sizeof(*s));
+ s->sread_sz = sread_sz;
+ s->swrite = (fd_set*) ((char*) s->sread + sread_sz);
+ s->swrite_sz = swrite_sz;
+
+ err = uv_async_init(stream->loop, &s->async, uv__stream_osx_select_cb);
+ if (err)
+ goto failed_async_init;
+
+ s->async.flags |= UV__HANDLE_INTERNAL;
+ uv__handle_unref(&s->async);
+
+ err = uv_sem_init(&s->close_sem, 0);
+ if (err != 0)
+ goto failed_close_sem_init;
+
+ err = uv_sem_init(&s->async_sem, 0);
+ if (err != 0)
+ goto failed_async_sem_init;
+
+ s->fake_fd = fds[0];
+ s->int_fd = fds[1];
+
+ old_fd = *fd;
+ s->stream = stream;
+ stream->select = s;
+ *fd = s->fake_fd;
+
+ err = uv_thread_create(&s->thread, uv__stream_osx_select, stream);
+ if (err != 0)
+ goto failed_thread_create;
+
+ return 0;
+
+failed_thread_create:
+ s->stream = NULL;
+ stream->select = NULL;
+ *fd = old_fd;
+
+ uv_sem_destroy(&s->async_sem);
+
+failed_async_sem_init:
+ uv_sem_destroy(&s->close_sem);
+
+failed_close_sem_init:
+ uv__close(fds[0]);
+ uv__close(fds[1]);
+ uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close);
+ return err;
+
+failed_async_init:
+ uv__free(s);
+
+failed_malloc:
+ uv__close(fds[0]);
+ uv__close(fds[1]);
+
+ return err;
+}
+#endif /* defined(__APPLE__) */
+
+
+int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
+#if defined(__APPLE__)
+ int enable;
+#endif
+
+ if (!(stream->io_watcher.fd == -1 || stream->io_watcher.fd == fd))
+ return -EBUSY;
+
+ assert(fd >= 0);
+ stream->flags |= flags;
+
+ if (stream->type == UV_TCP) {
+ if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay(fd, 1))
+ return -errno;
+
+ /* TODO Use delay the user passed in. */
+ if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive(fd, 1, 60))
+ return -errno;
+ }
+
+#if defined(__APPLE__)
+ enable = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) &&
+ errno != ENOTSOCK &&
+ errno != EINVAL) {
+ return -errno;
+ }
+#endif
+
+ stream->io_watcher.fd = fd;
+
+ return 0;
+}
+
+
+void uv__stream_flush_write_queue(uv_stream_t* stream, int error) {
+ uv_write_t* req;
+ QUEUE* q;
+ while (!QUEUE_EMPTY(&stream->write_queue)) {
+ q = QUEUE_HEAD(&stream->write_queue);
+ QUEUE_REMOVE(q);
+
+ req = QUEUE_DATA(q, uv_write_t, queue);
+ req->error = error;
+
+ QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue);
+ }
+}
+
+
+void uv__stream_destroy(uv_stream_t* stream) {
+ assert(!uv__io_active(&stream->io_watcher, UV__POLLIN | UV__POLLOUT));
+ assert(stream->flags & UV_CLOSED);
+
+ if (stream->connect_req) {
+ uv__req_unregister(stream->loop, stream->connect_req);
+ stream->connect_req->cb(stream->connect_req, -ECANCELED);
+ stream->connect_req = NULL;
+ }
+
+ uv__stream_flush_write_queue(stream, -ECANCELED);
+ uv__write_callbacks(stream);
+
+ if (stream->shutdown_req) {
+ /* The ECANCELED error code is a lie, the shutdown(2) syscall is a
+ * fait accompli at this point. Maybe we should revisit this in v0.11.
+ * A possible reason for leaving it unchanged is that it informs the
+ * callee that the handle has been destroyed.
+ */
+ uv__req_unregister(stream->loop, stream->shutdown_req);
+ stream->shutdown_req->cb(stream->shutdown_req, -ECANCELED);
+ stream->shutdown_req = NULL;
+ }
+
+ assert(stream->write_queue_size == 0);
+}
+
+
+/* Implements a best effort approach to mitigating accept() EMFILE errors.
+ * We have a spare file descriptor stashed away that we close to get below
+ * the EMFILE limit. Next, we accept all pending connections and close them
+ * immediately to signal the clients that we're overloaded - and we are, but
+ * we still keep on trucking.
+ *
+ * There is one caveat: it's not reliable in a multi-threaded environment.
+ * The file descriptor limit is per process. Our party trick fails if another
+ * thread opens a file or creates a socket in the time window between us
+ * calling close() and accept().
+ */
+static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) {
+ int err;
+ int emfile_fd;
+
+ if (loop->emfile_fd == -1)
+ return -EMFILE;
+
+ uv__close(loop->emfile_fd);
+ loop->emfile_fd = -1;
+
+ do {
+ err = uv__accept(accept_fd);
+ if (err >= 0)
+ uv__close(err);
+ } while (err >= 0 || err == -EINTR);
+
+ emfile_fd = uv__open_cloexec("/", O_RDONLY);
+ if (emfile_fd >= 0)
+ loop->emfile_fd = emfile_fd;
+
+ return err;
+}
+
+
+#if defined(UV_HAVE_KQUEUE)
+# define UV_DEC_BACKLOG(w) w->rcount--;
+#else
+# define UV_DEC_BACKLOG(w) /* no-op */
+#endif /* defined(UV_HAVE_KQUEUE) */
+
+
+void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+ uv_stream_t* stream;
+ int err;
+
+ stream = container_of(w, uv_stream_t, io_watcher);
+ assert(events == UV__POLLIN);
+ assert(stream->accepted_fd == -1);
+ assert(!(stream->flags & UV_CLOSING));
+
+ uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN);
+
+ /* connection_cb can close the server socket while we're
+ * in the loop so check it on each iteration.
+ */
+ while (uv__stream_fd(stream) != -1) {
+ assert(stream->accepted_fd == -1);
+
+#if defined(UV_HAVE_KQUEUE)
+ if (w->rcount <= 0)
+ return;
+#endif /* defined(UV_HAVE_KQUEUE) */
+
+ err = uv__accept(uv__stream_fd(stream));
+ if (err < 0) {
+ if (err == -EAGAIN || err == -EWOULDBLOCK)
+ return; /* Not an error. */
+
+ if (err == -ECONNABORTED)
+ continue; /* Ignore. Nothing we can do about that. */
+
+ if (err == -EMFILE || err == -ENFILE) {
+ err = uv__emfile_trick(loop, uv__stream_fd(stream));
+ if (err == -EAGAIN || err == -EWOULDBLOCK)
+ break;
+ }
+
+ stream->connection_cb(stream, err);
+ continue;
+ }
+
+ UV_DEC_BACKLOG(w)
+ stream->accepted_fd = err;
+ stream->connection_cb(stream, 0);
+
+ if (stream->accepted_fd != -1) {
+ /* The user hasn't yet accepted called uv_accept() */
+ uv__io_stop(loop, &stream->io_watcher, UV__POLLIN);
+ return;
+ }
+
+ if (stream->type == UV_TCP && (stream->flags & UV_TCP_SINGLE_ACCEPT)) {
+ /* Give other processes a chance to accept connections. */
+ struct timespec timeout = { 0, 1 };
+ nanosleep(&timeout, NULL);
+ }
+ }
+}
+
+
+#undef UV_DEC_BACKLOG
+
+
+int uv_accept(uv_stream_t* server, uv_stream_t* client) {
+ int err;
+
+ /* TODO document this */
+ assert(server->loop == client->loop);
+
+ if (server->accepted_fd == -1)
+ return -EAGAIN;
+
+ switch (client->type) {
+ case UV_NAMED_PIPE:
+ case UV_TCP:
+ err = uv__stream_open(client,
+ server->accepted_fd,
+ UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+ if (err) {
+ /* TODO handle error */
+ uv__close(server->accepted_fd);
+ goto done;
+ }
+ break;
+
+ case UV_UDP:
+ err = uv_udp_open((uv_udp_t*) client, server->accepted_fd);
+ if (err) {
+ uv__close(server->accepted_fd);
+ goto done;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+done:
+ /* Process queued fds */
+ if (server->queued_fds != NULL) {
+ uv__stream_queued_fds_t* queued_fds;
+
+ queued_fds = server->queued_fds;
+
+ /* Read first */
+ server->accepted_fd = queued_fds->fds[0];
+
+ /* All read, free */
+ assert(queued_fds->offset > 0);
+ if (--queued_fds->offset == 0) {
+ uv__free(queued_fds);
+ server->queued_fds = NULL;
+ } else {
+ /* Shift rest */
+ memmove(queued_fds->fds,
+ queued_fds->fds + 1,
+ queued_fds->offset * sizeof(*queued_fds->fds));
+ }
+ } else {
+ server->accepted_fd = -1;
+ if (err == 0)
+ uv__io_start(server->loop, &server->io_watcher, UV__POLLIN);
+ }
+ return err;
+}
+
+
+int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
+ int err;
+
+ switch (stream->type) {
+ case UV_TCP:
+ err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
+ break;
+
+ case UV_NAMED_PIPE:
+ err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb);
+ break;
+
+ default:
+ err = -EINVAL;
+ }
+
+ if (err == 0)
+ uv__handle_start(stream);
+
+ return err;
+}
+
+
+static void uv__drain(uv_stream_t* stream) {
+ uv_shutdown_t* req;
+ int err;
+
+ assert(QUEUE_EMPTY(&stream->write_queue));
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT);
+ uv__stream_osx_interrupt_select(stream);
+
+ /* Shutdown? */
+ if ((stream->flags & UV_STREAM_SHUTTING) &&
+ !(stream->flags & UV_CLOSING) &&
+ !(stream->flags & UV_STREAM_SHUT)) {
+ assert(stream->shutdown_req);
+
+ req = stream->shutdown_req;
+ stream->shutdown_req = NULL;
+ stream->flags &= ~UV_STREAM_SHUTTING;
+ uv__req_unregister(stream->loop, req);
+
+ err = 0;
+ if (shutdown(uv__stream_fd(stream), SHUT_WR))
+ err = -errno;
+
+ if (err == 0)
+ stream->flags |= UV_STREAM_SHUT;
+
+ if (req->cb != NULL)
+ req->cb(req, err);
+ }
+}
+
+
+static size_t uv__write_req_size(uv_write_t* req) {
+ size_t size;
+
+ assert(req->bufs != NULL);
+ size = uv__count_bufs(req->bufs + req->write_index,
+ req->nbufs - req->write_index);
+ assert(req->handle->write_queue_size >= size);
+
+ return size;
+}
+
+
+static void uv__write_req_finish(uv_write_t* req) {
+ uv_stream_t* stream = req->handle;
+
+ /* Pop the req off tcp->write_queue. */
+ QUEUE_REMOVE(&req->queue);
+
+ /* Only free when there was no error. On error, we touch up write_queue_size
+ * right before making the callback. The reason we don't do that right away
+ * is that a write_queue_size > 0 is our only way to signal to the user that
+ * they should stop writing - which they should if we got an error. Something
+ * to revisit in future revisions of the libuv API.
+ */
+ if (req->error == 0) {
+ if (req->bufs != req->bufsml)
+ uv__free(req->bufs);
+ req->bufs = NULL;
+ }
+
+ /* Add it to the write_completed_queue where it will have its
+ * callback called in the near future.
+ */
+ QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue);
+ uv__io_feed(stream->loop, &stream->io_watcher);
+}
+
+
+static int uv__handle_fd(uv_handle_t* handle) {
+ switch (handle->type) {
+ case UV_NAMED_PIPE:
+ case UV_TCP:
+ return ((uv_stream_t*) handle)->io_watcher.fd;
+
+ case UV_UDP:
+ return ((uv_udp_t*) handle)->io_watcher.fd;
+
+ default:
+ return -1;
+ }
+}
+
+static void uv__write(uv_stream_t* stream) {
+ struct iovec* iov;
+ QUEUE* q;
+ uv_write_t* req;
+ int iovmax;
+ int iovcnt;
+ ssize_t n;
+
+start:
+
+ assert(uv__stream_fd(stream) >= 0);
+
+ if (QUEUE_EMPTY(&stream->write_queue))
+ return;
+
+ q = QUEUE_HEAD(&stream->write_queue);
+ req = QUEUE_DATA(q, uv_write_t, queue);
+ assert(req->handle == stream);
+
+ /*
+ * Cast to iovec. We had to have our own uv_buf_t instead of iovec
+ * because Windows's WSABUF is not an iovec.
+ */
+ assert(sizeof(uv_buf_t) == sizeof(struct iovec));
+ iov = (struct iovec*) &(req->bufs[req->write_index]);
+ iovcnt = req->nbufs - req->write_index;
+
+ iovmax = uv__getiovmax();
+
+ /* Limit iov count to avoid EINVALs from writev() */
+ if (iovcnt > iovmax)
+ iovcnt = iovmax;
+
+ /*
+ * Now do the actual writev. Note that we've been updating the pointers
+ * inside the iov each time we write. So there is no need to offset it.
+ */
+
+ if (req->send_handle) {
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ int fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle);
+ char scratch[64] = {0};
+
+ assert(fd_to_send >= 0);
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = iovcnt;
+ msg.msg_flags = 0;
+
+ msg.msg_control = (void*) scratch;
+ msg.msg_controllen = CMSG_SPACE(sizeof(fd_to_send));
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd_to_send));
+
+ /* silence aliasing warning */
+ {
+ void* pv = CMSG_DATA(cmsg);
+ int* pi = pv;
+ *pi = fd_to_send;
+ }
+
+ do {
+ n = sendmsg(uv__stream_fd(stream), &msg, 0);
+ }
+#if defined(__APPLE__)
+ /*
+ * Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
+ * EPROTOTYPE can be returned while trying to write to a socket that is
+ * shutting down. If we retry the write, we should get the expected EPIPE
+ * instead.
+ */
+ while (n == -1 && (errno == EINTR || errno == EPROTOTYPE));
+#else
+ while (n == -1 && errno == EINTR);
+#endif
+ } else {
+ do {
+ if (iovcnt == 1) {
+ n = write(uv__stream_fd(stream), iov[0].iov_base, iov[0].iov_len);
+ } else {
+ n = writev(uv__stream_fd(stream), iov, iovcnt);
+ }
+ }
+#if defined(__APPLE__)
+ /*
+ * Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
+ * EPROTOTYPE can be returned while trying to write to a socket that is
+ * shutting down. If we retry the write, we should get the expected EPIPE
+ * instead.
+ */
+ while (n == -1 && (errno == EINTR || errno == EPROTOTYPE));
+#else
+ while (n == -1 && errno == EINTR);
+#endif
+ }
+
+ if (n < 0) {
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ /* Error */
+ req->error = -errno;
+ uv__write_req_finish(req);
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT);
+ if (!uv__io_active(&stream->io_watcher, UV__POLLIN))
+ uv__handle_stop(stream);
+ uv__stream_osx_interrupt_select(stream);
+ return;
+ } else if (stream->flags & UV_STREAM_BLOCKING) {
+ /* If this is a blocking stream, try again. */
+ goto start;
+ }
+ } else {
+ /* Successful write */
+
+ while (n >= 0) {
+ uv_buf_t* buf = &(req->bufs[req->write_index]);
+ size_t len = buf->len;
+
+ assert(req->write_index < req->nbufs);
+
+ if ((size_t)n < len) {
+ buf->base += n;
+ buf->len -= n;
+ stream->write_queue_size -= n;
+ n = 0;
+
+ /* There is more to write. */
+ if (stream->flags & UV_STREAM_BLOCKING) {
+ /*
+ * If we're blocking then we should not be enabling the write
+ * watcher - instead we need to try again.
+ */
+ goto start;
+ } else {
+ /* Break loop and ensure the watcher is pending. */
+ break;
+ }
+
+ } else {
+ /* Finished writing the buf at index req->write_index. */
+ req->write_index++;
+
+ assert((size_t)n >= len);
+ n -= len;
+
+ assert(stream->write_queue_size >= len);
+ stream->write_queue_size -= len;
+
+ if (req->write_index == req->nbufs) {
+ /* Then we're done! */
+ assert(n == 0);
+ uv__write_req_finish(req);
+ /* TODO: start trying to write the next request. */
+ return;
+ }
+ }
+ }
+ }
+
+ /* Either we've counted n down to zero or we've got EAGAIN. */
+ assert(n == 0 || n == -1);
+
+ /* Only non-blocking streams should use the write_watcher. */
+ assert(!(stream->flags & UV_STREAM_BLOCKING));
+
+ /* We're not done. */
+ uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT);
+
+ /* Notify select() thread about state change */
+ uv__stream_osx_interrupt_select(stream);
+}
+
+
+static void uv__write_callbacks(uv_stream_t* stream) {
+ uv_write_t* req;
+ QUEUE* q;
+
+ while (!QUEUE_EMPTY(&stream->write_completed_queue)) {
+ /* Pop a req off write_completed_queue. */
+ q = QUEUE_HEAD(&stream->write_completed_queue);
+ req = QUEUE_DATA(q, uv_write_t, queue);
+ QUEUE_REMOVE(q);
+ uv__req_unregister(stream->loop, req);
+
+ if (req->bufs != NULL) {
+ stream->write_queue_size -= uv__write_req_size(req);
+ if (req->bufs != req->bufsml)
+ uv__free(req->bufs);
+ req->bufs = NULL;
+ }
+
+ /* NOTE: call callback AFTER freeing the request data. */
+ if (req->cb)
+ req->cb(req, req->error);
+ }
+
+ assert(QUEUE_EMPTY(&stream->write_completed_queue));
+}
+
+
+uv_handle_type uv__handle_type(int fd) {
+ struct sockaddr_storage ss;
+ socklen_t len;
+ int type;
+
+ memset(&ss, 0, sizeof(ss));
+ len = sizeof(ss);
+
+ if (getsockname(fd, (struct sockaddr*)&ss, &len))
+ return UV_UNKNOWN_HANDLE;
+
+ len = sizeof type;
+
+ if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len))
+ return UV_UNKNOWN_HANDLE;
+
+ if (type == SOCK_STREAM) {
+ switch (ss.ss_family) {
+ case AF_UNIX:
+ return UV_NAMED_PIPE;
+ case AF_INET:
+ case AF_INET6:
+ return UV_TCP;
+ }
+ }
+
+ if (type == SOCK_DGRAM &&
+ (ss.ss_family == AF_INET || ss.ss_family == AF_INET6))
+ return UV_UDP;
+
+ return UV_UNKNOWN_HANDLE;
+}
+
+
+static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) {
+ stream->flags |= UV_STREAM_READ_EOF;
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN);
+ if (!uv__io_active(&stream->io_watcher, UV__POLLOUT))
+ uv__handle_stop(stream);
+ uv__stream_osx_interrupt_select(stream);
+ stream->read_cb(stream, UV_EOF, buf);
+ stream->flags &= ~UV_STREAM_READING;
+}
+
+
+static int uv__stream_queue_fd(uv_stream_t* stream, int fd) {
+ uv__stream_queued_fds_t* queued_fds;
+ unsigned int queue_size;
+
+ queued_fds = stream->queued_fds;
+ if (queued_fds == NULL) {
+ queue_size = 8;
+ queued_fds = uv__malloc((queue_size - 1) * sizeof(*queued_fds->fds) +
+ sizeof(*queued_fds));
+ if (queued_fds == NULL)
+ return -ENOMEM;
+ queued_fds->size = queue_size;
+ queued_fds->offset = 0;
+ stream->queued_fds = queued_fds;
+
+ /* Grow */
+ } else if (queued_fds->size == queued_fds->offset) {
+ queue_size = queued_fds->size + 8;
+ queued_fds = uv__realloc(queued_fds,
+ (queue_size - 1) * sizeof(*queued_fds->fds) +
+ sizeof(*queued_fds));
+
+ /*
+ * Allocation failure, report back.
+ * NOTE: if it is fatal - sockets will be closed in uv__stream_close
+ */
+ if (queued_fds == NULL)
+ return -ENOMEM;
+ queued_fds->size = queue_size;
+ stream->queued_fds = queued_fds;
+ }
+
+ /* Put fd in a queue */
+ queued_fds->fds[queued_fds->offset++] = fd;
+
+ return 0;
+}
+
+
+#define UV__CMSG_FD_COUNT 64
+#define UV__CMSG_FD_SIZE (UV__CMSG_FD_COUNT * sizeof(int))
+
+
+static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) {
+ struct cmsghdr* cmsg;
+
+ for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+ char* start;
+ char* end;
+ int err;
+ void* pv;
+ int* pi;
+ unsigned int i;
+ unsigned int count;
+
+ if (cmsg->cmsg_type != SCM_RIGHTS) {
+ fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n",
+ cmsg->cmsg_type);
+ continue;
+ }
+
+ /* silence aliasing warning */
+ pv = CMSG_DATA(cmsg);
+ pi = pv;
+
+ /* Count available fds */
+ start = (char*) cmsg;
+ end = (char*) cmsg + cmsg->cmsg_len;
+ count = 0;
+ while (start + CMSG_LEN(count * sizeof(*pi)) < end)
+ count++;
+ assert(start + CMSG_LEN(count * sizeof(*pi)) == end);
+
+ for (i = 0; i < count; i++) {
+ /* Already has accepted fd, queue now */
+ if (stream->accepted_fd != -1) {
+ err = uv__stream_queue_fd(stream, pi[i]);
+ if (err != 0) {
+ /* Close rest */
+ for (; i < count; i++)
+ uv__close(pi[i]);
+ return err;
+ }
+ } else {
+ stream->accepted_fd = pi[i];
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+static void uv__read(uv_stream_t* stream) {
+ uv_buf_t buf;
+ ssize_t nread;
+ struct msghdr msg;
+ char cmsg_space[CMSG_SPACE(UV__CMSG_FD_SIZE)];
+ int count;
+ int err;
+ int is_ipc;
+
+ stream->flags &= ~UV_STREAM_READ_PARTIAL;
+
+ /* Prevent loop starvation when the data comes in as fast as (or faster than)
+ * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
+ */
+ count = 32;
+
+ is_ipc = stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) stream)->ipc;
+
+ /* XXX: Maybe instead of having UV_STREAM_READING we just test if
+ * tcp->read_cb is NULL or not?
+ */
+ while (stream->read_cb
+ && (stream->flags & UV_STREAM_READING)
+ && (count-- > 0)) {
+ assert(stream->alloc_cb != NULL);
+
+ stream->alloc_cb((uv_handle_t*)stream, 64 * 1024, &buf);
+ if (buf.len == 0) {
+ /* User indicates it can't or won't handle the read. */
+ stream->read_cb(stream, UV_ENOBUFS, &buf);
+ return;
+ }
+
+ assert(buf.base != NULL);
+ assert(uv__stream_fd(stream) >= 0);
+
+ if (!is_ipc) {
+ do {
+ nread = read(uv__stream_fd(stream), buf.base, buf.len);
+ }
+ while (nread < 0 && errno == EINTR);
+ } else {
+ /* ipc uses recvmsg */
+ msg.msg_flags = 0;
+ msg.msg_iov = (struct iovec*) &buf;
+ msg.msg_iovlen = 1;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ /* Set up to receive a descriptor even if one isn't in the message */
+ msg.msg_controllen = sizeof(cmsg_space);
+ msg.msg_control = cmsg_space;
+
+ do {
+ nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0);
+ }
+ while (nread < 0 && errno == EINTR);
+ }
+
+ if (nread < 0) {
+ /* Error */
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ /* Wait for the next one. */
+ if (stream->flags & UV_STREAM_READING) {
+ uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN);
+ uv__stream_osx_interrupt_select(stream);
+ }
+ stream->read_cb(stream, 0, &buf);
+ } else {
+ /* Error. User should call uv_close(). */
+ stream->read_cb(stream, -errno, &buf);
+ if (stream->flags & UV_STREAM_READING) {
+ stream->flags &= ~UV_STREAM_READING;
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN);
+ if (!uv__io_active(&stream->io_watcher, UV__POLLOUT))
+ uv__handle_stop(stream);
+ uv__stream_osx_interrupt_select(stream);
+ }
+ }
+ return;
+ } else if (nread == 0) {
+ uv__stream_eof(stream, &buf);
+ return;
+ } else {
+ /* Successful read */
+ ssize_t buflen = buf.len;
+
+ if (is_ipc) {
+ err = uv__stream_recv_cmsg(stream, &msg);
+ if (err != 0) {
+ stream->read_cb(stream, err, &buf);
+ return;
+ }
+ }
+ stream->read_cb(stream, nread, &buf);
+
+ /* Return if we didn't fill the buffer, there is no more data to read. */
+ if (nread < buflen) {
+ stream->flags |= UV_STREAM_READ_PARTIAL;
+ return;
+ }
+ }
+ }
+}
+
+
+#undef UV__CMSG_FD_COUNT
+#undef UV__CMSG_FD_SIZE
+
+
+int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
+ assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE) &&
+ "uv_shutdown (unix) only supports uv_handle_t right now");
+
+ if (!(stream->flags & UV_STREAM_WRITABLE) ||
+ stream->flags & UV_STREAM_SHUT ||
+ stream->flags & UV_STREAM_SHUTTING ||
+ stream->flags & UV_CLOSED ||
+ stream->flags & UV_CLOSING) {
+ return -ENOTCONN;
+ }
+
+ assert(uv__stream_fd(stream) >= 0);
+
+ /* Initialize request */
+ uv__req_init(stream->loop, req, UV_SHUTDOWN);
+ req->handle = stream;
+ req->cb = cb;
+ stream->shutdown_req = req;
+ stream->flags |= UV_STREAM_SHUTTING;
+
+ uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT);
+ uv__stream_osx_interrupt_select(stream);
+
+ return 0;
+}
+
+
+static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+ uv_stream_t* stream;
+
+ stream = container_of(w, uv_stream_t, io_watcher);
+
+ assert(stream->type == UV_TCP ||
+ stream->type == UV_NAMED_PIPE ||
+ stream->type == UV_TTY);
+ assert(!(stream->flags & UV_CLOSING));
+
+ if (stream->connect_req) {
+ uv__stream_connect(stream);
+ return;
+ }
+
+ assert(uv__stream_fd(stream) >= 0);
+
+ /* Ignore POLLHUP here. Even it it's set, there may still be data to read. */
+ if (events & (UV__POLLIN | UV__POLLERR | UV__POLLHUP))
+ uv__read(stream);
+
+ if (uv__stream_fd(stream) == -1)
+ return; /* read_cb closed stream. */
+
+ /* Short-circuit iff POLLHUP is set, the user is still interested in read
+ * events and uv__read() reported a partial read but not EOF. If the EOF
+ * flag is set, uv__read() called read_cb with err=UV_EOF and we don't
+ * have to do anything. If the partial read flag is not set, we can't
+ * report the EOF yet because there is still data to read.
+ */
+ if ((events & UV__POLLHUP) &&
+ (stream->flags & UV_STREAM_READING) &&
+ (stream->flags & UV_STREAM_READ_PARTIAL) &&
+ !(stream->flags & UV_STREAM_READ_EOF)) {
+ uv_buf_t buf = { NULL, 0 };
+ uv__stream_eof(stream, &buf);
+ }
+
+ if (uv__stream_fd(stream) == -1)
+ return; /* read_cb closed stream. */
+
+ if (events & (UV__POLLOUT | UV__POLLERR | UV__POLLHUP)) {
+ uv__write(stream);
+ uv__write_callbacks(stream);
+
+ /* Write queue drained. */
+ if (QUEUE_EMPTY(&stream->write_queue))
+ uv__drain(stream);
+ }
+}
+
+
+/**
+ * We get called here from directly following a call to connect(2).
+ * In order to determine if we've errored out or succeeded must call
+ * getsockopt.
+ */
+static void uv__stream_connect(uv_stream_t* stream) {
+ int error;
+ uv_connect_t* req = stream->connect_req;
+ socklen_t errorsize = sizeof(int);
+
+ assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE);
+ assert(req);
+
+ if (stream->delayed_error) {
+ /* To smooth over the differences between unixes errors that
+ * were reported synchronously on the first connect can be delayed
+ * until the next tick--which is now.
+ */
+ error = stream->delayed_error;
+ stream->delayed_error = 0;
+ } else {
+ /* Normal situation: we need to get the socket error from the kernel. */
+ assert(uv__stream_fd(stream) >= 0);
+ getsockopt(uv__stream_fd(stream),
+ SOL_SOCKET,
+ SO_ERROR,
+ &error,
+ &errorsize);
+ error = -error;
+ }
+
+ if (error == -EINPROGRESS)
+ return;
+
+ stream->connect_req = NULL;
+ uv__req_unregister(stream->loop, req);
+
+ if (error < 0 || QUEUE_EMPTY(&stream->write_queue)) {
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT);
+ }
+
+ if (req->cb)
+ req->cb(req, error);
+
+ if (uv__stream_fd(stream) == -1)
+ return;
+
+ if (error < 0) {
+ uv__stream_flush_write_queue(stream, -ECANCELED);
+ uv__write_callbacks(stream);
+ }
+}
+
+
+int uv_write2(uv_write_t* req,
+ uv_stream_t* stream,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle,
+ uv_write_cb cb) {
+ int empty_queue;
+
+ assert(nbufs > 0);
+ assert((stream->type == UV_TCP ||
+ stream->type == UV_NAMED_PIPE ||
+ stream->type == UV_TTY) &&
+ "uv_write (unix) does not yet support other types of streams");
+
+ if (uv__stream_fd(stream) < 0)
+ return -EBADF;
+
+ if (send_handle) {
+ if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc)
+ return -EINVAL;
+
+ /* XXX We abuse uv_write2() to send over UDP handles to child processes.
+ * Don't call uv__stream_fd() on those handles, it's a macro that on OS X
+ * evaluates to a function that operates on a uv_stream_t with a couple of
+ * OS X specific fields. On other Unices it does (handle)->io_watcher.fd,
+ * which works but only by accident.
+ */
+ if (uv__handle_fd((uv_handle_t*) send_handle) < 0)
+ return -EBADF;
+ }
+
+ /* It's legal for write_queue_size > 0 even when the write_queue is empty;
+ * it means there are error-state requests in the write_completed_queue that
+ * will touch up write_queue_size later, see also uv__write_req_finish().
+ * We could check that write_queue is empty instead but that implies making
+ * a write() syscall when we know that the handle is in error mode.
+ */
+ empty_queue = (stream->write_queue_size == 0);
+
+ /* Initialize the req */
+ uv__req_init(stream->loop, req, UV_WRITE);
+ req->cb = cb;
+ req->handle = stream;
+ req->error = 0;
+ req->send_handle = send_handle;
+ QUEUE_INIT(&req->queue);
+
+ req->bufs = req->bufsml;
+ if (nbufs > ARRAY_SIZE(req->bufsml))
+ req->bufs = uv__malloc(nbufs * sizeof(bufs[0]));
+
+ if (req->bufs == NULL)
+ return -ENOMEM;
+
+ memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0]));
+ req->nbufs = nbufs;
+ req->write_index = 0;
+ stream->write_queue_size += uv__count_bufs(bufs, nbufs);
+
+ /* Append the request to write_queue. */
+ QUEUE_INSERT_TAIL(&stream->write_queue, &req->queue);
+
+ /* If the queue was empty when this function began, we should attempt to
+ * do the write immediately. Otherwise start the write_watcher and wait
+ * for the fd to become writable.
+ */
+ if (stream->connect_req) {
+ /* Still connecting, do nothing. */
+ }
+ else if (empty_queue) {
+ uv__write(stream);
+ }
+ else {
+ /*
+ * blocking streams should never have anything in the queue.
+ * if this assert fires then somehow the blocking stream isn't being
+ * sufficiently flushed in uv__write.
+ */
+ assert(!(stream->flags & UV_STREAM_BLOCKING));
+ uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT);
+ uv__stream_osx_interrupt_select(stream);
+ }
+
+ return 0;
+}
+
+
+/* The buffers to be written must remain valid until the callback is called.
+ * This is not required for the uv_buf_t array.
+ */
+int uv_write(uv_write_t* req,
+ uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb) {
+ return uv_write2(req, handle, bufs, nbufs, NULL, cb);
+}
+
+
+void uv_try_write_cb(uv_write_t* req, int status) {
+ /* Should not be called */
+ abort();
+}
+
+
+int uv_try_write(uv_stream_t* stream,
+ const uv_buf_t bufs[],
+ unsigned int nbufs) {
+ int r;
+ int has_pollout;
+ size_t written;
+ size_t req_size;
+ uv_write_t req;
+
+ /* Connecting or already writing some data */
+ if (stream->connect_req != NULL || stream->write_queue_size != 0)
+ return -EAGAIN;
+
+ has_pollout = uv__io_active(&stream->io_watcher, UV__POLLOUT);
+
+ r = uv_write(&req, stream, bufs, nbufs, uv_try_write_cb);
+ if (r != 0)
+ return r;
+
+ /* Remove not written bytes from write queue size */
+ written = uv__count_bufs(bufs, nbufs);
+ if (req.bufs != NULL)
+ req_size = uv__write_req_size(&req);
+ else
+ req_size = 0;
+ written -= req_size;
+ stream->write_queue_size -= req_size;
+
+ /* Unqueue request, regardless of immediateness */
+ QUEUE_REMOVE(&req.queue);
+ uv__req_unregister(stream->loop, &req);
+ if (req.bufs != req.bufsml)
+ uv__free(req.bufs);
+ req.bufs = NULL;
+
+ /* Do not poll for writable, if we wasn't before calling this */
+ if (!has_pollout) {
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT);
+ uv__stream_osx_interrupt_select(stream);
+ }
+
+ if (written == 0 && req_size != 0)
+ return -EAGAIN;
+ else
+ return written;
+}
+
+
+int uv_read_start(uv_stream_t* stream,
+ uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE ||
+ stream->type == UV_TTY);
+
+ if (stream->flags & UV_CLOSING)
+ return -EINVAL;
+
+ /* The UV_STREAM_READING flag is irrelevant of the state of the tcp - it just
+ * expresses the desired state of the user.
+ */
+ stream->flags |= UV_STREAM_READING;
+
+ /* TODO: try to do the read inline? */
+ /* TODO: keep track of tcp state. If we've gotten a EOF then we should
+ * not start the IO watcher.
+ */
+ assert(uv__stream_fd(stream) >= 0);
+ assert(alloc_cb);
+
+ stream->read_cb = read_cb;
+ stream->alloc_cb = alloc_cb;
+
+ uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN);
+ uv__handle_start(stream);
+ uv__stream_osx_interrupt_select(stream);
+
+ return 0;
+}
+
+
+int uv_read_stop(uv_stream_t* stream) {
+ if (!(stream->flags & UV_STREAM_READING))
+ return 0;
+
+ stream->flags &= ~UV_STREAM_READING;
+ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN);
+ if (!uv__io_active(&stream->io_watcher, UV__POLLOUT))
+ uv__handle_stop(stream);
+ uv__stream_osx_interrupt_select(stream);
+
+ stream->read_cb = NULL;
+ stream->alloc_cb = NULL;
+ return 0;
+}
+
+
+int uv_is_readable(const uv_stream_t* stream) {
+ return !!(stream->flags & UV_STREAM_READABLE);
+}
+
+
+int uv_is_writable(const uv_stream_t* stream) {
+ return !!(stream->flags & UV_STREAM_WRITABLE);
+}
+
+
+#if defined(__APPLE__)
+int uv___stream_fd(const uv_stream_t* handle) {
+ const uv__stream_select_t* s;
+
+ assert(handle->type == UV_TCP ||
+ handle->type == UV_TTY ||
+ handle->type == UV_NAMED_PIPE);
+
+ s = handle->select;
+ if (s != NULL)
+ return s->fd;
+
+ return handle->io_watcher.fd;
+}
+#endif /* defined(__APPLE__) */
+
+
+void uv__stream_close(uv_stream_t* handle) {
+ unsigned int i;
+ uv__stream_queued_fds_t* queued_fds;
+
+#if defined(__APPLE__)
+ /* Terminate select loop first */
+ if (handle->select != NULL) {
+ uv__stream_select_t* s;
+
+ s = handle->select;
+
+ uv_sem_post(&s->close_sem);
+ uv_sem_post(&s->async_sem);
+ uv__stream_osx_interrupt_select(handle);
+ uv_thread_join(&s->thread);
+ uv_sem_destroy(&s->close_sem);
+ uv_sem_destroy(&s->async_sem);
+ uv__close(s->fake_fd);
+ uv__close(s->int_fd);
+ uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close);
+
+ handle->select = NULL;
+ }
+#endif /* defined(__APPLE__) */
+
+ uv__io_close(handle->loop, &handle->io_watcher);
+ uv_read_stop(handle);
+ uv__handle_stop(handle);
+
+ if (handle->io_watcher.fd != -1) {
+ /* Don't close stdio file descriptors. Nothing good comes from it. */
+ if (handle->io_watcher.fd > STDERR_FILENO)
+ uv__close(handle->io_watcher.fd);
+ handle->io_watcher.fd = -1;
+ }
+
+ if (handle->accepted_fd != -1) {
+ uv__close(handle->accepted_fd);
+ handle->accepted_fd = -1;
+ }
+
+ /* Close all queued fds */
+ if (handle->queued_fds != NULL) {
+ queued_fds = handle->queued_fds;
+ for (i = 0; i < queued_fds->offset; i++)
+ uv__close(queued_fds->fds[i]);
+ uv__free(handle->queued_fds);
+ handle->queued_fds = NULL;
+ }
+
+ assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT));
+}
+
+
+int uv_stream_set_blocking(uv_stream_t* handle, int blocking) {
+ /* Don't need to check the file descriptor, uv__nonblock()
+ * will fail with EBADF if it's not valid.
+ */
+ return uv__nonblock(uv__stream_fd(handle), !blocking);
+}
diff --git a/3rdparty/libuv/src/unix/sunos.c b/3rdparty/libuv/src/unix/sunos.c
new file mode 100644
index 00000000000..0c46817b446
--- /dev/null
+++ b/3rdparty/libuv/src/unix/sunos.c
@@ -0,0 +1,765 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#ifndef SUNOS_NO_IFADDRS
+# include <ifaddrs.h>
+#endif
+#include <net/if.h>
+#include <net/if_dl.h>
+
+#include <sys/loadavg.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <kstat.h>
+#include <fcntl.h>
+
+#include <sys/port.h>
+#include <port.h>
+
+#define PORT_FIRED 0x69
+#define PORT_UNUSED 0x0
+#define PORT_LOADED 0x99
+#define PORT_DELETED -1
+
+#if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64)
+#define PROCFS_FILE_OFFSET_BITS_HACK 1
+#undef _FILE_OFFSET_BITS
+#else
+#define PROCFS_FILE_OFFSET_BITS_HACK 0
+#endif
+
+#include <procfs.h>
+
+#if (PROCFS_FILE_OFFSET_BITS_HACK - 0 == 1)
+#define _FILE_OFFSET_BITS 64
+#endif
+
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ int err;
+ int fd;
+
+ loop->fs_fd = -1;
+ loop->backend_fd = -1;
+
+ fd = port_create();
+ if (fd == -1)
+ return -errno;
+
+ err = uv__cloexec(fd, 1);
+ if (err) {
+ uv__close(fd);
+ return err;
+ }
+ loop->backend_fd = fd;
+
+ return 0;
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+ if (loop->fs_fd != -1) {
+ uv__close(loop->fs_fd);
+ loop->fs_fd = -1;
+ }
+
+ if (loop->backend_fd != -1) {
+ uv__close(loop->backend_fd);
+ loop->backend_fd = -1;
+ }
+}
+
+
+void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
+ struct port_event* events;
+ uintptr_t i;
+ uintptr_t nfds;
+
+ assert(loop->watchers != NULL);
+
+ events = (struct port_event*) loop->watchers[loop->nwatchers];
+ nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
+ if (events == NULL)
+ return;
+
+ /* Invalidate events with same file descriptor */
+ for (i = 0; i < nfds; i++)
+ if ((int) events[i].portev_object == fd)
+ events[i].portev_object = -1;
+}
+
+
+void uv__io_poll(uv_loop_t* loop, int timeout) {
+ struct port_event events[1024];
+ struct port_event* pe;
+ struct timespec spec;
+ QUEUE* q;
+ uv__io_t* w;
+ sigset_t* pset;
+ sigset_t set;
+ uint64_t base;
+ uint64_t diff;
+ unsigned int nfds;
+ unsigned int i;
+ int saved_errno;
+ int nevents;
+ int count;
+ int err;
+ int fd;
+
+ if (loop->nfds == 0) {
+ assert(QUEUE_EMPTY(&loop->watcher_queue));
+ return;
+ }
+
+ while (!QUEUE_EMPTY(&loop->watcher_queue)) {
+ q = QUEUE_HEAD(&loop->watcher_queue);
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q);
+
+ w = QUEUE_DATA(q, uv__io_t, watcher_queue);
+ assert(w->pevents != 0);
+
+ if (port_associate(loop->backend_fd, PORT_SOURCE_FD, w->fd, w->pevents, 0))
+ abort();
+
+ w->events = w->pevents;
+ }
+
+ pset = NULL;
+ if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
+ pset = &set;
+ sigemptyset(pset);
+ sigaddset(pset, SIGPROF);
+ }
+
+ assert(timeout >= -1);
+ base = loop->time;
+ count = 48; /* Benchmarks suggest this gives the best throughput. */
+
+ for (;;) {
+ if (timeout != -1) {
+ spec.tv_sec = timeout / 1000;
+ spec.tv_nsec = (timeout % 1000) * 1000000;
+ }
+
+ /* Work around a kernel bug where nfds is not updated. */
+ events[0].portev_source = 0;
+
+ nfds = 1;
+ saved_errno = 0;
+
+ if (pset != NULL)
+ pthread_sigmask(SIG_BLOCK, pset, NULL);
+
+ err = port_getn(loop->backend_fd,
+ events,
+ ARRAY_SIZE(events),
+ &nfds,
+ timeout == -1 ? NULL : &spec);
+
+ if (pset != NULL)
+ pthread_sigmask(SIG_UNBLOCK, pset, NULL);
+
+ if (err) {
+ /* Work around another kernel bug: port_getn() may return events even
+ * on error.
+ */
+ if (errno == EINTR || errno == ETIME)
+ saved_errno = errno;
+ else
+ abort();
+ }
+
+ /* Update loop->time unconditionally. It's tempting to skip the update when
+ * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
+ * operating system didn't reschedule our process while in the syscall.
+ */
+ SAVE_ERRNO(uv__update_time(loop));
+
+ if (events[0].portev_source == 0) {
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+ goto update_timeout;
+ }
+
+ if (nfds == 0) {
+ assert(timeout != -1);
+ return;
+ }
+
+ nevents = 0;
+
+ assert(loop->watchers != NULL);
+ loop->watchers[loop->nwatchers] = (void*) events;
+ loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
+ for (i = 0; i < nfds; i++) {
+ pe = events + i;
+ fd = pe->portev_object;
+
+ /* Skip invalidated events, see uv__platform_invalidate_fd */
+ if (fd == -1)
+ continue;
+
+ assert(fd >= 0);
+ assert((unsigned) fd < loop->nwatchers);
+
+ w = loop->watchers[fd];
+
+ /* File descriptor that we've stopped watching, ignore. */
+ if (w == NULL)
+ continue;
+
+ w->cb(loop, w, pe->portev_events);
+ nevents++;
+
+ if (w != loop->watchers[fd])
+ continue; /* Disabled by callback. */
+
+ /* Events Ports operates in oneshot mode, rearm timer on next run. */
+ if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue))
+ QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
+ }
+ loop->watchers[loop->nwatchers] = NULL;
+ loop->watchers[loop->nwatchers + 1] = NULL;
+
+ if (nevents != 0) {
+ if (nfds == ARRAY_SIZE(events) && --count != 0) {
+ /* Poll for more events but don't block this time. */
+ timeout = 0;
+ continue;
+ }
+ return;
+ }
+
+ if (saved_errno == ETIME) {
+ assert(timeout != -1);
+ return;
+ }
+
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+update_timeout:
+ assert(timeout > 0);
+
+ diff = loop->time - base;
+ if (diff >= (uint64_t) timeout)
+ return;
+
+ timeout -= diff;
+ }
+}
+
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ return gethrtime();
+}
+
+
+/*
+ * We could use a static buffer for the path manipulations that we need outside
+ * of the function, but this function could be called by multiple consumers and
+ * we don't want to potentially create a race condition in the use of snprintf.
+ */
+int uv_exepath(char* buffer, size_t* size) {
+ ssize_t res;
+ char buf[128];
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ snprintf(buf, sizeof(buf), "/proc/%lu/path/a.out", (unsigned long) getpid());
+
+ res = *size - 1;
+ if (res > 0)
+ res = readlink(buf, buffer, res);
+
+ if (res == -1)
+ return -errno;
+
+ buffer[res] = '\0';
+ *size = res;
+ return 0;
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES);
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
+}
+
+
+void uv_loadavg(double avg[3]) {
+ (void) getloadavg(avg, 3);
+}
+
+
+#if defined(PORT_SOURCE_FILE)
+
+static int uv__fs_event_rearm(uv_fs_event_t *handle) {
+ if (handle->fd == -1)
+ return -EBADF;
+
+ if (port_associate(handle->loop->fs_fd,
+ PORT_SOURCE_FILE,
+ (uintptr_t) &handle->fo,
+ FILE_ATTRIB | FILE_MODIFIED,
+ handle) == -1) {
+ return -errno;
+ }
+ handle->fd = PORT_LOADED;
+
+ return 0;
+}
+
+
+static void uv__fs_event_read(uv_loop_t* loop,
+ uv__io_t* w,
+ unsigned int revents) {
+ uv_fs_event_t *handle = NULL;
+ timespec_t timeout;
+ port_event_t pe;
+ int events;
+ int r;
+
+ (void) w;
+ (void) revents;
+
+ do {
+ uint_t n = 1;
+
+ /*
+ * Note that our use of port_getn() here (and not port_get()) is deliberate:
+ * there is a bug in event ports (Sun bug 6456558) whereby a zeroed timeout
+ * causes port_get() to return success instead of ETIME when there aren't
+ * actually any events (!); by using port_getn() in lieu of port_get(),
+ * we can at least workaround the bug by checking for zero returned events
+ * and treating it as we would ETIME.
+ */
+ do {
+ memset(&timeout, 0, sizeof timeout);
+ r = port_getn(loop->fs_fd, &pe, 1, &n, &timeout);
+ }
+ while (r == -1 && errno == EINTR);
+
+ if ((r == -1 && errno == ETIME) || n == 0)
+ break;
+
+ handle = (uv_fs_event_t*) pe.portev_user;
+ assert((r == 0) && "unexpected port_get() error");
+
+ events = 0;
+ if (pe.portev_events & (FILE_ATTRIB | FILE_MODIFIED))
+ events |= UV_CHANGE;
+ if (pe.portev_events & ~(FILE_ATTRIB | FILE_MODIFIED))
+ events |= UV_RENAME;
+ assert(events != 0);
+ handle->fd = PORT_FIRED;
+ handle->cb(handle, NULL, events, 0);
+
+ if (handle->fd != PORT_DELETED) {
+ r = uv__fs_event_rearm(handle);
+ if (r != 0)
+ handle->cb(handle, NULL, 0, r);
+ }
+ }
+ while (handle->fd != PORT_DELETED);
+}
+
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
+ return 0;
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* path,
+ unsigned int flags) {
+ int portfd;
+ int first_run;
+ int err;
+
+ if (uv__is_active(handle))
+ return -EINVAL;
+
+ first_run = 0;
+ if (handle->loop->fs_fd == -1) {
+ portfd = port_create();
+ if (portfd == -1)
+ return -errno;
+ handle->loop->fs_fd = portfd;
+ first_run = 1;
+ }
+
+ uv__handle_start(handle);
+ handle->path = uv__strdup(path);
+ handle->fd = PORT_UNUSED;
+ handle->cb = cb;
+
+ memset(&handle->fo, 0, sizeof handle->fo);
+ handle->fo.fo_name = handle->path;
+ err = uv__fs_event_rearm(handle);
+ if (err != 0)
+ return err;
+
+ if (first_run) {
+ uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd);
+ uv__io_start(handle->loop, &handle->loop->fs_event_watcher, UV__POLLIN);
+ }
+
+ return 0;
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+ if (!uv__is_active(handle))
+ return 0;
+
+ if (handle->fd == PORT_FIRED || handle->fd == PORT_LOADED) {
+ port_dissociate(handle->loop->fs_fd,
+ PORT_SOURCE_FILE,
+ (uintptr_t) &handle->fo);
+ }
+
+ handle->fd = PORT_DELETED;
+ uv__free(handle->path);
+ handle->path = NULL;
+ handle->fo.fo_name = NULL;
+ uv__handle_stop(handle);
+
+ return 0;
+}
+
+void uv__fs_event_close(uv_fs_event_t* handle) {
+ uv_fs_event_stop(handle);
+}
+
+#else /* !defined(PORT_SOURCE_FILE) */
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+ return -ENOSYS;
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* filename,
+ unsigned int flags) {
+ return -ENOSYS;
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+ return -ENOSYS;
+}
+
+
+void uv__fs_event_close(uv_fs_event_t* handle) {
+ UNREACHABLE();
+}
+
+#endif /* defined(PORT_SOURCE_FILE) */
+
+
+char** uv_setup_args(int argc, char** argv) {
+ return argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ if (size > 0) {
+ buffer[0] = '\0';
+ }
+ return 0;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ psinfo_t psinfo;
+ int err;
+ int fd;
+
+ fd = open("/proc/self/psinfo", O_RDONLY);
+ if (fd == -1)
+ return -errno;
+
+ /* FIXME(bnoordhuis) Handle EINTR. */
+ err = -EINVAL;
+ if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) {
+ *rss = (size_t)psinfo.pr_rssize * 1024;
+ err = 0;
+ }
+ uv__close(fd);
+
+ return err;
+}
+
+
+int uv_uptime(double* uptime) {
+ kstat_ctl_t *kc;
+ kstat_t *ksp;
+ kstat_named_t *knp;
+
+ long hz = sysconf(_SC_CLK_TCK);
+
+ kc = kstat_open();
+ if (kc == NULL)
+ return -EPERM;
+
+ ksp = kstat_lookup(kc, (char*) "unix", 0, (char*) "system_misc");
+ if (kstat_read(kc, ksp, NULL) == -1) {
+ *uptime = -1;
+ } else {
+ knp = (kstat_named_t*) kstat_data_lookup(ksp, (char*) "clk_intr");
+ *uptime = knp->value.ul / hz;
+ }
+ kstat_close(kc);
+
+ return 0;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ int lookup_instance;
+ kstat_ctl_t *kc;
+ kstat_t *ksp;
+ kstat_named_t *knp;
+ uv_cpu_info_t* cpu_info;
+
+ kc = kstat_open();
+ if (kc == NULL)
+ return -EPERM;
+
+ /* Get count of cpus */
+ lookup_instance = 0;
+ while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) {
+ lookup_instance++;
+ }
+
+ *cpu_infos = uv__malloc(lookup_instance * sizeof(**cpu_infos));
+ if (!(*cpu_infos)) {
+ kstat_close(kc);
+ return -ENOMEM;
+ }
+
+ *count = lookup_instance;
+
+ cpu_info = *cpu_infos;
+ lookup_instance = 0;
+ while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) {
+ if (kstat_read(kc, ksp, NULL) == -1) {
+ cpu_info->speed = 0;
+ cpu_info->model = NULL;
+ } else {
+ knp = kstat_data_lookup(ksp, (char*) "clock_MHz");
+ assert(knp->data_type == KSTAT_DATA_INT32 ||
+ knp->data_type == KSTAT_DATA_INT64);
+ cpu_info->speed = (knp->data_type == KSTAT_DATA_INT32) ? knp->value.i32
+ : knp->value.i64;
+
+ knp = kstat_data_lookup(ksp, (char*) "brand");
+ assert(knp->data_type == KSTAT_DATA_STRING);
+ cpu_info->model = uv__strdup(KSTAT_NAMED_STR_PTR(knp));
+ }
+
+ lookup_instance++;
+ cpu_info++;
+ }
+
+ cpu_info = *cpu_infos;
+ lookup_instance = 0;
+ for (;;) {
+ ksp = kstat_lookup(kc, (char*) "cpu", lookup_instance, (char*) "sys");
+
+ if (ksp == NULL)
+ break;
+
+ if (kstat_read(kc, ksp, NULL) == -1) {
+ cpu_info->cpu_times.user = 0;
+ cpu_info->cpu_times.nice = 0;
+ cpu_info->cpu_times.sys = 0;
+ cpu_info->cpu_times.idle = 0;
+ cpu_info->cpu_times.irq = 0;
+ } else {
+ knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_user");
+ assert(knp->data_type == KSTAT_DATA_UINT64);
+ cpu_info->cpu_times.user = knp->value.ui64;
+
+ knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_kernel");
+ assert(knp->data_type == KSTAT_DATA_UINT64);
+ cpu_info->cpu_times.sys = knp->value.ui64;
+
+ knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_idle");
+ assert(knp->data_type == KSTAT_DATA_UINT64);
+ cpu_info->cpu_times.idle = knp->value.ui64;
+
+ knp = kstat_data_lookup(ksp, (char*) "intr");
+ assert(knp->data_type == KSTAT_DATA_UINT64);
+ cpu_info->cpu_times.irq = knp->value.ui64;
+ cpu_info->cpu_times.nice = 0;
+ }
+
+ lookup_instance++;
+ cpu_info++;
+ }
+
+ kstat_close(kc);
+
+ return 0;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
+#ifdef SUNOS_NO_IFADDRS
+ return -ENOSYS;
+#else
+ uv_interface_address_t* address;
+ struct sockaddr_dl* sa_addr;
+ struct ifaddrs* addrs;
+ struct ifaddrs* ent;
+ int i;
+
+ if (getifaddrs(&addrs))
+ return -errno;
+
+ *count = 0;
+
+ /* Count the number of interfaces */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family == PF_PACKET)) {
+ continue;
+ }
+
+ (*count)++;
+ }
+
+ *addresses = uv__malloc(*count * sizeof(**addresses));
+ if (!(*addresses)) {
+ freeifaddrs(addrs);
+ return -ENOMEM;
+ }
+
+ address = *addresses;
+
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
+ continue;
+
+ if (ent->ifa_addr == NULL)
+ continue;
+
+ address->name = uv__strdup(ent->ifa_name);
+
+ if (ent->ifa_addr->sa_family == AF_INET6) {
+ address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
+ } else {
+ address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
+ }
+
+ if (ent->ifa_netmask->sa_family == AF_INET6) {
+ address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
+ } else {
+ address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
+ }
+
+ address->is_internal = !!((ent->ifa_flags & IFF_PRIVATE) ||
+ (ent->ifa_flags & IFF_LOOPBACK));
+
+ address++;
+ }
+
+ /* Fill in physical addresses for each interface */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family != AF_LINK)) {
+ continue;
+ }
+
+ address = *addresses;
+
+ for (i = 0; i < (*count); i++) {
+ if (strcmp(address->name, ent->ifa_name) == 0) {
+ sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
+ memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
+ }
+ address++;
+ }
+ }
+
+ freeifaddrs(addrs);
+
+ return 0;
+#endif /* SUNOS_NO_IFADDRS */
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(addresses[i].name);
+ }
+
+ uv__free(addresses);
+}
diff --git a/3rdparty/libuv/src/unix/tcp.c b/3rdparty/libuv/src/unix/tcp.c
new file mode 100644
index 00000000000..6d213a49778
--- /dev/null
+++ b/3rdparty/libuv/src/unix/tcp.c
@@ -0,0 +1,362 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+
+
+static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
+ int sockfd;
+ int err;
+
+ if (domain == AF_UNSPEC || uv__stream_fd(handle) != -1) {
+ handle->flags |= flags;
+ return 0;
+ }
+
+ err = uv__socket(domain, SOCK_STREAM, 0);
+ if (err < 0)
+ return err;
+ sockfd = err;
+
+ err = uv__stream_open((uv_stream_t*) handle, sockfd, flags);
+ if (err) {
+ uv__close(sockfd);
+ return err;
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
+ int domain;
+
+ /* Use the lower 8 bits for the domain */
+ domain = flags & 0xFF;
+ if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
+ return -EINVAL;
+
+ if (flags & ~0xFF)
+ return -EINVAL;
+
+ uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP);
+
+ /* If anything fails beyond this point we need to remove the handle from
+ * the handle queue, since it was added by uv__handle_init in uv_stream_init.
+ */
+
+ if (domain != AF_UNSPEC) {
+ int err = maybe_new_socket(tcp, domain, 0);
+ if (err) {
+ QUEUE_REMOVE(&tcp->handle_queue);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
+ return uv_tcp_init_ex(loop, tcp, AF_UNSPEC);
+}
+
+
+int uv__tcp_bind(uv_tcp_t* tcp,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ int err;
+ int on;
+
+ /* Cannot set IPv6-only mode on non-IPv6 socket. */
+ if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
+ return -EINVAL;
+
+ err = maybe_new_socket(tcp,
+ addr->sa_family,
+ UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+ if (err)
+ return err;
+
+ on = 1;
+ if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
+ return -errno;
+
+#ifdef IPV6_V6ONLY
+ if (addr->sa_family == AF_INET6) {
+ on = (flags & UV_TCP_IPV6ONLY) != 0;
+ if (setsockopt(tcp->io_watcher.fd,
+ IPPROTO_IPV6,
+ IPV6_V6ONLY,
+ &on,
+ sizeof on) == -1) {
+ return -errno;
+ }
+ }
+#endif
+
+ errno = 0;
+ if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) {
+ if (errno == EAFNOSUPPORT)
+ /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
+ * socket created with AF_INET to an AF_INET6 address or vice versa. */
+ return -EINVAL;
+ return -errno;
+ }
+ tcp->delayed_error = -errno;
+
+ if (addr->sa_family == AF_INET6)
+ tcp->flags |= UV_HANDLE_IPV6;
+
+ return 0;
+}
+
+
+int uv__tcp_connect(uv_connect_t* req,
+ uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_connect_cb cb) {
+ int err;
+ int r;
+
+ assert(handle->type == UV_TCP);
+
+ if (handle->connect_req != NULL)
+ return -EALREADY; /* FIXME(bnoordhuis) -EINVAL or maybe -EBUSY. */
+
+ err = maybe_new_socket(handle,
+ addr->sa_family,
+ UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+ if (err)
+ return err;
+
+ handle->delayed_error = 0;
+
+ do
+ r = connect(uv__stream_fd(handle), addr, addrlen);
+ while (r == -1 && errno == EINTR);
+
+ if (r == -1) {
+ if (errno == EINPROGRESS)
+ ; /* not an error */
+ else if (errno == ECONNREFUSED)
+ /* If we get a ECONNREFUSED wait until the next tick to report the
+ * error. Solaris wants to report immediately--other unixes want to
+ * wait.
+ */
+ handle->delayed_error = -errno;
+ else
+ return -errno;
+ }
+
+ uv__req_init(handle->loop, req, UV_CONNECT);
+ req->cb = cb;
+ req->handle = (uv_stream_t*) handle;
+ QUEUE_INIT(&req->queue);
+ handle->connect_req = req;
+
+ uv__io_start(handle->loop, &handle->io_watcher, UV__POLLOUT);
+
+ if (handle->delayed_error)
+ uv__io_feed(handle->loop, &handle->io_watcher);
+
+ return 0;
+}
+
+
+int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
+ int err;
+
+ err = uv__nonblock(sock, 1);
+ if (err)
+ return err;
+
+ return uv__stream_open((uv_stream_t*)handle,
+ sock,
+ UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+}
+
+
+int uv_tcp_getsockname(const uv_tcp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ socklen_t socklen;
+
+ if (handle->delayed_error)
+ return handle->delayed_error;
+
+ if (uv__stream_fd(handle) < 0)
+ return -EINVAL; /* FIXME(bnoordhuis) -EBADF */
+
+ /* sizeof(socklen_t) != sizeof(int) on some systems. */
+ socklen = (socklen_t) *namelen;
+
+ if (getsockname(uv__stream_fd(handle), name, &socklen))
+ return -errno;
+
+ *namelen = (int) socklen;
+ return 0;
+}
+
+
+int uv_tcp_getpeername(const uv_tcp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ socklen_t socklen;
+
+ if (handle->delayed_error)
+ return handle->delayed_error;
+
+ if (uv__stream_fd(handle) < 0)
+ return -EINVAL; /* FIXME(bnoordhuis) -EBADF */
+
+ /* sizeof(socklen_t) != sizeof(int) on some systems. */
+ socklen = (socklen_t) *namelen;
+
+ if (getpeername(uv__stream_fd(handle), name, &socklen))
+ return -errno;
+
+ *namelen = (int) socklen;
+ return 0;
+}
+
+
+int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
+ static int single_accept = -1;
+ int err;
+
+ if (tcp->delayed_error)
+ return tcp->delayed_error;
+
+ if (single_accept == -1) {
+ const char* val = getenv("UV_TCP_SINGLE_ACCEPT");
+ single_accept = (val != NULL && atoi(val) != 0); /* Off by default. */
+ }
+
+ if (single_accept)
+ tcp->flags |= UV_TCP_SINGLE_ACCEPT;
+
+ err = maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE);
+ if (err)
+ return err;
+
+ if (listen(tcp->io_watcher.fd, backlog))
+ return -errno;
+
+ tcp->connection_cb = cb;
+
+ /* Start listening for connections. */
+ tcp->io_watcher.cb = uv__server_io;
+ uv__io_start(tcp->loop, &tcp->io_watcher, UV__POLLIN);
+
+ return 0;
+}
+
+
+int uv__tcp_nodelay(int fd, int on) {
+ if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)))
+ return -errno;
+ return 0;
+}
+
+
+int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
+ if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)))
+ return -errno;
+
+#ifdef TCP_KEEPIDLE
+ if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
+ return -errno;
+#endif
+
+ /* Solaris/SmartOS, if you don't support keep-alive,
+ * then don't advertise it in your system headers...
+ */
+ /* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */
+#if defined(TCP_KEEPALIVE) && !defined(__sun)
+ if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay)))
+ return -errno;
+#endif
+
+ return 0;
+}
+
+
+int uv_tcp_nodelay(uv_tcp_t* handle, int on) {
+ int err;
+
+ if (uv__stream_fd(handle) != -1) {
+ err = uv__tcp_nodelay(uv__stream_fd(handle), on);
+ if (err)
+ return err;
+ }
+
+ if (on)
+ handle->flags |= UV_TCP_NODELAY;
+ else
+ handle->flags &= ~UV_TCP_NODELAY;
+
+ return 0;
+}
+
+
+int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) {
+ int err;
+
+ if (uv__stream_fd(handle) != -1) {
+ err =uv__tcp_keepalive(uv__stream_fd(handle), on, delay);
+ if (err)
+ return err;
+ }
+
+ if (on)
+ handle->flags |= UV_TCP_KEEPALIVE;
+ else
+ handle->flags &= ~UV_TCP_KEEPALIVE;
+
+ /* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge
+ * uv_tcp_t with an int that's almost never used...
+ */
+
+ return 0;
+}
+
+
+int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
+ if (enable)
+ handle->flags &= ~UV_TCP_SINGLE_ACCEPT;
+ else
+ handle->flags |= UV_TCP_SINGLE_ACCEPT;
+ return 0;
+}
+
+
+void uv__tcp_close(uv_tcp_t* handle) {
+ uv__stream_close((uv_stream_t*)handle);
+}
diff --git a/3rdparty/libuv/src/unix/thread.c b/3rdparty/libuv/src/unix/thread.c
new file mode 100644
index 00000000000..c56a3170259
--- /dev/null
+++ b/3rdparty/libuv/src/unix/thread.c
@@ -0,0 +1,525 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <pthread.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/time.h>
+
+#undef NANOSEC
+#define NANOSEC ((uint64_t) 1e9)
+
+
+struct thread_ctx {
+ void (*entry)(void* arg);
+ void* arg;
+};
+
+
+static void* uv__thread_start(void *arg)
+{
+ struct thread_ctx *ctx_p;
+ struct thread_ctx ctx;
+
+ ctx_p = arg;
+ ctx = *ctx_p;
+ uv__free(ctx_p);
+ ctx.entry(ctx.arg);
+
+ return 0;
+}
+
+
+int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
+ struct thread_ctx* ctx;
+ int err;
+
+ ctx = uv__malloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return UV_ENOMEM;
+
+ ctx->entry = entry;
+ ctx->arg = arg;
+
+ err = pthread_create(tid, NULL, uv__thread_start, ctx);
+
+ if (err)
+ uv__free(ctx);
+
+ return -err;
+}
+
+
+uv_thread_t uv_thread_self(void) {
+ return pthread_self();
+}
+
+int uv_thread_join(uv_thread_t *tid) {
+ return -pthread_join(*tid, NULL);
+}
+
+
+int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) {
+ return pthread_equal(*t1, *t2);
+}
+
+
+int uv_mutex_init(uv_mutex_t* mutex) {
+#if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK)
+ return -pthread_mutex_init(mutex, NULL);
+#else
+ pthread_mutexattr_t attr;
+ int err;
+
+ if (pthread_mutexattr_init(&attr))
+ abort();
+
+ if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK))
+ abort();
+
+ err = pthread_mutex_init(mutex, &attr);
+
+ if (pthread_mutexattr_destroy(&attr))
+ abort();
+
+ return -err;
+#endif
+}
+
+
+void uv_mutex_destroy(uv_mutex_t* mutex) {
+ if (pthread_mutex_destroy(mutex))
+ abort();
+}
+
+
+void uv_mutex_lock(uv_mutex_t* mutex) {
+ if (pthread_mutex_lock(mutex))
+ abort();
+}
+
+
+int uv_mutex_trylock(uv_mutex_t* mutex) {
+ int err;
+
+ err = pthread_mutex_trylock(mutex);
+ if (err) {
+ if (err != EBUSY && err != EAGAIN)
+ abort();
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+
+void uv_mutex_unlock(uv_mutex_t* mutex) {
+ if (pthread_mutex_unlock(mutex))
+ abort();
+}
+
+
+int uv_rwlock_init(uv_rwlock_t* rwlock) {
+ return -pthread_rwlock_init(rwlock, NULL);
+}
+
+
+void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
+ if (pthread_rwlock_destroy(rwlock))
+ abort();
+}
+
+
+void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
+ if (pthread_rwlock_rdlock(rwlock))
+ abort();
+}
+
+
+int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
+ int err;
+
+ err = pthread_rwlock_tryrdlock(rwlock);
+ if (err) {
+ if (err != EBUSY && err != EAGAIN)
+ abort();
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+
+void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
+ if (pthread_rwlock_unlock(rwlock))
+ abort();
+}
+
+
+void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
+ if (pthread_rwlock_wrlock(rwlock))
+ abort();
+}
+
+
+int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
+ int err;
+
+ err = pthread_rwlock_trywrlock(rwlock);
+ if (err) {
+ if (err != EBUSY && err != EAGAIN)
+ abort();
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+
+void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
+ if (pthread_rwlock_unlock(rwlock))
+ abort();
+}
+
+
+void uv_once(uv_once_t* guard, void (*callback)(void)) {
+ if (pthread_once(guard, callback))
+ abort();
+}
+
+#if defined(__APPLE__) && defined(__MACH__)
+
+int uv_sem_init(uv_sem_t* sem, unsigned int value) {
+ kern_return_t err;
+
+ err = semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, value);
+ if (err == KERN_SUCCESS)
+ return 0;
+ if (err == KERN_INVALID_ARGUMENT)
+ return -EINVAL;
+ if (err == KERN_RESOURCE_SHORTAGE)
+ return -ENOMEM;
+
+ abort();
+ return -EINVAL; /* Satisfy the compiler. */
+}
+
+
+void uv_sem_destroy(uv_sem_t* sem) {
+ if (semaphore_destroy(mach_task_self(), *sem))
+ abort();
+}
+
+
+void uv_sem_post(uv_sem_t* sem) {
+ if (semaphore_signal(*sem))
+ abort();
+}
+
+
+void uv_sem_wait(uv_sem_t* sem) {
+ int r;
+
+ do
+ r = semaphore_wait(*sem);
+ while (r == KERN_ABORTED);
+
+ if (r != KERN_SUCCESS)
+ abort();
+}
+
+
+int uv_sem_trywait(uv_sem_t* sem) {
+ mach_timespec_t interval;
+ kern_return_t err;
+
+ interval.tv_sec = 0;
+ interval.tv_nsec = 0;
+
+ err = semaphore_timedwait(*sem, interval);
+ if (err == KERN_SUCCESS)
+ return 0;
+ if (err == KERN_OPERATION_TIMED_OUT)
+ return -EAGAIN;
+
+ abort();
+ return -EINVAL; /* Satisfy the compiler. */
+}
+
+#else /* !(defined(__APPLE__) && defined(__MACH__)) */
+
+int uv_sem_init(uv_sem_t* sem, unsigned int value) {
+ if (sem_init(sem, 0, value))
+ return -errno;
+ return 0;
+}
+
+
+void uv_sem_destroy(uv_sem_t* sem) {
+ if (sem_destroy(sem))
+ abort();
+}
+
+
+void uv_sem_post(uv_sem_t* sem) {
+ if (sem_post(sem))
+ abort();
+}
+
+
+void uv_sem_wait(uv_sem_t* sem) {
+ int r;
+
+ do
+ r = sem_wait(sem);
+ while (r == -1 && errno == EINTR);
+
+ if (r)
+ abort();
+}
+
+
+int uv_sem_trywait(uv_sem_t* sem) {
+ int r;
+
+ do
+ r = sem_trywait(sem);
+ while (r == -1 && errno == EINTR);
+
+ if (r) {
+ if (errno == EAGAIN)
+ return -EAGAIN;
+ abort();
+ }
+
+ return 0;
+}
+
+#endif /* defined(__APPLE__) && defined(__MACH__) */
+
+
+#if defined(__APPLE__) && defined(__MACH__)
+
+int uv_cond_init(uv_cond_t* cond) {
+ return -pthread_cond_init(cond, NULL);
+}
+
+#else /* !(defined(__APPLE__) && defined(__MACH__)) */
+
+int uv_cond_init(uv_cond_t* cond) {
+ pthread_condattr_t attr;
+ int err;
+
+ err = pthread_condattr_init(&attr);
+ if (err)
+ return -err;
+
+#if !(defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
+ err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+ if (err)
+ goto error2;
+#endif
+
+ err = pthread_cond_init(cond, &attr);
+ if (err)
+ goto error2;
+
+ err = pthread_condattr_destroy(&attr);
+ if (err)
+ goto error;
+
+ return 0;
+
+error:
+ pthread_cond_destroy(cond);
+error2:
+ pthread_condattr_destroy(&attr);
+ return -err;
+}
+
+#endif /* defined(__APPLE__) && defined(__MACH__) */
+
+void uv_cond_destroy(uv_cond_t* cond) {
+ if (pthread_cond_destroy(cond))
+ abort();
+}
+
+void uv_cond_signal(uv_cond_t* cond) {
+ if (pthread_cond_signal(cond))
+ abort();
+}
+
+void uv_cond_broadcast(uv_cond_t* cond) {
+ if (pthread_cond_broadcast(cond))
+ abort();
+}
+
+void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
+ if (pthread_cond_wait(cond, mutex))
+ abort();
+}
+
+
+int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
+ int r;
+ struct timespec ts;
+
+#if defined(__APPLE__) && defined(__MACH__)
+ ts.tv_sec = timeout / NANOSEC;
+ ts.tv_nsec = timeout % NANOSEC;
+ r = pthread_cond_timedwait_relative_np(cond, mutex, &ts);
+#else
+ timeout += uv__hrtime(UV_CLOCK_PRECISE);
+ ts.tv_sec = timeout / NANOSEC;
+ ts.tv_nsec = timeout % NANOSEC;
+#if defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
+ /*
+ * The bionic pthread implementation doesn't support CLOCK_MONOTONIC,
+ * but has this alternative function instead.
+ */
+ r = pthread_cond_timedwait_monotonic_np(cond, mutex, &ts);
+#else
+ r = pthread_cond_timedwait(cond, mutex, &ts);
+#endif /* __ANDROID__ */
+#endif
+
+
+ if (r == 0)
+ return 0;
+
+ if (r == ETIMEDOUT)
+ return -ETIMEDOUT;
+
+ abort();
+ return -EINVAL; /* Satisfy the compiler. */
+}
+
+
+#if defined(__APPLE__) && defined(__MACH__)
+
+int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
+ int err;
+
+ barrier->n = count;
+ barrier->count = 0;
+
+ err = uv_mutex_init(&barrier->mutex);
+ if (err)
+ return -err;
+
+ err = uv_sem_init(&barrier->turnstile1, 0);
+ if (err)
+ goto error2;
+
+ err = uv_sem_init(&barrier->turnstile2, 1);
+ if (err)
+ goto error;
+
+ return 0;
+
+error:
+ uv_sem_destroy(&barrier->turnstile1);
+error2:
+ uv_mutex_destroy(&barrier->mutex);
+ return -err;
+
+}
+
+
+void uv_barrier_destroy(uv_barrier_t* barrier) {
+ uv_sem_destroy(&barrier->turnstile2);
+ uv_sem_destroy(&barrier->turnstile1);
+ uv_mutex_destroy(&barrier->mutex);
+}
+
+
+int uv_barrier_wait(uv_barrier_t* barrier) {
+ int serial_thread;
+
+ uv_mutex_lock(&barrier->mutex);
+ if (++barrier->count == barrier->n) {
+ uv_sem_wait(&barrier->turnstile2);
+ uv_sem_post(&barrier->turnstile1);
+ }
+ uv_mutex_unlock(&barrier->mutex);
+
+ uv_sem_wait(&barrier->turnstile1);
+ uv_sem_post(&barrier->turnstile1);
+
+ uv_mutex_lock(&barrier->mutex);
+ serial_thread = (--barrier->count == 0);
+ if (serial_thread) {
+ uv_sem_wait(&barrier->turnstile1);
+ uv_sem_post(&barrier->turnstile2);
+ }
+ uv_mutex_unlock(&barrier->mutex);
+
+ uv_sem_wait(&barrier->turnstile2);
+ uv_sem_post(&barrier->turnstile2);
+ return serial_thread;
+}
+
+#else /* !(defined(__APPLE__) && defined(__MACH__)) */
+
+int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
+ return -pthread_barrier_init(barrier, NULL, count);
+}
+
+
+void uv_barrier_destroy(uv_barrier_t* barrier) {
+ if (pthread_barrier_destroy(barrier))
+ abort();
+}
+
+
+int uv_barrier_wait(uv_barrier_t* barrier) {
+ int r = pthread_barrier_wait(barrier);
+ if (r && r != PTHREAD_BARRIER_SERIAL_THREAD)
+ abort();
+ return r == PTHREAD_BARRIER_SERIAL_THREAD;
+}
+
+#endif /* defined(__APPLE__) && defined(__MACH__) */
+
+int uv_key_create(uv_key_t* key) {
+ return -pthread_key_create(key, NULL);
+}
+
+
+void uv_key_delete(uv_key_t* key) {
+ if (pthread_key_delete(*key))
+ abort();
+}
+
+
+void* uv_key_get(uv_key_t* key) {
+ return pthread_getspecific(*key);
+}
+
+
+void uv_key_set(uv_key_t* key, void* value) {
+ if (pthread_setspecific(*key, value))
+ abort();
+}
diff --git a/3rdparty/libuv/src/unix/timer.c b/3rdparty/libuv/src/unix/timer.c
new file mode 100644
index 00000000000..ca3ec3db957
--- /dev/null
+++ b/3rdparty/libuv/src/unix/timer.c
@@ -0,0 +1,172 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+#include "heap-inl.h"
+
+#include <assert.h>
+#include <limits.h>
+
+
+static int timer_less_than(const struct heap_node* ha,
+ const struct heap_node* hb) {
+ const uv_timer_t* a;
+ const uv_timer_t* b;
+
+ a = container_of(ha, const uv_timer_t, heap_node);
+ b = container_of(hb, const uv_timer_t, heap_node);
+
+ if (a->timeout < b->timeout)
+ return 1;
+ if (b->timeout < a->timeout)
+ return 0;
+
+ /* Compare start_id when both have the same timeout. start_id is
+ * allocated with loop->timer_counter in uv_timer_start().
+ */
+ if (a->start_id < b->start_id)
+ return 1;
+ if (b->start_id < a->start_id)
+ return 0;
+
+ return 0;
+}
+
+
+int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER);
+ handle->timer_cb = NULL;
+ handle->repeat = 0;
+ return 0;
+}
+
+
+int uv_timer_start(uv_timer_t* handle,
+ uv_timer_cb cb,
+ uint64_t timeout,
+ uint64_t repeat) {
+ uint64_t clamped_timeout;
+
+ if (cb == NULL)
+ return -EINVAL;
+
+ if (uv__is_active(handle))
+ uv_timer_stop(handle);
+
+ clamped_timeout = handle->loop->time + timeout;
+ if (clamped_timeout < timeout)
+ clamped_timeout = (uint64_t) -1;
+
+ handle->timer_cb = cb;
+ handle->timeout = clamped_timeout;
+ handle->repeat = repeat;
+ /* start_id is the second index to be compared in uv__timer_cmp() */
+ handle->start_id = handle->loop->timer_counter++;
+
+ heap_insert((struct heap*) &handle->loop->timer_heap,
+ (struct heap_node*) &handle->heap_node,
+ timer_less_than);
+ uv__handle_start(handle);
+
+ return 0;
+}
+
+
+int uv_timer_stop(uv_timer_t* handle) {
+ if (!uv__is_active(handle))
+ return 0;
+
+ heap_remove((struct heap*) &handle->loop->timer_heap,
+ (struct heap_node*) &handle->heap_node,
+ timer_less_than);
+ uv__handle_stop(handle);
+
+ return 0;
+}
+
+
+int uv_timer_again(uv_timer_t* handle) {
+ if (handle->timer_cb == NULL)
+ return -EINVAL;
+
+ if (handle->repeat) {
+ uv_timer_stop(handle);
+ uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat);
+ }
+
+ return 0;
+}
+
+
+void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) {
+ handle->repeat = repeat;
+}
+
+
+uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
+ return handle->repeat;
+}
+
+
+int uv__next_timeout(const uv_loop_t* loop) {
+ const struct heap_node* heap_node;
+ const uv_timer_t* handle;
+ uint64_t diff;
+
+ heap_node = heap_min((const struct heap*) &loop->timer_heap);
+ if (heap_node == NULL)
+ return -1; /* block indefinitely */
+
+ handle = container_of(heap_node, const uv_timer_t, heap_node);
+ if (handle->timeout <= loop->time)
+ return 0;
+
+ diff = handle->timeout - loop->time;
+ if (diff > INT_MAX)
+ diff = INT_MAX;
+
+ return diff;
+}
+
+
+void uv__run_timers(uv_loop_t* loop) {
+ struct heap_node* heap_node;
+ uv_timer_t* handle;
+
+ for (;;) {
+ heap_node = heap_min((struct heap*) &loop->timer_heap);
+ if (heap_node == NULL)
+ break;
+
+ handle = container_of(heap_node, uv_timer_t, heap_node);
+ if (handle->timeout > loop->time)
+ break;
+
+ uv_timer_stop(handle);
+ uv_timer_again(handle);
+ handle->timer_cb(handle);
+ }
+}
+
+
+void uv__timer_close(uv_timer_t* handle) {
+ uv_timer_stop(handle);
+}
diff --git a/3rdparty/libuv/src/unix/tty.c b/3rdparty/libuv/src/unix/tty.c
new file mode 100644
index 00000000000..7cc5b714ed3
--- /dev/null
+++ b/3rdparty/libuv/src/unix/tty.c
@@ -0,0 +1,279 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+#include "spinlock.h"
+
+#include <assert.h>
+#include <unistd.h>
+#include <termios.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+
+static int orig_termios_fd = -1;
+static struct termios orig_termios;
+static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
+
+
+int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
+ uv_handle_type type;
+ int flags;
+ int newfd;
+ int r;
+
+ /* File descriptors that refer to files cannot be monitored with epoll.
+ * That restriction also applies to character devices like /dev/random
+ * (but obviously not /dev/tty.)
+ */
+ type = uv_guess_handle(fd);
+ if (type == UV_FILE || type == UV_UNKNOWN_HANDLE)
+ return -EINVAL;
+
+ flags = 0;
+ newfd = -1;
+
+ /* Reopen the file descriptor when it refers to a tty. This lets us put the
+ * tty in non-blocking mode without affecting other processes that share it
+ * with us.
+ *
+ * Example: `node | cat` - if we put our fd 0 in non-blocking mode, it also
+ * affects fd 1 of `cat` because both file descriptors refer to the same
+ * struct file in the kernel. When we reopen our fd 0, it points to a
+ * different struct file, hence changing its properties doesn't affect
+ * other processes.
+ */
+ if (type == UV_TTY) {
+ r = uv__open_cloexec("/dev/tty", O_RDWR);
+
+ if (r < 0) {
+ /* fallback to using blocking writes */
+ if (!readable)
+ flags |= UV_STREAM_BLOCKING;
+ goto skip;
+ }
+
+ newfd = r;
+
+ r = uv__dup2_cloexec(newfd, fd);
+ if (r < 0 && r != -EINVAL) {
+ /* EINVAL means newfd == fd which could conceivably happen if another
+ * thread called close(fd) between our calls to isatty() and open().
+ * That's a rather unlikely event but let's handle it anyway.
+ */
+ uv__close(newfd);
+ return r;
+ }
+
+ fd = newfd;
+ }
+
+skip:
+ uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
+
+ /* If anything fails beyond this point we need to remove the handle from
+ * the handle queue, since it was added by uv__handle_init in uv_stream_init.
+ */
+
+#if defined(__APPLE__)
+ r = uv__stream_try_select((uv_stream_t*) tty, &fd);
+ if (r) {
+ if (newfd != -1)
+ uv__close(newfd);
+ QUEUE_REMOVE(&tty->handle_queue);
+ return r;
+ }
+#endif
+
+ if (readable)
+ flags |= UV_STREAM_READABLE;
+ else
+ flags |= UV_STREAM_WRITABLE;
+
+ if (!(flags & UV_STREAM_BLOCKING))
+ uv__nonblock(fd, 1);
+
+ uv__stream_open((uv_stream_t*) tty, fd, flags);
+ tty->mode = UV_TTY_MODE_NORMAL;
+
+ return 0;
+}
+
+static void uv__tty_make_raw(struct termios* tio) {
+ assert(tio != NULL);
+
+#ifdef __sun
+ /*
+ * This implementation of cfmakeraw for Solaris and derivatives is taken from
+ * http://www.perkin.org.uk/posts/solaris-portability-cfmakeraw.html.
+ */
+ tio->c_iflag &= ~(IMAXBEL | IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR |
+ IGNCR | ICRNL | IXON);
+ tio->c_oflag &= ~OPOST;
+ tio->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+ tio->c_cflag &= ~(CSIZE | PARENB);
+ tio->c_cflag |= CS8;
+#else
+ cfmakeraw(tio);
+#endif /* #ifdef __sun */
+}
+
+int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
+ struct termios tmp;
+ int fd;
+
+ if (tty->mode == (int) mode)
+ return 0;
+
+ fd = uv__stream_fd(tty);
+ if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) {
+ if (tcgetattr(fd, &tty->orig_termios))
+ return -errno;
+
+ /* This is used for uv_tty_reset_mode() */
+ uv_spinlock_lock(&termios_spinlock);
+ if (orig_termios_fd == -1) {
+ orig_termios = tty->orig_termios;
+ orig_termios_fd = fd;
+ }
+ uv_spinlock_unlock(&termios_spinlock);
+ }
+
+ tmp = tty->orig_termios;
+ switch (mode) {
+ case UV_TTY_MODE_NORMAL:
+ break;
+ case UV_TTY_MODE_RAW:
+ tmp.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+ tmp.c_oflag |= (ONLCR);
+ tmp.c_cflag |= (CS8);
+ tmp.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+ tmp.c_cc[VMIN] = 1;
+ tmp.c_cc[VTIME] = 0;
+ break;
+ case UV_TTY_MODE_IO:
+ uv__tty_make_raw(&tmp);
+ break;
+ }
+
+ /* Apply changes after draining */
+ if (tcsetattr(fd, TCSADRAIN, &tmp))
+ return -errno;
+
+ tty->mode = mode;
+ return 0;
+}
+
+
+int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
+ struct winsize ws;
+
+ if (ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws))
+ return -errno;
+
+ *width = ws.ws_col;
+ *height = ws.ws_row;
+
+ return 0;
+}
+
+
+uv_handle_type uv_guess_handle(uv_file file) {
+ struct sockaddr sa;
+ struct stat s;
+ socklen_t len;
+ int type;
+
+ if (file < 0)
+ return UV_UNKNOWN_HANDLE;
+
+ if (isatty(file))
+ return UV_TTY;
+
+ if (fstat(file, &s))
+ return UV_UNKNOWN_HANDLE;
+
+ if (S_ISREG(s.st_mode))
+ return UV_FILE;
+
+ if (S_ISCHR(s.st_mode))
+ return UV_FILE; /* XXX UV_NAMED_PIPE? */
+
+ if (S_ISFIFO(s.st_mode))
+ return UV_NAMED_PIPE;
+
+ if (!S_ISSOCK(s.st_mode))
+ return UV_UNKNOWN_HANDLE;
+
+ len = sizeof(type);
+ if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len))
+ return UV_UNKNOWN_HANDLE;
+
+ len = sizeof(sa);
+ if (getsockname(file, &sa, &len))
+ return UV_UNKNOWN_HANDLE;
+
+ if (type == SOCK_DGRAM)
+ if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
+ return UV_UDP;
+
+ if (type == SOCK_STREAM) {
+#if defined(_AIX)
+ /* on AIX the getsockname call returns an empty sa structure
+ * for sockets of type AF_UNIX. For all other types it will
+ * return a properly filled in structure.
+ */
+ if (len == 0)
+ return UV_NAMED_PIPE;
+#endif /* defined(_AIX) */
+
+ if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
+ return UV_TCP;
+ if (sa.sa_family == AF_UNIX)
+ return UV_NAMED_PIPE;
+ }
+
+ return UV_UNKNOWN_HANDLE;
+}
+
+
+/* This function is async signal-safe, meaning that it's safe to call from
+ * inside a signal handler _unless_ execution was inside uv_tty_set_mode()'s
+ * critical section when the signal was raised.
+ */
+int uv_tty_reset_mode(void) {
+ int saved_errno;
+ int err;
+
+ saved_errno = errno;
+ if (!uv_spinlock_trylock(&termios_spinlock))
+ return -EBUSY; /* In uv_tty_set_mode(). */
+
+ err = 0;
+ if (orig_termios_fd != -1)
+ if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios))
+ err = -errno;
+
+ uv_spinlock_unlock(&termios_spinlock);
+ errno = saved_errno;
+
+ return err;
+}
diff --git a/3rdparty/libuv/src/unix/udp.c b/3rdparty/libuv/src/unix/udp.c
new file mode 100644
index 00000000000..39ade8de338
--- /dev/null
+++ b/3rdparty/libuv/src/unix/udp.c
@@ -0,0 +1,873 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP)
+# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
+#endif
+
+#if defined(IPV6_LEAVE_GROUP) && !defined(IPV6_DROP_MEMBERSHIP)
+# define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
+#endif
+
+
+static void uv__udp_run_completed(uv_udp_t* handle);
+static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents);
+static void uv__udp_recvmsg(uv_udp_t* handle);
+static void uv__udp_sendmsg(uv_udp_t* handle);
+static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
+ int domain,
+ unsigned int flags);
+
+
+void uv__udp_close(uv_udp_t* handle) {
+ uv__io_close(handle->loop, &handle->io_watcher);
+ uv__handle_stop(handle);
+
+ if (handle->io_watcher.fd != -1) {
+ uv__close(handle->io_watcher.fd);
+ handle->io_watcher.fd = -1;
+ }
+}
+
+
+void uv__udp_finish_close(uv_udp_t* handle) {
+ uv_udp_send_t* req;
+ QUEUE* q;
+
+ assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT));
+ assert(handle->io_watcher.fd == -1);
+
+ while (!QUEUE_EMPTY(&handle->write_queue)) {
+ q = QUEUE_HEAD(&handle->write_queue);
+ QUEUE_REMOVE(q);
+
+ req = QUEUE_DATA(q, uv_udp_send_t, queue);
+ req->status = -ECANCELED;
+ QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
+ }
+
+ uv__udp_run_completed(handle);
+
+ assert(handle->send_queue_size == 0);
+ assert(handle->send_queue_count == 0);
+
+ /* Now tear down the handle. */
+ handle->recv_cb = NULL;
+ handle->alloc_cb = NULL;
+ /* but _do not_ touch close_cb */
+}
+
+
+static void uv__udp_run_completed(uv_udp_t* handle) {
+ uv_udp_send_t* req;
+ QUEUE* q;
+
+ assert(!(handle->flags & UV_UDP_PROCESSING));
+ handle->flags |= UV_UDP_PROCESSING;
+
+ while (!QUEUE_EMPTY(&handle->write_completed_queue)) {
+ q = QUEUE_HEAD(&handle->write_completed_queue);
+ QUEUE_REMOVE(q);
+
+ req = QUEUE_DATA(q, uv_udp_send_t, queue);
+ uv__req_unregister(handle->loop, req);
+
+ handle->send_queue_size -= uv__count_bufs(req->bufs, req->nbufs);
+ handle->send_queue_count--;
+
+ if (req->bufs != req->bufsml)
+ uv__free(req->bufs);
+ req->bufs = NULL;
+
+ if (req->send_cb == NULL)
+ continue;
+
+ /* req->status >= 0 == bytes written
+ * req->status < 0 == errno
+ */
+ if (req->status >= 0)
+ req->send_cb(req, 0);
+ else
+ req->send_cb(req, req->status);
+ }
+
+ if (QUEUE_EMPTY(&handle->write_queue)) {
+ /* Pending queue and completion queue empty, stop watcher. */
+ uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLOUT);
+ if (!uv__io_active(&handle->io_watcher, UV__POLLIN))
+ uv__handle_stop(handle);
+ }
+
+ handle->flags &= ~UV_UDP_PROCESSING;
+}
+
+
+static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) {
+ uv_udp_t* handle;
+
+ handle = container_of(w, uv_udp_t, io_watcher);
+ assert(handle->type == UV_UDP);
+
+ if (revents & UV__POLLIN)
+ uv__udp_recvmsg(handle);
+
+ if (revents & UV__POLLOUT) {
+ uv__udp_sendmsg(handle);
+ uv__udp_run_completed(handle);
+ }
+}
+
+
+static void uv__udp_recvmsg(uv_udp_t* handle) {
+ struct sockaddr_storage peer;
+ struct msghdr h;
+ ssize_t nread;
+ uv_buf_t buf;
+ int flags;
+ int count;
+
+ assert(handle->recv_cb != NULL);
+ assert(handle->alloc_cb != NULL);
+
+ /* Prevent loop starvation when the data comes in as fast as (or faster than)
+ * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
+ */
+ count = 32;
+
+ memset(&h, 0, sizeof(h));
+ h.msg_name = &peer;
+
+ do {
+ handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf);
+ if (buf.len == 0) {
+ handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
+ return;
+ }
+ assert(buf.base != NULL);
+
+ h.msg_namelen = sizeof(peer);
+ h.msg_iov = (void*) &buf;
+ h.msg_iovlen = 1;
+
+ do {
+ nread = recvmsg(handle->io_watcher.fd, &h, 0);
+ }
+ while (nread == -1 && errno == EINTR);
+
+ if (nread == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ handle->recv_cb(handle, 0, &buf, NULL, 0);
+ else
+ handle->recv_cb(handle, -errno, &buf, NULL, 0);
+ }
+ else {
+ const struct sockaddr *addr;
+ if (h.msg_namelen == 0)
+ addr = NULL;
+ else
+ addr = (const struct sockaddr*) &peer;
+
+ flags = 0;
+ if (h.msg_flags & MSG_TRUNC)
+ flags |= UV_UDP_PARTIAL;
+
+ handle->recv_cb(handle, nread, &buf, addr, flags);
+ }
+ }
+ /* recv_cb callback may decide to pause or close the handle */
+ while (nread != -1
+ && count-- > 0
+ && handle->io_watcher.fd != -1
+ && handle->recv_cb != NULL);
+}
+
+
+static void uv__udp_sendmsg(uv_udp_t* handle) {
+ uv_udp_send_t* req;
+ QUEUE* q;
+ struct msghdr h;
+ ssize_t size;
+
+ while (!QUEUE_EMPTY(&handle->write_queue)) {
+ q = QUEUE_HEAD(&handle->write_queue);
+ assert(q != NULL);
+
+ req = QUEUE_DATA(q, uv_udp_send_t, queue);
+ assert(req != NULL);
+
+ memset(&h, 0, sizeof h);
+ h.msg_name = &req->addr;
+ h.msg_namelen = (req->addr.ss_family == AF_INET6 ?
+ sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
+ h.msg_iov = (struct iovec*) req->bufs;
+ h.msg_iovlen = req->nbufs;
+
+ do {
+ size = sendmsg(handle->io_watcher.fd, &h, 0);
+ } while (size == -1 && errno == EINTR);
+
+ if (size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
+ break;
+
+ req->status = (size == -1 ? -errno : size);
+
+ /* Sending a datagram is an atomic operation: either all data
+ * is written or nothing is (and EMSGSIZE is raised). That is
+ * why we don't handle partial writes. Just pop the request
+ * off the write queue and onto the completed queue, done.
+ */
+ QUEUE_REMOVE(&req->queue);
+ QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
+ uv__io_feed(handle->loop, &handle->io_watcher);
+ }
+}
+
+
+/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
+ * refinements for programs that use multicast.
+ *
+ * Linux as of 3.9 has a SO_REUSEPORT socket option but with semantics that
+ * are different from the BSDs: it _shares_ the port rather than steal it
+ * from the current listener. While useful, it's not something we can emulate
+ * on other platforms so we don't enable it.
+ */
+static int uv__set_reuse(int fd) {
+ int yes;
+
+#if defined(SO_REUSEPORT) && !defined(__linux__)
+ yes = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
+ return -errno;
+#else
+ yes = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
+ return -errno;
+#endif
+
+ return 0;
+}
+
+
+int uv__udp_bind(uv_udp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ int err;
+ int yes;
+ int fd;
+
+ /* Check for bad flags. */
+ if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR))
+ return -EINVAL;
+
+ /* Cannot set IPv6-only mode on non-IPv6 socket. */
+ if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6)
+ return -EINVAL;
+
+ fd = handle->io_watcher.fd;
+ if (fd == -1) {
+ err = uv__socket(addr->sa_family, SOCK_DGRAM, 0);
+ if (err < 0)
+ return err;
+ fd = err;
+ handle->io_watcher.fd = fd;
+ }
+
+ if (flags & UV_UDP_REUSEADDR) {
+ err = uv__set_reuse(fd);
+ if (err)
+ goto out;
+ }
+
+ if (flags & UV_UDP_IPV6ONLY) {
+#ifdef IPV6_V6ONLY
+ yes = 1;
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) {
+ err = -errno;
+ goto out;
+ }
+#else
+ err = -ENOTSUP;
+ goto out;
+#endif
+ }
+
+ if (bind(fd, addr, addrlen)) {
+ err = -errno;
+ if (errno == EAFNOSUPPORT)
+ /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
+ * socket created with AF_INET to an AF_INET6 address or vice versa. */
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (addr->sa_family == AF_INET6)
+ handle->flags |= UV_HANDLE_IPV6;
+
+ return 0;
+
+out:
+ uv__close(handle->io_watcher.fd);
+ handle->io_watcher.fd = -1;
+ return err;
+}
+
+
+static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
+ int domain,
+ unsigned int flags) {
+ unsigned char taddr[sizeof(struct sockaddr_in6)];
+ socklen_t addrlen;
+
+ if (handle->io_watcher.fd != -1)
+ return 0;
+
+ switch (domain) {
+ case AF_INET:
+ {
+ struct sockaddr_in* addr = (void*)&taddr;
+ memset(addr, 0, sizeof *addr);
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = INADDR_ANY;
+ addrlen = sizeof *addr;
+ break;
+ }
+ case AF_INET6:
+ {
+ struct sockaddr_in6* addr = (void*)&taddr;
+ memset(addr, 0, sizeof *addr);
+ addr->sin6_family = AF_INET6;
+ addr->sin6_addr = in6addr_any;
+ addrlen = sizeof *addr;
+ break;
+ }
+ default:
+ assert(0 && "unsupported address family");
+ abort();
+ }
+
+ return uv__udp_bind(handle, (const struct sockaddr*) &taddr, addrlen, flags);
+}
+
+
+int uv__udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_udp_send_cb send_cb) {
+ int err;
+ int empty_queue;
+
+ assert(nbufs > 0);
+
+ err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
+ if (err)
+ return err;
+
+ /* It's legal for send_queue_count > 0 even when the write_queue is empty;
+ * it means there are error-state requests in the write_completed_queue that
+ * will touch up send_queue_size/count later.
+ */
+ empty_queue = (handle->send_queue_count == 0);
+
+ uv__req_init(handle->loop, req, UV_UDP_SEND);
+ assert(addrlen <= sizeof(req->addr));
+ memcpy(&req->addr, addr, addrlen);
+ req->send_cb = send_cb;
+ req->handle = handle;
+ req->nbufs = nbufs;
+
+ req->bufs = req->bufsml;
+ if (nbufs > ARRAY_SIZE(req->bufsml))
+ req->bufs = uv__malloc(nbufs * sizeof(bufs[0]));
+
+ if (req->bufs == NULL) {
+ uv__req_unregister(handle->loop, req);
+ return -ENOMEM;
+ }
+
+ memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0]));
+ handle->send_queue_size += uv__count_bufs(req->bufs, req->nbufs);
+ handle->send_queue_count++;
+ QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue);
+ uv__handle_start(handle);
+
+ if (empty_queue && !(handle->flags & UV_UDP_PROCESSING)) {
+ uv__udp_sendmsg(handle);
+ } else {
+ uv__io_start(handle->loop, &handle->io_watcher, UV__POLLOUT);
+ }
+
+ return 0;
+}
+
+
+int uv__udp_try_send(uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen) {
+ int err;
+ struct msghdr h;
+ ssize_t size;
+
+ assert(nbufs > 0);
+
+ /* already sending a message */
+ if (handle->send_queue_count != 0)
+ return -EAGAIN;
+
+ err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
+ if (err)
+ return err;
+
+ memset(&h, 0, sizeof h);
+ h.msg_name = (struct sockaddr*) addr;
+ h.msg_namelen = addrlen;
+ h.msg_iov = (struct iovec*) bufs;
+ h.msg_iovlen = nbufs;
+
+ do {
+ size = sendmsg(handle->io_watcher.fd, &h, 0);
+ } while (size == -1 && errno == EINTR);
+
+ if (size == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ return -EAGAIN;
+ else
+ return -errno;
+ }
+
+ return size;
+}
+
+
+static int uv__udp_set_membership4(uv_udp_t* handle,
+ const struct sockaddr_in* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ struct ip_mreq mreq;
+ int optname;
+ int err;
+
+ memset(&mreq, 0, sizeof mreq);
+
+ if (interface_addr) {
+ err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
+ if (err)
+ return err;
+ } else {
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ }
+
+ mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
+
+ switch (membership) {
+ case UV_JOIN_GROUP:
+ optname = IP_ADD_MEMBERSHIP;
+ break;
+ case UV_LEAVE_GROUP:
+ optname = IP_DROP_MEMBERSHIP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (setsockopt(handle->io_watcher.fd,
+ IPPROTO_IP,
+ optname,
+ &mreq,
+ sizeof(mreq))) {
+ return -errno;
+ }
+
+ return 0;
+}
+
+
+static int uv__udp_set_membership6(uv_udp_t* handle,
+ const struct sockaddr_in6* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ int optname;
+ struct ipv6_mreq mreq;
+ struct sockaddr_in6 addr6;
+
+ memset(&mreq, 0, sizeof mreq);
+
+ if (interface_addr) {
+ if (uv_ip6_addr(interface_addr, 0, &addr6))
+ return -EINVAL;
+ mreq.ipv6mr_interface = addr6.sin6_scope_id;
+ } else {
+ mreq.ipv6mr_interface = 0;
+ }
+
+ mreq.ipv6mr_multiaddr = multicast_addr->sin6_addr;
+
+ switch (membership) {
+ case UV_JOIN_GROUP:
+ optname = IPV6_ADD_MEMBERSHIP;
+ break;
+ case UV_LEAVE_GROUP:
+ optname = IPV6_DROP_MEMBERSHIP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (setsockopt(handle->io_watcher.fd,
+ IPPROTO_IPV6,
+ optname,
+ &mreq,
+ sizeof(mreq))) {
+ return -errno;
+ }
+
+ return 0;
+}
+
+
+int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
+ int domain;
+ int err;
+ int fd;
+
+ /* Use the lower 8 bits for the domain */
+ domain = flags & 0xFF;
+ if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
+ return -EINVAL;
+
+ if (flags & ~0xFF)
+ return -EINVAL;
+
+ if (domain != AF_UNSPEC) {
+ err = uv__socket(domain, SOCK_DGRAM, 0);
+ if (err < 0)
+ return err;
+ fd = err;
+ } else {
+ fd = -1;
+ }
+
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP);
+ handle->alloc_cb = NULL;
+ handle->recv_cb = NULL;
+ handle->send_queue_size = 0;
+ handle->send_queue_count = 0;
+ uv__io_init(&handle->io_watcher, uv__udp_io, fd);
+ QUEUE_INIT(&handle->write_queue);
+ QUEUE_INIT(&handle->write_completed_queue);
+ return 0;
+}
+
+
+int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
+ return uv_udp_init_ex(loop, handle, AF_UNSPEC);
+}
+
+
+int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
+ int err;
+
+ /* Check for already active socket. */
+ if (handle->io_watcher.fd != -1)
+ return -EBUSY;
+
+ err = uv__nonblock(sock, 1);
+ if (err)
+ return err;
+
+ err = uv__set_reuse(sock);
+ if (err)
+ return err;
+
+ handle->io_watcher.fd = sock;
+ return 0;
+}
+
+
+int uv_udp_set_membership(uv_udp_t* handle,
+ const char* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ int err;
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+
+ if (uv_ip4_addr(multicast_addr, 0, &addr4) == 0) {
+ err = uv__udp_maybe_deferred_bind(handle, AF_INET, UV_UDP_REUSEADDR);
+ if (err)
+ return err;
+ return uv__udp_set_membership4(handle, &addr4, interface_addr, membership);
+ } else if (uv_ip6_addr(multicast_addr, 0, &addr6) == 0) {
+ err = uv__udp_maybe_deferred_bind(handle, AF_INET6, UV_UDP_REUSEADDR);
+ if (err)
+ return err;
+ return uv__udp_set_membership6(handle, &addr6, interface_addr, membership);
+ } else {
+ return -EINVAL;
+ }
+}
+
+static int uv__setsockopt(uv_udp_t* handle,
+ int option4,
+ int option6,
+ const void* val,
+ size_t size) {
+ int r;
+
+ if (handle->flags & UV_HANDLE_IPV6)
+ r = setsockopt(handle->io_watcher.fd,
+ IPPROTO_IPV6,
+ option6,
+ val,
+ size);
+ else
+ r = setsockopt(handle->io_watcher.fd,
+ IPPROTO_IP,
+ option4,
+ val,
+ size);
+ if (r)
+ return -errno;
+
+ return 0;
+}
+
+static int uv__setsockopt_maybe_char(uv_udp_t* handle,
+ int option4,
+ int option6,
+ int val) {
+#if defined(__sun) || defined(_AIX)
+ char arg = val;
+#elif defined(__OpenBSD__)
+ unsigned char arg = val;
+#else
+ int arg = val;
+#endif
+
+ if (val < 0 || val > 255)
+ return -EINVAL;
+
+ return uv__setsockopt(handle, option4, option6, &arg, sizeof(arg));
+}
+
+
+int uv_udp_set_broadcast(uv_udp_t* handle, int on) {
+ if (setsockopt(handle->io_watcher.fd,
+ SOL_SOCKET,
+ SO_BROADCAST,
+ &on,
+ sizeof(on))) {
+ return -errno;
+ }
+
+ return 0;
+}
+
+
+int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
+ if (ttl < 1 || ttl > 255)
+ return -EINVAL;
+
+/*
+ * On Solaris and derivatives such as SmartOS, the length of socket options
+ * is sizeof(int) for IP_TTL and IPV6_UNICAST_HOPS,
+ * so hardcode the size of these options on this platform,
+ * and use the general uv__setsockopt_maybe_char call on other platforms.
+ */
+#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__)
+ return uv__setsockopt(handle,
+ IP_TTL,
+ IPV6_UNICAST_HOPS,
+ &ttl,
+ sizeof(ttl));
+#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) */
+
+ return uv__setsockopt_maybe_char(handle,
+ IP_TTL,
+ IPV6_UNICAST_HOPS,
+ ttl);
+}
+
+
+int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
+/*
+ * On Solaris and derivatives such as SmartOS, the length of socket options
+ * is sizeof(int) for IPV6_MULTICAST_HOPS and sizeof(char) for
+ * IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case,
+ * and use the general uv__setsockopt_maybe_char call otherwise.
+ */
+#if defined(__sun) || defined(_AIX)
+ if (handle->flags & UV_HANDLE_IPV6)
+ return uv__setsockopt(handle,
+ IP_MULTICAST_TTL,
+ IPV6_MULTICAST_HOPS,
+ &ttl,
+ sizeof(ttl));
+#endif /* defined(__sun) || defined(_AIX) */
+
+ return uv__setsockopt_maybe_char(handle,
+ IP_MULTICAST_TTL,
+ IPV6_MULTICAST_HOPS,
+ ttl);
+}
+
+
+int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
+/*
+ * On Solaris and derivatives such as SmartOS, the length of socket options
+ * is sizeof(int) for IPV6_MULTICAST_LOOP and sizeof(char) for
+ * IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case,
+ * and use the general uv__setsockopt_maybe_char call otherwise.
+ */
+#if defined(__sun) || defined(_AIX)
+ if (handle->flags & UV_HANDLE_IPV6)
+ return uv__setsockopt(handle,
+ IP_MULTICAST_LOOP,
+ IPV6_MULTICAST_LOOP,
+ &on,
+ sizeof(on));
+#endif /* defined(__sun) || defined(_AIX) */
+
+ return uv__setsockopt_maybe_char(handle,
+ IP_MULTICAST_LOOP,
+ IPV6_MULTICAST_LOOP,
+ on);
+}
+
+int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
+ struct sockaddr_storage addr_st;
+ struct sockaddr_in* addr4;
+ struct sockaddr_in6* addr6;
+
+ addr4 = (struct sockaddr_in*) &addr_st;
+ addr6 = (struct sockaddr_in6*) &addr_st;
+
+ if (!interface_addr) {
+ memset(&addr_st, 0, sizeof addr_st);
+ if (handle->flags & UV_HANDLE_IPV6) {
+ addr_st.ss_family = AF_INET6;
+ addr6->sin6_scope_id = 0;
+ } else {
+ addr_st.ss_family = AF_INET;
+ addr4->sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+ } else if (uv_ip4_addr(interface_addr, 0, addr4) == 0) {
+ /* nothing, address was parsed */
+ } else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) {
+ /* nothing, address was parsed */
+ } else {
+ return -EINVAL;
+ }
+
+ if (addr_st.ss_family == AF_INET) {
+ if (setsockopt(handle->io_watcher.fd,
+ IPPROTO_IP,
+ IP_MULTICAST_IF,
+ (void*) &addr4->sin_addr,
+ sizeof(addr4->sin_addr)) == -1) {
+ return -errno;
+ }
+ } else if (addr_st.ss_family == AF_INET6) {
+ if (setsockopt(handle->io_watcher.fd,
+ IPPROTO_IPV6,
+ IPV6_MULTICAST_IF,
+ &addr6->sin6_scope_id,
+ sizeof(addr6->sin6_scope_id)) == -1) {
+ return -errno;
+ }
+ } else {
+ assert(0 && "unexpected address family");
+ abort();
+ }
+
+ return 0;
+}
+
+
+int uv_udp_getsockname(const uv_udp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ socklen_t socklen;
+
+ if (handle->io_watcher.fd == -1)
+ return -EINVAL; /* FIXME(bnoordhuis) -EBADF */
+
+ /* sizeof(socklen_t) != sizeof(int) on some systems. */
+ socklen = (socklen_t) *namelen;
+
+ if (getsockname(handle->io_watcher.fd, name, &socklen))
+ return -errno;
+
+ *namelen = (int) socklen;
+ return 0;
+}
+
+
+int uv__udp_recv_start(uv_udp_t* handle,
+ uv_alloc_cb alloc_cb,
+ uv_udp_recv_cb recv_cb) {
+ int err;
+
+ if (alloc_cb == NULL || recv_cb == NULL)
+ return -EINVAL;
+
+ if (uv__io_active(&handle->io_watcher, UV__POLLIN))
+ return -EALREADY; /* FIXME(bnoordhuis) Should be -EBUSY. */
+
+ err = uv__udp_maybe_deferred_bind(handle, AF_INET, 0);
+ if (err)
+ return err;
+
+ handle->alloc_cb = alloc_cb;
+ handle->recv_cb = recv_cb;
+
+ uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN);
+ uv__handle_start(handle);
+
+ return 0;
+}
+
+
+int uv__udp_recv_stop(uv_udp_t* handle) {
+ uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLIN);
+
+ if (!uv__io_active(&handle->io_watcher, UV__POLLOUT))
+ uv__handle_stop(handle);
+
+ handle->alloc_cb = NULL;
+ handle->recv_cb = NULL;
+
+ return 0;
+}
diff --git a/3rdparty/libuv/src/uv-common.c b/3rdparty/libuv/src/uv-common.c
new file mode 100644
index 00000000000..40ed28fec5a
--- /dev/null
+++ b/3rdparty/libuv/src/uv-common.c
@@ -0,0 +1,627 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "uv-common.h"
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stddef.h> /* NULL */
+#include <stdlib.h> /* malloc */
+#include <string.h> /* memset */
+
+#if defined(_WIN32)
+# include <malloc.h> /* malloc */
+#else
+# include <net/if.h> /* if_nametoindex */
+#endif
+
+
+typedef struct {
+ uv_malloc_func local_malloc;
+ uv_realloc_func local_realloc;
+ uv_calloc_func local_calloc;
+ uv_free_func local_free;
+} uv__allocator_t;
+
+static uv__allocator_t uv__allocator = {
+ malloc,
+ realloc,
+ calloc,
+ free,
+};
+
+char* uv__strdup(const char* s) {
+ size_t len = strlen(s) + 1;
+ char* m = uv__malloc(len);
+ if (m == NULL)
+ return NULL;
+ return memcpy(m, s, len);
+}
+
+char* uv__strndup(const char* s, size_t n) {
+ char* m;
+ size_t len = strlen(s);
+ if (n < len)
+ len = n;
+ m = uv__malloc(len + 1);
+ if (m == NULL)
+ return NULL;
+ m[len] = '\0';
+ return memcpy(m, s, len);
+}
+
+void* uv__malloc(size_t size) {
+ return uv__allocator.local_malloc(size);
+}
+
+void uv__free(void* ptr) {
+ uv__allocator.local_free(ptr);
+}
+
+void* uv__calloc(size_t count, size_t size) {
+ return uv__allocator.local_calloc(count, size);
+}
+
+void* uv__realloc(void* ptr, size_t size) {
+ return uv__allocator.local_realloc(ptr, size);
+}
+
+int uv_replace_allocator(uv_malloc_func malloc_func,
+ uv_realloc_func realloc_func,
+ uv_calloc_func calloc_func,
+ uv_free_func free_func) {
+ if (malloc_func == NULL || realloc_func == NULL ||
+ calloc_func == NULL || free_func == NULL) {
+ return UV_EINVAL;
+ }
+
+ uv__allocator.local_malloc = malloc_func;
+ uv__allocator.local_realloc = realloc_func;
+ uv__allocator.local_calloc = calloc_func;
+ uv__allocator.local_free = free_func;
+
+ return 0;
+}
+
+#define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t);
+
+size_t uv_handle_size(uv_handle_type type) {
+ switch (type) {
+ UV_HANDLE_TYPE_MAP(XX)
+ default:
+ return -1;
+ }
+}
+
+size_t uv_req_size(uv_req_type type) {
+ switch(type) {
+ UV_REQ_TYPE_MAP(XX)
+ default:
+ return -1;
+ }
+}
+
+#undef XX
+
+
+size_t uv_loop_size(void) {
+ return sizeof(uv_loop_t);
+}
+
+
+uv_buf_t uv_buf_init(char* base, unsigned int len) {
+ uv_buf_t buf;
+ buf.base = base;
+ buf.len = len;
+ return buf;
+}
+
+
+static const char* uv__unknown_err_code(int err) {
+ char buf[32];
+ char* copy;
+
+ snprintf(buf, sizeof(buf), "Unknown system error %d", err);
+ copy = uv__strdup(buf);
+
+ return copy != NULL ? copy : "Unknown system error";
+}
+
+
+#define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name;
+const char* uv_err_name(int err) {
+ switch (err) {
+ UV_ERRNO_MAP(UV_ERR_NAME_GEN)
+ }
+ return uv__unknown_err_code(err);
+}
+#undef UV_ERR_NAME_GEN
+
+
+#define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg;
+const char* uv_strerror(int err) {
+ switch (err) {
+ UV_ERRNO_MAP(UV_STRERROR_GEN)
+ }
+ return uv__unknown_err_code(err);
+}
+#undef UV_STRERROR_GEN
+
+
+int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr) {
+ memset(addr, 0, sizeof(*addr));
+ addr->sin_family = AF_INET;
+ addr->sin_port = htons(port);
+ return uv_inet_pton(AF_INET, ip, &(addr->sin_addr.s_addr));
+}
+
+
+int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr) {
+ char address_part[40];
+ size_t address_part_size;
+ const char* zone_index;
+
+ memset(addr, 0, sizeof(*addr));
+ addr->sin6_family = AF_INET6;
+ addr->sin6_port = htons(port);
+
+ zone_index = strchr(ip, '%');
+ if (zone_index != NULL) {
+ address_part_size = zone_index - ip;
+ if (address_part_size >= sizeof(address_part))
+ address_part_size = sizeof(address_part) - 1;
+
+ memcpy(address_part, ip, address_part_size);
+ address_part[address_part_size] = '\0';
+ ip = address_part;
+
+ zone_index++; /* skip '%' */
+ /* NOTE: unknown interface (id=0) is silently ignored */
+#ifdef _WIN32
+ addr->sin6_scope_id = atoi(zone_index);
+#else
+ addr->sin6_scope_id = if_nametoindex(zone_index);
+#endif
+ }
+
+ return uv_inet_pton(AF_INET6, ip, &addr->sin6_addr);
+}
+
+
+int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size) {
+ return uv_inet_ntop(AF_INET, &src->sin_addr, dst, size);
+}
+
+
+int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size) {
+ return uv_inet_ntop(AF_INET6, &src->sin6_addr, dst, size);
+}
+
+
+int uv_tcp_bind(uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int flags) {
+ unsigned int addrlen;
+
+ if (handle->type != UV_TCP)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET)
+ addrlen = sizeof(struct sockaddr_in);
+ else if (addr->sa_family == AF_INET6)
+ addrlen = sizeof(struct sockaddr_in6);
+ else
+ return UV_EINVAL;
+
+ return uv__tcp_bind(handle, addr, addrlen, flags);
+}
+
+
+int uv_udp_bind(uv_udp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int flags) {
+ unsigned int addrlen;
+
+ if (handle->type != UV_UDP)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET)
+ addrlen = sizeof(struct sockaddr_in);
+ else if (addr->sa_family == AF_INET6)
+ addrlen = sizeof(struct sockaddr_in6);
+ else
+ return UV_EINVAL;
+
+ return uv__udp_bind(handle, addr, addrlen, flags);
+}
+
+
+int uv_tcp_connect(uv_connect_t* req,
+ uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ uv_connect_cb cb) {
+ unsigned int addrlen;
+
+ if (handle->type != UV_TCP)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET)
+ addrlen = sizeof(struct sockaddr_in);
+ else if (addr->sa_family == AF_INET6)
+ addrlen = sizeof(struct sockaddr_in6);
+ else
+ return UV_EINVAL;
+
+ return uv__tcp_connect(req, handle, addr, addrlen, cb);
+}
+
+
+int uv_udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ uv_udp_send_cb send_cb) {
+ unsigned int addrlen;
+
+ if (handle->type != UV_UDP)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET)
+ addrlen = sizeof(struct sockaddr_in);
+ else if (addr->sa_family == AF_INET6)
+ addrlen = sizeof(struct sockaddr_in6);
+ else
+ return UV_EINVAL;
+
+ return uv__udp_send(req, handle, bufs, nbufs, addr, addrlen, send_cb);
+}
+
+
+int uv_udp_try_send(uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr) {
+ unsigned int addrlen;
+
+ if (handle->type != UV_UDP)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET)
+ addrlen = sizeof(struct sockaddr_in);
+ else if (addr->sa_family == AF_INET6)
+ addrlen = sizeof(struct sockaddr_in6);
+ else
+ return UV_EINVAL;
+
+ return uv__udp_try_send(handle, bufs, nbufs, addr, addrlen);
+}
+
+
+int uv_udp_recv_start(uv_udp_t* handle,
+ uv_alloc_cb alloc_cb,
+ uv_udp_recv_cb recv_cb) {
+ if (handle->type != UV_UDP || alloc_cb == NULL || recv_cb == NULL)
+ return UV_EINVAL;
+ else
+ return uv__udp_recv_start(handle, alloc_cb, recv_cb);
+}
+
+
+int uv_udp_recv_stop(uv_udp_t* handle) {
+ if (handle->type != UV_UDP)
+ return UV_EINVAL;
+ else
+ return uv__udp_recv_stop(handle);
+}
+
+
+void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
+ QUEUE queue;
+ QUEUE* q;
+ uv_handle_t* h;
+
+ QUEUE_MOVE(&loop->handle_queue, &queue);
+ while (!QUEUE_EMPTY(&queue)) {
+ q = QUEUE_HEAD(&queue);
+ h = QUEUE_DATA(q, uv_handle_t, handle_queue);
+
+ QUEUE_REMOVE(q);
+ QUEUE_INSERT_TAIL(&loop->handle_queue, q);
+
+ if (h->flags & UV__HANDLE_INTERNAL) continue;
+ walk_cb(h, arg);
+ }
+}
+
+
+static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) {
+ const char* type;
+ QUEUE* q;
+ uv_handle_t* h;
+
+ if (loop == NULL)
+ loop = uv_default_loop();
+
+ QUEUE_FOREACH(q, &loop->handle_queue) {
+ h = QUEUE_DATA(q, uv_handle_t, handle_queue);
+
+ if (only_active && !uv__is_active(h))
+ continue;
+
+ switch (h->type) {
+#define X(uc, lc) case UV_##uc: type = #lc; break;
+ UV_HANDLE_TYPE_MAP(X)
+#undef X
+ default: type = "<unknown>";
+ }
+
+ fprintf(stream,
+ "[%c%c%c] %-8s %p\n",
+ "R-"[!(h->flags & UV__HANDLE_REF)],
+ "A-"[!(h->flags & UV__HANDLE_ACTIVE)],
+ "I-"[!(h->flags & UV__HANDLE_INTERNAL)],
+ type,
+ (void*)h);
+ }
+}
+
+
+void uv_print_all_handles(uv_loop_t* loop, FILE* stream) {
+ uv__print_handles(loop, 0, stream);
+}
+
+
+void uv_print_active_handles(uv_loop_t* loop, FILE* stream) {
+ uv__print_handles(loop, 1, stream);
+}
+
+
+void uv_ref(uv_handle_t* handle) {
+ uv__handle_ref(handle);
+}
+
+
+void uv_unref(uv_handle_t* handle) {
+ uv__handle_unref(handle);
+}
+
+
+int uv_has_ref(const uv_handle_t* handle) {
+ return uv__has_ref(handle);
+}
+
+
+void uv_stop(uv_loop_t* loop) {
+ loop->stop_flag = 1;
+}
+
+
+uint64_t uv_now(const uv_loop_t* loop) {
+ return loop->time;
+}
+
+
+
+size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs) {
+ unsigned int i;
+ size_t bytes;
+
+ bytes = 0;
+ for (i = 0; i < nbufs; i++)
+ bytes += (size_t) bufs[i].len;
+
+ return bytes;
+}
+
+int uv_recv_buffer_size(uv_handle_t* handle, int* value) {
+ return uv__socket_sockopt(handle, SO_RCVBUF, value);
+}
+
+int uv_send_buffer_size(uv_handle_t* handle, int *value) {
+ return uv__socket_sockopt(handle, SO_SNDBUF, value);
+}
+
+int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) {
+ size_t required_len;
+
+ if (!uv__is_active(handle)) {
+ *size = 0;
+ return UV_EINVAL;
+ }
+
+ required_len = strlen(handle->path);
+ if (required_len > *size) {
+ *size = required_len;
+ return UV_ENOBUFS;
+ }
+
+ memcpy(buffer, handle->path, required_len);
+ *size = required_len;
+
+ return 0;
+}
+
+/* The windows implementation does not have the same structure layout as
+ * the unix implementation (nbufs is not directly inside req but is
+ * contained in a nested union/struct) so this function locates it.
+*/
+static unsigned int* uv__get_nbufs(uv_fs_t* req) {
+#ifdef _WIN32
+ return &req->fs.info.nbufs;
+#else
+ return &req->nbufs;
+#endif
+}
+
+void uv__fs_scandir_cleanup(uv_fs_t* req) {
+ uv__dirent_t** dents;
+
+ unsigned int* nbufs = uv__get_nbufs(req);
+
+ dents = req->ptr;
+ if (*nbufs > 0 && *nbufs != (unsigned int) req->result)
+ (*nbufs)--;
+ for (; *nbufs < (unsigned int) req->result; (*nbufs)++)
+ uv__free(dents[*nbufs]);
+}
+
+
+int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) {
+ uv__dirent_t** dents;
+ uv__dirent_t* dent;
+
+ unsigned int* nbufs = uv__get_nbufs(req);
+
+ dents = req->ptr;
+
+ /* Free previous entity */
+ if (*nbufs > 0)
+ uv__free(dents[*nbufs - 1]);
+
+ /* End was already reached */
+ if (*nbufs == (unsigned int) req->result) {
+ uv__free(dents);
+ req->ptr = NULL;
+ return UV_EOF;
+ }
+
+ dent = dents[(*nbufs)++];
+
+ ent->name = dent->d_name;
+#ifdef HAVE_DIRENT_TYPES
+ switch (dent->d_type) {
+ case UV__DT_DIR:
+ ent->type = UV_DIRENT_DIR;
+ break;
+ case UV__DT_FILE:
+ ent->type = UV_DIRENT_FILE;
+ break;
+ case UV__DT_LINK:
+ ent->type = UV_DIRENT_LINK;
+ break;
+ case UV__DT_FIFO:
+ ent->type = UV_DIRENT_FIFO;
+ break;
+ case UV__DT_SOCKET:
+ ent->type = UV_DIRENT_SOCKET;
+ break;
+ case UV__DT_CHAR:
+ ent->type = UV_DIRENT_CHAR;
+ break;
+ case UV__DT_BLOCK:
+ ent->type = UV_DIRENT_BLOCK;
+ break;
+ default:
+ ent->type = UV_DIRENT_UNKNOWN;
+ }
+#else
+ ent->type = UV_DIRENT_UNKNOWN;
+#endif
+
+ return 0;
+}
+
+
+int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) {
+ va_list ap;
+ int err;
+
+ va_start(ap, option);
+ /* Any platform-agnostic options should be handled here. */
+ err = uv__loop_configure(loop, option, ap);
+ va_end(ap);
+
+ return err;
+}
+
+
+static uv_loop_t default_loop_struct;
+static uv_loop_t* default_loop_ptr;
+
+
+uv_loop_t* uv_default_loop(void) {
+ if (default_loop_ptr != NULL)
+ return default_loop_ptr;
+
+ if (uv_loop_init(&default_loop_struct))
+ return NULL;
+
+ default_loop_ptr = &default_loop_struct;
+ return default_loop_ptr;
+}
+
+
+uv_loop_t* uv_loop_new(void) {
+ uv_loop_t* loop;
+
+ loop = uv__malloc(sizeof(*loop));
+ if (loop == NULL)
+ return NULL;
+
+ if (uv_loop_init(loop)) {
+ uv__free(loop);
+ return NULL;
+ }
+
+ return loop;
+}
+
+
+int uv_loop_close(uv_loop_t* loop) {
+ QUEUE* q;
+ uv_handle_t* h;
+
+ if (!QUEUE_EMPTY(&(loop)->active_reqs))
+ return UV_EBUSY;
+
+ QUEUE_FOREACH(q, &loop->handle_queue) {
+ h = QUEUE_DATA(q, uv_handle_t, handle_queue);
+ if (!(h->flags & UV__HANDLE_INTERNAL))
+ return UV_EBUSY;
+ }
+
+ uv__loop_close(loop);
+
+#ifndef NDEBUG
+ memset(loop, -1, sizeof(*loop));
+#endif
+ if (loop == default_loop_ptr)
+ default_loop_ptr = NULL;
+
+ return 0;
+}
+
+
+void uv_loop_delete(uv_loop_t* loop) {
+ uv_loop_t* default_loop;
+ int err;
+
+ default_loop = default_loop_ptr;
+
+ err = uv_loop_close(loop);
+ (void) err; /* Squelch compiler warnings. */
+ assert(err == 0);
+ if (loop != default_loop)
+ uv__free(loop);
+}
diff --git a/3rdparty/libuv/src/uv-common.h b/3rdparty/libuv/src/uv-common.h
new file mode 100644
index 00000000000..27902fdf864
--- /dev/null
+++ b/3rdparty/libuv/src/uv-common.h
@@ -0,0 +1,227 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/*
+ * This file is private to libuv. It provides common functionality to both
+ * Windows and Unix backends.
+ */
+
+#ifndef UV_COMMON_H_
+#define UV_COMMON_H_
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stddef.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+# include "stdint-msvc2008.h"
+#else
+# include <stdint.h>
+#endif
+
+#include "uv.h"
+#include "tree.h"
+#include "queue.h"
+
+#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900
+extern int snprintf(char*, size_t, const char*, ...);
+#endif
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+#define container_of(ptr, type, member) \
+ ((type *) ((char *) (ptr) - offsetof(type, member)))
+
+#define STATIC_ASSERT(expr) \
+ void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)])
+
+#ifndef _WIN32
+enum {
+ UV__HANDLE_INTERNAL = 0x8000,
+ UV__HANDLE_ACTIVE = 0x4000,
+ UV__HANDLE_REF = 0x2000,
+ UV__HANDLE_CLOSING = 0 /* no-op on unix */
+};
+#else
+# define UV__HANDLE_INTERNAL 0x80
+# define UV__HANDLE_ACTIVE 0x40
+# define UV__HANDLE_REF 0x20
+# define UV__HANDLE_CLOSING 0x01
+#endif
+
+int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap);
+
+void uv__loop_close(uv_loop_t* loop);
+
+int uv__tcp_bind(uv_tcp_t* tcp,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags);
+
+int uv__tcp_connect(uv_connect_t* req,
+ uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_connect_cb cb);
+
+int uv__udp_bind(uv_udp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags);
+
+int uv__udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_udp_send_cb send_cb);
+
+int uv__udp_try_send(uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen);
+
+int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloccb,
+ uv_udp_recv_cb recv_cb);
+
+int uv__udp_recv_stop(uv_udp_t* handle);
+
+void uv__fs_poll_close(uv_fs_poll_t* handle);
+
+int uv__getaddrinfo_translate_error(int sys_err); /* EAI_* error. */
+
+void uv__work_submit(uv_loop_t* loop,
+ struct uv__work *w,
+ void (*work)(struct uv__work *w),
+ void (*done)(struct uv__work *w, int status));
+
+void uv__work_done(uv_async_t* handle);
+
+size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs);
+
+int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value);
+
+void uv__fs_scandir_cleanup(uv_fs_t* req);
+
+#define uv__has_active_reqs(loop) \
+ (QUEUE_EMPTY(&(loop)->active_reqs) == 0)
+
+#define uv__req_register(loop, req) \
+ do { \
+ QUEUE_INSERT_TAIL(&(loop)->active_reqs, &(req)->active_queue); \
+ } \
+ while (0)
+
+#define uv__req_unregister(loop, req) \
+ do { \
+ assert(uv__has_active_reqs(loop)); \
+ QUEUE_REMOVE(&(req)->active_queue); \
+ } \
+ while (0)
+
+#define uv__has_active_handles(loop) \
+ ((loop)->active_handles > 0)
+
+#define uv__active_handle_add(h) \
+ do { \
+ (h)->loop->active_handles++; \
+ } \
+ while (0)
+
+#define uv__active_handle_rm(h) \
+ do { \
+ (h)->loop->active_handles--; \
+ } \
+ while (0)
+
+#define uv__is_active(h) \
+ (((h)->flags & UV__HANDLE_ACTIVE) != 0)
+
+#define uv__is_closing(h) \
+ (((h)->flags & (UV_CLOSING | UV_CLOSED)) != 0)
+
+#define uv__handle_start(h) \
+ do { \
+ assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \
+ if (((h)->flags & UV__HANDLE_ACTIVE) != 0) break; \
+ (h)->flags |= UV__HANDLE_ACTIVE; \
+ if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_add(h); \
+ } \
+ while (0)
+
+#define uv__handle_stop(h) \
+ do { \
+ assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \
+ if (((h)->flags & UV__HANDLE_ACTIVE) == 0) break; \
+ (h)->flags &= ~UV__HANDLE_ACTIVE; \
+ if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_rm(h); \
+ } \
+ while (0)
+
+#define uv__handle_ref(h) \
+ do { \
+ if (((h)->flags & UV__HANDLE_REF) != 0) break; \
+ (h)->flags |= UV__HANDLE_REF; \
+ if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \
+ if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_add(h); \
+ } \
+ while (0)
+
+#define uv__handle_unref(h) \
+ do { \
+ if (((h)->flags & UV__HANDLE_REF) == 0) break; \
+ (h)->flags &= ~UV__HANDLE_REF; \
+ if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \
+ if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_rm(h); \
+ } \
+ while (0)
+
+#define uv__has_ref(h) \
+ (((h)->flags & UV__HANDLE_REF) != 0)
+
+#if defined(_WIN32)
+# define uv__handle_platform_init(h) ((h)->u.fd = -1)
+#else
+# define uv__handle_platform_init(h) ((h)->next_closing = NULL)
+#endif
+
+#define uv__handle_init(loop_, h, type_) \
+ do { \
+ (h)->loop = (loop_); \
+ (h)->type = (type_); \
+ (h)->flags = UV__HANDLE_REF; /* Ref the loop when active. */ \
+ QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue); \
+ uv__handle_platform_init(h); \
+ } \
+ while (0)
+
+
+/* Allocator prototypes */
+void *uv__calloc(size_t count, size_t size);
+char *uv__strdup(const char* s);
+char *uv__strndup(const char* s, size_t n);
+void* uv__malloc(size_t size);
+void uv__free(void* ptr);
+void* uv__realloc(void* ptr, size_t size);
+
+#endif /* UV_COMMON_H_ */
diff --git a/3rdparty/libuv/src/version.c b/3rdparty/libuv/src/version.c
new file mode 100644
index 00000000000..686dedd98d6
--- /dev/null
+++ b/3rdparty/libuv/src/version.c
@@ -0,0 +1,45 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+
+#define UV_STRINGIFY(v) UV_STRINGIFY_HELPER(v)
+#define UV_STRINGIFY_HELPER(v) #v
+
+#define UV_VERSION_STRING_BASE UV_STRINGIFY(UV_VERSION_MAJOR) "." \
+ UV_STRINGIFY(UV_VERSION_MINOR) "." \
+ UV_STRINGIFY(UV_VERSION_PATCH)
+
+#if UV_VERSION_IS_RELEASE
+# define UV_VERSION_STRING UV_VERSION_STRING_BASE
+#else
+# define UV_VERSION_STRING UV_VERSION_STRING_BASE "-" UV_VERSION_SUFFIX
+#endif
+
+
+unsigned int uv_version(void) {
+ return UV_VERSION_HEX;
+}
+
+
+const char* uv_version_string(void) {
+ return UV_VERSION_STRING;
+}
diff --git a/3rdparty/libuv/src/win/async.c b/3rdparty/libuv/src/win/async.c
new file mode 100644
index 00000000000..ad240ab8972
--- /dev/null
+++ b/3rdparty/libuv/src/win/async.c
@@ -0,0 +1,99 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "atomicops-inl.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) {
+ if (handle->flags & UV__HANDLE_CLOSING &&
+ !handle->async_sent) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ uv__handle_close(handle);
+ }
+}
+
+
+int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
+ uv_req_t* req;
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_ASYNC);
+ handle->async_sent = 0;
+ handle->async_cb = async_cb;
+
+ req = &handle->async_req;
+ uv_req_init(loop, req);
+ req->type = UV_WAKEUP;
+ req->data = handle;
+
+ uv__handle_start(handle);
+
+ return 0;
+}
+
+
+void uv_async_close(uv_loop_t* loop, uv_async_t* handle) {
+ if (!((uv_async_t*)handle)->async_sent) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+
+ uv__handle_closing(handle);
+}
+
+
+int uv_async_send(uv_async_t* handle) {
+ uv_loop_t* loop = handle->loop;
+
+ if (handle->type != UV_ASYNC) {
+ /* Can't set errno because that's not thread-safe. */
+ return -1;
+ }
+
+ /* The user should make sure never to call uv_async_send to a closing */
+ /* or closed handle. */
+ assert(!(handle->flags & UV__HANDLE_CLOSING));
+
+ if (!uv__atomic_exchange_set(&handle->async_sent)) {
+ POST_COMPLETION_FOR_REQ(loop, &handle->async_req);
+ }
+
+ return 0;
+}
+
+
+void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
+ uv_req_t* req) {
+ assert(handle->type == UV_ASYNC);
+ assert(req->type == UV_WAKEUP);
+
+ handle->async_sent = 0;
+
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ } else if (handle->async_cb != NULL) {
+ handle->async_cb(handle);
+ }
+}
diff --git a/3rdparty/libuv/src/win/atomicops-inl.h b/3rdparty/libuv/src/win/atomicops-inl.h
new file mode 100644
index 00000000000..61e006026c1
--- /dev/null
+++ b/3rdparty/libuv/src/win/atomicops-inl.h
@@ -0,0 +1,56 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_ATOMICOPS_INL_H_
+#define UV_WIN_ATOMICOPS_INL_H_
+
+#include "uv.h"
+
+
+/* Atomic set operation on char */
+#ifdef _MSC_VER /* MSVC */
+
+/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less */
+/* efficient than InterlockedExchange, but InterlockedExchange8 does not */
+/* exist, and interlocked operations on larger targets might require the */
+/* target to be aligned. */
+#pragma intrinsic(_InterlockedOr8)
+
+static char __declspec(inline) uv__atomic_exchange_set(char volatile* target) {
+ return _InterlockedOr8(target, 1);
+}
+
+#else /* GCC */
+
+/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */
+static inline char uv__atomic_exchange_set(char volatile* target) {
+ const char one = 1;
+ char old_value;
+ __asm__ __volatile__ ("lock xchgb %0, %1\n\t"
+ : "=r"(old_value), "=m"(*target)
+ : "0"(one), "m"(*target)
+ : "memory");
+ return old_value;
+}
+
+#endif
+
+#endif /* UV_WIN_ATOMICOPS_INL_H_ */
diff --git a/3rdparty/libuv/src/win/core.c b/3rdparty/libuv/src/win/core.c
new file mode 100644
index 00000000000..de0483e1023
--- /dev/null
+++ b/3rdparty/libuv/src/win/core.c
@@ -0,0 +1,457 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
+#include <crtdbg.h>
+#endif
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+static uv_loop_t default_loop_struct;
+static uv_loop_t* default_loop_ptr;
+
+/* uv_once initialization guards */
+static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
+
+
+#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
+/* Our crt debug report handler allows us to temporarily disable asserts
+ * just for the current thread.
+ */
+
+UV_THREAD_LOCAL int uv__crt_assert_enabled = TRUE;
+
+static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_val) {
+ if (uv__crt_assert_enabled || report_type != _CRT_ASSERT)
+ return FALSE;
+
+ if (ret_val) {
+ /* Set ret_val to 0 to continue with normal execution.
+ * Set ret_val to 1 to trigger a breakpoint.
+ */
+
+ if(IsDebuggerPresent())
+ *ret_val = 1;
+ else
+ *ret_val = 0;
+ }
+
+ /* Don't call _CrtDbgReport. */
+ return TRUE;
+}
+#else
+UV_THREAD_LOCAL int uv__crt_assert_enabled = FALSE;
+#endif
+
+
+#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
+static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
+ const wchar_t* function, const wchar_t * file, unsigned int line,
+ uintptr_t reserved) {
+ /* No-op. */
+}
+#endif
+
+
+static void uv_init(void) {
+ /* Tell Windows that we will handle critical errors. */
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
+ SEM_NOOPENFILEERRORBOX);
+
+ /* Tell the CRT to not exit the application when an invalid parameter is
+ * passed. The main issue is that invalid FDs will trigger this behavior.
+ */
+#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
+ _set_invalid_parameter_handler(uv__crt_invalid_parameter_handler);
+#endif
+
+ /* We also need to setup our debug report handler because some CRT
+ * functions (eg _get_osfhandle) raise an assert when called with invalid
+ * FDs even though they return the proper error code in the release build.
+ */
+#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
+ _CrtSetReportHook(uv__crt_dbg_report_handler);
+#endif
+
+ /* Fetch winapi function pointers. This must be done first because other
+ * initialization code might need these function pointers to be loaded.
+ */
+ uv_winapi_init();
+
+ /* Initialize winsock */
+ uv_winsock_init();
+
+ /* Initialize FS */
+ uv_fs_init();
+
+ /* Initialize signal stuff */
+ uv_signals_init();
+
+ /* Initialize console */
+ uv_console_init();
+
+ /* Initialize utilities */
+ uv__util_init();
+}
+
+
+int uv_loop_init(uv_loop_t* loop) {
+ int err;
+
+ /* Initialize libuv itself first */
+ uv__once_init();
+
+ /* Create an I/O completion port */
+ loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
+ if (loop->iocp == NULL)
+ return uv_translate_sys_error(GetLastError());
+
+ /* To prevent uninitialized memory access, loop->time must be initialized
+ * to zero before calling uv_update_time for the first time.
+ */
+ loop->time = 0;
+ uv_update_time(loop);
+
+ QUEUE_INIT(&loop->wq);
+ QUEUE_INIT(&loop->handle_queue);
+ QUEUE_INIT(&loop->active_reqs);
+ loop->active_handles = 0;
+
+ loop->pending_reqs_tail = NULL;
+
+ loop->endgame_handles = NULL;
+
+ RB_INIT(&loop->timers);
+
+ loop->check_handles = NULL;
+ loop->prepare_handles = NULL;
+ loop->idle_handles = NULL;
+
+ loop->next_prepare_handle = NULL;
+ loop->next_check_handle = NULL;
+ loop->next_idle_handle = NULL;
+
+ memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets);
+
+ loop->active_tcp_streams = 0;
+ loop->active_udp_streams = 0;
+
+ loop->timer_counter = 0;
+ loop->stop_flag = 0;
+
+ err = uv_mutex_init(&loop->wq_mutex);
+ if (err)
+ goto fail_mutex_init;
+
+ err = uv_async_init(loop, &loop->wq_async, uv__work_done);
+ if (err)
+ goto fail_async_init;
+
+ uv__handle_unref(&loop->wq_async);
+ loop->wq_async.flags |= UV__HANDLE_INTERNAL;
+
+ return 0;
+
+fail_async_init:
+ uv_mutex_destroy(&loop->wq_mutex);
+
+fail_mutex_init:
+ CloseHandle(loop->iocp);
+ loop->iocp = INVALID_HANDLE_VALUE;
+
+ return err;
+}
+
+
+void uv__once_init(void) {
+ uv_once(&uv_init_guard_, uv_init);
+}
+
+
+void uv__loop_close(uv_loop_t* loop) {
+ size_t i;
+
+ /* close the async handle without needing an extra loop iteration */
+ assert(!loop->wq_async.async_sent);
+ loop->wq_async.close_cb = NULL;
+ uv__handle_closing(&loop->wq_async);
+ uv__handle_close(&loop->wq_async);
+
+ for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) {
+ SOCKET sock = loop->poll_peer_sockets[i];
+ if (sock != 0 && sock != INVALID_SOCKET)
+ closesocket(sock);
+ }
+
+ uv_mutex_lock(&loop->wq_mutex);
+ assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
+ assert(!uv__has_active_reqs(loop));
+ uv_mutex_unlock(&loop->wq_mutex);
+ uv_mutex_destroy(&loop->wq_mutex);
+
+ CloseHandle(loop->iocp);
+}
+
+
+int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
+ return UV_ENOSYS;
+}
+
+
+int uv_backend_fd(const uv_loop_t* loop) {
+ return -1;
+}
+
+
+int uv_backend_timeout(const uv_loop_t* loop) {
+ if (loop->stop_flag != 0)
+ return 0;
+
+ if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
+ return 0;
+
+ if (loop->pending_reqs_tail)
+ return 0;
+
+ if (loop->endgame_handles)
+ return 0;
+
+ if (loop->idle_handles)
+ return 0;
+
+ return uv__next_timeout(loop);
+}
+
+
+static void uv_poll(uv_loop_t* loop, DWORD timeout) {
+ DWORD bytes;
+ ULONG_PTR key;
+ OVERLAPPED* overlapped;
+ uv_req_t* req;
+
+ GetQueuedCompletionStatus(loop->iocp,
+ &bytes,
+ &key,
+ &overlapped,
+ timeout);
+
+ if (overlapped) {
+ /* Package was dequeued */
+ req = uv_overlapped_to_req(overlapped);
+ uv_insert_pending_req(loop, req);
+
+ /* Some time might have passed waiting for I/O,
+ * so update the loop time here.
+ */
+ uv_update_time(loop);
+ } else if (GetLastError() != WAIT_TIMEOUT) {
+ /* Serious error */
+ uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
+ } else if (timeout > 0) {
+ /* GetQueuedCompletionStatus can occasionally return a little early.
+ * Make sure that the desired timeout is reflected in the loop time.
+ */
+ uv__time_forward(loop, timeout);
+ }
+}
+
+
+static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) {
+ BOOL success;
+ uv_req_t* req;
+ OVERLAPPED_ENTRY overlappeds[128];
+ ULONG count;
+ ULONG i;
+
+ success = pGetQueuedCompletionStatusEx(loop->iocp,
+ overlappeds,
+ ARRAY_SIZE(overlappeds),
+ &count,
+ timeout,
+ FALSE);
+
+ if (success) {
+ for (i = 0; i < count; i++) {
+ /* Package was dequeued */
+ req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
+ uv_insert_pending_req(loop, req);
+ }
+
+ /* Some time might have passed waiting for I/O,
+ * so update the loop time here.
+ */
+ uv_update_time(loop);
+ } else if (GetLastError() != WAIT_TIMEOUT) {
+ /* Serious error */
+ uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx");
+ } else if (timeout > 0) {
+ /* GetQueuedCompletionStatus can occasionally return a little early.
+ * Make sure that the desired timeout is reflected in the loop time.
+ */
+ uv__time_forward(loop, timeout);
+ }
+}
+
+
+static int uv__loop_alive(const uv_loop_t* loop) {
+ return loop->active_handles > 0 ||
+ !QUEUE_EMPTY(&loop->active_reqs) ||
+ loop->endgame_handles != NULL;
+}
+
+
+int uv_loop_alive(const uv_loop_t* loop) {
+ return uv__loop_alive(loop);
+}
+
+
+int uv_run(uv_loop_t *loop, uv_run_mode mode) {
+ DWORD timeout;
+ int r;
+ int ran_pending;
+ void (*poll)(uv_loop_t* loop, DWORD timeout);
+
+ if (pGetQueuedCompletionStatusEx)
+ poll = &uv_poll_ex;
+ else
+ poll = &uv_poll;
+
+ r = uv__loop_alive(loop);
+ if (!r)
+ uv_update_time(loop);
+
+ while (r != 0 && loop->stop_flag == 0) {
+ uv_update_time(loop);
+ uv_process_timers(loop);
+
+ ran_pending = uv_process_reqs(loop);
+ uv_idle_invoke(loop);
+ uv_prepare_invoke(loop);
+
+ timeout = 0;
+ if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
+ timeout = uv_backend_timeout(loop);
+
+ (*poll)(loop, timeout);
+
+ uv_check_invoke(loop);
+ uv_process_endgames(loop);
+
+ if (mode == UV_RUN_ONCE) {
+ /* UV_RUN_ONCE implies forward progress: at least one callback must have
+ * been invoked when it returns. uv__io_poll() can return without doing
+ * I/O (meaning: no callbacks) when its timeout expires - which means we
+ * have pending timers that satisfy the forward progress constraint.
+ *
+ * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
+ * the check.
+ */
+ uv_process_timers(loop);
+ }
+
+ r = uv__loop_alive(loop);
+ if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
+ break;
+ }
+
+ /* The if statement lets the compiler compile it to a conditional store.
+ * Avoids dirtying a cache line.
+ */
+ if (loop->stop_flag != 0)
+ loop->stop_flag = 0;
+
+ return r;
+}
+
+
+int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
+ uv_os_fd_t fd_out;
+
+ switch (handle->type) {
+ case UV_TCP:
+ fd_out = (uv_os_fd_t)((uv_tcp_t*) handle)->socket;
+ break;
+
+ case UV_NAMED_PIPE:
+ fd_out = ((uv_pipe_t*) handle)->handle;
+ break;
+
+ case UV_TTY:
+ fd_out = ((uv_tty_t*) handle)->handle;
+ break;
+
+ case UV_UDP:
+ fd_out = (uv_os_fd_t)((uv_udp_t*) handle)->socket;
+ break;
+
+ case UV_POLL:
+ fd_out = (uv_os_fd_t)((uv_poll_t*) handle)->socket;
+ break;
+
+ default:
+ return UV_EINVAL;
+ }
+
+ if (uv_is_closing(handle) || fd_out == INVALID_HANDLE_VALUE)
+ return UV_EBADF;
+
+ *fd = fd_out;
+ return 0;
+}
+
+
+int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
+ int r;
+ int len;
+ SOCKET socket;
+
+ if (handle == NULL || value == NULL)
+ return UV_EINVAL;
+
+ if (handle->type == UV_TCP)
+ socket = ((uv_tcp_t*) handle)->socket;
+ else if (handle->type == UV_UDP)
+ socket = ((uv_udp_t*) handle)->socket;
+ else
+ return UV_ENOTSUP;
+
+ len = sizeof(*value);
+
+ if (*value == 0)
+ r = getsockopt(socket, SOL_SOCKET, optname, (char*) value, &len);
+ else
+ r = setsockopt(socket, SOL_SOCKET, optname, (const char*) value, len);
+
+ if (r == SOCKET_ERROR)
+ return uv_translate_sys_error(WSAGetLastError());
+
+ return 0;
+}
diff --git a/3rdparty/libuv/src/win/dl.c b/3rdparty/libuv/src/win/dl.c
new file mode 100644
index 00000000000..e5f3407f8eb
--- /dev/null
+++ b/3rdparty/libuv/src/win/dl.c
@@ -0,0 +1,113 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+static int uv__dlerror(uv_lib_t* lib, int errorno);
+
+
+int uv_dlopen(const char* filename, uv_lib_t* lib) {
+ WCHAR filename_w[32768];
+
+ lib->handle = NULL;
+ lib->errmsg = NULL;
+
+ if (!uv_utf8_to_utf16(filename, filename_w, ARRAY_SIZE(filename_w))) {
+ return uv__dlerror(lib, GetLastError());
+ }
+
+ lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (lib->handle == NULL) {
+ return uv__dlerror(lib, GetLastError());
+ }
+
+ return 0;
+}
+
+
+void uv_dlclose(uv_lib_t* lib) {
+ if (lib->errmsg) {
+ LocalFree((void*)lib->errmsg);
+ lib->errmsg = NULL;
+ }
+
+ if (lib->handle) {
+ /* Ignore errors. No good way to signal them without leaking memory. */
+ FreeLibrary(lib->handle);
+ lib->handle = NULL;
+ }
+}
+
+
+int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
+ *ptr = (void*) GetProcAddress(lib->handle, name);
+ return uv__dlerror(lib, *ptr ? 0 : GetLastError());
+}
+
+
+const char* uv_dlerror(const uv_lib_t* lib) {
+ return lib->errmsg ? lib->errmsg : "no error";
+}
+
+
+static void uv__format_fallback_error(uv_lib_t* lib, int errorno){
+ DWORD_PTR args[1] = { (DWORD_PTR) errorno };
+ LPSTR fallback_error = "error: %1!d!";
+
+ FormatMessageA(FORMAT_MESSAGE_FROM_STRING |
+ FORMAT_MESSAGE_ARGUMENT_ARRAY |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ fallback_error, 0, 0,
+ (LPSTR) &lib->errmsg,
+ 0, (va_list*) args);
+}
+
+
+
+static int uv__dlerror(uv_lib_t* lib, int errorno) {
+ DWORD res;
+
+ if (lib->errmsg) {
+ LocalFree((void*)lib->errmsg);
+ lib->errmsg = NULL;
+ }
+
+ if (errorno) {
+ res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+ (LPSTR) &lib->errmsg, 0, NULL);
+ if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) {
+ res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
+ 0, (LPSTR) &lib->errmsg, 0, NULL);
+ }
+
+ if (!res) {
+ uv__format_fallback_error(lib, errorno);
+ }
+ }
+
+ return errorno ? -1 : 0;
+}
diff --git a/3rdparty/libuv/src/win/error.c b/3rdparty/libuv/src/win/error.c
new file mode 100644
index 00000000000..c512f35af97
--- /dev/null
+++ b/3rdparty/libuv/src/win/error.c
@@ -0,0 +1,170 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+/*
+ * Display an error message and abort the event loop.
+ */
+void uv_fatal_error(const int errorno, const char* syscall) {
+ char* buf = NULL;
+ const char* errmsg;
+
+ FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL);
+
+ if (buf) {
+ errmsg = buf;
+ } else {
+ errmsg = "Unknown error";
+ }
+
+ /* FormatMessage messages include a newline character already, */
+ /* so don't add another. */
+ if (syscall) {
+ fprintf(stderr, "%s: (%d) %s", syscall, errorno, errmsg);
+ } else {
+ fprintf(stderr, "(%d) %s", errorno, errmsg);
+ }
+
+ if (buf) {
+ LocalFree(buf);
+ }
+
+ *((char*)NULL) = 0xff; /* Force debug break */
+ abort();
+}
+
+
+int uv_translate_sys_error(int sys_errno) {
+ if (sys_errno <= 0) {
+ return sys_errno; /* If < 0 then it's already a libuv error. */
+ }
+
+ switch (sys_errno) {
+ case ERROR_NOACCESS: return UV_EACCES;
+ case WSAEACCES: return UV_EACCES;
+ case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
+ case WSAEADDRINUSE: return UV_EADDRINUSE;
+ case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
+ case WSAEAFNOSUPPORT: return UV_EAFNOSUPPORT;
+ case WSAEWOULDBLOCK: return UV_EAGAIN;
+ case WSAEALREADY: return UV_EALREADY;
+ case ERROR_INVALID_FLAGS: return UV_EBADF;
+ case ERROR_INVALID_HANDLE: return UV_EBADF;
+ case ERROR_LOCK_VIOLATION: return UV_EBUSY;
+ case ERROR_PIPE_BUSY: return UV_EBUSY;
+ case ERROR_SHARING_VIOLATION: return UV_EBUSY;
+ case ERROR_OPERATION_ABORTED: return UV_ECANCELED;
+ case WSAEINTR: return UV_ECANCELED;
+ case ERROR_NO_UNICODE_TRANSLATION: return UV_ECHARSET;
+ case ERROR_CONNECTION_ABORTED: return UV_ECONNABORTED;
+ case WSAECONNABORTED: return UV_ECONNABORTED;
+ case ERROR_CONNECTION_REFUSED: return UV_ECONNREFUSED;
+ case WSAECONNREFUSED: return UV_ECONNREFUSED;
+ case ERROR_NETNAME_DELETED: return UV_ECONNRESET;
+ case WSAECONNRESET: return UV_ECONNRESET;
+ case ERROR_ALREADY_EXISTS: return UV_EEXIST;
+ case ERROR_FILE_EXISTS: return UV_EEXIST;
+ case ERROR_BUFFER_OVERFLOW: return UV_EFAULT;
+ case WSAEFAULT: return UV_EFAULT;
+ case ERROR_HOST_UNREACHABLE: return UV_EHOSTUNREACH;
+ case WSAEHOSTUNREACH: return UV_EHOSTUNREACH;
+ case ERROR_INSUFFICIENT_BUFFER: return UV_EINVAL;
+ case ERROR_INVALID_DATA: return UV_EINVAL;
+ case ERROR_INVALID_PARAMETER: return UV_EINVAL;
+ case ERROR_SYMLINK_NOT_SUPPORTED: return UV_EINVAL;
+ case WSAEINVAL: return UV_EINVAL;
+ case WSAEPFNOSUPPORT: return UV_EINVAL;
+ case WSAESOCKTNOSUPPORT: return UV_EINVAL;
+ case ERROR_BEGINNING_OF_MEDIA: return UV_EIO;
+ case ERROR_BUS_RESET: return UV_EIO;
+ case ERROR_CRC: return UV_EIO;
+ case ERROR_DEVICE_DOOR_OPEN: return UV_EIO;
+ case ERROR_DEVICE_REQUIRES_CLEANING: return UV_EIO;
+ case ERROR_DISK_CORRUPT: return UV_EIO;
+ case ERROR_EOM_OVERFLOW: return UV_EIO;
+ case ERROR_FILEMARK_DETECTED: return UV_EIO;
+ case ERROR_GEN_FAILURE: return UV_EIO;
+ case ERROR_INVALID_BLOCK_LENGTH: return UV_EIO;
+ case ERROR_IO_DEVICE: return UV_EIO;
+ case ERROR_NO_DATA_DETECTED: return UV_EIO;
+ case ERROR_NO_SIGNAL_SENT: return UV_EIO;
+ case ERROR_OPEN_FAILED: return UV_EIO;
+ case ERROR_SETMARK_DETECTED: return UV_EIO;
+ case ERROR_SIGNAL_REFUSED: return UV_EIO;
+ case WSAEISCONN: return UV_EISCONN;
+ case ERROR_CANT_RESOLVE_FILENAME: return UV_ELOOP;
+ case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE;
+ case WSAEMFILE: return UV_EMFILE;
+ case WSAEMSGSIZE: return UV_EMSGSIZE;
+ case ERROR_FILENAME_EXCED_RANGE: return UV_ENAMETOOLONG;
+ case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH;
+ case WSAENETUNREACH: return UV_ENETUNREACH;
+ case WSAENOBUFS: return UV_ENOBUFS;
+ case ERROR_BAD_PATHNAME: return UV_ENOENT;
+ case ERROR_DIRECTORY: return UV_ENOENT;
+ case ERROR_FILE_NOT_FOUND: return UV_ENOENT;
+ case ERROR_INVALID_NAME: return UV_ENOENT;
+ case ERROR_INVALID_DRIVE: return UV_ENOENT;
+ case ERROR_INVALID_REPARSE_DATA: return UV_ENOENT;
+ case ERROR_MOD_NOT_FOUND: return UV_ENOENT;
+ case ERROR_PATH_NOT_FOUND: return UV_ENOENT;
+ case WSAHOST_NOT_FOUND: return UV_ENOENT;
+ case WSANO_DATA: return UV_ENOENT;
+ case ERROR_NOT_ENOUGH_MEMORY: return UV_ENOMEM;
+ case ERROR_OUTOFMEMORY: return UV_ENOMEM;
+ case ERROR_CANNOT_MAKE: return UV_ENOSPC;
+ case ERROR_DISK_FULL: return UV_ENOSPC;
+ case ERROR_EA_TABLE_FULL: return UV_ENOSPC;
+ case ERROR_END_OF_MEDIA: return UV_ENOSPC;
+ case ERROR_HANDLE_DISK_FULL: return UV_ENOSPC;
+ case ERROR_NOT_CONNECTED: return UV_ENOTCONN;
+ case WSAENOTCONN: return UV_ENOTCONN;
+ case ERROR_DIR_NOT_EMPTY: return UV_ENOTEMPTY;
+ case WSAENOTSOCK: return UV_ENOTSOCK;
+ case ERROR_NOT_SUPPORTED: return UV_ENOTSUP;
+ case ERROR_BROKEN_PIPE: return UV_EOF;
+ case ERROR_ACCESS_DENIED: return UV_EPERM;
+ case ERROR_PRIVILEGE_NOT_HELD: return UV_EPERM;
+ case ERROR_BAD_PIPE: return UV_EPIPE;
+ case ERROR_NO_DATA: return UV_EPIPE;
+ case ERROR_PIPE_NOT_CONNECTED: return UV_EPIPE;
+ case WSAESHUTDOWN: return UV_EPIPE;
+ case WSAEPROTONOSUPPORT: return UV_EPROTONOSUPPORT;
+ case ERROR_WRITE_PROTECT: return UV_EROFS;
+ case ERROR_SEM_TIMEOUT: return UV_ETIMEDOUT;
+ case WSAETIMEDOUT: return UV_ETIMEDOUT;
+ case ERROR_NOT_SAME_DEVICE: return UV_EXDEV;
+ case ERROR_INVALID_FUNCTION: return UV_EISDIR;
+ case ERROR_META_EXPANSION_TOO_LONG: return UV_E2BIG;
+ default: return UV_UNKNOWN;
+ }
+}
diff --git a/3rdparty/libuv/src/win/fs-event.c b/3rdparty/libuv/src/win/fs-event.c
new file mode 100644
index 00000000000..76ecfebaa24
--- /dev/null
+++ b/3rdparty/libuv/src/win/fs-event.c
@@ -0,0 +1,552 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+const unsigned int uv_directory_watcher_buffer_size = 4096;
+
+
+static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
+ uv_fs_event_t* handle) {
+ assert(handle->dir_handle != INVALID_HANDLE_VALUE);
+ assert(!handle->req_pending);
+
+ memset(&(handle->req.u.io.overlapped), 0,
+ sizeof(handle->req.u.io.overlapped));
+ if (!ReadDirectoryChangesW(handle->dir_handle,
+ handle->buffer,
+ uv_directory_watcher_buffer_size,
+ (handle->flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
+ FILE_NOTIFY_CHANGE_FILE_NAME |
+ FILE_NOTIFY_CHANGE_DIR_NAME |
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
+ FILE_NOTIFY_CHANGE_SIZE |
+ FILE_NOTIFY_CHANGE_LAST_WRITE |
+ FILE_NOTIFY_CHANGE_LAST_ACCESS |
+ FILE_NOTIFY_CHANGE_CREATION |
+ FILE_NOTIFY_CHANGE_SECURITY,
+ NULL,
+ &handle->req.u.io.overlapped,
+ NULL)) {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(&handle->req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)&handle->req);
+ }
+
+ handle->req_pending = 1;
+}
+
+static int uv_relative_path(const WCHAR* filename,
+ const WCHAR* dir,
+ WCHAR** relpath) {
+ int dirlen = wcslen(dir);
+ int filelen = wcslen(filename);
+ if (dir[dirlen - 1] == '\\')
+ dirlen--;
+ *relpath = uv__malloc((MAX_PATH + 1) * sizeof(WCHAR));
+ if (!*relpath)
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ wcsncpy(*relpath, filename + dirlen + 1, filelen - dirlen - 1);
+ (*relpath)[filelen - dirlen - 1] = L'\0';
+ return 0;
+}
+
+static int uv_split_path(const WCHAR* filename, WCHAR** dir,
+ WCHAR** file) {
+ int len = wcslen(filename);
+ int i = len;
+ while (i > 0 && filename[--i] != '\\' && filename[i] != '/');
+
+ if (i == 0) {
+ if (dir) {
+ *dir = (WCHAR*)uv__malloc((MAX_PATH + 1) * sizeof(WCHAR));
+ if (!*dir) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ if (!GetCurrentDirectoryW(MAX_PATH, *dir)) {
+ uv__free(*dir);
+ *dir = NULL;
+ return -1;
+ }
+ }
+
+ *file = wcsdup(filename);
+ } else {
+ if (dir) {
+ *dir = (WCHAR*)uv__malloc((i + 1) * sizeof(WCHAR));
+ if (!*dir) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+ wcsncpy(*dir, filename, i);
+ (*dir)[i] = L'\0';
+ }
+
+ *file = (WCHAR*)uv__malloc((len - i) * sizeof(WCHAR));
+ if (!*file) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+ wcsncpy(*file, filename + i + 1, len - i - 1);
+ (*file)[len - i - 1] = L'\0';
+ }
+
+ return 0;
+}
+
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_FS_EVENT);
+ handle->dir_handle = INVALID_HANDLE_VALUE;
+ handle->buffer = NULL;
+ handle->req_pending = 0;
+ handle->filew = NULL;
+ handle->short_filew = NULL;
+ handle->dirw = NULL;
+
+ uv_req_init(loop, (uv_req_t*)&handle->req);
+ handle->req.type = UV_FS_EVENT_REQ;
+ handle->req.data = handle;
+
+ return 0;
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* path,
+ unsigned int flags) {
+ int name_size, is_path_dir;
+ DWORD attr, last_error;
+ WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL;
+ WCHAR short_path[MAX_PATH];
+
+ if (uv__is_active(handle))
+ return UV_EINVAL;
+
+ handle->cb = cb;
+ handle->path = uv__strdup(path);
+ if (!handle->path) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ uv__handle_start(handle);
+
+ /* Convert name to UTF16. */
+ name_size = uv_utf8_to_utf16(path, NULL, 0) * sizeof(WCHAR);
+ pathw = (WCHAR*)uv__malloc(name_size);
+ if (!pathw) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ if (!uv_utf8_to_utf16(path, pathw,
+ name_size / sizeof(WCHAR))) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ /* Determine whether path is a file or a directory. */
+ attr = GetFileAttributesW(pathw);
+ if (attr == INVALID_FILE_ATTRIBUTES) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
+
+ if (is_path_dir) {
+ /* path is a directory, so that's the directory that we will watch. */
+ handle->dirw = pathw;
+ dir_to_watch = pathw;
+ } else {
+ /*
+ * path is a file. So we split path into dir & file parts, and
+ * watch the dir directory.
+ */
+
+ /* Convert to short path. */
+ if (!GetShortPathNameW(pathw, short_path, ARRAY_SIZE(short_path))) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ if (uv_split_path(pathw, &dir, &handle->filew) != 0) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ if (uv_split_path(short_path, NULL, &handle->short_filew) != 0) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ dir_to_watch = dir;
+ uv__free(pathw);
+ pathw = NULL;
+ }
+
+ handle->dir_handle = CreateFileW(dir_to_watch,
+ FILE_LIST_DIRECTORY,
+ FILE_SHARE_READ | FILE_SHARE_DELETE |
+ FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS |
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ if (dir) {
+ uv__free(dir);
+ dir = NULL;
+ }
+
+ if (handle->dir_handle == INVALID_HANDLE_VALUE) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ if (CreateIoCompletionPort(handle->dir_handle,
+ handle->loop->iocp,
+ (ULONG_PTR)handle,
+ 0) == NULL) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ if (!handle->buffer) {
+ handle->buffer = (char*)uv__malloc(uv_directory_watcher_buffer_size);
+ }
+ if (!handle->buffer) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ memset(&(handle->req.u.io.overlapped), 0,
+ sizeof(handle->req.u.io.overlapped));
+
+ if (!ReadDirectoryChangesW(handle->dir_handle,
+ handle->buffer,
+ uv_directory_watcher_buffer_size,
+ (flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
+ FILE_NOTIFY_CHANGE_FILE_NAME |
+ FILE_NOTIFY_CHANGE_DIR_NAME |
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
+ FILE_NOTIFY_CHANGE_SIZE |
+ FILE_NOTIFY_CHANGE_LAST_WRITE |
+ FILE_NOTIFY_CHANGE_LAST_ACCESS |
+ FILE_NOTIFY_CHANGE_CREATION |
+ FILE_NOTIFY_CHANGE_SECURITY,
+ NULL,
+ &handle->req.u.io.overlapped,
+ NULL)) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ handle->req_pending = 1;
+ return 0;
+
+error:
+ if (handle->path) {
+ uv__free(handle->path);
+ handle->path = NULL;
+ }
+
+ if (handle->filew) {
+ uv__free(handle->filew);
+ handle->filew = NULL;
+ }
+
+ if (handle->short_filew) {
+ uv__free(handle->short_filew);
+ handle->short_filew = NULL;
+ }
+
+ uv__free(pathw);
+
+ if (handle->dir_handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle->dir_handle);
+ handle->dir_handle = INVALID_HANDLE_VALUE;
+ }
+
+ if (handle->buffer) {
+ uv__free(handle->buffer);
+ handle->buffer = NULL;
+ }
+
+ return uv_translate_sys_error(last_error);
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+ if (!uv__is_active(handle))
+ return 0;
+
+ if (handle->dir_handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle->dir_handle);
+ handle->dir_handle = INVALID_HANDLE_VALUE;
+ }
+
+ uv__handle_stop(handle);
+
+ if (handle->filew) {
+ uv__free(handle->filew);
+ handle->filew = NULL;
+ }
+
+ if (handle->short_filew) {
+ uv__free(handle->short_filew);
+ handle->short_filew = NULL;
+ }
+
+ if (handle->path) {
+ uv__free(handle->path);
+ handle->path = NULL;
+ }
+
+ if (handle->dirw) {
+ uv__free(handle->dirw);
+ handle->dirw = NULL;
+ }
+
+ return 0;
+}
+
+
+void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
+ uv_fs_event_t* handle) {
+ FILE_NOTIFY_INFORMATION* file_info;
+ int err, sizew, size, result;
+ char* filename = NULL;
+ WCHAR* filenamew, *long_filenamew = NULL;
+ DWORD offset = 0;
+
+ assert(req->type == UV_FS_EVENT_REQ);
+ assert(handle->req_pending);
+ handle->req_pending = 0;
+
+ /* Don't report any callbacks if:
+ * - We're closing, just push the handle onto the endgame queue
+ * - We are not active, just ignore the callback
+ */
+ if (!uv__is_active(handle)) {
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+ return;
+ }
+
+ file_info = (FILE_NOTIFY_INFORMATION*)(handle->buffer + offset);
+
+ if (REQ_SUCCESS(req)) {
+ if (req->u.io.overlapped.InternalHigh > 0) {
+ do {
+ file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset);
+ assert(!filename);
+ assert(!long_filenamew);
+
+ /*
+ * Fire the event only if we were asked to watch a directory,
+ * or if the filename filter matches.
+ */
+ if (handle->dirw ||
+ _wcsnicmp(handle->filew, file_info->FileName,
+ file_info->FileNameLength / sizeof(WCHAR)) == 0 ||
+ _wcsnicmp(handle->short_filew, file_info->FileName,
+ file_info->FileNameLength / sizeof(WCHAR)) == 0) {
+
+ if (handle->dirw) {
+ /*
+ * We attempt to resolve the long form of the file name explicitly.
+ * We only do this for file names that might still exist on disk.
+ * If this fails, we use the name given by ReadDirectoryChangesW.
+ * This may be the long form or the 8.3 short name in some cases.
+ */
+ if (file_info->Action != FILE_ACTION_REMOVED &&
+ file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) {
+ /* Construct a full path to the file. */
+ size = wcslen(handle->dirw) +
+ file_info->FileNameLength / sizeof(WCHAR) + 2;
+
+ filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
+ if (!filenamew) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ _snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw,
+ file_info->FileNameLength / sizeof(WCHAR),
+ file_info->FileName);
+
+ filenamew[size - 1] = L'\0';
+
+ /* Convert to long name. */
+ size = GetLongPathNameW(filenamew, NULL, 0);
+
+ if (size) {
+ long_filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
+ if (!long_filenamew) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ size = GetLongPathNameW(filenamew, long_filenamew, size);
+ if (size) {
+ long_filenamew[size] = '\0';
+ } else {
+ uv__free(long_filenamew);
+ long_filenamew = NULL;
+ }
+ }
+
+ uv__free(filenamew);
+
+ if (long_filenamew) {
+ /* Get the file name out of the long path. */
+ result = uv_relative_path(long_filenamew,
+ handle->dirw,
+ &filenamew);
+ uv__free(long_filenamew);
+
+ if (result == 0) {
+ long_filenamew = filenamew;
+ sizew = -1;
+ } else {
+ long_filenamew = NULL;
+ }
+ }
+
+ /*
+ * We could not resolve the long form explicitly.
+ * We therefore use the name given by ReadDirectoryChangesW.
+ * This may be the long form or the 8.3 short name in some cases.
+ */
+ if (!long_filenamew) {
+ filenamew = file_info->FileName;
+ sizew = file_info->FileNameLength / sizeof(WCHAR);
+ }
+ } else {
+ /*
+ * Removed or renamed events cannot be resolved to the long form.
+ * We therefore use the name given by ReadDirectoryChangesW.
+ * This may be the long form or the 8.3 short name in some cases.
+ */
+ if (!long_filenamew) {
+ filenamew = file_info->FileName;
+ sizew = file_info->FileNameLength / sizeof(WCHAR);
+ }
+ }
+ } else {
+ /* We already have the long name of the file, so just use it. */
+ filenamew = handle->filew;
+ sizew = -1;
+ }
+
+ if (filenamew) {
+ /* Convert the filename to utf8. */
+ size = uv_utf16_to_utf8(filenamew,
+ sizew,
+ NULL,
+ 0);
+ if (size) {
+ filename = (char*)uv__malloc(size + 1);
+ if (!filename) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ size = uv_utf16_to_utf8(filenamew,
+ sizew,
+ filename,
+ size);
+ if (size) {
+ filename[size] = '\0';
+ } else {
+ uv__free(filename);
+ filename = NULL;
+ }
+ }
+ }
+
+ switch (file_info->Action) {
+ case FILE_ACTION_ADDED:
+ case FILE_ACTION_REMOVED:
+ case FILE_ACTION_RENAMED_OLD_NAME:
+ case FILE_ACTION_RENAMED_NEW_NAME:
+ handle->cb(handle, filename, UV_RENAME, 0);
+ break;
+
+ case FILE_ACTION_MODIFIED:
+ handle->cb(handle, filename, UV_CHANGE, 0);
+ break;
+ }
+
+ uv__free(filename);
+ filename = NULL;
+ uv__free(long_filenamew);
+ long_filenamew = NULL;
+ }
+
+ offset = file_info->NextEntryOffset;
+ } while (offset && !(handle->flags & UV__HANDLE_CLOSING));
+ } else {
+ handle->cb(handle, NULL, UV_CHANGE, 0);
+ }
+ } else {
+ err = GET_REQ_ERROR(req);
+ handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
+ }
+
+ if (!(handle->flags & UV__HANDLE_CLOSING)) {
+ uv_fs_event_queue_readdirchanges(loop, handle);
+ } else {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+}
+
+
+void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) {
+ uv_fs_event_stop(handle);
+
+ uv__handle_closing(handle);
+
+ if (!handle->req_pending) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+
+}
+
+
+void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
+ if ((handle->flags & UV__HANDLE_CLOSING) && !handle->req_pending) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ if (handle->buffer) {
+ uv__free(handle->buffer);
+ handle->buffer = NULL;
+ }
+
+ uv__handle_close(handle);
+ }
+}
diff --git a/3rdparty/libuv/src/win/fs.c b/3rdparty/libuv/src/win/fs.c
new file mode 100644
index 00000000000..a32b0127f7e
--- /dev/null
+++ b/3rdparty/libuv/src/win/fs.c
@@ -0,0 +1,2468 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <direct.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <io.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/utime.h>
+#include <stdio.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "req-inl.h"
+#include "handle-inl.h"
+
+#include <wincrypt.h>
+
+
+#define UV_FS_FREE_PATHS 0x0002
+#define UV_FS_FREE_PTR 0x0008
+#define UV_FS_CLEANEDUP 0x0010
+
+
+#define QUEUE_FS_TP_JOB(loop, req) \
+ do { \
+ uv__req_register(loop, req); \
+ uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done); \
+ } while (0)
+
+#define SET_REQ_RESULT(req, result_value) \
+ do { \
+ req->result = (result_value); \
+ if (req->result == -1) { \
+ req->sys_errno_ = _doserrno; \
+ req->result = uv_translate_sys_error(req->sys_errno_); \
+ } \
+ } while (0)
+
+#define SET_REQ_WIN32_ERROR(req, sys_errno) \
+ do { \
+ req->sys_errno_ = (sys_errno); \
+ req->result = uv_translate_sys_error(req->sys_errno_); \
+ } while (0)
+
+#define SET_REQ_UV_ERROR(req, uv_errno, sys_errno) \
+ do { \
+ req->result = (uv_errno); \
+ req->sys_errno_ = (sys_errno); \
+ } while (0)
+
+#define VERIFY_FD(fd, req) \
+ if (fd == -1) { \
+ req->result = UV_EBADF; \
+ req->sys_errno_ = ERROR_INVALID_HANDLE; \
+ return; \
+ }
+
+#define FILETIME_TO_UINT(filetime) \
+ (*((uint64_t*) &(filetime)) - 116444736000000000ULL)
+
+#define FILETIME_TO_TIME_T(filetime) \
+ (FILETIME_TO_UINT(filetime) / 10000000ULL)
+
+#define FILETIME_TO_TIME_NS(filetime, secs) \
+ ((FILETIME_TO_UINT(filetime) - (secs * 10000000ULL)) * 100)
+
+#define FILETIME_TO_TIMESPEC(ts, filetime) \
+ do { \
+ (ts).tv_sec = (long) FILETIME_TO_TIME_T(filetime); \
+ (ts).tv_nsec = (long) FILETIME_TO_TIME_NS(filetime, (ts).tv_sec); \
+ } while(0)
+
+#define TIME_T_TO_FILETIME(time, filetime_ptr) \
+ do { \
+ uint64_t bigtime = ((int64_t) (time) * 10000000LL) + \
+ 116444736000000000ULL; \
+ (filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \
+ (filetime_ptr)->dwHighDateTime = bigtime >> 32; \
+ } while(0)
+
+#define IS_SLASH(c) ((c) == L'\\' || (c) == L'/')
+#define IS_LETTER(c) (((c) >= L'a' && (c) <= L'z') || \
+ ((c) >= L'A' && (c) <= L'Z'))
+
+const WCHAR JUNCTION_PREFIX[] = L"\\??\\";
+const WCHAR JUNCTION_PREFIX_LEN = 4;
+
+const WCHAR LONG_PATH_PREFIX[] = L"\\\\?\\";
+const WCHAR LONG_PATH_PREFIX_LEN = 4;
+
+const WCHAR UNC_PATH_PREFIX[] = L"\\\\?\\UNC\\";
+const WCHAR UNC_PATH_PREFIX_LEN = 8;
+
+
+void uv_fs_init() {
+ _fmode = _O_BINARY;
+}
+
+
+INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
+ const char* new_path, const int copy_path) {
+ char* buf;
+ char* pos;
+ ssize_t buf_sz = 0, path_len, pathw_len = 0, new_pathw_len = 0;
+
+ /* new_path can only be set if path is also set. */
+ assert(new_path == NULL || path != NULL);
+
+ if (path != NULL) {
+ pathw_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ path,
+ -1,
+ NULL,
+ 0);
+ if (pathw_len == 0) {
+ return GetLastError();
+ }
+
+ buf_sz += pathw_len * sizeof(WCHAR);
+ }
+
+ if (path != NULL && copy_path) {
+ path_len = 1 + strlen(path);
+ buf_sz += path_len;
+ }
+
+ if (new_path != NULL) {
+ new_pathw_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ new_path,
+ -1,
+ NULL,
+ 0);
+ if (new_pathw_len == 0) {
+ return GetLastError();
+ }
+
+ buf_sz += new_pathw_len * sizeof(WCHAR);
+ }
+
+
+ if (buf_sz == 0) {
+ req->file.pathw = NULL;
+ req->fs.info.new_pathw = NULL;
+ req->path = NULL;
+ return 0;
+ }
+
+ buf = (char*) uv__malloc(buf_sz);
+ if (buf == NULL) {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ pos = buf;
+
+ if (path != NULL) {
+ DWORD r = MultiByteToWideChar(CP_UTF8,
+ 0,
+ path,
+ -1,
+ (WCHAR*) pos,
+ pathw_len);
+ assert(r == (DWORD) pathw_len);
+ req->file.pathw = (WCHAR*) pos;
+ pos += r * sizeof(WCHAR);
+ } else {
+ req->file.pathw = NULL;
+ }
+
+ if (new_path != NULL) {
+ DWORD r = MultiByteToWideChar(CP_UTF8,
+ 0,
+ new_path,
+ -1,
+ (WCHAR*) pos,
+ new_pathw_len);
+ assert(r == (DWORD) new_pathw_len);
+ req->fs.info.new_pathw = (WCHAR*) pos;
+ pos += r * sizeof(WCHAR);
+ } else {
+ req->fs.info.new_pathw = NULL;
+ }
+
+ if (!copy_path) {
+ req->path = path;
+ } else if (path) {
+ memcpy(pos, path, path_len);
+ assert(path_len == buf_sz - (pos - buf));
+ req->path = pos;
+ } else {
+ req->path = NULL;
+ }
+
+ req->flags |= UV_FS_FREE_PATHS;
+
+ return 0;
+}
+
+
+
+INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req,
+ uv_fs_type fs_type, const uv_fs_cb cb) {
+ uv_req_init(loop, (uv_req_t*) req);
+
+ req->type = UV_FS;
+ req->loop = loop;
+ req->flags = 0;
+ req->fs_type = fs_type;
+ req->result = 0;
+ req->ptr = NULL;
+ req->path = NULL;
+ req->cb = cb;
+}
+
+
+static int fs__wide_to_utf8(WCHAR* w_source_ptr,
+ DWORD w_source_len,
+ char** target_ptr,
+ uint64_t* target_len_ptr) {
+ int r;
+ int target_len;
+ char* target;
+ target_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ w_source_ptr,
+ w_source_len,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+
+ if (target_len == 0) {
+ return -1;
+ }
+
+ if (target_len_ptr != NULL) {
+ *target_len_ptr = target_len;
+ }
+
+ if (target_ptr == NULL) {
+ return 0;
+ }
+
+ target = uv__malloc(target_len + 1);
+ if (target == NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return -1;
+ }
+
+ r = WideCharToMultiByte(CP_UTF8,
+ 0,
+ w_source_ptr,
+ w_source_len,
+ target,
+ target_len,
+ NULL,
+ NULL);
+ assert(r == target_len);
+ target[target_len] = '\0';
+ *target_ptr = target;
+ return 0;
+}
+
+
+INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
+ uint64_t* target_len_ptr) {
+ char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+ REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer;
+ WCHAR* w_target;
+ DWORD w_target_len;
+ DWORD bytes;
+
+ if (!DeviceIoControl(handle,
+ FSCTL_GET_REPARSE_POINT,
+ NULL,
+ 0,
+ buffer,
+ sizeof buffer,
+ &bytes,
+ NULL)) {
+ return -1;
+ }
+
+ if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
+ /* Real symlink */
+ w_target = reparse_data->SymbolicLinkReparseBuffer.PathBuffer +
+ (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset /
+ sizeof(WCHAR));
+ w_target_len =
+ reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength /
+ sizeof(WCHAR);
+
+ /* Real symlinks can contain pretty much everything, but the only thing */
+ /* we really care about is undoing the implicit conversion to an NT */
+ /* namespaced path that CreateSymbolicLink will perform on absolute */
+ /* paths. If the path is win32-namespaced then the user must have */
+ /* explicitly made it so, and we better just return the unmodified */
+ /* reparse data. */
+ if (w_target_len >= 4 &&
+ w_target[0] == L'\\' &&
+ w_target[1] == L'?' &&
+ w_target[2] == L'?' &&
+ w_target[3] == L'\\') {
+ /* Starts with \??\ */
+ if (w_target_len >= 6 &&
+ ((w_target[4] >= L'A' && w_target[4] <= L'Z') ||
+ (w_target[4] >= L'a' && w_target[4] <= L'z')) &&
+ w_target[5] == L':' &&
+ (w_target_len == 6 || w_target[6] == L'\\')) {
+ /* \??\<drive>:\ */
+ w_target += 4;
+ w_target_len -= 4;
+
+ } else if (w_target_len >= 8 &&
+ (w_target[4] == L'U' || w_target[4] == L'u') &&
+ (w_target[5] == L'N' || w_target[5] == L'n') &&
+ (w_target[6] == L'C' || w_target[6] == L'c') &&
+ w_target[7] == L'\\') {
+ /* \??\UNC\<server>\<share>\ - make sure the final path looks like */
+ /* \\<server>\<share>\ */
+ w_target += 6;
+ w_target[0] = L'\\';
+ w_target_len -= 6;
+ }
+ }
+
+ } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
+ /* Junction. */
+ w_target = reparse_data->MountPointReparseBuffer.PathBuffer +
+ (reparse_data->MountPointReparseBuffer.SubstituteNameOffset /
+ sizeof(WCHAR));
+ w_target_len = reparse_data->MountPointReparseBuffer.SubstituteNameLength /
+ sizeof(WCHAR);
+
+ /* Only treat junctions that look like \??\<drive>:\ as symlink. */
+ /* Junctions can also be used as mount points, like \??\Volume{<guid>}, */
+ /* but that's confusing for programs since they wouldn't be able to */
+ /* actually understand such a path when returned by uv_readlink(). */
+ /* UNC paths are never valid for junctions so we don't care about them. */
+ if (!(w_target_len >= 6 &&
+ w_target[0] == L'\\' &&
+ w_target[1] == L'?' &&
+ w_target[2] == L'?' &&
+ w_target[3] == L'\\' &&
+ ((w_target[4] >= L'A' && w_target[4] <= L'Z') ||
+ (w_target[4] >= L'a' && w_target[4] <= L'z')) &&
+ w_target[5] == L':' &&
+ (w_target_len == 6 || w_target[6] == L'\\'))) {
+ SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
+ return -1;
+ }
+
+ /* Remove leading \??\ */
+ w_target += 4;
+ w_target_len -= 4;
+
+ } else {
+ /* Reparse tag does not indicate a symlink. */
+ SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
+ return -1;
+ }
+
+ return fs__wide_to_utf8(w_target, w_target_len, target_ptr, target_len_ptr);
+}
+
+
+void fs__open(uv_fs_t* req) {
+ DWORD access;
+ DWORD share;
+ DWORD disposition;
+ DWORD attributes = 0;
+ HANDLE file;
+ int fd, current_umask;
+ int flags = req->fs.info.file_flags;
+
+ /* Obtain the active umask. umask() never fails and returns the previous */
+ /* umask. */
+ current_umask = umask(0);
+ umask(current_umask);
+
+ /* convert flags and mode to CreateFile parameters */
+ switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
+ case _O_RDONLY:
+ access = FILE_GENERIC_READ;
+ attributes |= FILE_FLAG_BACKUP_SEMANTICS;
+ break;
+ case _O_WRONLY:
+ access = FILE_GENERIC_WRITE;
+ break;
+ case _O_RDWR:
+ access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
+ break;
+ default:
+ goto einval;
+ }
+
+ if (flags & _O_APPEND) {
+ access &= ~FILE_WRITE_DATA;
+ access |= FILE_APPEND_DATA;
+ attributes &= ~FILE_FLAG_BACKUP_SEMANTICS;
+ }
+
+ /*
+ * Here is where we deviate significantly from what CRT's _open()
+ * does. We indiscriminately use all the sharing modes, to match
+ * UNIX semantics. In particular, this ensures that the file can
+ * be deleted even whilst it's open, fixing issue #1449.
+ */
+ share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+
+ switch (flags & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
+ case 0:
+ case _O_EXCL:
+ disposition = OPEN_EXISTING;
+ break;
+ case _O_CREAT:
+ disposition = OPEN_ALWAYS;
+ break;
+ case _O_CREAT | _O_EXCL:
+ case _O_CREAT | _O_TRUNC | _O_EXCL:
+ disposition = CREATE_NEW;
+ break;
+ case _O_TRUNC:
+ case _O_TRUNC | _O_EXCL:
+ disposition = TRUNCATE_EXISTING;
+ break;
+ case _O_CREAT | _O_TRUNC:
+ disposition = CREATE_ALWAYS;
+ break;
+ default:
+ goto einval;
+ }
+
+ attributes |= FILE_ATTRIBUTE_NORMAL;
+ if (flags & _O_CREAT) {
+ if (!((req->fs.info.mode & ~current_umask) & _S_IWRITE)) {
+ attributes |= FILE_ATTRIBUTE_READONLY;
+ }
+ }
+
+ if (flags & _O_TEMPORARY ) {
+ attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY;
+ access |= DELETE;
+ }
+
+ if (flags & _O_SHORT_LIVED) {
+ attributes |= FILE_ATTRIBUTE_TEMPORARY;
+ }
+
+ switch (flags & (_O_SEQUENTIAL | _O_RANDOM)) {
+ case 0:
+ break;
+ case _O_SEQUENTIAL:
+ attributes |= FILE_FLAG_SEQUENTIAL_SCAN;
+ break;
+ case _O_RANDOM:
+ attributes |= FILE_FLAG_RANDOM_ACCESS;
+ break;
+ default:
+ goto einval;
+ }
+
+ /* Setting this flag makes it possible to open a directory. */
+ attributes |= FILE_FLAG_BACKUP_SEMANTICS;
+
+ file = CreateFileW(req->file.pathw,
+ access,
+ share,
+ NULL,
+ disposition,
+ attributes,
+ NULL);
+ if (file == INVALID_HANDLE_VALUE) {
+ DWORD error = GetLastError();
+ if (error == ERROR_FILE_EXISTS && (flags & _O_CREAT) &&
+ !(flags & _O_EXCL)) {
+ /* Special case: when ERROR_FILE_EXISTS happens and O_CREAT was */
+ /* specified, it means the path referred to a directory. */
+ SET_REQ_UV_ERROR(req, UV_EISDIR, error);
+ } else {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ }
+ return;
+ }
+
+ fd = _open_osfhandle((intptr_t) file, flags);
+ if (fd < 0) {
+ /* The only known failure mode for _open_osfhandle() is EMFILE, in which
+ * case GetLastError() will return zero. However we'll try to handle other
+ * errors as well, should they ever occur.
+ */
+ if (errno == EMFILE)
+ SET_REQ_UV_ERROR(req, UV_EMFILE, ERROR_TOO_MANY_OPEN_FILES);
+ else if (GetLastError() != ERROR_SUCCESS)
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ else
+ SET_REQ_WIN32_ERROR(req, UV_UNKNOWN);
+ CloseHandle(file);
+ return;
+ }
+
+ SET_REQ_RESULT(req, fd);
+ return;
+
+ einval:
+ SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
+}
+
+void fs__close(uv_fs_t* req) {
+ int fd = req->file.fd;
+ int result;
+
+ VERIFY_FD(fd, req);
+
+ if (fd > 2)
+ result = _close(fd);
+ else
+ result = 0;
+
+ /* _close doesn't set _doserrno on failure, but it does always set errno
+ * to EBADF on failure.
+ */
+ if (result == -1) {
+ assert(errno == EBADF);
+ SET_REQ_UV_ERROR(req, UV_EBADF, ERROR_INVALID_HANDLE);
+ } else {
+ req->result = 0;
+ }
+}
+
+
+void fs__read(uv_fs_t* req) {
+ int fd = req->file.fd;
+ int64_t offset = req->fs.info.offset;
+ HANDLE handle;
+ OVERLAPPED overlapped, *overlapped_ptr;
+ LARGE_INTEGER offset_;
+ DWORD bytes;
+ DWORD error;
+ int result;
+ unsigned int index;
+
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
+ return;
+ }
+
+ if (offset != -1) {
+ memset(&overlapped, 0, sizeof overlapped);
+ overlapped_ptr = &overlapped;
+ } else {
+ overlapped_ptr = NULL;
+ }
+
+ index = 0;
+ bytes = 0;
+ do {
+ DWORD incremental_bytes;
+
+ if (offset != -1) {
+ offset_.QuadPart = offset + bytes;
+ overlapped.Offset = offset_.LowPart;
+ overlapped.OffsetHigh = offset_.HighPart;
+ }
+
+ result = ReadFile(handle,
+ req->fs.info.bufs[index].base,
+ req->fs.info.bufs[index].len,
+ &incremental_bytes,
+ overlapped_ptr);
+ bytes += incremental_bytes;
+ ++index;
+ } while (result && index < req->fs.info.nbufs);
+
+ if (result || bytes > 0) {
+ SET_REQ_RESULT(req, bytes);
+ } else {
+ error = GetLastError();
+ if (error == ERROR_HANDLE_EOF) {
+ SET_REQ_RESULT(req, bytes);
+ } else {
+ SET_REQ_WIN32_ERROR(req, error);
+ }
+ }
+}
+
+
+void fs__write(uv_fs_t* req) {
+ int fd = req->file.fd;
+ int64_t offset = req->fs.info.offset;
+ HANDLE handle;
+ OVERLAPPED overlapped, *overlapped_ptr;
+ LARGE_INTEGER offset_;
+ DWORD bytes;
+ int result;
+ unsigned int index;
+
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
+ return;
+ }
+
+ if (offset != -1) {
+ memset(&overlapped, 0, sizeof overlapped);
+ overlapped_ptr = &overlapped;
+ } else {
+ overlapped_ptr = NULL;
+ }
+
+ index = 0;
+ bytes = 0;
+ do {
+ DWORD incremental_bytes;
+
+ if (offset != -1) {
+ offset_.QuadPart = offset + bytes;
+ overlapped.Offset = offset_.LowPart;
+ overlapped.OffsetHigh = offset_.HighPart;
+ }
+
+ result = WriteFile(handle,
+ req->fs.info.bufs[index].base,
+ req->fs.info.bufs[index].len,
+ &incremental_bytes,
+ overlapped_ptr);
+ bytes += incremental_bytes;
+ ++index;
+ } while (result && index < req->fs.info.nbufs);
+
+ if (result || bytes > 0) {
+ SET_REQ_RESULT(req, bytes);
+ } else {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ }
+}
+
+
+void fs__rmdir(uv_fs_t* req) {
+ int result = _wrmdir(req->file.pathw);
+ SET_REQ_RESULT(req, result);
+}
+
+
+void fs__unlink(uv_fs_t* req) {
+ const WCHAR* pathw = req->file.pathw;
+ HANDLE handle;
+ BY_HANDLE_FILE_INFORMATION info;
+ FILE_DISPOSITION_INFORMATION disposition;
+ IO_STATUS_BLOCK iosb;
+ NTSTATUS status;
+
+ handle = CreateFileW(pathw,
+ FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (!GetFileInformationByHandle(handle, &info)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ CloseHandle(handle);
+ return;
+ }
+
+ if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ /* Do not allow deletion of directories, unless it is a symlink. When */
+ /* the path refers to a non-symlink directory, report EPERM as mandated */
+ /* by POSIX.1. */
+
+ /* Check if it is a reparse point. If it's not, it's a normal directory. */
+ if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
+ SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
+ CloseHandle(handle);
+ return;
+ }
+
+ /* Read the reparse point and check if it is a valid symlink. */
+ /* If not, don't unlink. */
+ if (fs__readlink_handle(handle, NULL, NULL) < 0) {
+ DWORD error = GetLastError();
+ if (error == ERROR_SYMLINK_NOT_SUPPORTED)
+ error = ERROR_ACCESS_DENIED;
+ SET_REQ_WIN32_ERROR(req, error);
+ CloseHandle(handle);
+ return;
+ }
+ }
+
+ if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
+ /* Remove read-only attribute */
+ FILE_BASIC_INFORMATION basic = { 0 };
+
+ basic.FileAttributes = info.dwFileAttributes & ~(FILE_ATTRIBUTE_READONLY);
+
+ status = pNtSetInformationFile(handle,
+ &iosb,
+ &basic,
+ sizeof basic,
+ FileBasicInformation);
+ if (!NT_SUCCESS(status)) {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
+ CloseHandle(handle);
+ return;
+ }
+ }
+
+ /* Try to set the delete flag. */
+ disposition.DeleteFile = TRUE;
+ status = pNtSetInformationFile(handle,
+ &iosb,
+ &disposition,
+ sizeof disposition,
+ FileDispositionInformation);
+ if (NT_SUCCESS(status)) {
+ SET_REQ_SUCCESS(req);
+ } else {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
+ }
+
+ CloseHandle(handle);
+}
+
+
+void fs__mkdir(uv_fs_t* req) {
+ /* TODO: use req->mode. */
+ int result = _wmkdir(req->file.pathw);
+ SET_REQ_RESULT(req, result);
+}
+
+
+/* OpenBSD original: lib/libc/stdio/mktemp.c */
+void fs__mkdtemp(uv_fs_t* req) {
+ static const WCHAR *tempchars =
+ L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ static const size_t num_chars = 62;
+ static const size_t num_x = 6;
+ WCHAR *cp, *ep;
+ unsigned int tries, i;
+ size_t len;
+ HCRYPTPROV h_crypt_prov;
+ uint64_t v;
+ BOOL released;
+
+ len = wcslen(req->file.pathw);
+ ep = req->file.pathw + len;
+ if (len < num_x || wcsncmp(ep - num_x, L"XXXXXX", num_x)) {
+ SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
+ return;
+ }
+
+ if (!CryptAcquireContext(&h_crypt_prov, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ tries = TMP_MAX;
+ do {
+ if (!CryptGenRandom(h_crypt_prov, sizeof(v), (BYTE*) &v)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ break;
+ }
+
+ cp = ep - num_x;
+ for (i = 0; i < num_x; i++) {
+ *cp++ = tempchars[v % num_chars];
+ v /= num_chars;
+ }
+
+ if (_wmkdir(req->file.pathw) == 0) {
+ len = strlen(req->path);
+ wcstombs((char*) req->path + len - num_x, ep - num_x, num_x);
+ SET_REQ_RESULT(req, 0);
+ break;
+ } else if (errno != EEXIST) {
+ SET_REQ_RESULT(req, -1);
+ break;
+ }
+ } while (--tries);
+
+ released = CryptReleaseContext(h_crypt_prov, 0);
+ assert(released);
+ if (tries == 0) {
+ SET_REQ_RESULT(req, -1);
+ }
+}
+
+
+void fs__scandir(uv_fs_t* req) {
+ static const size_t dirents_initial_size = 32;
+
+ HANDLE dir_handle = INVALID_HANDLE_VALUE;
+
+ uv__dirent_t** dirents = NULL;
+ size_t dirents_size = 0;
+ size_t dirents_used = 0;
+
+ IO_STATUS_BLOCK iosb;
+ NTSTATUS status;
+
+ /* Buffer to hold directory entries returned by NtQueryDirectoryFile.
+ * It's important that this buffer can hold at least one entry, regardless
+ * of the length of the file names present in the enumerated directory.
+ * A file name is at most 256 WCHARs long.
+ * According to MSDN, the buffer must be aligned at an 8-byte boundary.
+ */
+#if _MSC_VER
+ __declspec(align(8)) char buffer[8192];
+#else
+ __attribute__ ((aligned (8))) char buffer[8192];
+#endif
+
+ STATIC_ASSERT(sizeof buffer >=
+ sizeof(FILE_DIRECTORY_INFORMATION) + 256 * sizeof(WCHAR));
+
+ /* Open the directory. */
+ dir_handle =
+ CreateFileW(req->file.pathw,
+ FILE_LIST_DIRECTORY | SYNCHRONIZE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+ if (dir_handle == INVALID_HANDLE_VALUE)
+ goto win32_error;
+
+ /* Read the first chunk. */
+ status = pNtQueryDirectoryFile(dir_handle,
+ NULL,
+ NULL,
+ NULL,
+ &iosb,
+ &buffer,
+ sizeof buffer,
+ FileDirectoryInformation,
+ FALSE,
+ NULL,
+ TRUE);
+
+ /* If the handle is not a directory, we'll get STATUS_INVALID_PARAMETER.
+ * This should be reported back as UV_ENOTDIR.
+ */
+ if (status == STATUS_INVALID_PARAMETER)
+ goto not_a_directory_error;
+
+ while (NT_SUCCESS(status)) {
+ char* position = buffer;
+ size_t next_entry_offset = 0;
+
+ do {
+ FILE_DIRECTORY_INFORMATION* info;
+ uv__dirent_t* dirent;
+
+ size_t wchar_len;
+ size_t utf8_len;
+
+ /* Obtain a pointer to the current directory entry. */
+ position += next_entry_offset;
+ info = (FILE_DIRECTORY_INFORMATION*) position;
+
+ /* Fetch the offset to the next directory entry. */
+ next_entry_offset = info->NextEntryOffset;
+
+ /* Compute the length of the filename in WCHARs. */
+ wchar_len = info->FileNameLength / sizeof info->FileName[0];
+
+ /* Skip over '.' and '..' entries. */
+ if (wchar_len == 1 && info->FileName[0] == L'.')
+ continue;
+ if (wchar_len == 2 && info->FileName[0] == L'.' &&
+ info->FileName[1] == L'.')
+ continue;
+
+ /* Compute the space required to store the filename as UTF-8. */
+ utf8_len = WideCharToMultiByte(
+ CP_UTF8, 0, &info->FileName[0], wchar_len, NULL, 0, NULL, NULL);
+ if (utf8_len == 0)
+ goto win32_error;
+
+ /* Resize the dirent array if needed. */
+ if (dirents_used >= dirents_size) {
+ size_t new_dirents_size =
+ dirents_size == 0 ? dirents_initial_size : dirents_size << 1;
+ uv__dirent_t** new_dirents =
+ uv__realloc(dirents, new_dirents_size * sizeof *dirents);
+
+ if (new_dirents == NULL)
+ goto out_of_memory_error;
+
+ dirents_size = new_dirents_size;
+ dirents = new_dirents;
+ }
+
+ /* Allocate space for the uv dirent structure. The dirent structure
+ * includes room for the first character of the filename, but `utf8_len`
+ * doesn't count the NULL terminator at this point.
+ */
+ dirent = uv__malloc(sizeof *dirent + utf8_len);
+ if (dirent == NULL)
+ goto out_of_memory_error;
+
+ dirents[dirents_used++] = dirent;
+
+ /* Convert file name to UTF-8. */
+ if (WideCharToMultiByte(CP_UTF8,
+ 0,
+ &info->FileName[0],
+ wchar_len,
+ &dirent->d_name[0],
+ utf8_len,
+ NULL,
+ NULL) == 0)
+ goto win32_error;
+
+ /* Add a null terminator to the filename. */
+ dirent->d_name[utf8_len] = '\0';
+
+ /* Fill out the type field. */
+ if (info->FileAttributes & FILE_ATTRIBUTE_DEVICE)
+ dirent->d_type = UV__DT_CHAR;
+ else if (info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
+ dirent->d_type = UV__DT_LINK;
+ else if (info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ dirent->d_type = UV__DT_DIR;
+ else
+ dirent->d_type = UV__DT_FILE;
+ } while (next_entry_offset != 0);
+
+ /* Read the next chunk. */
+ status = pNtQueryDirectoryFile(dir_handle,
+ NULL,
+ NULL,
+ NULL,
+ &iosb,
+ &buffer,
+ sizeof buffer,
+ FileDirectoryInformation,
+ FALSE,
+ NULL,
+ FALSE);
+
+ /* After the first pNtQueryDirectoryFile call, the function may return
+ * STATUS_SUCCESS even if the buffer was too small to hold at least one
+ * directory entry.
+ */
+ if (status == STATUS_SUCCESS && iosb.Information == 0)
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ if (status != STATUS_NO_MORE_FILES)
+ goto nt_error;
+
+ CloseHandle(dir_handle);
+
+ /* Store the result in the request object. */
+ req->ptr = dirents;
+ if (dirents != NULL)
+ req->flags |= UV_FS_FREE_PTR;
+
+ SET_REQ_RESULT(req, dirents_used);
+
+ /* `nbufs` will be used as index by uv_fs_scandir_next. */
+ req->fs.info.nbufs = 0;
+
+ return;
+
+nt_error:
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
+ goto cleanup;
+
+win32_error:
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ goto cleanup;
+
+not_a_directory_error:
+ SET_REQ_UV_ERROR(req, UV_ENOTDIR, ERROR_DIRECTORY);
+ goto cleanup;
+
+out_of_memory_error:
+ SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
+ goto cleanup;
+
+cleanup:
+ if (dir_handle != INVALID_HANDLE_VALUE)
+ CloseHandle(dir_handle);
+ while (dirents_used > 0)
+ uv__free(dirents[--dirents_used]);
+ if (dirents != NULL)
+ uv__free(dirents);
+}
+
+
+INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) {
+ FILE_ALL_INFORMATION file_info;
+ FILE_FS_VOLUME_INFORMATION volume_info;
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+
+ nt_status = pNtQueryInformationFile(handle,
+ &io_status,
+ &file_info,
+ sizeof file_info,
+ FileAllInformation);
+
+ /* Buffer overflow (a warning status code) is expected here. */
+ if (NT_ERROR(nt_status)) {
+ SetLastError(pRtlNtStatusToDosError(nt_status));
+ return -1;
+ }
+
+ nt_status = pNtQueryVolumeInformationFile(handle,
+ &io_status,
+ &volume_info,
+ sizeof volume_info,
+ FileFsVolumeInformation);
+
+ /* Buffer overflow (a warning status code) is expected here. */
+ if (io_status.Status == STATUS_NOT_IMPLEMENTED) {
+ statbuf->st_dev = 0;
+ } else if (NT_ERROR(nt_status)) {
+ SetLastError(pRtlNtStatusToDosError(nt_status));
+ return -1;
+ } else {
+ statbuf->st_dev = volume_info.VolumeSerialNumber;
+ }
+
+ /* Todo: st_mode should probably always be 0666 for everyone. We might also
+ * want to report 0777 if the file is a .exe or a directory.
+ *
+ * Currently it's based on whether the 'readonly' attribute is set, which
+ * makes little sense because the semantics are so different: the 'read-only'
+ * flag is just a way for a user to protect against accidental deletion, and
+ * serves no security purpose. Windows uses ACLs for that.
+ *
+ * Also people now use uv_fs_chmod() to take away the writable bit for good
+ * reasons. Windows however just makes the file read-only, which makes it
+ * impossible to delete the file afterwards, since read-only files can't be
+ * deleted.
+ *
+ * IOW it's all just a clusterfuck and we should think of something that
+ * makes slightly more sense.
+ *
+ * And uv_fs_chmod should probably just fail on windows or be a total no-op.
+ * There's nothing sensible it can do anyway.
+ */
+ statbuf->st_mode = 0;
+
+ if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ statbuf->st_mode |= S_IFLNK;
+ if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0)
+ return -1;
+
+ } else if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ statbuf->st_mode |= _S_IFDIR;
+ statbuf->st_size = 0;
+
+ } else {
+ statbuf->st_mode |= _S_IFREG;
+ statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart;
+ }
+
+ if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY)
+ statbuf->st_mode |= _S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6);
+ else
+ statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) |
+ ((_S_IREAD | _S_IWRITE) >> 6);
+
+ FILETIME_TO_TIMESPEC(statbuf->st_atim, file_info.BasicInformation.LastAccessTime);
+ FILETIME_TO_TIMESPEC(statbuf->st_ctim, file_info.BasicInformation.ChangeTime);
+ FILETIME_TO_TIMESPEC(statbuf->st_mtim, file_info.BasicInformation.LastWriteTime);
+ FILETIME_TO_TIMESPEC(statbuf->st_birthtim, file_info.BasicInformation.CreationTime);
+
+ statbuf->st_ino = file_info.InternalInformation.IndexNumber.QuadPart;
+
+ /* st_blocks contains the on-disk allocation size in 512-byte units. */
+ statbuf->st_blocks =
+ file_info.StandardInformation.AllocationSize.QuadPart >> 9ULL;
+
+ statbuf->st_nlink = file_info.StandardInformation.NumberOfLinks;
+
+ /* The st_blksize is supposed to be the 'optimal' number of bytes for reading
+ * and writing to the disk. That is, for any definition of 'optimal' - it's
+ * supposed to at least avoid read-update-write behavior when writing to the
+ * disk.
+ *
+ * However nobody knows this and even fewer people actually use this value,
+ * and in order to fill it out we'd have to make another syscall to query the
+ * volume for FILE_FS_SECTOR_SIZE_INFORMATION.
+ *
+ * Therefore we'll just report a sensible value that's quite commonly okay
+ * on modern hardware.
+ */
+ statbuf->st_blksize = 2048;
+
+ /* Todo: set st_flags to something meaningful. Also provide a wrapper for
+ * chattr(2).
+ */
+ statbuf->st_flags = 0;
+
+ /* Windows has nothing sensible to say about these values, so they'll just
+ * remain empty.
+ */
+ statbuf->st_gid = 0;
+ statbuf->st_uid = 0;
+ statbuf->st_rdev = 0;
+ statbuf->st_gen = 0;
+
+ return 0;
+}
+
+
+INLINE static void fs__stat_prepare_path(WCHAR* pathw) {
+ size_t len = wcslen(pathw);
+
+ /* TODO: ignore namespaced paths. */
+ if (len > 1 && pathw[len - 2] != L':' &&
+ (pathw[len - 1] == L'\\' || pathw[len - 1] == L'/')) {
+ pathw[len - 1] = '\0';
+ }
+}
+
+
+INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) {
+ HANDLE handle;
+ DWORD flags;
+
+ flags = FILE_FLAG_BACKUP_SEMANTICS;
+ if (do_lstat) {
+ flags |= FILE_FLAG_OPEN_REPARSE_POINT;
+ }
+
+ handle = CreateFileW(req->file.pathw,
+ FILE_READ_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ flags,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (fs__stat_handle(handle, &req->statbuf) != 0) {
+ DWORD error = GetLastError();
+ if (do_lstat && error == ERROR_SYMLINK_NOT_SUPPORTED) {
+ /* We opened a reparse point but it was not a symlink. Try again. */
+ fs__stat_impl(req, 0);
+
+ } else {
+ /* Stat failed. */
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ }
+
+ CloseHandle(handle);
+ return;
+ }
+
+ req->ptr = &req->statbuf;
+ req->result = 0;
+ CloseHandle(handle);
+}
+
+
+static void fs__stat(uv_fs_t* req) {
+ fs__stat_prepare_path(req->file.pathw);
+ fs__stat_impl(req, 0);
+}
+
+
+static void fs__lstat(uv_fs_t* req) {
+ fs__stat_prepare_path(req->file.pathw);
+ fs__stat_impl(req, 1);
+}
+
+
+static void fs__fstat(uv_fs_t* req) {
+ int fd = req->file.fd;
+ HANDLE handle;
+
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
+ return;
+ }
+
+ if (fs__stat_handle(handle, &req->statbuf) != 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ req->ptr = &req->statbuf;
+ req->result = 0;
+}
+
+
+static void fs__rename(uv_fs_t* req) {
+ if (!MoveFileExW(req->file.pathw, req->fs.info.new_pathw, MOVEFILE_REPLACE_EXISTING)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ SET_REQ_RESULT(req, 0);
+}
+
+
+INLINE static void fs__sync_impl(uv_fs_t* req) {
+ int fd = req->file.fd;
+ int result;
+
+ VERIFY_FD(fd, req);
+
+ result = FlushFileBuffers(uv__get_osfhandle(fd)) ? 0 : -1;
+ if (result == -1) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ } else {
+ SET_REQ_RESULT(req, result);
+ }
+}
+
+
+static void fs__fsync(uv_fs_t* req) {
+ fs__sync_impl(req);
+}
+
+
+static void fs__fdatasync(uv_fs_t* req) {
+ fs__sync_impl(req);
+}
+
+
+static void fs__ftruncate(uv_fs_t* req) {
+ int fd = req->file.fd;
+ HANDLE handle;
+ NTSTATUS status;
+ IO_STATUS_BLOCK io_status;
+ FILE_END_OF_FILE_INFORMATION eof_info;
+
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+
+ eof_info.EndOfFile.QuadPart = req->fs.info.offset;
+
+ status = pNtSetInformationFile(handle,
+ &io_status,
+ &eof_info,
+ sizeof eof_info,
+ FileEndOfFileInformation);
+
+ if (NT_SUCCESS(status)) {
+ SET_REQ_RESULT(req, 0);
+ } else {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
+ }
+}
+
+
+static void fs__sendfile(uv_fs_t* req) {
+ int fd_in = req->file.fd, fd_out = req->fs.info.fd_out;
+ size_t length = req->fs.info.bufsml[0].len;
+ int64_t offset = req->fs.info.offset;
+ const size_t max_buf_size = 65536;
+ size_t buf_size = length < max_buf_size ? length : max_buf_size;
+ int n, result = 0;
+ int64_t result_offset = 0;
+ char* buf = (char*) uv__malloc(buf_size);
+ if (!buf) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ if (offset != -1) {
+ result_offset = _lseeki64(fd_in, offset, SEEK_SET);
+ }
+
+ if (result_offset == -1) {
+ result = -1;
+ } else {
+ while (length > 0) {
+ n = _read(fd_in, buf, length < buf_size ? length : buf_size);
+ if (n == 0) {
+ break;
+ } else if (n == -1) {
+ result = -1;
+ break;
+ }
+
+ length -= n;
+
+ n = _write(fd_out, buf, n);
+ if (n == -1) {
+ result = -1;
+ break;
+ }
+
+ result += n;
+ }
+ }
+
+ uv__free(buf);
+
+ SET_REQ_RESULT(req, result);
+}
+
+
+static void fs__access(uv_fs_t* req) {
+ DWORD attr = GetFileAttributesW(req->file.pathw);
+
+ if (attr == INVALID_FILE_ATTRIBUTES) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ /*
+ * Access is possible if
+ * - write access wasn't requested,
+ * - or the file isn't read-only,
+ * - or it's a directory.
+ * (Directories cannot be read-only on Windows.)
+ */
+ if (!(req->flags & W_OK) ||
+ !(attr & FILE_ATTRIBUTE_READONLY) ||
+ (attr & FILE_ATTRIBUTE_DIRECTORY)) {
+ SET_REQ_RESULT(req, 0);
+ } else {
+ SET_REQ_WIN32_ERROR(req, UV_EPERM);
+ }
+
+}
+
+
+static void fs__chmod(uv_fs_t* req) {
+ int result = _wchmod(req->file.pathw, req->fs.info.mode);
+ SET_REQ_RESULT(req, result);
+}
+
+
+static void fs__fchmod(uv_fs_t* req) {
+ int fd = req->file.fd;
+ HANDLE handle;
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_BASIC_INFORMATION file_info;
+
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+
+ nt_status = pNtQueryInformationFile(handle,
+ &io_status,
+ &file_info,
+ sizeof file_info,
+ FileBasicInformation);
+
+ if (!NT_SUCCESS(nt_status)) {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
+ return;
+ }
+
+ if (req->fs.info.mode & _S_IWRITE) {
+ file_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
+ } else {
+ file_info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
+ }
+
+ nt_status = pNtSetInformationFile(handle,
+ &io_status,
+ &file_info,
+ sizeof file_info,
+ FileBasicInformation);
+
+ if (!NT_SUCCESS(nt_status)) {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
+ return;
+ }
+
+ SET_REQ_SUCCESS(req);
+}
+
+
+INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) {
+ FILETIME filetime_a, filetime_m;
+
+ TIME_T_TO_FILETIME((time_t) atime, &filetime_a);
+ TIME_T_TO_FILETIME((time_t) mtime, &filetime_m);
+
+ if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void fs__utime(uv_fs_t* req) {
+ HANDLE handle;
+
+ handle = CreateFileW(req->file.pathw,
+ FILE_WRITE_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ CloseHandle(handle);
+ return;
+ }
+
+ CloseHandle(handle);
+
+ req->result = 0;
+}
+
+
+static void fs__futime(uv_fs_t* req) {
+ int fd = req->file.fd;
+ HANDLE handle;
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
+ return;
+ }
+
+ if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ req->result = 0;
+}
+
+
+static void fs__link(uv_fs_t* req) {
+ DWORD r = CreateHardLinkW(req->fs.info.new_pathw, req->file.pathw, NULL);
+ if (r == 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ } else {
+ req->result = 0;
+ }
+}
+
+
+static void fs__create_junction(uv_fs_t* req, const WCHAR* path,
+ const WCHAR* new_path) {
+ HANDLE handle = INVALID_HANDLE_VALUE;
+ REPARSE_DATA_BUFFER *buffer = NULL;
+ int created = 0;
+ int target_len;
+ int is_absolute, is_long_path;
+ int needed_buf_size, used_buf_size, used_data_size, path_buf_len;
+ int start, len, i;
+ int add_slash;
+ DWORD bytes;
+ WCHAR* path_buf;
+
+ target_len = wcslen(path);
+ is_long_path = wcsncmp(path, LONG_PATH_PREFIX, LONG_PATH_PREFIX_LEN) == 0;
+
+ if (is_long_path) {
+ is_absolute = 1;
+ } else {
+ is_absolute = target_len >= 3 && IS_LETTER(path[0]) &&
+ path[1] == L':' && IS_SLASH(path[2]);
+ }
+
+ if (!is_absolute) {
+ /* Not supporting relative paths */
+ SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_NOT_SUPPORTED);
+ return;
+ }
+
+ /* Do a pessimistic calculation of the required buffer size */
+ needed_buf_size =
+ FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
+ JUNCTION_PREFIX_LEN * sizeof(WCHAR) +
+ 2 * (target_len + 2) * sizeof(WCHAR);
+
+ /* Allocate the buffer */
+ buffer = (REPARSE_DATA_BUFFER*)uv__malloc(needed_buf_size);
+ if (!buffer) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ /* Grab a pointer to the part of the buffer where filenames go */
+ path_buf = (WCHAR*)&(buffer->MountPointReparseBuffer.PathBuffer);
+ path_buf_len = 0;
+
+ /* Copy the substitute (internal) target path */
+ start = path_buf_len;
+
+ wcsncpy((WCHAR*)&path_buf[path_buf_len], JUNCTION_PREFIX,
+ JUNCTION_PREFIX_LEN);
+ path_buf_len += JUNCTION_PREFIX_LEN;
+
+ add_slash = 0;
+ for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) {
+ if (IS_SLASH(path[i])) {
+ add_slash = 1;
+ continue;
+ }
+
+ if (add_slash) {
+ path_buf[path_buf_len++] = L'\\';
+ add_slash = 0;
+ }
+
+ path_buf[path_buf_len++] = path[i];
+ }
+ path_buf[path_buf_len++] = L'\\';
+ len = path_buf_len - start;
+
+ /* Set the info about the substitute name */
+ buffer->MountPointReparseBuffer.SubstituteNameOffset = start * sizeof(WCHAR);
+ buffer->MountPointReparseBuffer.SubstituteNameLength = len * sizeof(WCHAR);
+
+ /* Insert null terminator */
+ path_buf[path_buf_len++] = L'\0';
+
+ /* Copy the print name of the target path */
+ start = path_buf_len;
+ add_slash = 0;
+ for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) {
+ if (IS_SLASH(path[i])) {
+ add_slash = 1;
+ continue;
+ }
+
+ if (add_slash) {
+ path_buf[path_buf_len++] = L'\\';
+ add_slash = 0;
+ }
+
+ path_buf[path_buf_len++] = path[i];
+ }
+ len = path_buf_len - start;
+ if (len == 2) {
+ path_buf[path_buf_len++] = L'\\';
+ len++;
+ }
+
+ /* Set the info about the print name */
+ buffer->MountPointReparseBuffer.PrintNameOffset = start * sizeof(WCHAR);
+ buffer->MountPointReparseBuffer.PrintNameLength = len * sizeof(WCHAR);
+
+ /* Insert another null terminator */
+ path_buf[path_buf_len++] = L'\0';
+
+ /* Calculate how much buffer space was actually used */
+ used_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
+ path_buf_len * sizeof(WCHAR);
+ used_data_size = used_buf_size -
+ FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer);
+
+ /* Put general info in the data buffer */
+ buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+ buffer->ReparseDataLength = used_data_size;
+ buffer->Reserved = 0;
+
+ /* Create a new directory */
+ if (!CreateDirectoryW(new_path, NULL)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ goto error;
+ }
+ created = 1;
+
+ /* Open the directory */
+ handle = CreateFileW(new_path,
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS |
+ FILE_FLAG_OPEN_REPARSE_POINT,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ goto error;
+ }
+
+ /* Create the actual reparse point */
+ if (!DeviceIoControl(handle,
+ FSCTL_SET_REPARSE_POINT,
+ buffer,
+ used_buf_size,
+ NULL,
+ 0,
+ &bytes,
+ NULL)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ goto error;
+ }
+
+ /* Clean up */
+ CloseHandle(handle);
+ uv__free(buffer);
+
+ SET_REQ_RESULT(req, 0);
+ return;
+
+error:
+ uv__free(buffer);
+
+ if (handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle);
+ }
+
+ if (created) {
+ RemoveDirectoryW(new_path);
+ }
+}
+
+
+static void fs__symlink(uv_fs_t* req) {
+ WCHAR* pathw = req->file.pathw;
+ WCHAR* new_pathw = req->fs.info.new_pathw;
+ int flags = req->fs.info.file_flags;
+ int result;
+
+
+ if (flags & UV_FS_SYMLINK_JUNCTION) {
+ fs__create_junction(req, pathw, new_pathw);
+ } else if (pCreateSymbolicLinkW) {
+ result = pCreateSymbolicLinkW(new_pathw,
+ pathw,
+ flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1;
+ if (result == -1) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ } else {
+ SET_REQ_RESULT(req, result);
+ }
+ } else {
+ SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
+ }
+}
+
+
+static void fs__readlink(uv_fs_t* req) {
+ HANDLE handle;
+
+ handle = CreateFileW(req->file.pathw,
+ 0,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (fs__readlink_handle(handle, (char**) &req->ptr, NULL) != 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ CloseHandle(handle);
+ return;
+ }
+
+ req->flags |= UV_FS_FREE_PTR;
+ SET_REQ_RESULT(req, 0);
+
+ CloseHandle(handle);
+}
+
+
+static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
+ int r;
+ DWORD w_realpath_len;
+ WCHAR* w_realpath_ptr;
+ WCHAR* w_finalpath_ptr = NULL;
+
+ w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS);
+ if (w_realpath_len == 0) {
+ return -1;
+ }
+
+ w_realpath_ptr = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR));
+ if (w_realpath_ptr == NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return -1;
+ }
+
+ if (pGetFinalPathNameByHandleW(handle,
+ w_realpath_ptr,
+ w_realpath_len,
+ VOLUME_NAME_DOS) == 0) {
+ uv__free(w_realpath_ptr);
+ SetLastError(ERROR_INVALID_HANDLE);
+ return -1;
+ }
+
+ /* convert UNC path to long path */
+ if (wcsncmp(w_realpath_ptr,
+ UNC_PATH_PREFIX,
+ UNC_PATH_PREFIX_LEN) == 0) {
+ w_finalpath_ptr = w_realpath_ptr + 6;
+ *w_finalpath_ptr = L'\\';
+ } else if (wcsncmp(w_realpath_ptr,
+ LONG_PATH_PREFIX,
+ LONG_PATH_PREFIX_LEN) == 0) {
+ w_finalpath_ptr = w_realpath_ptr + 4;
+ } else {
+ uv__free(w_realpath_ptr);
+ SetLastError(ERROR_INVALID_HANDLE);
+ return -1;
+ }
+
+ r = fs__wide_to_utf8(w_finalpath_ptr, w_realpath_len, realpath_ptr, NULL);
+ uv__free(w_realpath_ptr);
+ return r;
+}
+
+static void fs__realpath(uv_fs_t* req) {
+ HANDLE handle;
+
+ if (!pGetFinalPathNameByHandleW) {
+ SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
+ return;
+ }
+
+ handle = CreateFileW(req->file.pathw,
+ 0,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (fs__realpath_handle(handle, (char**) &req->ptr) == -1) {
+ CloseHandle(handle);
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ CloseHandle(handle);
+ req->flags |= UV_FS_FREE_PTR;
+ SET_REQ_RESULT(req, 0);
+}
+
+
+static void fs__chown(uv_fs_t* req) {
+ req->result = 0;
+}
+
+
+static void fs__fchown(uv_fs_t* req) {
+ req->result = 0;
+}
+
+
+static void uv__fs_work(struct uv__work* w) {
+ uv_fs_t* req;
+
+ req = container_of(w, uv_fs_t, work_req);
+ assert(req->type == UV_FS);
+
+#define XX(uc, lc) case UV_FS_##uc: fs__##lc(req); break;
+ switch (req->fs_type) {
+ XX(OPEN, open)
+ XX(CLOSE, close)
+ XX(READ, read)
+ XX(WRITE, write)
+ XX(SENDFILE, sendfile)
+ XX(STAT, stat)
+ XX(LSTAT, lstat)
+ XX(FSTAT, fstat)
+ XX(FTRUNCATE, ftruncate)
+ XX(UTIME, utime)
+ XX(FUTIME, futime)
+ XX(ACCESS, access)
+ XX(CHMOD, chmod)
+ XX(FCHMOD, fchmod)
+ XX(FSYNC, fsync)
+ XX(FDATASYNC, fdatasync)
+ XX(UNLINK, unlink)
+ XX(RMDIR, rmdir)
+ XX(MKDIR, mkdir)
+ XX(MKDTEMP, mkdtemp)
+ XX(RENAME, rename)
+ XX(SCANDIR, scandir)
+ XX(LINK, link)
+ XX(SYMLINK, symlink)
+ XX(READLINK, readlink)
+ XX(REALPATH, realpath)
+ XX(CHOWN, chown)
+ XX(FCHOWN, fchown);
+ default:
+ assert(!"bad uv_fs_type");
+ }
+}
+
+
+static void uv__fs_done(struct uv__work* w, int status) {
+ uv_fs_t* req;
+
+ req = container_of(w, uv_fs_t, work_req);
+ uv__req_unregister(req->loop, req);
+
+ if (status == UV_ECANCELED) {
+ assert(req->result == 0);
+ req->result = UV_ECANCELED;
+ }
+
+ req->cb(req);
+}
+
+
+void uv_fs_req_cleanup(uv_fs_t* req) {
+ if (req->flags & UV_FS_CLEANEDUP)
+ return;
+
+ if (req->flags & UV_FS_FREE_PATHS)
+ uv__free(req->file.pathw);
+
+ if (req->flags & UV_FS_FREE_PTR)
+ uv__free(req->ptr);
+
+ req->path = NULL;
+ req->file.pathw = NULL;
+ req->fs.info.new_pathw = NULL;
+ req->ptr = NULL;
+
+ req->flags |= UV_FS_CLEANEDUP;
+}
+
+
+int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
+ int mode, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_OPEN, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.info.file_flags = flags;
+ req->fs.info.mode = mode;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__open(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_CLOSE, cb);
+ req->file.fd = fd;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__close(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_read(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file fd,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ int64_t offset,
+ uv_fs_cb cb) {
+ if (bufs == NULL || nbufs == 0)
+ return UV_EINVAL;
+
+ uv_fs_req_init(loop, req, UV_FS_READ, cb);
+
+ req->file.fd = fd;
+
+ req->fs.info.nbufs = nbufs;
+ req->fs.info.bufs = req->fs.info.bufsml;
+ if (nbufs > ARRAY_SIZE(req->fs.info.bufsml))
+ req->fs.info.bufs = uv__malloc(nbufs * sizeof(*bufs));
+
+ if (req->fs.info.bufs == NULL)
+ return UV_ENOMEM;
+
+ memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
+
+ req->fs.info.offset = offset;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__read(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_write(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file fd,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ int64_t offset,
+ uv_fs_cb cb) {
+ if (bufs == NULL || nbufs == 0)
+ return UV_EINVAL;
+
+ uv_fs_req_init(loop, req, UV_FS_WRITE, cb);
+
+ req->file.fd = fd;
+
+ req->fs.info.nbufs = nbufs;
+ req->fs.info.bufs = req->fs.info.bufsml;
+ if (nbufs > ARRAY_SIZE(req->fs.info.bufsml))
+ req->fs.info.bufs = uv__malloc(nbufs * sizeof(*bufs));
+
+ if (req->fs.info.bufs == NULL)
+ return UV_ENOMEM;
+
+ memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
+
+ req->fs.info.offset = offset;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__write(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_UNLINK, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__unlink(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_MKDIR, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.info.mode = mode;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__mkdir(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_MKDTEMP, cb);
+
+ err = fs__capture_path(req, tpl, NULL, TRUE);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__mkdtemp(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_RMDIR, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__rmdir(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_SCANDIR, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.info.file_flags = flags;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__scandir(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ const char* new_path, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_LINK, cb);
+
+ err = fs__capture_path(req, path, new_path, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__link(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ const char* new_path, int flags, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_SYMLINK, cb);
+
+ err = fs__capture_path(req, path, new_path, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.info.file_flags = flags;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__symlink(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_READLINK, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__readlink(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ uv_fs_cb cb) {
+ int err;
+
+ if (!req || !path) {
+ return UV_EINVAL;
+ }
+
+ uv_fs_req_init(loop, req, UV_FS_REALPATH, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__realpath(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
+ uv_gid_t gid, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_CHOWN, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__chown(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid,
+ uv_gid_t gid, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FCHOWN, cb);
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__fchown(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_STAT, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__stat(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_LSTAT, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__lstat(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FSTAT, cb);
+ req->file.fd = fd;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__fstat(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ const char* new_path, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_RENAME, cb);
+
+ err = fs__capture_path(req, path, new_path, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__rename(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FSYNC, cb);
+ req->file.fd = fd;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__fsync(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FDATASYNC, cb);
+ req->file.fd = fd;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__fdatasync(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd,
+ int64_t offset, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FTRUNCATE, cb);
+
+ req->file.fd = fd;
+ req->fs.info.offset = offset;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__ftruncate(req);
+ return req->result;
+ }
+}
+
+
+
+int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out,
+ uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_SENDFILE, cb);
+
+ req->file.fd = fd_in;
+ req->fs.info.fd_out = fd_out;
+ req->fs.info.offset = in_offset;
+ req->fs.info.bufsml[0].len = length;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__sendfile(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_access(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int flags,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_ACCESS, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ req->flags = flags;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ }
+
+ fs__access(req);
+ return req->result;
+}
+
+
+int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_CHMOD, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.info.mode = mode;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__chmod(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode,
+ uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FCHMOD, cb);
+
+ req->file.fd = fd;
+ req->fs.info.mode = mode;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__fchmod(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
+ double mtime, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_UTIME, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.time.atime = atime;
+ req->fs.time.mtime = mtime;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__utime(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
+ double mtime, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FUTIME, cb);
+
+ req->file.fd = fd;
+ req->fs.time.atime = atime;
+ req->fs.time.mtime = mtime;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__futime(req);
+ return req->result;
+ }
+}
diff --git a/3rdparty/libuv/src/win/getaddrinfo.c b/3rdparty/libuv/src/win/getaddrinfo.c
new file mode 100644
index 00000000000..ceed3b7638b
--- /dev/null
+++ b/3rdparty/libuv/src/win/getaddrinfo.c
@@ -0,0 +1,358 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "req-inl.h"
+
+/* EAI_* constants. */
+#include <winsock2.h>
+
+
+int uv__getaddrinfo_translate_error(int sys_err) {
+ switch (sys_err) {
+ case 0: return 0;
+ case WSATRY_AGAIN: return UV_EAI_AGAIN;
+ case WSAEINVAL: return UV_EAI_BADFLAGS;
+ case WSANO_RECOVERY: return UV_EAI_FAIL;
+ case WSAEAFNOSUPPORT: return UV_EAI_FAMILY;
+ case WSA_NOT_ENOUGH_MEMORY: return UV_EAI_MEMORY;
+ case WSAHOST_NOT_FOUND: return UV_EAI_NONAME;
+ case WSATYPE_NOT_FOUND: return UV_EAI_SERVICE;
+ case WSAESOCKTNOSUPPORT: return UV_EAI_SOCKTYPE;
+ default: return uv_translate_sys_error(sys_err);
+ }
+}
+
+
+/*
+ * MinGW is missing this
+ */
+#if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)
+ typedef struct addrinfoW {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ WCHAR* ai_canonname;
+ struct sockaddr* ai_addr;
+ struct addrinfoW* ai_next;
+ } ADDRINFOW, *PADDRINFOW;
+
+ DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR* node,
+ const WCHAR* service,
+ const ADDRINFOW* hints,
+ PADDRINFOW* result);
+
+ DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo);
+#endif
+
+
+/* adjust size value to be multiple of 4. Use to keep pointer aligned */
+/* Do we need different versions of this for different architectures? */
+#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2)
+
+
+static void uv__getaddrinfo_work(struct uv__work* w) {
+ uv_getaddrinfo_t* req;
+ struct addrinfoW* hints;
+ int err;
+
+ req = container_of(w, uv_getaddrinfo_t, work_req);
+ hints = req->addrinfow;
+ req->addrinfow = NULL;
+ err = GetAddrInfoW(req->node, req->service, hints, &req->addrinfow);
+ req->retcode = uv__getaddrinfo_translate_error(err);
+}
+
+
+/*
+ * Called from uv_run when complete. Call user specified callback
+ * then free returned addrinfo
+ * Returned addrinfo strings are converted from UTF-16 to UTF-8.
+ *
+ * To minimize allocation we calculate total size required,
+ * and copy all structs and referenced strings into the one block.
+ * Each size calculation is adjusted to avoid unaligned pointers.
+ */
+static void uv__getaddrinfo_done(struct uv__work* w, int status) {
+ uv_getaddrinfo_t* req;
+ int addrinfo_len = 0;
+ int name_len = 0;
+ size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));
+ struct addrinfoW* addrinfow_ptr;
+ struct addrinfo* addrinfo_ptr;
+ char* alloc_ptr = NULL;
+ char* cur_ptr = NULL;
+
+ req = container_of(w, uv_getaddrinfo_t, work_req);
+
+ /* release input parameter memory */
+ uv__free(req->alloc);
+ req->alloc = NULL;
+
+ if (status == UV_ECANCELED) {
+ assert(req->retcode == 0);
+ req->retcode = UV_EAI_CANCELED;
+ goto complete;
+ }
+
+ if (req->retcode == 0) {
+ /* convert addrinfoW to addrinfo */
+ /* first calculate required length */
+ addrinfow_ptr = req->addrinfow;
+ while (addrinfow_ptr != NULL) {
+ addrinfo_len += addrinfo_struct_len +
+ ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
+ if (addrinfow_ptr->ai_canonname != NULL) {
+ name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0);
+ if (name_len == 0) {
+ req->retcode = uv_translate_sys_error(GetLastError());
+ goto complete;
+ }
+ addrinfo_len += ALIGNED_SIZE(name_len);
+ }
+ addrinfow_ptr = addrinfow_ptr->ai_next;
+ }
+
+ /* allocate memory for addrinfo results */
+ alloc_ptr = (char*)uv__malloc(addrinfo_len);
+
+ /* do conversions */
+ if (alloc_ptr != NULL) {
+ cur_ptr = alloc_ptr;
+ addrinfow_ptr = req->addrinfow;
+
+ while (addrinfow_ptr != NULL) {
+ /* copy addrinfo struct data */
+ assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len);
+ addrinfo_ptr = (struct addrinfo*)cur_ptr;
+ addrinfo_ptr->ai_family = addrinfow_ptr->ai_family;
+ addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype;
+ addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol;
+ addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags;
+ addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen;
+ addrinfo_ptr->ai_canonname = NULL;
+ addrinfo_ptr->ai_addr = NULL;
+ addrinfo_ptr->ai_next = NULL;
+
+ cur_ptr += addrinfo_struct_len;
+
+ /* copy sockaddr */
+ if (addrinfo_ptr->ai_addrlen > 0) {
+ assert(cur_ptr + addrinfo_ptr->ai_addrlen <=
+ alloc_ptr + addrinfo_len);
+ memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen);
+ addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr;
+ cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen);
+ }
+
+ /* convert canonical name to UTF-8 */
+ if (addrinfow_ptr->ai_canonname != NULL) {
+ name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname,
+ -1,
+ NULL,
+ 0);
+ assert(name_len > 0);
+ assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len);
+ name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname,
+ -1,
+ cur_ptr,
+ name_len);
+ assert(name_len > 0);
+ addrinfo_ptr->ai_canonname = cur_ptr;
+ cur_ptr += ALIGNED_SIZE(name_len);
+ }
+ assert(cur_ptr <= alloc_ptr + addrinfo_len);
+
+ /* set next ptr */
+ addrinfow_ptr = addrinfow_ptr->ai_next;
+ if (addrinfow_ptr != NULL) {
+ addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr;
+ }
+ }
+ req->addrinfo = (struct addrinfo*)alloc_ptr;
+ } else {
+ req->retcode = UV_EAI_MEMORY;
+ }
+ }
+
+ /* return memory to system */
+ if (req->addrinfow != NULL) {
+ FreeAddrInfoW(req->addrinfow);
+ req->addrinfow = NULL;
+ }
+
+complete:
+ uv__req_unregister(req->loop, req);
+
+ /* finally do callback with converted result */
+ if (req->getaddrinfo_cb)
+ req->getaddrinfo_cb(req, req->retcode, req->addrinfo);
+}
+
+
+void uv_freeaddrinfo(struct addrinfo* ai) {
+ char* alloc_ptr = (char*)ai;
+
+ /* release copied result memory */
+ uv__free(alloc_ptr);
+}
+
+
+/*
+ * Entry point for getaddrinfo
+ * we convert the UTF-8 strings to UNICODE
+ * and save the UNICODE string pointers in the req
+ * We also copy hints so that caller does not need to keep memory until the
+ * callback.
+ * return 0 if a callback will be made
+ * return error code if validation fails
+ *
+ * To minimize allocation we calculate total size required,
+ * and copy all structs and referenced strings into the one block.
+ * Each size calculation is adjusted to avoid unaligned pointers.
+ */
+int uv_getaddrinfo(uv_loop_t* loop,
+ uv_getaddrinfo_t* req,
+ uv_getaddrinfo_cb getaddrinfo_cb,
+ const char* node,
+ const char* service,
+ const struct addrinfo* hints) {
+ int nodesize = 0;
+ int servicesize = 0;
+ int hintssize = 0;
+ char* alloc_ptr = NULL;
+ int err;
+
+ if (req == NULL || (node == NULL && service == NULL)) {
+ err = WSAEINVAL;
+ goto error;
+ }
+
+ uv_req_init(loop, (uv_req_t*)req);
+
+ req->getaddrinfo_cb = getaddrinfo_cb;
+ req->addrinfo = NULL;
+ req->type = UV_GETADDRINFO;
+ req->loop = loop;
+ req->retcode = 0;
+
+ /* calculate required memory size for all input values */
+ if (node != NULL) {
+ nodesize = ALIGNED_SIZE(uv_utf8_to_utf16(node, NULL, 0) * sizeof(WCHAR));
+ if (nodesize == 0) {
+ err = GetLastError();
+ goto error;
+ }
+ }
+
+ if (service != NULL) {
+ servicesize = ALIGNED_SIZE(uv_utf8_to_utf16(service, NULL, 0) *
+ sizeof(WCHAR));
+ if (servicesize == 0) {
+ err = GetLastError();
+ goto error;
+ }
+ }
+ if (hints != NULL) {
+ hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW));
+ }
+
+ /* allocate memory for inputs, and partition it as needed */
+ alloc_ptr = (char*)uv__malloc(nodesize + servicesize + hintssize);
+ if (!alloc_ptr) {
+ err = WSAENOBUFS;
+ goto error;
+ }
+
+ /* save alloc_ptr now so we can free if error */
+ req->alloc = (void*)alloc_ptr;
+
+ /* convert node string to UTF16 into allocated memory and save pointer in */
+ /* the request. */
+ if (node != NULL) {
+ req->node = (WCHAR*)alloc_ptr;
+ if (uv_utf8_to_utf16(node,
+ (WCHAR*) alloc_ptr,
+ nodesize / sizeof(WCHAR)) == 0) {
+ err = GetLastError();
+ goto error;
+ }
+ alloc_ptr += nodesize;
+ } else {
+ req->node = NULL;
+ }
+
+ /* convert service string to UTF16 into allocated memory and save pointer */
+ /* in the req. */
+ if (service != NULL) {
+ req->service = (WCHAR*)alloc_ptr;
+ if (uv_utf8_to_utf16(service,
+ (WCHAR*) alloc_ptr,
+ servicesize / sizeof(WCHAR)) == 0) {
+ err = GetLastError();
+ goto error;
+ }
+ alloc_ptr += servicesize;
+ } else {
+ req->service = NULL;
+ }
+
+ /* copy hints to allocated memory and save pointer in req */
+ if (hints != NULL) {
+ req->addrinfow = (struct addrinfoW*)alloc_ptr;
+ req->addrinfow->ai_family = hints->ai_family;
+ req->addrinfow->ai_socktype = hints->ai_socktype;
+ req->addrinfow->ai_protocol = hints->ai_protocol;
+ req->addrinfow->ai_flags = hints->ai_flags;
+ req->addrinfow->ai_addrlen = 0;
+ req->addrinfow->ai_canonname = NULL;
+ req->addrinfow->ai_addr = NULL;
+ req->addrinfow->ai_next = NULL;
+ } else {
+ req->addrinfow = NULL;
+ }
+
+ uv__req_register(loop, req);
+
+ if (getaddrinfo_cb) {
+ uv__work_submit(loop,
+ &req->work_req,
+ uv__getaddrinfo_work,
+ uv__getaddrinfo_done);
+ return 0;
+ } else {
+ uv__getaddrinfo_work(&req->work_req);
+ uv__getaddrinfo_done(&req->work_req, 0);
+ return req->retcode;
+ }
+
+error:
+ if (req != NULL) {
+ uv__free(req->alloc);
+ req->alloc = NULL;
+ }
+ return uv_translate_sys_error(err);
+}
diff --git a/3rdparty/libuv/src/win/getnameinfo.c b/3rdparty/libuv/src/win/getnameinfo.c
new file mode 100644
index 00000000000..66b64b88324
--- /dev/null
+++ b/3rdparty/libuv/src/win/getnameinfo.c
@@ -0,0 +1,150 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to
+* deal in the Software without restriction, including without limitation the
+* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+* sell copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+* IN THE SOFTWARE.
+*/
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "req-inl.h"
+
+#ifndef GetNameInfo
+int WSAAPI GetNameInfoW(
+ const SOCKADDR *pSockaddr,
+ socklen_t SockaddrLength,
+ PWCHAR pNodeBuffer,
+ DWORD NodeBufferSize,
+ PWCHAR pServiceBuffer,
+ DWORD ServiceBufferSize,
+ INT Flags
+);
+#endif
+
+static void uv__getnameinfo_work(struct uv__work* w) {
+ uv_getnameinfo_t* req;
+ WCHAR host[NI_MAXHOST];
+ WCHAR service[NI_MAXSERV];
+ int ret = 0;
+
+ req = container_of(w, uv_getnameinfo_t, work_req);
+ if (GetNameInfoW((struct sockaddr*)&req->storage,
+ sizeof(req->storage),
+ host,
+ ARRAY_SIZE(host),
+ service,
+ ARRAY_SIZE(service),
+ req->flags)) {
+ ret = WSAGetLastError();
+ }
+ req->retcode = uv__getaddrinfo_translate_error(ret);
+
+ /* convert results to UTF-8 */
+ WideCharToMultiByte(CP_UTF8,
+ 0,
+ host,
+ -1,
+ req->host,
+ sizeof(req->host),
+ NULL,
+ NULL);
+
+ WideCharToMultiByte(CP_UTF8,
+ 0,
+ service,
+ -1,
+ req->service,
+ sizeof(req->service),
+ NULL,
+ NULL);
+}
+
+
+/*
+* Called from uv_run when complete.
+*/
+static void uv__getnameinfo_done(struct uv__work* w, int status) {
+ uv_getnameinfo_t* req;
+ char* host;
+ char* service;
+
+ req = container_of(w, uv_getnameinfo_t, work_req);
+ uv__req_unregister(req->loop, req);
+ host = service = NULL;
+
+ if (status == UV_ECANCELED) {
+ assert(req->retcode == 0);
+ req->retcode = UV_EAI_CANCELED;
+ } else if (req->retcode == 0) {
+ host = req->host;
+ service = req->service;
+ }
+
+ if (req->getnameinfo_cb)
+ req->getnameinfo_cb(req, req->retcode, host, service);
+}
+
+
+/*
+* Entry point for getnameinfo
+* return 0 if a callback will be made
+* return error code if validation fails
+*/
+int uv_getnameinfo(uv_loop_t* loop,
+ uv_getnameinfo_t* req,
+ uv_getnameinfo_cb getnameinfo_cb,
+ const struct sockaddr* addr,
+ int flags) {
+ if (req == NULL || addr == NULL)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in));
+ } else if (addr->sa_family == AF_INET6) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in6));
+ } else {
+ return UV_EINVAL;
+ }
+
+ uv_req_init(loop, (uv_req_t*)req);
+ uv__req_register(loop, req);
+
+ req->getnameinfo_cb = getnameinfo_cb;
+ req->flags = flags;
+ req->type = UV_GETNAMEINFO;
+ req->loop = loop;
+ req->retcode = 0;
+
+ if (getnameinfo_cb) {
+ uv__work_submit(loop,
+ &req->work_req,
+ uv__getnameinfo_work,
+ uv__getnameinfo_done);
+ return 0;
+ } else {
+ uv__getnameinfo_work(&req->work_req);
+ uv__getnameinfo_done(&req->work_req, 0);
+ return req->retcode;
+ }
+}
diff --git a/3rdparty/libuv/src/win/handle-inl.h b/3rdparty/libuv/src/win/handle-inl.h
new file mode 100644
index 00000000000..8d0334cc52a
--- /dev/null
+++ b/3rdparty/libuv/src/win/handle-inl.h
@@ -0,0 +1,179 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_HANDLE_INL_H_
+#define UV_WIN_HANDLE_INL_H_
+
+#include <assert.h>
+#include <io.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+#define DECREASE_ACTIVE_COUNT(loop, handle) \
+ do { \
+ if (--(handle)->activecnt == 0 && \
+ !((handle)->flags & UV__HANDLE_CLOSING)) { \
+ uv__handle_stop((handle)); \
+ } \
+ assert((handle)->activecnt >= 0); \
+ } while (0)
+
+
+#define INCREASE_ACTIVE_COUNT(loop, handle) \
+ do { \
+ if ((handle)->activecnt++ == 0) { \
+ uv__handle_start((handle)); \
+ } \
+ assert((handle)->activecnt > 0); \
+ } while (0)
+
+
+#define DECREASE_PENDING_REQ_COUNT(handle) \
+ do { \
+ assert(handle->reqs_pending > 0); \
+ handle->reqs_pending--; \
+ \
+ if (handle->flags & UV__HANDLE_CLOSING && \
+ handle->reqs_pending == 0) { \
+ uv_want_endgame(loop, (uv_handle_t*)handle); \
+ } \
+ } while (0)
+
+
+#define uv__handle_closing(handle) \
+ do { \
+ assert(!((handle)->flags & UV__HANDLE_CLOSING)); \
+ \
+ if (!(((handle)->flags & UV__HANDLE_ACTIVE) && \
+ ((handle)->flags & UV__HANDLE_REF))) \
+ uv__active_handle_add((uv_handle_t*) (handle)); \
+ \
+ (handle)->flags |= UV__HANDLE_CLOSING; \
+ (handle)->flags &= ~UV__HANDLE_ACTIVE; \
+ } while (0)
+
+
+#define uv__handle_close(handle) \
+ do { \
+ QUEUE_REMOVE(&(handle)->handle_queue); \
+ uv__active_handle_rm((uv_handle_t*) (handle)); \
+ \
+ (handle)->flags |= UV_HANDLE_CLOSED; \
+ \
+ if ((handle)->close_cb) \
+ (handle)->close_cb((uv_handle_t*) (handle)); \
+ } while (0)
+
+
+INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) {
+ if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) {
+ handle->flags |= UV_HANDLE_ENDGAME_QUEUED;
+
+ handle->endgame_next = loop->endgame_handles;
+ loop->endgame_handles = handle;
+ }
+}
+
+
+INLINE static void uv_process_endgames(uv_loop_t* loop) {
+ uv_handle_t* handle;
+
+ while (loop->endgame_handles) {
+ handle = loop->endgame_handles;
+ loop->endgame_handles = handle->endgame_next;
+
+ handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED;
+
+ switch (handle->type) {
+ case UV_TCP:
+ uv_tcp_endgame(loop, (uv_tcp_t*) handle);
+ break;
+
+ case UV_NAMED_PIPE:
+ uv_pipe_endgame(loop, (uv_pipe_t*) handle);
+ break;
+
+ case UV_TTY:
+ uv_tty_endgame(loop, (uv_tty_t*) handle);
+ break;
+
+ case UV_UDP:
+ uv_udp_endgame(loop, (uv_udp_t*) handle);
+ break;
+
+ case UV_POLL:
+ uv_poll_endgame(loop, (uv_poll_t*) handle);
+ break;
+
+ case UV_TIMER:
+ uv_timer_endgame(loop, (uv_timer_t*) handle);
+ break;
+
+ case UV_PREPARE:
+ case UV_CHECK:
+ case UV_IDLE:
+ uv_loop_watcher_endgame(loop, handle);
+ break;
+
+ case UV_ASYNC:
+ uv_async_endgame(loop, (uv_async_t*) handle);
+ break;
+
+ case UV_SIGNAL:
+ uv_signal_endgame(loop, (uv_signal_t*) handle);
+ break;
+
+ case UV_PROCESS:
+ uv_process_endgame(loop, (uv_process_t*) handle);
+ break;
+
+ case UV_FS_EVENT:
+ uv_fs_event_endgame(loop, (uv_fs_event_t*) handle);
+ break;
+
+ case UV_FS_POLL:
+ uv__fs_poll_endgame(loop, (uv_fs_poll_t*) handle);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ }
+}
+
+INLINE static HANDLE uv__get_osfhandle(int fd)
+{
+ /* _get_osfhandle() raises an assert in debug builds if the FD is invalid. */
+ /* But it also correctly checks the FD and returns INVALID_HANDLE_VALUE */
+ /* for invalid FDs in release builds (or if you let the assert continue). */
+ /* So this wrapper function disables asserts when calling _get_osfhandle. */
+
+ HANDLE handle;
+ UV_BEGIN_DISABLE_CRT_ASSERT();
+ handle = (HANDLE) _get_osfhandle(fd);
+ UV_END_DISABLE_CRT_ASSERT();
+ return handle;
+}
+
+#endif /* UV_WIN_HANDLE_INL_H_ */
diff --git a/3rdparty/libuv/src/win/handle.c b/3rdparty/libuv/src/win/handle.c
new file mode 100644
index 00000000000..72b49d97904
--- /dev/null
+++ b/3rdparty/libuv/src/win/handle.c
@@ -0,0 +1,154 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <io.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+
+
+uv_handle_type uv_guess_handle(uv_file file) {
+ HANDLE handle;
+ DWORD mode;
+
+ if (file < 0) {
+ return UV_UNKNOWN_HANDLE;
+ }
+
+ handle = uv__get_osfhandle(file);
+
+ switch (GetFileType(handle)) {
+ case FILE_TYPE_CHAR:
+ if (GetConsoleMode(handle, &mode)) {
+ return UV_TTY;
+ } else {
+ return UV_FILE;
+ }
+
+ case FILE_TYPE_PIPE:
+ return UV_NAMED_PIPE;
+
+ case FILE_TYPE_DISK:
+ return UV_FILE;
+
+ default:
+ return UV_UNKNOWN_HANDLE;
+ }
+}
+
+
+int uv_is_active(const uv_handle_t* handle) {
+ return (handle->flags & UV__HANDLE_ACTIVE) &&
+ !(handle->flags & UV__HANDLE_CLOSING);
+}
+
+
+void uv_close(uv_handle_t* handle, uv_close_cb cb) {
+ uv_loop_t* loop = handle->loop;
+
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ assert(0);
+ return;
+ }
+
+ handle->close_cb = cb;
+
+ /* Handle-specific close actions */
+ switch (handle->type) {
+ case UV_TCP:
+ uv_tcp_close(loop, (uv_tcp_t*)handle);
+ return;
+
+ case UV_NAMED_PIPE:
+ uv_pipe_close(loop, (uv_pipe_t*) handle);
+ return;
+
+ case UV_TTY:
+ uv_tty_close((uv_tty_t*) handle);
+ return;
+
+ case UV_UDP:
+ uv_udp_close(loop, (uv_udp_t*) handle);
+ return;
+
+ case UV_POLL:
+ uv_poll_close(loop, (uv_poll_t*) handle);
+ return;
+
+ case UV_TIMER:
+ uv_timer_stop((uv_timer_t*)handle);
+ uv__handle_closing(handle);
+ uv_want_endgame(loop, handle);
+ return;
+
+ case UV_PREPARE:
+ uv_prepare_stop((uv_prepare_t*)handle);
+ uv__handle_closing(handle);
+ uv_want_endgame(loop, handle);
+ return;
+
+ case UV_CHECK:
+ uv_check_stop((uv_check_t*)handle);
+ uv__handle_closing(handle);
+ uv_want_endgame(loop, handle);
+ return;
+
+ case UV_IDLE:
+ uv_idle_stop((uv_idle_t*)handle);
+ uv__handle_closing(handle);
+ uv_want_endgame(loop, handle);
+ return;
+
+ case UV_ASYNC:
+ uv_async_close(loop, (uv_async_t*) handle);
+ return;
+
+ case UV_SIGNAL:
+ uv_signal_close(loop, (uv_signal_t*) handle);
+ return;
+
+ case UV_PROCESS:
+ uv_process_close(loop, (uv_process_t*) handle);
+ return;
+
+ case UV_FS_EVENT:
+ uv_fs_event_close(loop, (uv_fs_event_t*) handle);
+ return;
+
+ case UV_FS_POLL:
+ uv__fs_poll_close((uv_fs_poll_t*) handle);
+ uv__handle_closing(handle);
+ uv_want_endgame(loop, handle);
+ return;
+
+ default:
+ /* Not supported */
+ abort();
+ }
+}
+
+
+int uv_is_closing(const uv_handle_t* handle) {
+ return !!(handle->flags & (UV__HANDLE_CLOSING | UV_HANDLE_CLOSED));
+}
diff --git a/3rdparty/libuv/src/win/internal.h b/3rdparty/libuv/src/win/internal.h
new file mode 100644
index 00000000000..783f21af0fe
--- /dev/null
+++ b/3rdparty/libuv/src/win/internal.h
@@ -0,0 +1,382 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_INTERNAL_H_
+#define UV_WIN_INTERNAL_H_
+
+#include "uv.h"
+#include "../uv-common.h"
+
+#include "tree.h"
+#include "winapi.h"
+#include "winsock.h"
+
+#ifdef _MSC_VER
+# define INLINE __inline
+# define UV_THREAD_LOCAL __declspec( thread )
+#else
+# define INLINE inline
+# define UV_THREAD_LOCAL __thread
+#endif
+
+
+#ifdef _DEBUG
+
+extern UV_THREAD_LOCAL int uv__crt_assert_enabled;
+
+#define UV_BEGIN_DISABLE_CRT_ASSERT() \
+ { \
+ int uv__saved_crt_assert_enabled = uv__crt_assert_enabled; \
+ uv__crt_assert_enabled = FALSE;
+
+
+#define UV_END_DISABLE_CRT_ASSERT() \
+ uv__crt_assert_enabled = uv__saved_crt_assert_enabled; \
+ }
+
+#else
+#define UV_BEGIN_DISABLE_CRT_ASSERT()
+#define UV_END_DISABLE_CRT_ASSERT()
+#endif
+
+/*
+ * Handles
+ * (also see handle-inl.h)
+ */
+
+/* Used by all handles. */
+#define UV_HANDLE_CLOSED 0x00000002
+#define UV_HANDLE_ENDGAME_QUEUED 0x00000008
+
+/* uv-common.h: #define UV__HANDLE_CLOSING 0x00000001 */
+/* uv-common.h: #define UV__HANDLE_ACTIVE 0x00000040 */
+/* uv-common.h: #define UV__HANDLE_REF 0x00000020 */
+/* uv-common.h: #define UV_HANDLE_INTERNAL 0x00000080 */
+
+/* Used by streams and UDP handles. */
+#define UV_HANDLE_READING 0x00000100
+#define UV_HANDLE_BOUND 0x00000200
+#define UV_HANDLE_LISTENING 0x00000800
+#define UV_HANDLE_CONNECTION 0x00001000
+#define UV_HANDLE_READABLE 0x00008000
+#define UV_HANDLE_WRITABLE 0x00010000
+#define UV_HANDLE_READ_PENDING 0x00020000
+#define UV_HANDLE_SYNC_BYPASS_IOCP 0x00040000
+#define UV_HANDLE_ZERO_READ 0x00080000
+#define UV_HANDLE_EMULATE_IOCP 0x00100000
+#define UV_HANDLE_BLOCKING_WRITES 0x00200000
+
+/* Used by uv_tcp_t and uv_udp_t handles */
+#define UV_HANDLE_IPV6 0x01000000
+
+/* Only used by uv_tcp_t handles. */
+#define UV_HANDLE_TCP_NODELAY 0x02000000
+#define UV_HANDLE_TCP_KEEPALIVE 0x04000000
+#define UV_HANDLE_TCP_SINGLE_ACCEPT 0x08000000
+#define UV_HANDLE_TCP_ACCEPT_STATE_CHANGING 0x10000000
+#define UV_HANDLE_TCP_SOCKET_CLOSED 0x20000000
+#define UV_HANDLE_SHARED_TCP_SOCKET 0x40000000
+
+/* Only used by uv_pipe_t handles. */
+#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x01000000
+#define UV_HANDLE_PIPESERVER 0x02000000
+#define UV_HANDLE_PIPE_READ_CANCELABLE 0x04000000
+
+/* Only used by uv_tty_t handles. */
+#define UV_HANDLE_TTY_READABLE 0x01000000
+#define UV_HANDLE_TTY_RAW 0x02000000
+#define UV_HANDLE_TTY_SAVED_POSITION 0x04000000
+#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x08000000
+
+/* Only used by uv_poll_t handles. */
+#define UV_HANDLE_POLL_SLOW 0x02000000
+
+
+/*
+ * Requests: see req-inl.h
+ */
+
+
+/*
+ * Streams: see stream-inl.h
+ */
+
+
+/*
+ * TCP
+ */
+
+typedef struct {
+ WSAPROTOCOL_INFOW socket_info;
+ int delayed_error;
+} uv__ipc_socket_info_ex;
+
+int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb);
+int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client);
+int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb);
+int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle,
+ const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
+int uv__tcp_try_write(uv_tcp_t* handle, const uv_buf_t bufs[],
+ unsigned int nbufs);
+
+void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req);
+void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_write_t* req);
+void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_req_t* req);
+void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_connect_t* req);
+
+void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp);
+void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
+
+int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
+ int tcp_connection);
+
+int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
+ LPWSAPROTOCOL_INFOW protocol_info);
+
+
+/*
+ * UDP
+ */
+void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req);
+void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
+ uv_udp_send_t* req);
+
+void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle);
+void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle);
+
+
+/*
+ * Pipes
+ */
+int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
+ char* name, size_t nameSize);
+
+int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
+int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client);
+int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb);
+int uv_pipe_write(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle,
+ const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
+int uv_pipe_write2(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle,
+ const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle,
+ uv_write_cb cb);
+void uv__pipe_pause_read(uv_pipe_t* handle);
+void uv__pipe_unpause_read(uv_pipe_t* handle);
+void uv__pipe_stop_read(uv_pipe_t* handle);
+
+void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_req_t* req);
+void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_write_t* req);
+void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_req_t* raw_req);
+void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_connect_t* req);
+void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_shutdown_t* req);
+
+void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle);
+void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle);
+void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle);
+
+
+/*
+ * TTY
+ */
+void uv_console_init();
+
+int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb);
+int uv_tty_read_stop(uv_tty_t* handle);
+int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle,
+ const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
+int uv__tty_try_write(uv_tty_t* handle, const uv_buf_t bufs[],
+ unsigned int nbufs);
+void uv_tty_close(uv_tty_t* handle);
+
+void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* req);
+void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_write_t* req);
+/* TODO: remove me */
+void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* raw_req);
+/* TODO: remove me */
+void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_connect_t* req);
+
+void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle);
+
+
+/*
+ * Poll watchers
+ */
+void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
+ uv_req_t* req);
+
+int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle);
+void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle);
+
+
+/*
+ * Timers
+ */
+void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle);
+
+DWORD uv__next_timeout(const uv_loop_t* loop);
+void uv__time_forward(uv_loop_t* loop, uint64_t msecs);
+void uv_process_timers(uv_loop_t* loop);
+
+
+/*
+ * Loop watchers
+ */
+void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle);
+
+void uv_prepare_invoke(uv_loop_t* loop);
+void uv_check_invoke(uv_loop_t* loop);
+void uv_idle_invoke(uv_loop_t* loop);
+
+void uv__once_init();
+
+
+/*
+ * Async watcher
+ */
+void uv_async_close(uv_loop_t* loop, uv_async_t* handle);
+void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle);
+
+void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
+ uv_req_t* req);
+
+
+/*
+ * Signal watcher
+ */
+void uv_signals_init();
+int uv__signal_dispatch(int signum);
+
+void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle);
+void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle);
+
+void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
+ uv_req_t* req);
+
+
+/*
+ * Spawn
+ */
+void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle);
+void uv_process_close(uv_loop_t* loop, uv_process_t* handle);
+void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle);
+
+
+/*
+ * Error
+ */
+int uv_translate_sys_error(int sys_errno);
+
+
+/*
+ * FS
+ */
+void uv_fs_init();
+
+
+/*
+ * FS Event
+ */
+void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
+ uv_fs_event_t* handle);
+void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle);
+void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle);
+
+
+/*
+ * Stat poller.
+ */
+void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle);
+
+
+/*
+ * Utilities.
+ */
+void uv__util_init();
+
+uint64_t uv__hrtime(double scale);
+int uv_parent_pid();
+int uv_current_pid();
+__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
+
+
+/*
+ * Process stdio handles.
+ */
+int uv__stdio_create(uv_loop_t* loop,
+ const uv_process_options_t* options,
+ BYTE** buffer_ptr);
+void uv__stdio_destroy(BYTE* buffer);
+void uv__stdio_noinherit(BYTE* buffer);
+int uv__stdio_verify(BYTE* buffer, WORD size);
+WORD uv__stdio_size(BYTE* buffer);
+HANDLE uv__stdio_handle(BYTE* buffer, int fd);
+
+
+/*
+ * Winapi and ntapi utility functions
+ */
+void uv_winapi_init();
+
+
+/*
+ * Winsock utility functions
+ */
+void uv_winsock_init();
+
+int uv_ntstatus_to_winsock_error(NTSTATUS status);
+
+BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target);
+BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target);
+
+int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
+ DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
+int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
+ DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
+ int* addr_len, WSAOVERLAPPED *overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
+
+int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
+ AFD_POLL_INFO* info_out, OVERLAPPED* overlapped);
+
+/* Whether there are any non-IFS LSPs stacked on TCP */
+extern int uv_tcp_non_ifs_lsp_ipv4;
+extern int uv_tcp_non_ifs_lsp_ipv6;
+
+/* Ip address used to bind to any port at any interface */
+extern struct sockaddr_in uv_addr_ip4_any_;
+extern struct sockaddr_in6 uv_addr_ip6_any_;
+
+#endif /* UV_WIN_INTERNAL_H_ */
diff --git a/3rdparty/libuv/src/win/loop-watcher.c b/3rdparty/libuv/src/win/loop-watcher.c
new file mode 100644
index 00000000000..20e4509f838
--- /dev/null
+++ b/3rdparty/libuv/src/win/loop-watcher.c
@@ -0,0 +1,122 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+
+
+void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ handle->flags |= UV_HANDLE_CLOSED;
+ uv__handle_close(handle);
+ }
+}
+
+
+#define UV_LOOP_WATCHER_DEFINE(name, NAME) \
+ int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_##NAME); \
+ \
+ return 0; \
+ } \
+ \
+ \
+ int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
+ uv_loop_t* loop = handle->loop; \
+ uv_##name##_t* old_head; \
+ \
+ assert(handle->type == UV_##NAME); \
+ \
+ if (uv__is_active(handle)) \
+ return 0; \
+ \
+ if (cb == NULL) \
+ return UV_EINVAL; \
+ \
+ old_head = loop->name##_handles; \
+ \
+ handle->name##_next = old_head; \
+ handle->name##_prev = NULL; \
+ \
+ if (old_head) { \
+ old_head->name##_prev = handle; \
+ } \
+ \
+ loop->name##_handles = handle; \
+ \
+ handle->name##_cb = cb; \
+ uv__handle_start(handle); \
+ \
+ return 0; \
+ } \
+ \
+ \
+ int uv_##name##_stop(uv_##name##_t* handle) { \
+ uv_loop_t* loop = handle->loop; \
+ \
+ assert(handle->type == UV_##NAME); \
+ \
+ if (!uv__is_active(handle)) \
+ return 0; \
+ \
+ /* Update loop head if needed */ \
+ if (loop->name##_handles == handle) { \
+ loop->name##_handles = handle->name##_next; \
+ } \
+ \
+ /* Update the iterator-next pointer of needed */ \
+ if (loop->next_##name##_handle == handle) { \
+ loop->next_##name##_handle = handle->name##_next; \
+ } \
+ \
+ if (handle->name##_prev) { \
+ handle->name##_prev->name##_next = handle->name##_next; \
+ } \
+ if (handle->name##_next) { \
+ handle->name##_next->name##_prev = handle->name##_prev; \
+ } \
+ \
+ uv__handle_stop(handle); \
+ \
+ return 0; \
+ } \
+ \
+ \
+ void uv_##name##_invoke(uv_loop_t* loop) { \
+ uv_##name##_t* handle; \
+ \
+ (loop)->next_##name##_handle = (loop)->name##_handles; \
+ \
+ while ((loop)->next_##name##_handle != NULL) { \
+ handle = (loop)->next_##name##_handle; \
+ (loop)->next_##name##_handle = handle->name##_next; \
+ \
+ handle->name##_cb(handle); \
+ } \
+ }
+
+UV_LOOP_WATCHER_DEFINE(prepare, PREPARE)
+UV_LOOP_WATCHER_DEFINE(check, CHECK)
+UV_LOOP_WATCHER_DEFINE(idle, IDLE)
diff --git a/3rdparty/libuv/src/win/pipe.c b/3rdparty/libuv/src/win/pipe.c
new file mode 100644
index 00000000000..bcce80c77e5
--- /dev/null
+++ b/3rdparty/libuv/src/win/pipe.c
@@ -0,0 +1,2118 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <io.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "stream-inl.h"
+#include "req-inl.h"
+
+typedef struct uv__ipc_queue_item_s uv__ipc_queue_item_t;
+
+struct uv__ipc_queue_item_s {
+ /*
+ * NOTE: It is important for socket_info_ex to be the first field,
+ * because we will we assigning it to the pending_ipc_info.socket_info
+ */
+ uv__ipc_socket_info_ex socket_info_ex;
+ QUEUE member;
+ int tcp_connection;
+};
+
+/* A zero-size buffer for use by uv_pipe_read */
+static char uv_zero_[] = "";
+
+/* Null uv_buf_t */
+static const uv_buf_t uv_null_buf_ = { 0, NULL };
+
+/* The timeout that the pipe will wait for the remote end to write data */
+/* when the local ends wants to shut it down. */
+static const int64_t eof_timeout = 50; /* ms */
+
+static const int default_pending_pipe_instances = 4;
+
+/* Pipe prefix */
+static char pipe_prefix[] = "\\\\?\\pipe";
+static const int pipe_prefix_len = sizeof(pipe_prefix) - 1;
+
+/* IPC protocol flags. */
+#define UV_IPC_RAW_DATA 0x0001
+#define UV_IPC_TCP_SERVER 0x0002
+#define UV_IPC_TCP_CONNECTION 0x0004
+
+/* IPC frame header. */
+typedef struct {
+ int flags;
+ uint64_t raw_data_length;
+} uv_ipc_frame_header_t;
+
+/* IPC frame, which contains an imported TCP socket stream. */
+typedef struct {
+ uv_ipc_frame_header_t header;
+ uv__ipc_socket_info_ex socket_info_ex;
+} uv_ipc_frame_uv_stream;
+
+static void eof_timer_init(uv_pipe_t* pipe);
+static void eof_timer_start(uv_pipe_t* pipe);
+static void eof_timer_stop(uv_pipe_t* pipe);
+static void eof_timer_cb(uv_timer_t* timer);
+static void eof_timer_destroy(uv_pipe_t* pipe);
+static void eof_timer_close_cb(uv_handle_t* handle);
+
+
+static void uv_unique_pipe_name(char* ptr, char* name, size_t size) {
+ snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%u", ptr, GetCurrentProcessId());
+}
+
+
+int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
+ uv_stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
+
+ handle->reqs_pending = 0;
+ handle->handle = INVALID_HANDLE_VALUE;
+ handle->name = NULL;
+ handle->pipe.conn.ipc_pid = 0;
+ handle->pipe.conn.remaining_ipc_rawdata_bytes = 0;
+ QUEUE_INIT(&handle->pipe.conn.pending_ipc_info.queue);
+ handle->pipe.conn.pending_ipc_info.queue_len = 0;
+ handle->ipc = ipc;
+ handle->pipe.conn.non_overlapped_writes_tail = NULL;
+ handle->pipe.conn.readfile_thread = NULL;
+
+ uv_req_init(loop, (uv_req_t*) &handle->pipe.conn.ipc_header_write_req);
+
+ return 0;
+}
+
+
+static void uv_pipe_connection_init(uv_pipe_t* handle) {
+ uv_connection_init((uv_stream_t*) handle);
+ handle->read_req.data = handle;
+ handle->pipe.conn.eof_timer = NULL;
+ assert(!(handle->flags & UV_HANDLE_PIPESERVER));
+ if (pCancelSynchronousIo &&
+ handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
+ uv_mutex_init(&handle->pipe.conn.readfile_mutex);
+ handle->flags |= UV_HANDLE_PIPE_READ_CANCELABLE;
+ }
+}
+
+
+static HANDLE open_named_pipe(const WCHAR* name, DWORD* duplex_flags) {
+ HANDLE pipeHandle;
+
+ /*
+ * Assume that we have a duplex pipe first, so attempt to
+ * connect with GENERIC_READ | GENERIC_WRITE.
+ */
+ pipeHandle = CreateFileW(name,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ *duplex_flags = UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+ return pipeHandle;
+ }
+
+ /*
+ * If the pipe is not duplex CreateFileW fails with
+ * ERROR_ACCESS_DENIED. In that case try to connect
+ * as a read-only or write-only.
+ */
+ if (GetLastError() == ERROR_ACCESS_DENIED) {
+ pipeHandle = CreateFileW(name,
+ GENERIC_READ | FILE_WRITE_ATTRIBUTES,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ *duplex_flags = UV_HANDLE_READABLE;
+ return pipeHandle;
+ }
+ }
+
+ if (GetLastError() == ERROR_ACCESS_DENIED) {
+ pipeHandle = CreateFileW(name,
+ GENERIC_WRITE | FILE_READ_ATTRIBUTES,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ *duplex_flags = UV_HANDLE_WRITABLE;
+ return pipeHandle;
+ }
+ }
+
+ return INVALID_HANDLE_VALUE;
+}
+
+
+static void close_pipe(uv_pipe_t* pipe) {
+ assert(pipe->u.fd == -1 || pipe->u.fd > 2);
+ if (pipe->u.fd == -1)
+ CloseHandle(pipe->handle);
+ else
+ close(pipe->u.fd);
+
+ pipe->u.fd = -1;
+ pipe->handle = INVALID_HANDLE_VALUE;
+}
+
+
+int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
+ char* name, size_t nameSize) {
+ HANDLE pipeHandle;
+ int err;
+ char* ptr = (char*)handle;
+
+ for (;;) {
+ uv_unique_pipe_name(ptr, name, nameSize);
+
+ pipeHandle = CreateNamedPipeA(name,
+ access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0,
+ NULL);
+
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ /* No name collisions. We're done. */
+ break;
+ }
+
+ err = GetLastError();
+ if (err != ERROR_PIPE_BUSY && err != ERROR_ACCESS_DENIED) {
+ goto error;
+ }
+
+ /* Pipe name collision. Increment the pointer and try again. */
+ ptr++;
+ }
+
+ if (CreateIoCompletionPort(pipeHandle,
+ loop->iocp,
+ (ULONG_PTR)handle,
+ 0) == NULL) {
+ err = GetLastError();
+ goto error;
+ }
+
+ uv_pipe_connection_init(handle);
+ handle->handle = pipeHandle;
+
+ return 0;
+
+ error:
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(pipeHandle);
+ }
+
+ return err;
+}
+
+
+static int uv_set_pipe_handle(uv_loop_t* loop,
+ uv_pipe_t* handle,
+ HANDLE pipeHandle,
+ int fd,
+ DWORD duplex_flags) {
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_MODE_INFORMATION mode_info;
+ DWORD mode = PIPE_READMODE_BYTE | PIPE_WAIT;
+ DWORD current_mode = 0;
+ DWORD err = 0;
+
+ if (!(handle->flags & UV_HANDLE_PIPESERVER) &&
+ handle->handle != INVALID_HANDLE_VALUE)
+ return UV_EBUSY;
+
+ if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) {
+ err = GetLastError();
+ if (err == ERROR_ACCESS_DENIED) {
+ /*
+ * SetNamedPipeHandleState can fail if the handle doesn't have either
+ * GENERIC_WRITE or FILE_WRITE_ATTRIBUTES.
+ * But if the handle already has the desired wait and blocking modes
+ * we can continue.
+ */
+ if (!GetNamedPipeHandleState(pipeHandle, &current_mode, NULL, NULL,
+ NULL, NULL, 0)) {
+ return -1;
+ } else if (current_mode & PIPE_NOWAIT) {
+ SetLastError(ERROR_ACCESS_DENIED);
+ return -1;
+ }
+ } else {
+ /* If this returns ERROR_INVALID_PARAMETER we probably opened
+ * something that is not a pipe. */
+ if (err == ERROR_INVALID_PARAMETER) {
+ SetLastError(WSAENOTSOCK);
+ }
+ return -1;
+ }
+ }
+
+ /* Check if the pipe was created with FILE_FLAG_OVERLAPPED. */
+ nt_status = pNtQueryInformationFile(pipeHandle,
+ &io_status,
+ &mode_info,
+ sizeof(mode_info),
+ FileModeInformation);
+ if (nt_status != STATUS_SUCCESS) {
+ return -1;
+ }
+
+ if (mode_info.Mode & FILE_SYNCHRONOUS_IO_ALERT ||
+ mode_info.Mode & FILE_SYNCHRONOUS_IO_NONALERT) {
+ /* Non-overlapped pipe. */
+ handle->flags |= UV_HANDLE_NON_OVERLAPPED_PIPE;
+ } else {
+ /* Overlapped pipe. Try to associate with IOCP. */
+ if (CreateIoCompletionPort(pipeHandle,
+ loop->iocp,
+ (ULONG_PTR)handle,
+ 0) == NULL) {
+ handle->flags |= UV_HANDLE_EMULATE_IOCP;
+ }
+ }
+
+ handle->handle = pipeHandle;
+ handle->u.fd = fd;
+ handle->flags |= duplex_flags;
+
+ return 0;
+}
+
+
+static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) {
+ uv_loop_t* loop;
+ uv_pipe_t* handle;
+ uv_shutdown_t* req;
+
+ req = (uv_shutdown_t*) parameter;
+ assert(req);
+ handle = (uv_pipe_t*) req->handle;
+ assert(handle);
+ loop = handle->loop;
+ assert(loop);
+
+ FlushFileBuffers(handle->handle);
+
+ /* Post completed */
+ POST_COMPLETION_FOR_REQ(loop, req);
+
+ return 0;
+}
+
+
+void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
+ int err;
+ DWORD result;
+ uv_shutdown_t* req;
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_PIPE_LOCAL_INFORMATION pipe_info;
+ uv__ipc_queue_item_t* item;
+
+ if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ handle->flags &= ~UV_HANDLE_PIPE_READ_CANCELABLE;
+ uv_mutex_destroy(&handle->pipe.conn.readfile_mutex);
+ }
+
+ if ((handle->flags & UV_HANDLE_CONNECTION) &&
+ handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+ req = handle->stream.conn.shutdown_req;
+
+ /* Clear the shutdown_req field so we don't go here again. */
+ handle->stream.conn.shutdown_req = NULL;
+
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ /* Already closing. Cancel the shutdown. */
+ if (req->cb) {
+ req->cb(req, UV_ECANCELED);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+
+ /* Try to avoid flushing the pipe buffer in the thread pool. */
+ nt_status = pNtQueryInformationFile(handle->handle,
+ &io_status,
+ &pipe_info,
+ sizeof pipe_info,
+ FilePipeLocalInformation);
+
+ if (nt_status != STATUS_SUCCESS) {
+ /* Failure */
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */
+ if (req->cb) {
+ err = pRtlNtStatusToDosError(nt_status);
+ req->cb(req, uv_translate_sys_error(err));
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+
+ if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) {
+ /* Short-circuit, no need to call FlushFileBuffers. */
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ return;
+ }
+
+ /* Run FlushFileBuffers in the thread pool. */
+ result = QueueUserWorkItem(pipe_shutdown_thread_proc,
+ req,
+ WT_EXECUTELONGFUNCTION);
+ if (result) {
+ return;
+
+ } else {
+ /* Failure. */
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */
+ if (req->cb) {
+ err = GetLastError();
+ req->cb(req, uv_translate_sys_error(err));
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+ }
+
+ if (handle->flags & UV__HANDLE_CLOSING &&
+ handle->reqs_pending == 0) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ if (handle->flags & UV_HANDLE_CONNECTION) {
+ /* Free pending sockets */
+ while (!QUEUE_EMPTY(&handle->pipe.conn.pending_ipc_info.queue)) {
+ QUEUE* q;
+ SOCKET socket;
+
+ q = QUEUE_HEAD(&handle->pipe.conn.pending_ipc_info.queue);
+ QUEUE_REMOVE(q);
+ item = QUEUE_DATA(q, uv__ipc_queue_item_t, member);
+
+ /* Materialize socket and close it */
+ socket = WSASocketW(FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ &item->socket_info_ex.socket_info,
+ 0,
+ WSA_FLAG_OVERLAPPED);
+ uv__free(item);
+
+ if (socket != INVALID_SOCKET)
+ closesocket(socket);
+ }
+ handle->pipe.conn.pending_ipc_info.queue_len = 0;
+
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(handle->read_req.wait_handle);
+ handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
+ }
+ if (handle->read_req.event_handle) {
+ CloseHandle(handle->read_req.event_handle);
+ handle->read_req.event_handle = NULL;
+ }
+ }
+ }
+
+ if (handle->flags & UV_HANDLE_PIPESERVER) {
+ assert(handle->pipe.serv.accept_reqs);
+ uv__free(handle->pipe.serv.accept_reqs);
+ handle->pipe.serv.accept_reqs = NULL;
+ }
+
+ uv__handle_close(handle);
+ }
+}
+
+
+void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
+ if (handle->flags & UV_HANDLE_BOUND)
+ return;
+ handle->pipe.serv.pending_instances = count;
+ handle->flags |= UV_HANDLE_PIPESERVER;
+}
+
+
+/* Creates a pipe server. */
+int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
+ uv_loop_t* loop = handle->loop;
+ int i, err, nameSize;
+ uv_pipe_accept_t* req;
+
+ if (handle->flags & UV_HANDLE_BOUND) {
+ return UV_EINVAL;
+ }
+
+ if (!name) {
+ return UV_EINVAL;
+ }
+
+ if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
+ handle->pipe.serv.pending_instances = default_pending_pipe_instances;
+ }
+
+ handle->pipe.serv.accept_reqs = (uv_pipe_accept_t*)
+ uv__malloc(sizeof(uv_pipe_accept_t) * handle->pipe.serv.pending_instances);
+ if (!handle->pipe.serv.accept_reqs) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
+ req = &handle->pipe.serv.accept_reqs[i];
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_ACCEPT;
+ req->data = handle;
+ req->pipeHandle = INVALID_HANDLE_VALUE;
+ req->next_pending = NULL;
+ }
+
+ /* Convert name to UTF16. */
+ nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR);
+ handle->name = (WCHAR*)uv__malloc(nameSize);
+ if (!handle->name) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) {
+ err = GetLastError();
+ goto error;
+ }
+
+ /*
+ * Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE.
+ * If this fails then there's already a pipe server for the given pipe name.
+ */
+ handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
+ FILE_FLAG_FIRST_PIPE_INSTANCE,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
+
+ if (handle->pipe.serv.accept_reqs[0].pipeHandle == INVALID_HANDLE_VALUE) {
+ err = GetLastError();
+ if (err == ERROR_ACCESS_DENIED) {
+ err = WSAEADDRINUSE; /* Translates to UV_EADDRINUSE. */
+ } else if (err == ERROR_PATH_NOT_FOUND || err == ERROR_INVALID_NAME) {
+ err = WSAEACCES; /* Translates to UV_EACCES. */
+ }
+ goto error;
+ }
+
+ if (uv_set_pipe_handle(loop,
+ handle,
+ handle->pipe.serv.accept_reqs[0].pipeHandle,
+ -1,
+ 0)) {
+ err = GetLastError();
+ goto error;
+ }
+
+ handle->pipe.serv.pending_accepts = NULL;
+ handle->flags |= UV_HANDLE_PIPESERVER;
+ handle->flags |= UV_HANDLE_BOUND;
+
+ return 0;
+
+error:
+ if (handle->name) {
+ uv__free(handle->name);
+ handle->name = NULL;
+ }
+
+ if (handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle->pipe.serv.accept_reqs[0].pipeHandle);
+ handle->pipe.serv.accept_reqs[0].pipeHandle = INVALID_HANDLE_VALUE;
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
+ uv_loop_t* loop;
+ uv_pipe_t* handle;
+ uv_connect_t* req;
+ HANDLE pipeHandle = INVALID_HANDLE_VALUE;
+ DWORD duplex_flags;
+
+ req = (uv_connect_t*) parameter;
+ assert(req);
+ handle = (uv_pipe_t*) req->handle;
+ assert(handle);
+ loop = handle->loop;
+ assert(loop);
+
+ /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. */
+ /* We wait for the pipe to become available with WaitNamedPipe. */
+ while (WaitNamedPipeW(handle->name, 30000)) {
+ /* The pipe is now available, try to connect. */
+ pipeHandle = open_named_pipe(handle->name, &duplex_flags);
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ break;
+ }
+
+ SwitchToThread();
+ }
+
+ if (pipeHandle != INVALID_HANDLE_VALUE &&
+ !uv_set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags)) {
+ SET_REQ_SUCCESS(req);
+ } else {
+ SET_REQ_ERROR(req, GetLastError());
+ }
+
+ /* Post completed */
+ POST_COMPLETION_FOR_REQ(loop, req);
+
+ return 0;
+}
+
+
+void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
+ const char* name, uv_connect_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ int err, nameSize;
+ HANDLE pipeHandle = INVALID_HANDLE_VALUE;
+ DWORD duplex_flags;
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_CONNECT;
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+
+ /* Convert name to UTF16. */
+ nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR);
+ handle->name = (WCHAR*)uv__malloc(nameSize);
+ if (!handle->name) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) {
+ err = GetLastError();
+ goto error;
+ }
+
+ pipeHandle = open_named_pipe(handle->name, &duplex_flags);
+ if (pipeHandle == INVALID_HANDLE_VALUE) {
+ if (GetLastError() == ERROR_PIPE_BUSY) {
+ /* Wait for the server to make a pipe instance available. */
+ if (!QueueUserWorkItem(&pipe_connect_thread_proc,
+ req,
+ WT_EXECUTELONGFUNCTION)) {
+ err = GetLastError();
+ goto error;
+ }
+
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ handle->reqs_pending++;
+
+ return;
+ }
+
+ err = GetLastError();
+ goto error;
+ }
+
+ assert(pipeHandle != INVALID_HANDLE_VALUE);
+
+ if (uv_set_pipe_handle(loop,
+ (uv_pipe_t*) req->handle,
+ pipeHandle,
+ -1,
+ duplex_flags)) {
+ err = GetLastError();
+ goto error;
+ }
+
+ SET_REQ_SUCCESS(req);
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ return;
+
+error:
+ if (handle->name) {
+ uv__free(handle->name);
+ handle->name = NULL;
+ }
+
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(pipeHandle);
+ }
+
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, err);
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ return;
+}
+
+
+void uv__pipe_pause_read(uv_pipe_t* handle) {
+ if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ /* Pause the ReadFile task briefly, to work
+ around the Windows kernel bug that causes
+ any access to a NamedPipe to deadlock if
+ any process has called ReadFile */
+ HANDLE h;
+ uv_mutex_lock(&handle->pipe.conn.readfile_mutex);
+ h = handle->pipe.conn.readfile_thread;
+ while (h) {
+ /* spinlock: we expect this to finish quickly,
+ or we are probably about to deadlock anyways
+ (in the kernel), so it doesn't matter */
+ pCancelSynchronousIo(h);
+ SwitchToThread(); /* yield thread control briefly */
+ h = handle->pipe.conn.readfile_thread;
+ }
+ }
+}
+
+
+void uv__pipe_unpause_read(uv_pipe_t* handle) {
+ if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ uv_mutex_unlock(&handle->pipe.conn.readfile_mutex);
+ }
+}
+
+
+void uv__pipe_stop_read(uv_pipe_t* handle) {
+ handle->flags &= ~UV_HANDLE_READING;
+ uv__pipe_pause_read((uv_pipe_t*)handle);
+ uv__pipe_unpause_read((uv_pipe_t*)handle);
+}
+
+
+/* Cleans up uv_pipe_t (server or connection) and all resources associated */
+/* with it. */
+void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) {
+ int i;
+ HANDLE pipeHandle;
+
+ uv__pipe_stop_read(handle);
+
+ if (handle->name) {
+ uv__free(handle->name);
+ handle->name = NULL;
+ }
+
+ if (handle->flags & UV_HANDLE_PIPESERVER) {
+ for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
+ pipeHandle = handle->pipe.serv.accept_reqs[i].pipeHandle;
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(pipeHandle);
+ handle->pipe.serv.accept_reqs[i].pipeHandle = INVALID_HANDLE_VALUE;
+ }
+ }
+ handle->handle = INVALID_HANDLE_VALUE;
+ }
+
+ if (handle->flags & UV_HANDLE_CONNECTION) {
+ handle->flags &= ~UV_HANDLE_WRITABLE;
+ eof_timer_destroy(handle);
+ }
+
+ if ((handle->flags & UV_HANDLE_CONNECTION)
+ && handle->handle != INVALID_HANDLE_VALUE)
+ close_pipe(handle);
+}
+
+
+void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) {
+ if (handle->flags & UV_HANDLE_READING) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ }
+
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ handle->flags &= ~UV_HANDLE_LISTENING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ }
+
+ uv_pipe_cleanup(loop, handle);
+
+ if (handle->reqs_pending == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+
+ handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
+ uv__handle_closing(handle);
+}
+
+
+static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_pipe_accept_t* req, BOOL firstInstance) {
+ assert(handle->flags & UV_HANDLE_LISTENING);
+
+ if (!firstInstance) {
+ assert(req->pipeHandle == INVALID_HANDLE_VALUE);
+
+ req->pipeHandle = CreateNamedPipeW(handle->name,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
+
+ if (req->pipeHandle == INVALID_HANDLE_VALUE) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ handle->reqs_pending++;
+ return;
+ }
+
+ if (uv_set_pipe_handle(loop, handle, req->pipeHandle, -1, 0)) {
+ CloseHandle(req->pipeHandle);
+ req->pipeHandle = INVALID_HANDLE_VALUE;
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ handle->reqs_pending++;
+ return;
+ }
+ }
+
+ assert(req->pipeHandle != INVALID_HANDLE_VALUE);
+
+ /* Prepare the overlapped structure. */
+ memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
+
+ if (!ConnectNamedPipe(req->pipeHandle, &req->u.io.overlapped) &&
+ GetLastError() != ERROR_IO_PENDING) {
+ if (GetLastError() == ERROR_PIPE_CONNECTED) {
+ SET_REQ_SUCCESS(req);
+ } else {
+ CloseHandle(req->pipeHandle);
+ req->pipeHandle = INVALID_HANDLE_VALUE;
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, GetLastError());
+ }
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ handle->reqs_pending++;
+ return;
+ }
+
+ handle->reqs_pending++;
+}
+
+
+int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
+ uv_loop_t* loop = server->loop;
+ uv_pipe_t* pipe_client;
+ uv_pipe_accept_t* req;
+ QUEUE* q;
+ uv__ipc_queue_item_t* item;
+ int err;
+
+ if (server->ipc) {
+ if (QUEUE_EMPTY(&server->pipe.conn.pending_ipc_info.queue)) {
+ /* No valid pending sockets. */
+ return WSAEWOULDBLOCK;
+ }
+
+ q = QUEUE_HEAD(&server->pipe.conn.pending_ipc_info.queue);
+ QUEUE_REMOVE(q);
+ server->pipe.conn.pending_ipc_info.queue_len--;
+ item = QUEUE_DATA(q, uv__ipc_queue_item_t, member);
+
+ err = uv_tcp_import((uv_tcp_t*)client,
+ &item->socket_info_ex,
+ item->tcp_connection);
+ if (err != 0)
+ return err;
+
+ uv__free(item);
+
+ } else {
+ pipe_client = (uv_pipe_t*)client;
+
+ /* Find a connection instance that has been connected, but not yet */
+ /* accepted. */
+ req = server->pipe.serv.pending_accepts;
+
+ if (!req) {
+ /* No valid connections found, so we error out. */
+ return WSAEWOULDBLOCK;
+ }
+
+ /* Initialize the client handle and copy the pipeHandle to the client */
+ uv_pipe_connection_init(pipe_client);
+ pipe_client->handle = req->pipeHandle;
+ pipe_client->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+
+ /* Prepare the req to pick up a new connection */
+ server->pipe.serv.pending_accepts = req->next_pending;
+ req->next_pending = NULL;
+ req->pipeHandle = INVALID_HANDLE_VALUE;
+
+ if (!(server->flags & UV__HANDLE_CLOSING)) {
+ uv_pipe_queue_accept(loop, server, req, FALSE);
+ }
+ }
+
+ return 0;
+}
+
+
+/* Starts listening for connections for the given pipe. */
+int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ int i;
+
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ handle->stream.serv.connection_cb = cb;
+ }
+
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ return WSAEINVAL;
+ }
+
+ if (handle->flags & UV_HANDLE_READING) {
+ return WSAEISCONN;
+ }
+
+ if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
+ return ERROR_NOT_SUPPORTED;
+ }
+
+ handle->flags |= UV_HANDLE_LISTENING;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+ handle->stream.serv.connection_cb = cb;
+
+ /* First pipe handle should have already been created in uv_pipe_bind */
+ assert(handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE);
+
+ for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
+ uv_pipe_queue_accept(loop, handle, &handle->pipe.serv.accept_reqs[i], i == 0);
+ }
+
+ return 0;
+}
+
+
+static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) {
+ int result;
+ DWORD bytes;
+ uv_read_t* req = (uv_read_t*) parameter;
+ uv_pipe_t* handle = (uv_pipe_t*) req->data;
+ uv_loop_t* loop = handle->loop;
+ HANDLE hThread = NULL;
+ DWORD err;
+ uv_mutex_t *m = &handle->pipe.conn.readfile_mutex;
+
+ assert(req != NULL);
+ assert(req->type == UV_READ);
+ assert(handle->type == UV_NAMED_PIPE);
+
+ if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ uv_mutex_lock(m); /* mutex controls *setting* of readfile_thread */
+ if (DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
+ GetCurrentProcess(), &hThread,
+ 0, TRUE, DUPLICATE_SAME_ACCESS)) {
+ handle->pipe.conn.readfile_thread = hThread;
+ } else {
+ hThread = NULL;
+ }
+ uv_mutex_unlock(m);
+ }
+restart_readfile:
+ result = ReadFile(handle->handle,
+ &uv_zero_,
+ 0,
+ &bytes,
+ NULL);
+ if (!result) {
+ err = GetLastError();
+ if (err == ERROR_OPERATION_ABORTED &&
+ handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ if (handle->flags & UV_HANDLE_READING) {
+ /* just a brief break to do something else */
+ handle->pipe.conn.readfile_thread = NULL;
+ /* resume after it is finished */
+ uv_mutex_lock(m);
+ handle->pipe.conn.readfile_thread = hThread;
+ uv_mutex_unlock(m);
+ goto restart_readfile;
+ } else {
+ result = 1; /* successfully stopped reading */
+ }
+ }
+ }
+ if (hThread) {
+ assert(hThread == handle->pipe.conn.readfile_thread);
+ /* mutex does not control clearing readfile_thread */
+ handle->pipe.conn.readfile_thread = NULL;
+ uv_mutex_lock(m);
+ /* only when we hold the mutex lock is it safe to
+ open or close the handle */
+ CloseHandle(hThread);
+ uv_mutex_unlock(m);
+ }
+
+ if (!result) {
+ SET_REQ_ERROR(req, err);
+ }
+
+ POST_COMPLETION_FOR_REQ(loop, req);
+ return 0;
+}
+
+
+static DWORD WINAPI uv_pipe_writefile_thread_proc(void* parameter) {
+ int result;
+ DWORD bytes;
+ uv_write_t* req = (uv_write_t*) parameter;
+ uv_pipe_t* handle = (uv_pipe_t*) req->handle;
+ uv_loop_t* loop = handle->loop;
+
+ assert(req != NULL);
+ assert(req->type == UV_WRITE);
+ assert(handle->type == UV_NAMED_PIPE);
+ assert(req->write_buffer.base);
+
+ result = WriteFile(handle->handle,
+ req->write_buffer.base,
+ req->write_buffer.len,
+ &bytes,
+ NULL);
+
+ if (!result) {
+ SET_REQ_ERROR(req, GetLastError());
+ }
+
+ POST_COMPLETION_FOR_REQ(loop, req);
+ return 0;
+}
+
+
+static void CALLBACK post_completion_read_wait(void* context, BOOLEAN timed_out) {
+ uv_read_t* req;
+ uv_tcp_t* handle;
+
+ req = (uv_read_t*) context;
+ assert(req != NULL);
+ handle = (uv_tcp_t*)req->data;
+ assert(handle != NULL);
+ assert(!timed_out);
+
+ if (!PostQueuedCompletionStatus(handle->loop->iocp,
+ req->u.io.overlapped.InternalHigh,
+ 0,
+ &req->u.io.overlapped)) {
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+ }
+}
+
+
+static void CALLBACK post_completion_write_wait(void* context, BOOLEAN timed_out) {
+ uv_write_t* req;
+ uv_tcp_t* handle;
+
+ req = (uv_write_t*) context;
+ assert(req != NULL);
+ handle = (uv_tcp_t*)req->handle;
+ assert(handle != NULL);
+ assert(!timed_out);
+
+ if (!PostQueuedCompletionStatus(handle->loop->iocp,
+ req->u.io.overlapped.InternalHigh,
+ 0,
+ &req->u.io.overlapped)) {
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+ }
+}
+
+
+static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
+ uv_read_t* req;
+ int result;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+
+ assert(handle->handle != INVALID_HANDLE_VALUE);
+
+ req = &handle->read_req;
+
+ if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
+ if (!QueueUserWorkItem(&uv_pipe_zero_readfile_thread_proc,
+ req,
+ WT_EXECUTELONGFUNCTION)) {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, GetLastError());
+ goto error;
+ }
+ } else {
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1);
+ }
+
+ /* Do 0-read */
+ result = ReadFile(handle->handle,
+ &uv_zero_,
+ 0,
+ NULL,
+ &req->u.io.overlapped);
+
+ if (!result && GetLastError() != ERROR_IO_PENDING) {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, GetLastError());
+ goto error;
+ }
+
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ if (!req->event_handle) {
+ req->event_handle = CreateEvent(NULL, 0, 0, NULL);
+ if (!req->event_handle) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+ }
+ if (req->wait_handle == INVALID_HANDLE_VALUE) {
+ if (!RegisterWaitForSingleObject(&req->wait_handle,
+ req->u.io.overlapped.hEvent, post_completion_read_wait, (void*) req,
+ INFINITE, WT_EXECUTEINWAITTHREAD)) {
+ SET_REQ_ERROR(req, GetLastError());
+ goto error;
+ }
+ }
+ }
+ }
+
+ /* Start the eof timer if there is one */
+ eof_timer_start(handle);
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+ return;
+
+error:
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+}
+
+
+int uv_pipe_read_start(uv_pipe_t* handle,
+ uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ uv_loop_t* loop = handle->loop;
+
+ handle->flags |= UV_HANDLE_READING;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb = read_cb;
+ handle->alloc_cb = alloc_cb;
+
+ /* If reading was stopped and then started again, there could still be a */
+ /* read request pending. */
+ if (!(handle->flags & UV_HANDLE_READ_PENDING))
+ uv_pipe_queue_read(loop, handle);
+
+ return 0;
+}
+
+
+static void uv_insert_non_overlapped_write_req(uv_pipe_t* handle,
+ uv_write_t* req) {
+ req->next_req = NULL;
+ if (handle->pipe.conn.non_overlapped_writes_tail) {
+ req->next_req =
+ handle->pipe.conn.non_overlapped_writes_tail->next_req;
+ handle->pipe.conn.non_overlapped_writes_tail->next_req = (uv_req_t*)req;
+ handle->pipe.conn.non_overlapped_writes_tail = req;
+ } else {
+ req->next_req = (uv_req_t*)req;
+ handle->pipe.conn.non_overlapped_writes_tail = req;
+ }
+}
+
+
+static uv_write_t* uv_remove_non_overlapped_write_req(uv_pipe_t* handle) {
+ uv_write_t* req;
+
+ if (handle->pipe.conn.non_overlapped_writes_tail) {
+ req = (uv_write_t*)handle->pipe.conn.non_overlapped_writes_tail->next_req;
+
+ if (req == handle->pipe.conn.non_overlapped_writes_tail) {
+ handle->pipe.conn.non_overlapped_writes_tail = NULL;
+ } else {
+ handle->pipe.conn.non_overlapped_writes_tail->next_req =
+ req->next_req;
+ }
+
+ return req;
+ } else {
+ /* queue empty */
+ return NULL;
+ }
+}
+
+
+static void uv_queue_non_overlapped_write(uv_pipe_t* handle) {
+ uv_write_t* req = uv_remove_non_overlapped_write_req(handle);
+ if (req) {
+ if (!QueueUserWorkItem(&uv_pipe_writefile_thread_proc,
+ req,
+ WT_EXECUTELONGFUNCTION)) {
+ uv_fatal_error(GetLastError(), "QueueUserWorkItem");
+ }
+ }
+}
+
+
+static int uv_pipe_write_impl(uv_loop_t* loop,
+ uv_write_t* req,
+ uv_pipe_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle,
+ uv_write_cb cb) {
+ int err;
+ int result;
+ uv_tcp_t* tcp_send_handle;
+ uv_write_t* ipc_header_req = NULL;
+ uv_ipc_frame_uv_stream ipc_frame;
+
+ if (nbufs != 1 && (nbufs != 0 || !send_handle)) {
+ return ERROR_NOT_SUPPORTED;
+ }
+
+ /* Only TCP handles are supported for sharing. */
+ if (send_handle && ((send_handle->type != UV_TCP) ||
+ (!(send_handle->flags & UV_HANDLE_BOUND) &&
+ !(send_handle->flags & UV_HANDLE_CONNECTION)))) {
+ return ERROR_NOT_SUPPORTED;
+ }
+
+ assert(handle->handle != INVALID_HANDLE_VALUE);
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_WRITE;
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+ req->ipc_header = 0;
+ req->event_handle = NULL;
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ if (handle->ipc) {
+ assert(!(handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
+ ipc_frame.header.flags = 0;
+
+ /* Use the IPC framing protocol. */
+ if (send_handle) {
+ tcp_send_handle = (uv_tcp_t*)send_handle;
+
+ if (handle->pipe.conn.ipc_pid == 0) {
+ handle->pipe.conn.ipc_pid = uv_current_pid();
+ }
+
+ err = uv_tcp_duplicate_socket(tcp_send_handle, handle->pipe.conn.ipc_pid,
+ &ipc_frame.socket_info_ex.socket_info);
+ if (err) {
+ return err;
+ }
+
+ ipc_frame.socket_info_ex.delayed_error = tcp_send_handle->delayed_error;
+
+ ipc_frame.header.flags |= UV_IPC_TCP_SERVER;
+
+ if (tcp_send_handle->flags & UV_HANDLE_CONNECTION) {
+ ipc_frame.header.flags |= UV_IPC_TCP_CONNECTION;
+ }
+ }
+
+ if (nbufs == 1) {
+ ipc_frame.header.flags |= UV_IPC_RAW_DATA;
+ ipc_frame.header.raw_data_length = bufs[0].len;
+ }
+
+ /*
+ * Use the provided req if we're only doing a single write.
+ * If we're doing multiple writes, use ipc_header_write_req to do
+ * the first write, and then use the provided req for the second write.
+ */
+ if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) {
+ ipc_header_req = req;
+ } else {
+ /*
+ * Try to use the preallocated write req if it's available.
+ * Otherwise allocate a new one.
+ */
+ if (handle->pipe.conn.ipc_header_write_req.type != UV_WRITE) {
+ ipc_header_req = (uv_write_t*)&handle->pipe.conn.ipc_header_write_req;
+ } else {
+ ipc_header_req = (uv_write_t*)uv__malloc(sizeof(uv_write_t));
+ if (!ipc_header_req) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+ }
+
+ uv_req_init(loop, (uv_req_t*) ipc_header_req);
+ ipc_header_req->type = UV_WRITE;
+ ipc_header_req->handle = (uv_stream_t*) handle;
+ ipc_header_req->cb = NULL;
+ ipc_header_req->ipc_header = 1;
+ }
+
+ /* Write the header or the whole frame. */
+ memset(&ipc_header_req->u.io.overlapped, 0,
+ sizeof(ipc_header_req->u.io.overlapped));
+
+ /* Using overlapped IO, but wait for completion before returning.
+ This write is blocking because ipc_frame is on stack. */
+ ipc_header_req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL);
+ if (!ipc_header_req->u.io.overlapped.hEvent) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+
+ result = WriteFile(handle->handle,
+ &ipc_frame,
+ ipc_frame.header.flags & UV_IPC_TCP_SERVER ?
+ sizeof(ipc_frame) : sizeof(ipc_frame.header),
+ NULL,
+ &ipc_header_req->u.io.overlapped);
+ if (!result && GetLastError() != ERROR_IO_PENDING) {
+ err = GetLastError();
+ CloseHandle(ipc_header_req->u.io.overlapped.hEvent);
+ return err;
+ }
+
+ if (!result) {
+ /* Request not completed immediately. Wait for it.*/
+ if (WaitForSingleObject(ipc_header_req->u.io.overlapped.hEvent, INFINITE) !=
+ WAIT_OBJECT_0) {
+ err = GetLastError();
+ CloseHandle(ipc_header_req->u.io.overlapped.hEvent);
+ return err;
+ }
+ }
+ ipc_header_req->u.io.queued_bytes = 0;
+ CloseHandle(ipc_header_req->u.io.overlapped.hEvent);
+ ipc_header_req->u.io.overlapped.hEvent = NULL;
+
+ REGISTER_HANDLE_REQ(loop, handle, ipc_header_req);
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+
+ /* If we don't have any raw data to write - we're done. */
+ if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) {
+ return 0;
+ }
+ }
+
+ if ((handle->flags &
+ (UV_HANDLE_BLOCKING_WRITES | UV_HANDLE_NON_OVERLAPPED_PIPE)) ==
+ (UV_HANDLE_BLOCKING_WRITES | UV_HANDLE_NON_OVERLAPPED_PIPE)) {
+ DWORD bytes;
+ result = WriteFile(handle->handle,
+ bufs[0].base,
+ bufs[0].len,
+ &bytes,
+ NULL);
+
+ if (!result) {
+ err = GetLastError();
+ return err;
+ } else {
+ /* Request completed immediately. */
+ req->u.io.queued_bytes = 0;
+ }
+
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ POST_COMPLETION_FOR_REQ(loop, req);
+ return 0;
+ } else if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
+ req->write_buffer = bufs[0];
+ uv_insert_non_overlapped_write_req(handle, req);
+ if (handle->stream.conn.write_reqs_pending == 0) {
+ uv_queue_non_overlapped_write(handle);
+ }
+
+ /* Request queued by the kernel. */
+ req->u.io.queued_bytes = bufs[0].len;
+ handle->write_queue_size += req->u.io.queued_bytes;
+ } else if (handle->flags & UV_HANDLE_BLOCKING_WRITES) {
+ /* Using overlapped IO, but wait for completion before returning */
+ req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL);
+ if (!req->u.io.overlapped.hEvent) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+
+ result = WriteFile(handle->handle,
+ bufs[0].base,
+ bufs[0].len,
+ NULL,
+ &req->u.io.overlapped);
+
+ if (!result && GetLastError() != ERROR_IO_PENDING) {
+ err = GetLastError();
+ CloseHandle(req->u.io.overlapped.hEvent);
+ return err;
+ }
+
+ if (result) {
+ /* Request completed immediately. */
+ req->u.io.queued_bytes = 0;
+ } else {
+ /* Request queued by the kernel. */
+ req->u.io.queued_bytes = bufs[0].len;
+ handle->write_queue_size += req->u.io.queued_bytes;
+ if (WaitForSingleObject(req->u.io.overlapped.hEvent, INFINITE) !=
+ WAIT_OBJECT_0) {
+ err = GetLastError();
+ CloseHandle(req->u.io.overlapped.hEvent);
+ return uv_translate_sys_error(err);
+ }
+ }
+ CloseHandle(req->u.io.overlapped.hEvent);
+
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ return 0;
+ } else {
+ result = WriteFile(handle->handle,
+ bufs[0].base,
+ bufs[0].len,
+ NULL,
+ &req->u.io.overlapped);
+
+ if (!result && GetLastError() != ERROR_IO_PENDING) {
+ return GetLastError();
+ }
+
+ if (result) {
+ /* Request completed immediately. */
+ req->u.io.queued_bytes = 0;
+ } else {
+ /* Request queued by the kernel. */
+ req->u.io.queued_bytes = bufs[0].len;
+ handle->write_queue_size += req->u.io.queued_bytes;
+ }
+
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ req->event_handle = CreateEvent(NULL, 0, 0, NULL);
+ if (!req->event_handle) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+ if (!RegisterWaitForSingleObject(&req->wait_handle,
+ req->u.io.overlapped.hEvent, post_completion_write_wait, (void*) req,
+ INFINITE, WT_EXECUTEINWAITTHREAD)) {
+ return GetLastError();
+ }
+ }
+ }
+
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+
+ return 0;
+}
+
+
+int uv_pipe_write(uv_loop_t* loop,
+ uv_write_t* req,
+ uv_pipe_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb) {
+ return uv_pipe_write_impl(loop, req, handle, bufs, nbufs, NULL, cb);
+}
+
+
+int uv_pipe_write2(uv_loop_t* loop,
+ uv_write_t* req,
+ uv_pipe_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle,
+ uv_write_cb cb) {
+ if (!handle->ipc) {
+ return WSAEINVAL;
+ }
+
+ return uv_pipe_write_impl(loop, req, handle, bufs, nbufs, send_handle, cb);
+}
+
+
+static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_buf_t buf) {
+ /* If there is an eof timer running, we don't need it any more, */
+ /* so discard it. */
+ eof_timer_destroy(handle);
+
+ handle->flags &= ~UV_HANDLE_READABLE;
+ uv_read_stop((uv_stream_t*) handle);
+
+ handle->read_cb((uv_stream_t*) handle, UV_EOF, &buf);
+}
+
+
+static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error,
+ uv_buf_t buf) {
+ /* If there is an eof timer running, we don't need it any more, */
+ /* so discard it. */
+ eof_timer_destroy(handle);
+
+ uv_read_stop((uv_stream_t*) handle);
+
+ handle->read_cb((uv_stream_t*)handle, uv_translate_sys_error(error), &buf);
+}
+
+
+static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle,
+ int error, uv_buf_t buf) {
+ if (error == ERROR_BROKEN_PIPE) {
+ uv_pipe_read_eof(loop, handle, buf);
+ } else {
+ uv_pipe_read_error(loop, handle, error, buf);
+ }
+}
+
+
+void uv__pipe_insert_pending_socket(uv_pipe_t* handle,
+ uv__ipc_socket_info_ex* info,
+ int tcp_connection) {
+ uv__ipc_queue_item_t* item;
+
+ item = (uv__ipc_queue_item_t*) uv__malloc(sizeof(*item));
+ if (item == NULL)
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+
+ memcpy(&item->socket_info_ex, info, sizeof(item->socket_info_ex));
+ item->tcp_connection = tcp_connection;
+ QUEUE_INSERT_TAIL(&handle->pipe.conn.pending_ipc_info.queue, &item->member);
+ handle->pipe.conn.pending_ipc_info.queue_len++;
+}
+
+
+void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_req_t* req) {
+ DWORD bytes, avail;
+ uv_buf_t buf;
+ uv_ipc_frame_uv_stream ipc_frame;
+
+ assert(handle->type == UV_NAMED_PIPE);
+
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+ eof_timer_stop(handle);
+
+ if (!REQ_SUCCESS(req)) {
+ /* An error occurred doing the 0-read. */
+ if (handle->flags & UV_HANDLE_READING) {
+ uv_pipe_read_error_or_eof(loop,
+ handle,
+ GET_REQ_ERROR(req),
+ uv_null_buf_);
+ }
+ } else {
+ /* Do non-blocking reads until the buffer is empty */
+ while (handle->flags & UV_HANDLE_READING) {
+ if (!PeekNamedPipe(handle->handle,
+ NULL,
+ 0,
+ NULL,
+ &avail,
+ NULL)) {
+ uv_pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_);
+ break;
+ }
+
+ if (avail == 0) {
+ /* There is nothing to read after all. */
+ break;
+ }
+
+ if (handle->ipc) {
+ /* Use the IPC framing protocol to read the incoming data. */
+ if (handle->pipe.conn.remaining_ipc_rawdata_bytes == 0) {
+ /* We're reading a new frame. First, read the header. */
+ assert(avail >= sizeof(ipc_frame.header));
+
+ if (!ReadFile(handle->handle,
+ &ipc_frame.header,
+ sizeof(ipc_frame.header),
+ &bytes,
+ NULL)) {
+ uv_pipe_read_error_or_eof(loop, handle, GetLastError(),
+ uv_null_buf_);
+ break;
+ }
+
+ assert(bytes == sizeof(ipc_frame.header));
+ assert(ipc_frame.header.flags <= (UV_IPC_TCP_SERVER | UV_IPC_RAW_DATA |
+ UV_IPC_TCP_CONNECTION));
+
+ if (ipc_frame.header.flags & UV_IPC_TCP_SERVER) {
+ assert(avail - sizeof(ipc_frame.header) >=
+ sizeof(ipc_frame.socket_info_ex));
+
+ /* Read the TCP socket info. */
+ if (!ReadFile(handle->handle,
+ &ipc_frame.socket_info_ex,
+ sizeof(ipc_frame) - sizeof(ipc_frame.header),
+ &bytes,
+ NULL)) {
+ uv_pipe_read_error_or_eof(loop, handle, GetLastError(),
+ uv_null_buf_);
+ break;
+ }
+
+ assert(bytes == sizeof(ipc_frame) - sizeof(ipc_frame.header));
+
+ /* Store the pending socket info. */
+ uv__pipe_insert_pending_socket(
+ handle,
+ &ipc_frame.socket_info_ex,
+ ipc_frame.header.flags & UV_IPC_TCP_CONNECTION);
+ }
+
+ if (ipc_frame.header.flags & UV_IPC_RAW_DATA) {
+ handle->pipe.conn.remaining_ipc_rawdata_bytes =
+ ipc_frame.header.raw_data_length;
+ continue;
+ }
+ } else {
+ avail = min(avail, (DWORD)handle->pipe.conn.remaining_ipc_rawdata_bytes);
+ }
+ }
+
+ handle->alloc_cb((uv_handle_t*) handle, avail, &buf);
+ if (buf.len == 0) {
+ handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
+ break;
+ }
+ assert(buf.base != NULL);
+
+ if (ReadFile(handle->handle,
+ buf.base,
+ min(buf.len, avail),
+ &bytes,
+ NULL)) {
+ /* Successful read */
+ if (handle->ipc) {
+ assert(handle->pipe.conn.remaining_ipc_rawdata_bytes >= bytes);
+ handle->pipe.conn.remaining_ipc_rawdata_bytes =
+ handle->pipe.conn.remaining_ipc_rawdata_bytes - bytes;
+ }
+ handle->read_cb((uv_stream_t*)handle, bytes, &buf);
+
+ /* Read again only if bytes == buf.len */
+ if (bytes <= buf.len) {
+ break;
+ }
+ } else {
+ uv_pipe_read_error_or_eof(loop, handle, GetLastError(), buf);
+ break;
+ }
+ }
+
+ /* Post another 0-read if still reading and not closing. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_pipe_queue_read(loop, handle);
+ }
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_write_t* req) {
+ int err;
+
+ assert(handle->type == UV_NAMED_PIPE);
+
+ assert(handle->write_queue_size >= req->u.io.queued_bytes);
+ handle->write_queue_size -= req->u.io.queued_bytes;
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ if (req->wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(req->wait_handle);
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ }
+ if (req->event_handle) {
+ CloseHandle(req->event_handle);
+ req->event_handle = NULL;
+ }
+ }
+
+ if (req->ipc_header) {
+ if (req == &handle->pipe.conn.ipc_header_write_req) {
+ req->type = UV_UNKNOWN_REQ;
+ } else {
+ uv__free(req);
+ }
+ } else {
+ if (req->cb) {
+ err = GET_REQ_ERROR(req);
+ req->cb(req, uv_translate_sys_error(err));
+ }
+ }
+
+ handle->stream.conn.write_reqs_pending--;
+
+ if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE &&
+ handle->pipe.conn.non_overlapped_writes_tail) {
+ assert(handle->stream.conn.write_reqs_pending > 0);
+ uv_queue_non_overlapped_write(handle);
+ }
+
+ if (handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_req_t* raw_req) {
+ uv_pipe_accept_t* req = (uv_pipe_accept_t*) raw_req;
+
+ assert(handle->type == UV_NAMED_PIPE);
+
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ /* The req->pipeHandle should be freed already in uv_pipe_cleanup(). */
+ assert(req->pipeHandle == INVALID_HANDLE_VALUE);
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+
+ if (REQ_SUCCESS(req)) {
+ assert(req->pipeHandle != INVALID_HANDLE_VALUE);
+ req->next_pending = handle->pipe.serv.pending_accepts;
+ handle->pipe.serv.pending_accepts = req;
+
+ if (handle->stream.serv.connection_cb) {
+ handle->stream.serv.connection_cb((uv_stream_t*)handle, 0);
+ }
+ } else {
+ if (req->pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(req->pipeHandle);
+ req->pipeHandle = INVALID_HANDLE_VALUE;
+ }
+ if (!(handle->flags & UV__HANDLE_CLOSING)) {
+ uv_pipe_queue_accept(loop, handle, req, FALSE);
+ }
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_connect_t* req) {
+ int err;
+
+ assert(handle->type == UV_NAMED_PIPE);
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (req->cb) {
+ err = 0;
+ if (REQ_SUCCESS(req)) {
+ uv_pipe_connection_init(handle);
+ } else {
+ err = GET_REQ_ERROR(req);
+ }
+ req->cb(req, uv_translate_sys_error(err));
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_shutdown_t* req) {
+ assert(handle->type == UV_NAMED_PIPE);
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (handle->flags & UV_HANDLE_READABLE) {
+ /* Initialize and optionally start the eof timer. Only do this if the */
+ /* pipe is readable and we haven't seen EOF come in ourselves. */
+ eof_timer_init(handle);
+
+ /* If reading start the timer right now. */
+ /* Otherwise uv_pipe_queue_read will start it. */
+ if (handle->flags & UV_HANDLE_READ_PENDING) {
+ eof_timer_start(handle);
+ }
+
+ } else {
+ /* This pipe is not readable. We can just close it to let the other end */
+ /* know that we're done writing. */
+ close_pipe(handle);
+ }
+
+ if (req->cb) {
+ req->cb(req, 0);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+static void eof_timer_init(uv_pipe_t* pipe) {
+ int r;
+
+ assert(pipe->pipe.conn.eof_timer == NULL);
+ assert(pipe->flags & UV_HANDLE_CONNECTION);
+
+ pipe->pipe.conn.eof_timer = (uv_timer_t*) uv__malloc(sizeof *pipe->pipe.conn.eof_timer);
+
+ r = uv_timer_init(pipe->loop, pipe->pipe.conn.eof_timer);
+ assert(r == 0); /* timers can't fail */
+ pipe->pipe.conn.eof_timer->data = pipe;
+ uv_unref((uv_handle_t*) pipe->pipe.conn.eof_timer);
+}
+
+
+static void eof_timer_start(uv_pipe_t* pipe) {
+ assert(pipe->flags & UV_HANDLE_CONNECTION);
+
+ if (pipe->pipe.conn.eof_timer != NULL) {
+ uv_timer_start(pipe->pipe.conn.eof_timer, eof_timer_cb, eof_timeout, 0);
+ }
+}
+
+
+static void eof_timer_stop(uv_pipe_t* pipe) {
+ assert(pipe->flags & UV_HANDLE_CONNECTION);
+
+ if (pipe->pipe.conn.eof_timer != NULL) {
+ uv_timer_stop(pipe->pipe.conn.eof_timer);
+ }
+}
+
+
+static void eof_timer_cb(uv_timer_t* timer) {
+ uv_pipe_t* pipe = (uv_pipe_t*) timer->data;
+ uv_loop_t* loop = timer->loop;
+
+ assert(pipe->type == UV_NAMED_PIPE);
+
+ /* This should always be true, since we start the timer only */
+ /* in uv_pipe_queue_read after successfully calling ReadFile, */
+ /* or in uv_process_pipe_shutdown_req if a read is pending, */
+ /* and we always immediately stop the timer in */
+ /* uv_process_pipe_read_req. */
+ assert(pipe->flags & UV_HANDLE_READ_PENDING);
+
+ /* If there are many packets coming off the iocp then the timer callback */
+ /* may be called before the read request is coming off the queue. */
+ /* Therefore we check here if the read request has completed but will */
+ /* be processed later. */
+ if ((pipe->flags & UV_HANDLE_READ_PENDING) &&
+ HasOverlappedIoCompleted(&pipe->read_req.u.io.overlapped)) {
+ return;
+ }
+
+ /* Force both ends off the pipe. */
+ close_pipe(pipe);
+
+ /* Stop reading, so the pending read that is going to fail will */
+ /* not be reported to the user. */
+ uv_read_stop((uv_stream_t*) pipe);
+
+ /* Report the eof and update flags. This will get reported even if the */
+ /* user stopped reading in the meantime. TODO: is that okay? */
+ uv_pipe_read_eof(loop, pipe, uv_null_buf_);
+}
+
+
+static void eof_timer_destroy(uv_pipe_t* pipe) {
+ assert(pipe->flags & UV_HANDLE_CONNECTION);
+
+ if (pipe->pipe.conn.eof_timer) {
+ uv_close((uv_handle_t*) pipe->pipe.conn.eof_timer, eof_timer_close_cb);
+ pipe->pipe.conn.eof_timer = NULL;
+ }
+}
+
+
+static void eof_timer_close_cb(uv_handle_t* handle) {
+ assert(handle->type == UV_TIMER);
+ uv__free(handle);
+}
+
+
+int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
+ HANDLE os_handle = uv__get_osfhandle(file);
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_ACCESS_INFORMATION access;
+ DWORD duplex_flags = 0;
+
+ if (os_handle == INVALID_HANDLE_VALUE)
+ return UV_EBADF;
+
+ /* In order to avoid closing a stdio file descriptor 0-2, duplicate the
+ * underlying OS handle and forget about the original fd.
+ * We could also opt to use the original OS handle and just never close it,
+ * but then there would be no reliable way to cancel pending read operations
+ * upon close.
+ */
+ if (file <= 2) {
+ if (!DuplicateHandle(INVALID_HANDLE_VALUE,
+ os_handle,
+ INVALID_HANDLE_VALUE,
+ &os_handle,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS))
+ return uv_translate_sys_error(GetLastError());
+ file = -1;
+ }
+
+ /* Determine what kind of permissions we have on this handle.
+ * Cygwin opens the pipe in message mode, but we can support it,
+ * just query the access flags and set the stream flags accordingly.
+ */
+ nt_status = pNtQueryInformationFile(os_handle,
+ &io_status,
+ &access,
+ sizeof(access),
+ FileAccessInformation);
+ if (nt_status != STATUS_SUCCESS)
+ return UV_EINVAL;
+
+ if (pipe->ipc) {
+ if (!(access.AccessFlags & FILE_WRITE_DATA) ||
+ !(access.AccessFlags & FILE_READ_DATA)) {
+ return UV_EINVAL;
+ }
+ }
+
+ if (access.AccessFlags & FILE_WRITE_DATA)
+ duplex_flags |= UV_HANDLE_WRITABLE;
+ if (access.AccessFlags & FILE_READ_DATA)
+ duplex_flags |= UV_HANDLE_READABLE;
+
+ if (os_handle == INVALID_HANDLE_VALUE ||
+ uv_set_pipe_handle(pipe->loop,
+ pipe,
+ os_handle,
+ file,
+ duplex_flags) == -1) {
+ return UV_EINVAL;
+ }
+
+ uv_pipe_connection_init(pipe);
+
+ if (pipe->ipc) {
+ assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
+ pipe->pipe.conn.ipc_pid = uv_parent_pid();
+ assert(pipe->pipe.conn.ipc_pid != -1);
+ }
+ return 0;
+}
+
+
+static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) {
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_NAME_INFORMATION tmp_name_info;
+ FILE_NAME_INFORMATION* name_info;
+ WCHAR* name_buf;
+ unsigned int addrlen;
+ unsigned int name_size;
+ unsigned int name_len;
+ int err;
+
+ name_info = NULL;
+
+ if (handle->handle == INVALID_HANDLE_VALUE) {
+ *size = 0;
+ return UV_EINVAL;
+ }
+
+ uv__pipe_pause_read((uv_pipe_t*)handle); /* cast away const warning */
+
+ nt_status = pNtQueryInformationFile(handle->handle,
+ &io_status,
+ &tmp_name_info,
+ sizeof tmp_name_info,
+ FileNameInformation);
+ if (nt_status == STATUS_BUFFER_OVERFLOW) {
+ name_size = sizeof(*name_info) + tmp_name_info.FileNameLength;
+ name_info = uv__malloc(name_size);
+ if (!name_info) {
+ *size = 0;
+ err = UV_ENOMEM;
+ goto cleanup;
+ }
+
+ nt_status = pNtQueryInformationFile(handle->handle,
+ &io_status,
+ name_info,
+ name_size,
+ FileNameInformation);
+ }
+
+ if (nt_status != STATUS_SUCCESS) {
+ *size = 0;
+ err = uv_translate_sys_error(pRtlNtStatusToDosError(nt_status));
+ goto error;
+ }
+
+ if (!name_info) {
+ /* the struct on stack was used */
+ name_buf = tmp_name_info.FileName;
+ name_len = tmp_name_info.FileNameLength;
+ } else {
+ name_buf = name_info->FileName;
+ name_len = name_info->FileNameLength;
+ }
+
+ if (name_len == 0) {
+ *size = 0;
+ err = 0;
+ goto error;
+ }
+
+ name_len /= sizeof(WCHAR);
+
+ /* check how much space we need */
+ addrlen = WideCharToMultiByte(CP_UTF8,
+ 0,
+ name_buf,
+ name_len,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ if (!addrlen) {
+ *size = 0;
+ err = uv_translate_sys_error(GetLastError());
+ goto error;
+ } else if (pipe_prefix_len + addrlen > *size) {
+ /* "\\\\.\\pipe" + name */
+ *size = pipe_prefix_len + addrlen;
+ err = UV_ENOBUFS;
+ goto error;
+ }
+
+ memcpy(buffer, pipe_prefix, pipe_prefix_len);
+ addrlen = WideCharToMultiByte(CP_UTF8,
+ 0,
+ name_buf,
+ name_len,
+ buffer+pipe_prefix_len,
+ *size-pipe_prefix_len,
+ NULL,
+ NULL);
+ if (!addrlen) {
+ *size = 0;
+ err = uv_translate_sys_error(GetLastError());
+ goto error;
+ }
+
+ addrlen += pipe_prefix_len;
+ *size = addrlen;
+
+ err = 0;
+ goto cleanup;
+
+error:
+ uv__free(name_info);
+
+cleanup:
+ uv__pipe_unpause_read((uv_pipe_t*)handle); /* cast away const warning */
+ return err;
+}
+
+
+int uv_pipe_pending_count(uv_pipe_t* handle) {
+ if (!handle->ipc)
+ return 0;
+ return handle->pipe.conn.pending_ipc_info.queue_len;
+}
+
+
+int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
+ if (handle->flags & UV_HANDLE_BOUND)
+ return uv__pipe_getname(handle, buffer, size);
+
+ if (handle->flags & UV_HANDLE_CONNECTION ||
+ handle->handle != INVALID_HANDLE_VALUE) {
+ *size = 0;
+ return 0;
+ }
+
+ return UV_EBADF;
+}
+
+
+int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
+ /* emulate unix behaviour */
+ if (handle->flags & UV_HANDLE_BOUND)
+ return UV_ENOTCONN;
+
+ if (handle->handle != INVALID_HANDLE_VALUE)
+ return uv__pipe_getname(handle, buffer, size);
+
+ return UV_EBADF;
+}
+
+
+uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
+ if (!handle->ipc)
+ return UV_UNKNOWN_HANDLE;
+ if (handle->pipe.conn.pending_ipc_info.queue_len == 0)
+ return UV_UNKNOWN_HANDLE;
+ else
+ return UV_TCP;
+}
diff --git a/3rdparty/libuv/src/win/poll.c b/3rdparty/libuv/src/win/poll.c
new file mode 100644
index 00000000000..ce861d6ffc4
--- /dev/null
+++ b/3rdparty/libuv/src/win/poll.c
@@ -0,0 +1,635 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <io.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = {
+ {0xe70f1aa0, 0xab8b, 0x11cf,
+ {0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}},
+ {0xf9eab0c0, 0x26d4, 0x11d0,
+ {0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}},
+ {0x9fc48064, 0x7298, 0x43e4,
+ {0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}}
+};
+
+typedef struct uv_single_fd_set_s {
+ unsigned int fd_count;
+ SOCKET fd_array[1];
+} uv_single_fd_set_t;
+
+
+static OVERLAPPED overlapped_dummy_;
+static uv_once_t overlapped_dummy_init_guard_ = UV_ONCE_INIT;
+
+static AFD_POLL_INFO afd_poll_info_dummy_;
+
+
+static void uv__init_overlapped_dummy(void) {
+ HANDLE event;
+
+ event = CreateEvent(NULL, TRUE, TRUE, NULL);
+ if (event == NULL)
+ uv_fatal_error(GetLastError(), "CreateEvent");
+
+ memset(&overlapped_dummy_, 0, sizeof overlapped_dummy_);
+ overlapped_dummy_.hEvent = (HANDLE) ((uintptr_t) event | 1);
+}
+
+
+static OVERLAPPED* uv__get_overlapped_dummy() {
+ uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy);
+ return &overlapped_dummy_;
+}
+
+
+static AFD_POLL_INFO* uv__get_afd_poll_info_dummy() {
+ return &afd_poll_info_dummy_;
+}
+
+
+static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
+ uv_req_t* req;
+ AFD_POLL_INFO* afd_poll_info;
+ DWORD result;
+
+ /* Find a yet unsubmitted req to submit. */
+ if (handle->submitted_events_1 == 0) {
+ req = &handle->poll_req_1;
+ afd_poll_info = &handle->afd_poll_info_1;
+ handle->submitted_events_1 = handle->events;
+ handle->mask_events_1 = 0;
+ handle->mask_events_2 = handle->events;
+ } else if (handle->submitted_events_2 == 0) {
+ req = &handle->poll_req_2;
+ afd_poll_info = &handle->afd_poll_info_2;
+ handle->submitted_events_2 = handle->events;
+ handle->mask_events_1 = handle->events;
+ handle->mask_events_2 = 0;
+ } else {
+ assert(0);
+ return;
+ }
+
+ /* Setting Exclusive to TRUE makes the other poll request return if there */
+ /* is any. */
+ afd_poll_info->Exclusive = TRUE;
+ afd_poll_info->NumberOfHandles = 1;
+ afd_poll_info->Timeout.QuadPart = INT64_MAX;
+ afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket;
+ afd_poll_info->Handles[0].Status = 0;
+ afd_poll_info->Handles[0].Events = 0;
+
+ if (handle->events & UV_READABLE) {
+ afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE |
+ AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT;
+ }
+ if (handle->events & UV_WRITABLE) {
+ afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL;
+ }
+
+ memset(&req->u.io.overlapped, 0, sizeof req->u.io.overlapped);
+
+ result = uv_msafd_poll((SOCKET) handle->peer_socket,
+ afd_poll_info,
+ afd_poll_info,
+ &req->u.io.overlapped);
+ if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) {
+ /* Queue this req, reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, req);
+ }
+}
+
+
+static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
+ AFD_POLL_INFO afd_poll_info;
+ DWORD result;
+
+ afd_poll_info.Exclusive = TRUE;
+ afd_poll_info.NumberOfHandles = 1;
+ afd_poll_info.Timeout.QuadPart = INT64_MAX;
+ afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket;
+ afd_poll_info.Handles[0].Status = 0;
+ afd_poll_info.Handles[0].Events = AFD_POLL_ALL;
+
+ result = uv_msafd_poll(handle->socket,
+ &afd_poll_info,
+ uv__get_afd_poll_info_dummy(),
+ uv__get_overlapped_dummy());
+
+ if (result == SOCKET_ERROR) {
+ DWORD error = WSAGetLastError();
+ if (error != WSA_IO_PENDING)
+ return error;
+ }
+
+ return 0;
+}
+
+
+static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
+ uv_req_t* req) {
+ unsigned char mask_events;
+ AFD_POLL_INFO* afd_poll_info;
+
+ if (req == &handle->poll_req_1) {
+ afd_poll_info = &handle->afd_poll_info_1;
+ handle->submitted_events_1 = 0;
+ mask_events = handle->mask_events_1;
+ } else if (req == &handle->poll_req_2) {
+ afd_poll_info = &handle->afd_poll_info_2;
+ handle->submitted_events_2 = 0;
+ mask_events = handle->mask_events_2;
+ } else {
+ assert(0);
+ return;
+ }
+
+ /* Report an error unless the select was just interrupted. */
+ if (!REQ_SUCCESS(req)) {
+ DWORD error = GET_REQ_SOCK_ERROR(req);
+ if (error != WSAEINTR && handle->events != 0) {
+ handle->events = 0; /* Stop the watcher */
+ handle->poll_cb(handle, uv_translate_sys_error(error), 0);
+ }
+
+ } else if (afd_poll_info->NumberOfHandles >= 1) {
+ unsigned char events = 0;
+
+ if ((afd_poll_info->Handles[0].Events & (AFD_POLL_RECEIVE |
+ AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT)) != 0) {
+ events |= UV_READABLE;
+ }
+ if ((afd_poll_info->Handles[0].Events & (AFD_POLL_SEND |
+ AFD_POLL_CONNECT_FAIL)) != 0) {
+ events |= UV_WRITABLE;
+ }
+
+ events &= handle->events & ~mask_events;
+
+ if (afd_poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) {
+ /* Stop polling. */
+ handle->events = 0;
+ if (uv__is_active(handle))
+ uv__handle_stop(handle);
+ }
+
+ if (events != 0) {
+ handle->poll_cb(handle, 0, events);
+ }
+ }
+
+ if ((handle->events & ~(handle->submitted_events_1 |
+ handle->submitted_events_2)) != 0) {
+ uv__fast_poll_submit_poll_req(loop, handle);
+ } else if ((handle->flags & UV__HANDLE_CLOSING) &&
+ handle->submitted_events_1 == 0 &&
+ handle->submitted_events_2 == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+}
+
+
+static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
+ assert(handle->type == UV_POLL);
+ assert(!(handle->flags & UV__HANDLE_CLOSING));
+ assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
+
+ handle->events = events;
+
+ if (handle->events != 0) {
+ uv__handle_start(handle);
+ } else {
+ uv__handle_stop(handle);
+ }
+
+ if ((handle->events & ~(handle->submitted_events_1 |
+ handle->submitted_events_2)) != 0) {
+ uv__fast_poll_submit_poll_req(handle->loop, handle);
+ }
+
+ return 0;
+}
+
+
+static int uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
+ handle->events = 0;
+ uv__handle_closing(handle);
+
+ if (handle->submitted_events_1 == 0 &&
+ handle->submitted_events_2 == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ return 0;
+ } else {
+ /* Cancel outstanding poll requests by executing another, unique poll */
+ /* request that forces the outstanding ones to return. */
+ return uv__fast_poll_cancel_poll_req(loop, handle);
+ }
+}
+
+
+static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp,
+ WSAPROTOCOL_INFOW* protocol_info) {
+ SOCKET sock = 0;
+
+ sock = WSASocketW(protocol_info->iAddressFamily,
+ protocol_info->iSocketType,
+ protocol_info->iProtocol,
+ protocol_info,
+ 0,
+ WSA_FLAG_OVERLAPPED);
+ if (sock == INVALID_SOCKET) {
+ return INVALID_SOCKET;
+ }
+
+ if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) {
+ goto error;
+ };
+
+ if (CreateIoCompletionPort((HANDLE) sock,
+ iocp,
+ (ULONG_PTR) sock,
+ 0) == NULL) {
+ goto error;
+ }
+
+ return sock;
+
+ error:
+ closesocket(sock);
+ return INVALID_SOCKET;
+}
+
+
+static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop,
+ WSAPROTOCOL_INFOW* protocol_info) {
+ int index, i;
+ SOCKET peer_socket;
+
+ index = -1;
+ for (i = 0; (size_t) i < ARRAY_SIZE(uv_msafd_provider_ids); i++) {
+ if (memcmp((void*) &protocol_info->ProviderId,
+ (void*) &uv_msafd_provider_ids[i],
+ sizeof protocol_info->ProviderId) == 0) {
+ index = i;
+ }
+ }
+
+ /* Check if the protocol uses an msafd socket. */
+ if (index < 0) {
+ return INVALID_SOCKET;
+ }
+
+ /* If we didn't (try) to create a peer socket yet, try to make one. Don't */
+ /* try again if the peer socket creation failed earlier for the same */
+ /* protocol. */
+ peer_socket = loop->poll_peer_sockets[index];
+ if (peer_socket == 0) {
+ peer_socket = uv__fast_poll_create_peer_socket(loop->iocp, protocol_info);
+ loop->poll_peer_sockets[index] = peer_socket;
+ }
+
+ return peer_socket;
+}
+
+
+static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) {
+ uv_req_t* req = (uv_req_t*) arg;
+ uv_poll_t* handle = (uv_poll_t*) req->data;
+ unsigned char reported_events;
+ int r;
+ uv_single_fd_set_t rfds, wfds, efds;
+ struct timeval timeout;
+
+ assert(handle->type == UV_POLL);
+ assert(req->type == UV_POLL_REQ);
+
+ if (handle->events & UV_READABLE) {
+ rfds.fd_count = 1;
+ rfds.fd_array[0] = handle->socket;
+ } else {
+ rfds.fd_count = 0;
+ }
+
+ if (handle->events & UV_WRITABLE) {
+ wfds.fd_count = 1;
+ wfds.fd_array[0] = handle->socket;
+ efds.fd_count = 1;
+ efds.fd_array[0] = handle->socket;
+ } else {
+ wfds.fd_count = 0;
+ efds.fd_count = 0;
+ }
+
+ /* Make the select() time out after 3 minutes. If select() hangs because */
+ /* the user closed the socket, we will at least not hang indefinitely. */
+ timeout.tv_sec = 3 * 60;
+ timeout.tv_usec = 0;
+
+ r = select(1, (fd_set*) &rfds, (fd_set*) &wfds, (fd_set*) &efds, &timeout);
+ if (r == SOCKET_ERROR) {
+ /* Queue this req, reporting an error. */
+ SET_REQ_ERROR(&handle->poll_req_1, WSAGetLastError());
+ POST_COMPLETION_FOR_REQ(handle->loop, req);
+ return 0;
+ }
+
+ reported_events = 0;
+
+ if (r > 0) {
+ if (rfds.fd_count > 0) {
+ assert(rfds.fd_count == 1);
+ assert(rfds.fd_array[0] == handle->socket);
+ reported_events |= UV_READABLE;
+ }
+
+ if (wfds.fd_count > 0) {
+ assert(wfds.fd_count == 1);
+ assert(wfds.fd_array[0] == handle->socket);
+ reported_events |= UV_WRITABLE;
+ } else if (efds.fd_count > 0) {
+ assert(efds.fd_count == 1);
+ assert(efds.fd_array[0] == handle->socket);
+ reported_events |= UV_WRITABLE;
+ }
+ }
+
+ SET_REQ_SUCCESS(req);
+ req->u.io.overlapped.InternalHigh = (DWORD) reported_events;
+ POST_COMPLETION_FOR_REQ(handle->loop, req);
+
+ return 0;
+}
+
+
+static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
+ uv_req_t* req;
+
+ /* Find a yet unsubmitted req to submit. */
+ if (handle->submitted_events_1 == 0) {
+ req = &handle->poll_req_1;
+ handle->submitted_events_1 = handle->events;
+ handle->mask_events_1 = 0;
+ handle->mask_events_2 = handle->events;
+ } else if (handle->submitted_events_2 == 0) {
+ req = &handle->poll_req_2;
+ handle->submitted_events_2 = handle->events;
+ handle->mask_events_1 = handle->events;
+ handle->mask_events_2 = 0;
+ } else {
+ assert(0);
+ return;
+ }
+
+ if (!QueueUserWorkItem(uv__slow_poll_thread_proc,
+ (void*) req,
+ WT_EXECUTELONGFUNCTION)) {
+ /* Make this req pending, reporting an error. */
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, req);
+ }
+}
+
+
+
+static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
+ uv_req_t* req) {
+ unsigned char mask_events;
+ int err;
+
+ if (req == &handle->poll_req_1) {
+ handle->submitted_events_1 = 0;
+ mask_events = handle->mask_events_1;
+ } else if (req == &handle->poll_req_2) {
+ handle->submitted_events_2 = 0;
+ mask_events = handle->mask_events_2;
+ } else {
+ assert(0);
+ return;
+ }
+
+ if (!REQ_SUCCESS(req)) {
+ /* Error. */
+ if (handle->events != 0) {
+ err = GET_REQ_ERROR(req);
+ handle->events = 0; /* Stop the watcher */
+ handle->poll_cb(handle, uv_translate_sys_error(err), 0);
+ }
+ } else {
+ /* Got some events. */
+ int events = req->u.io.overlapped.InternalHigh & handle->events & ~mask_events;
+ if (events != 0) {
+ handle->poll_cb(handle, 0, events);
+ }
+ }
+
+ if ((handle->events & ~(handle->submitted_events_1 |
+ handle->submitted_events_2)) != 0) {
+ uv__slow_poll_submit_poll_req(loop, handle);
+ } else if ((handle->flags & UV__HANDLE_CLOSING) &&
+ handle->submitted_events_1 == 0 &&
+ handle->submitted_events_2 == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+}
+
+
+static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
+ assert(handle->type == UV_POLL);
+ assert(!(handle->flags & UV__HANDLE_CLOSING));
+ assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
+
+ handle->events = events;
+
+ if (handle->events != 0) {
+ uv__handle_start(handle);
+ } else {
+ uv__handle_stop(handle);
+ }
+
+ if ((handle->events &
+ ~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) {
+ uv__slow_poll_submit_poll_req(handle->loop, handle);
+ }
+
+ return 0;
+}
+
+
+static int uv__slow_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
+ handle->events = 0;
+ uv__handle_closing(handle);
+
+ if (handle->submitted_events_1 == 0 &&
+ handle->submitted_events_2 == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+
+ return 0;
+}
+
+
+int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
+ return uv_poll_init_socket(loop, handle, (SOCKET) uv__get_osfhandle(fd));
+}
+
+
+int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
+ uv_os_sock_t socket) {
+ WSAPROTOCOL_INFOW protocol_info;
+ int len;
+ SOCKET peer_socket, base_socket;
+ DWORD bytes;
+ DWORD yes = 1;
+
+ /* Set the socket to nonblocking mode */
+ if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR)
+ return uv_translate_sys_error(WSAGetLastError());
+
+ /* Try to obtain a base handle for the socket. This increases this chances */
+ /* that we find an AFD handle and are able to use the fast poll mechanism. */
+ /* This will always fail on windows XP/2k3, since they don't support the */
+ /* SIO_BASE_HANDLE ioctl. */
+#ifndef NDEBUG
+ base_socket = INVALID_SOCKET;
+#endif
+
+ if (WSAIoctl(socket,
+ SIO_BASE_HANDLE,
+ NULL,
+ 0,
+ &base_socket,
+ sizeof base_socket,
+ &bytes,
+ NULL,
+ NULL) == 0) {
+ assert(base_socket != 0 && base_socket != INVALID_SOCKET);
+ socket = base_socket;
+ }
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL);
+ handle->socket = socket;
+ handle->events = 0;
+
+ /* Obtain protocol information about the socket. */
+ len = sizeof protocol_info;
+ if (getsockopt(socket,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &protocol_info,
+ &len) != 0) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ /* Get the peer socket that is needed to enable fast poll. If the returned */
+ /* value is NULL, the protocol is not implemented by MSAFD and we'll have */
+ /* to use slow mode. */
+ peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info);
+
+ if (peer_socket != INVALID_SOCKET) {
+ /* Initialize fast poll specific fields. */
+ handle->peer_socket = peer_socket;
+ } else {
+ /* Initialize slow poll specific fields. */
+ handle->flags |= UV_HANDLE_POLL_SLOW;
+ }
+
+ /* Initialize 2 poll reqs. */
+ handle->submitted_events_1 = 0;
+ uv_req_init(loop, (uv_req_t*) &(handle->poll_req_1));
+ handle->poll_req_1.type = UV_POLL_REQ;
+ handle->poll_req_1.data = handle;
+
+ handle->submitted_events_2 = 0;
+ uv_req_init(loop, (uv_req_t*) &(handle->poll_req_2));
+ handle->poll_req_2.type = UV_POLL_REQ;
+ handle->poll_req_2.data = handle;
+
+ return 0;
+}
+
+
+int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) {
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
+ err = uv__fast_poll_set(handle->loop, handle, events);
+ } else {
+ err = uv__slow_poll_set(handle->loop, handle, events);
+ }
+
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ handle->poll_cb = cb;
+
+ return 0;
+}
+
+
+int uv_poll_stop(uv_poll_t* handle) {
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
+ err = uv__fast_poll_set(handle->loop, handle, 0);
+ } else {
+ err = uv__slow_poll_set(handle->loop, handle, 0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
+ if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
+ uv__fast_poll_process_poll_req(loop, handle, req);
+ } else {
+ uv__slow_poll_process_poll_req(loop, handle, req);
+ }
+}
+
+
+int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
+ if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
+ return uv__fast_poll_close(loop, handle);
+ } else {
+ return uv__slow_poll_close(loop, handle);
+ }
+}
+
+
+void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
+ assert(handle->flags & UV__HANDLE_CLOSING);
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ assert(handle->submitted_events_1 == 0);
+ assert(handle->submitted_events_2 == 0);
+
+ uv__handle_close(handle);
+}
diff --git a/3rdparty/libuv/src/win/process-stdio.c b/3rdparty/libuv/src/win/process-stdio.c
new file mode 100644
index 00000000000..e3c06f57dea
--- /dev/null
+++ b/3rdparty/libuv/src/win/process-stdio.c
@@ -0,0 +1,510 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+
+
+/*
+ * The `child_stdio_buffer` buffer has the following layout:
+ * int number_of_fds
+ * unsigned char crt_flags[number_of_fds]
+ * HANDLE os_handle[number_of_fds]
+ */
+#define CHILD_STDIO_SIZE(count) \
+ (sizeof(int) + \
+ sizeof(unsigned char) * (count) + \
+ sizeof(uintptr_t) * (count))
+
+#define CHILD_STDIO_COUNT(buffer) \
+ *((unsigned int*) (buffer))
+
+#define CHILD_STDIO_CRT_FLAGS(buffer, fd) \
+ *((unsigned char*) (buffer) + sizeof(int) + fd)
+
+#define CHILD_STDIO_HANDLE(buffer, fd) \
+ *((HANDLE*) ((unsigned char*) (buffer) + \
+ sizeof(int) + \
+ sizeof(unsigned char) * \
+ CHILD_STDIO_COUNT((buffer)) + \
+ sizeof(HANDLE) * (fd)))
+
+
+/* CRT file descriptor mode flags */
+#define FOPEN 0x01
+#define FEOFLAG 0x02
+#define FCRLF 0x04
+#define FPIPE 0x08
+#define FNOINHERIT 0x10
+#define FAPPEND 0x20
+#define FDEV 0x40
+#define FTEXT 0x80
+
+
+/*
+ * Clear the HANDLE_FLAG_INHERIT flag from all HANDLEs that were inherited
+ * the parent process. Don't check for errors - the stdio handles may not be
+ * valid, or may be closed already. There is no guarantee that this function
+ * does a perfect job.
+ */
+void uv_disable_stdio_inheritance(void) {
+ HANDLE handle;
+ STARTUPINFOW si;
+
+ /* Make the windows stdio handles non-inheritable. */
+ handle = GetStdHandle(STD_INPUT_HANDLE);
+ if (handle != NULL && handle != INVALID_HANDLE_VALUE)
+ SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
+
+ handle = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (handle != NULL && handle != INVALID_HANDLE_VALUE)
+ SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
+
+ handle = GetStdHandle(STD_ERROR_HANDLE);
+ if (handle != NULL && handle != INVALID_HANDLE_VALUE)
+ SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
+
+ /* Make inherited CRT FDs non-inheritable. */
+ GetStartupInfoW(&si);
+ if (uv__stdio_verify(si.lpReserved2, si.cbReserved2))
+ uv__stdio_noinherit(si.lpReserved2);
+}
+
+
+static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
+ uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) {
+ char pipe_name[64];
+ SECURITY_ATTRIBUTES sa;
+ DWORD server_access = 0;
+ DWORD client_access = 0;
+ HANDLE child_pipe = INVALID_HANDLE_VALUE;
+ int err;
+
+ if (flags & UV_READABLE_PIPE) {
+ /* The server needs inbound access too, otherwise CreateNamedPipe() */
+ /* won't give us the FILE_READ_ATTRIBUTES permission. We need that to */
+ /* probe the state of the write buffer when we're trying to shutdown */
+ /* the pipe. */
+ server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND;
+ client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
+ }
+ if (flags & UV_WRITABLE_PIPE) {
+ server_access |= PIPE_ACCESS_INBOUND;
+ client_access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
+ }
+
+ /* Create server pipe handle. */
+ err = uv_stdio_pipe_server(loop,
+ server_pipe,
+ server_access,
+ pipe_name,
+ sizeof(pipe_name));
+ if (err)
+ goto error;
+
+ /* Create child pipe handle. */
+ sa.nLength = sizeof sa;
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+
+ child_pipe = CreateFileA(pipe_name,
+ client_access,
+ 0,
+ &sa,
+ OPEN_EXISTING,
+ server_pipe->ipc ? FILE_FLAG_OVERLAPPED : 0,
+ NULL);
+ if (child_pipe == INVALID_HANDLE_VALUE) {
+ err = GetLastError();
+ goto error;
+ }
+
+#ifndef NDEBUG
+ /* Validate that the pipe was opened in the right mode. */
+ {
+ DWORD mode;
+ BOOL r = GetNamedPipeHandleState(child_pipe,
+ &mode,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0);
+ assert(r == TRUE);
+ assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT));
+ }
+#endif
+
+ /* Do a blocking ConnectNamedPipe. This should not block because we have */
+ /* both ends of the pipe created. */
+ if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
+ if (GetLastError() != ERROR_PIPE_CONNECTED) {
+ err = GetLastError();
+ goto error;
+ }
+ }
+
+ /* The server end is now readable and/or writable. */
+ if (flags & UV_READABLE_PIPE)
+ server_pipe->flags |= UV_HANDLE_WRITABLE;
+ if (flags & UV_WRITABLE_PIPE)
+ server_pipe->flags |= UV_HANDLE_READABLE;
+
+ *child_pipe_ptr = child_pipe;
+ return 0;
+
+ error:
+ if (server_pipe->handle != INVALID_HANDLE_VALUE) {
+ uv_pipe_cleanup(loop, server_pipe);
+ }
+
+ if (child_pipe != INVALID_HANDLE_VALUE) {
+ CloseHandle(child_pipe);
+ }
+
+ return err;
+}
+
+
+static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
+ HANDLE current_process;
+
+
+ /* _get_osfhandle will sometimes return -2 in case of an error. This seems */
+ /* to happen when fd <= 2 and the process' corresponding stdio handle is */
+ /* set to NULL. Unfortunately DuplicateHandle will happily duplicate */
+ /* (HANDLE) -2, so this situation goes unnoticed until someone tries to */
+ /* use the duplicate. Therefore we filter out known-invalid handles here. */
+ if (handle == INVALID_HANDLE_VALUE ||
+ handle == NULL ||
+ handle == (HANDLE) -2) {
+ *dup = INVALID_HANDLE_VALUE;
+ return ERROR_INVALID_HANDLE;
+ }
+
+ current_process = GetCurrentProcess();
+
+ if (!DuplicateHandle(current_process,
+ handle,
+ current_process,
+ dup,
+ 0,
+ TRUE,
+ DUPLICATE_SAME_ACCESS)) {
+ *dup = INVALID_HANDLE_VALUE;
+ return GetLastError();
+ }
+
+ return 0;
+}
+
+
+static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) {
+ HANDLE handle;
+
+ if (fd == -1) {
+ *dup = INVALID_HANDLE_VALUE;
+ return ERROR_INVALID_HANDLE;
+ }
+
+ handle = uv__get_osfhandle(fd);
+ return uv__duplicate_handle(loop, handle, dup);
+}
+
+
+int uv__create_nul_handle(HANDLE* handle_ptr,
+ DWORD access) {
+ HANDLE handle;
+ SECURITY_ATTRIBUTES sa;
+
+ sa.nLength = sizeof sa;
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+
+ handle = CreateFileW(L"NUL",
+ access,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &sa,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ return GetLastError();
+ }
+
+ *handle_ptr = handle;
+ return 0;
+}
+
+
+int uv__stdio_create(uv_loop_t* loop,
+ const uv_process_options_t* options,
+ BYTE** buffer_ptr) {
+ BYTE* buffer;
+ int count, i;
+ int err;
+
+ count = options->stdio_count;
+
+ if (count < 0 || count > 255) {
+ /* Only support FDs 0-255 */
+ return ERROR_NOT_SUPPORTED;
+ } else if (count < 3) {
+ /* There should always be at least 3 stdio handles. */
+ count = 3;
+ }
+
+ /* Allocate the child stdio buffer */
+ buffer = (BYTE*) uv__malloc(CHILD_STDIO_SIZE(count));
+ if (buffer == NULL) {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can */
+ /* clean up on failure. */
+ CHILD_STDIO_COUNT(buffer) = count;
+ for (i = 0; i < count; i++) {
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
+ CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
+ }
+
+ for (i = 0; i < count; i++) {
+ uv_stdio_container_t fdopt;
+ if (i < options->stdio_count) {
+ fdopt = options->stdio[i];
+ } else {
+ fdopt.flags = UV_IGNORE;
+ }
+
+ switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
+ UV_INHERIT_STREAM)) {
+ case UV_IGNORE:
+ /* Starting a process with no stdin/stout/stderr can confuse it. */
+ /* So no matter what the user specified, we make sure the first */
+ /* three FDs are always open in their typical modes, e.g. stdin */
+ /* be readable and stdout/err should be writable. For FDs > 2, don't */
+ /* do anything - all handles in the stdio buffer are initialized with */
+ /* INVALID_HANDLE_VALUE, which should be okay. */
+ if (i <= 2) {
+ DWORD access = (i == 0) ? FILE_GENERIC_READ :
+ FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;
+
+ err = uv__create_nul_handle(&CHILD_STDIO_HANDLE(buffer, i),
+ access);
+ if (err)
+ goto error;
+
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
+ }
+ break;
+
+ case UV_CREATE_PIPE: {
+ /* Create a pair of two connected pipe ends; one end is turned into */
+ /* an uv_pipe_t for use by the parent. The other one is given to */
+ /* the child. */
+ uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream;
+ HANDLE child_pipe = INVALID_HANDLE_VALUE;
+
+ /* Create a new, connected pipe pair. stdio[i].stream should point */
+ /* to an uninitialized, but not connected pipe handle. */
+ assert(fdopt.data.stream->type == UV_NAMED_PIPE);
+ assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION));
+ assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER));
+
+ err = uv__create_stdio_pipe_pair(loop,
+ parent_pipe,
+ &child_pipe,
+ fdopt.flags);
+ if (err)
+ goto error;
+
+ CHILD_STDIO_HANDLE(buffer, i) = child_pipe;
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
+ break;
+ }
+
+ case UV_INHERIT_FD: {
+ /* Inherit a raw FD. */
+ HANDLE child_handle;
+
+ /* Make an inheritable duplicate of the handle. */
+ err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle);
+ if (err) {
+ /* If fdopt.data.fd is not valid and fd fd <= 2, then ignore the */
+ /* error. */
+ if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) {
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
+ CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
+ break;
+ }
+ goto error;
+ }
+
+ /* Figure out what the type is. */
+ switch (GetFileType(child_handle)) {
+ case FILE_TYPE_DISK:
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN;
+ break;
+
+ case FILE_TYPE_PIPE:
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
+
+ case FILE_TYPE_CHAR:
+ case FILE_TYPE_REMOTE:
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
+ break;
+
+ case FILE_TYPE_UNKNOWN:
+ if (GetLastError() != 0) {
+ err = GetLastError();
+ CloseHandle(child_handle);
+ goto error;
+ }
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
+ break;
+
+ default:
+ assert(0);
+ return -1;
+ }
+
+ CHILD_STDIO_HANDLE(buffer, i) = child_handle;
+ break;
+ }
+
+ case UV_INHERIT_STREAM: {
+ /* Use an existing stream as the stdio handle for the child. */
+ HANDLE stream_handle, child_handle;
+ unsigned char crt_flags;
+ uv_stream_t* stream = fdopt.data.stream;
+
+ /* Leech the handle out of the stream. */
+ if (stream->type == UV_TTY) {
+ stream_handle = ((uv_tty_t*) stream)->handle;
+ crt_flags = FOPEN | FDEV;
+ } else if (stream->type == UV_NAMED_PIPE &&
+ stream->flags & UV_HANDLE_CONNECTION) {
+ stream_handle = ((uv_pipe_t*) stream)->handle;
+ crt_flags = FOPEN | FPIPE;
+ } else {
+ stream_handle = INVALID_HANDLE_VALUE;
+ crt_flags = 0;
+ }
+
+ if (stream_handle == NULL ||
+ stream_handle == INVALID_HANDLE_VALUE) {
+ /* The handle is already closed, or not yet created, or the */
+ /* stream type is not supported. */
+ err = ERROR_NOT_SUPPORTED;
+ goto error;
+ }
+
+ /* Make an inheritable copy of the handle. */
+ err = uv__duplicate_handle(loop, stream_handle, &child_handle);
+ if (err)
+ goto error;
+
+ CHILD_STDIO_HANDLE(buffer, i) = child_handle;
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags;
+ break;
+ }
+
+ default:
+ assert(0);
+ return -1;
+ }
+ }
+
+ *buffer_ptr = buffer;
+ return 0;
+
+ error:
+ uv__stdio_destroy(buffer);
+ return err;
+}
+
+
+void uv__stdio_destroy(BYTE* buffer) {
+ int i, count;
+
+ count = CHILD_STDIO_COUNT(buffer);
+ for (i = 0; i < count; i++) {
+ HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
+ if (handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle);
+ }
+ }
+
+ uv__free(buffer);
+}
+
+
+void uv__stdio_noinherit(BYTE* buffer) {
+ int i, count;
+
+ count = CHILD_STDIO_COUNT(buffer);
+ for (i = 0; i < count; i++) {
+ HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
+ if (handle != INVALID_HANDLE_VALUE) {
+ SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
+ }
+ }
+}
+
+
+int uv__stdio_verify(BYTE* buffer, WORD size) {
+ unsigned int count;
+
+ /* Check the buffer pointer. */
+ if (buffer == NULL)
+ return 0;
+
+ /* Verify that the buffer is at least big enough to hold the count. */
+ if (size < CHILD_STDIO_SIZE(0))
+ return 0;
+
+ /* Verify if the count is within range. */
+ count = CHILD_STDIO_COUNT(buffer);
+ if (count > 256)
+ return 0;
+
+ /* Verify that the buffer size is big enough to hold info for N FDs. */
+ if (size < CHILD_STDIO_SIZE(count))
+ return 0;
+
+ return 1;
+}
+
+
+WORD uv__stdio_size(BYTE* buffer) {
+ return (WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer)));
+}
+
+
+HANDLE uv__stdio_handle(BYTE* buffer, int fd) {
+ return CHILD_STDIO_HANDLE(buffer, fd);
+}
diff --git a/3rdparty/libuv/src/win/process.c b/3rdparty/libuv/src/win/process.c
new file mode 100644
index 00000000000..855c3740816
--- /dev/null
+++ b/3rdparty/libuv/src/win/process.c
@@ -0,0 +1,1247 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <limits.h>
+#include <wchar.h>
+#include <malloc.h> /* alloca */
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+#define SIGKILL 9
+
+
+typedef struct env_var {
+ const WCHAR* const wide;
+ const WCHAR* const wide_eq;
+ const size_t len; /* including null or '=' */
+} env_var_t;
+
+#define E_V(str) { L##str, L##str L"=", sizeof(str) }
+
+static const env_var_t required_vars[] = { /* keep me sorted */
+ E_V("HOMEDRIVE"),
+ E_V("HOMEPATH"),
+ E_V("LOGONSERVER"),
+ E_V("PATH"),
+ E_V("SYSTEMDRIVE"),
+ E_V("SYSTEMROOT"),
+ E_V("TEMP"),
+ E_V("USERDOMAIN"),
+ E_V("USERNAME"),
+ E_V("USERPROFILE"),
+ E_V("WINDIR"),
+};
+static size_t n_required_vars = ARRAY_SIZE(required_vars);
+
+
+static HANDLE uv_global_job_handle_;
+static uv_once_t uv_global_job_handle_init_guard_ = UV_ONCE_INIT;
+
+
+static void uv__init_global_job_handle(void) {
+ /* Create a job object and set it up to kill all contained processes when
+ * it's closed. Since this handle is made non-inheritable and we're not
+ * giving it to anyone, we're the only process holding a reference to it.
+ * That means that if this process exits it is closed and all the processes
+ * it contains are killed. All processes created with uv_spawn that are not
+ * spawned with the UV_PROCESS_DETACHED flag are assigned to this job.
+ *
+ * We're setting the JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag so only the
+ * processes that we explicitly add are affected, and *their* subprocesses
+ * are not. This ensures that our child processes are not limited in their
+ * ability to use job control on Windows versions that don't deal with
+ * nested jobs (prior to Windows 8 / Server 2012). It also lets our child
+ * processes created detached processes without explicitly breaking away
+ * from job control (which uv_spawn doesn't, either).
+ */
+ SECURITY_ATTRIBUTES attr;
+ JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
+
+ memset(&attr, 0, sizeof attr);
+ attr.bInheritHandle = FALSE;
+
+ memset(&info, 0, sizeof info);
+ info.BasicLimitInformation.LimitFlags =
+ JOB_OBJECT_LIMIT_BREAKAWAY_OK |
+ JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK |
+ JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION |
+ JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+
+ uv_global_job_handle_ = CreateJobObjectW(&attr, NULL);
+ if (uv_global_job_handle_ == NULL)
+ uv_fatal_error(GetLastError(), "CreateJobObjectW");
+
+ if (!SetInformationJobObject(uv_global_job_handle_,
+ JobObjectExtendedLimitInformation,
+ &info,
+ sizeof info))
+ uv_fatal_error(GetLastError(), "SetInformationJobObject");
+}
+
+
+static int uv_utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) {
+ int ws_len, r;
+ WCHAR* ws;
+
+ ws_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ s,
+ -1,
+ NULL,
+ 0);
+ if (ws_len <= 0) {
+ return GetLastError();
+ }
+
+ ws = (WCHAR*) uv__malloc(ws_len * sizeof(WCHAR));
+ if (ws == NULL) {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ r = MultiByteToWideChar(CP_UTF8,
+ 0,
+ s,
+ -1,
+ ws,
+ ws_len);
+ assert(r == ws_len);
+
+ *ws_ptr = ws;
+ return 0;
+}
+
+
+static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS);
+ handle->exit_cb = NULL;
+ handle->pid = 0;
+ handle->exit_signal = 0;
+ handle->wait_handle = INVALID_HANDLE_VALUE;
+ handle->process_handle = INVALID_HANDLE_VALUE;
+ handle->child_stdio_buffer = NULL;
+ handle->exit_cb_pending = 0;
+
+ uv_req_init(loop, (uv_req_t*)&handle->exit_req);
+ handle->exit_req.type = UV_PROCESS_EXIT;
+ handle->exit_req.data = handle;
+}
+
+
+/*
+ * Path search functions
+ */
+
+/*
+ * Helper function for search_path
+ */
+static WCHAR* search_path_join_test(const WCHAR* dir,
+ size_t dir_len,
+ const WCHAR* name,
+ size_t name_len,
+ const WCHAR* ext,
+ size_t ext_len,
+ const WCHAR* cwd,
+ size_t cwd_len) {
+ WCHAR *result, *result_pos;
+ DWORD attrs;
+ if (dir_len > 2 && dir[0] == L'\\' && dir[1] == L'\\') {
+ /* It's a UNC path so ignore cwd */
+ cwd_len = 0;
+ } else if (dir_len >= 1 && (dir[0] == L'/' || dir[0] == L'\\')) {
+ /* It's a full path without drive letter, use cwd's drive letter only */
+ cwd_len = 2;
+ } else if (dir_len >= 2 && dir[1] == L':' &&
+ (dir_len < 3 || (dir[2] != L'/' && dir[2] != L'\\'))) {
+ /* It's a relative path with drive letter (ext.g. D:../some/file)
+ * Replace drive letter in dir by full cwd if it points to the same drive,
+ * otherwise use the dir only.
+ */
+ if (cwd_len < 2 || _wcsnicmp(cwd, dir, 2) != 0) {
+ cwd_len = 0;
+ } else {
+ dir += 2;
+ dir_len -= 2;
+ }
+ } else if (dir_len > 2 && dir[1] == L':') {
+ /* It's an absolute path with drive letter
+ * Don't use the cwd at all
+ */
+ cwd_len = 0;
+ }
+
+ /* Allocate buffer for output */
+ result = result_pos = (WCHAR*)uv__malloc(sizeof(WCHAR) *
+ (cwd_len + 1 + dir_len + 1 + name_len + 1 + ext_len + 1));
+
+ /* Copy cwd */
+ wcsncpy(result_pos, cwd, cwd_len);
+ result_pos += cwd_len;
+
+ /* Add a path separator if cwd didn't end with one */
+ if (cwd_len && wcsrchr(L"\\/:", result_pos[-1]) == NULL) {
+ result_pos[0] = L'\\';
+ result_pos++;
+ }
+
+ /* Copy dir */
+ wcsncpy(result_pos, dir, dir_len);
+ result_pos += dir_len;
+
+ /* Add a separator if the dir didn't end with one */
+ if (dir_len && wcsrchr(L"\\/:", result_pos[-1]) == NULL) {
+ result_pos[0] = L'\\';
+ result_pos++;
+ }
+
+ /* Copy filename */
+ wcsncpy(result_pos, name, name_len);
+ result_pos += name_len;
+
+ if (ext_len) {
+ /* Add a dot if the filename didn't end with one */
+ if (name_len && result_pos[-1] != '.') {
+ result_pos[0] = L'.';
+ result_pos++;
+ }
+
+ /* Copy extension */
+ wcsncpy(result_pos, ext, ext_len);
+ result_pos += ext_len;
+ }
+
+ /* Null terminator */
+ result_pos[0] = L'\0';
+
+ attrs = GetFileAttributesW(result);
+
+ if (attrs != INVALID_FILE_ATTRIBUTES &&
+ !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
+ return result;
+ }
+
+ uv__free(result);
+ return NULL;
+}
+
+
+/*
+ * Helper function for search_path
+ */
+static WCHAR* path_search_walk_ext(const WCHAR *dir,
+ size_t dir_len,
+ const WCHAR *name,
+ size_t name_len,
+ WCHAR *cwd,
+ size_t cwd_len,
+ int name_has_ext) {
+ WCHAR* result;
+
+ /* If the name itself has a nonempty extension, try this extension first */
+ if (name_has_ext) {
+ result = search_path_join_test(dir, dir_len,
+ name, name_len,
+ L"", 0,
+ cwd, cwd_len);
+ if (result != NULL) {
+ return result;
+ }
+ }
+
+ /* Try .com extension */
+ result = search_path_join_test(dir, dir_len,
+ name, name_len,
+ L"com", 3,
+ cwd, cwd_len);
+ if (result != NULL) {
+ return result;
+ }
+
+ /* Try .exe extension */
+ result = search_path_join_test(dir, dir_len,
+ name, name_len,
+ L"exe", 3,
+ cwd, cwd_len);
+ if (result != NULL) {
+ return result;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * search_path searches the system path for an executable filename -
+ * the windows API doesn't provide this as a standalone function nor as an
+ * option to CreateProcess.
+ *
+ * It tries to return an absolute filename.
+ *
+ * Furthermore, it tries to follow the semantics that cmd.exe, with this
+ * exception that PATHEXT environment variable isn't used. Since CreateProcess
+ * can start only .com and .exe files, only those extensions are tried. This
+ * behavior equals that of msvcrt's spawn functions.
+ *
+ * - Do not search the path if the filename already contains a path (either
+ * relative or absolute).
+ *
+ * - If there's really only a filename, check the current directory for file,
+ * then search all path directories.
+ *
+ * - If filename specified has *any* extension, search for the file with the
+ * specified extension first.
+ *
+ * - If the literal filename is not found in a directory, try *appending*
+ * (not replacing) .com first and then .exe.
+ *
+ * - The path variable may contain relative paths; relative paths are relative
+ * to the cwd.
+ *
+ * - Directories in path may or may not end with a trailing backslash.
+ *
+ * - CMD does not trim leading/trailing whitespace from path/pathex entries
+ * nor from the environment variables as a whole.
+ *
+ * - When cmd.exe cannot read a directory, it will just skip it and go on
+ * searching. However, unlike posix-y systems, it will happily try to run a
+ * file that is not readable/executable; if the spawn fails it will not
+ * continue searching.
+ *
+ * UNC path support: we are dealing with UNC paths in both the path and the
+ * filename. This is a deviation from what cmd.exe does (it does not let you
+ * start a program by specifying an UNC path on the command line) but this is
+ * really a pointless restriction.
+ *
+ */
+static WCHAR* search_path(const WCHAR *file,
+ WCHAR *cwd,
+ const WCHAR *path) {
+ int file_has_dir;
+ WCHAR* result = NULL;
+ WCHAR *file_name_start;
+ WCHAR *dot;
+ const WCHAR *dir_start, *dir_end, *dir_path;
+ size_t dir_len;
+ int name_has_ext;
+
+ size_t file_len = wcslen(file);
+ size_t cwd_len = wcslen(cwd);
+
+ /* If the caller supplies an empty filename,
+ * we're not gonna return c:\windows\.exe -- GFY!
+ */
+ if (file_len == 0
+ || (file_len == 1 && file[0] == L'.')) {
+ return NULL;
+ }
+
+ /* Find the start of the filename so we can split the directory from the */
+ /* name. */
+ for (file_name_start = (WCHAR*)file + file_len;
+ file_name_start > file
+ && file_name_start[-1] != L'\\'
+ && file_name_start[-1] != L'/'
+ && file_name_start[-1] != L':';
+ file_name_start--);
+
+ file_has_dir = file_name_start != file;
+
+ /* Check if the filename includes an extension */
+ dot = wcschr(file_name_start, L'.');
+ name_has_ext = (dot != NULL && dot[1] != L'\0');
+
+ if (file_has_dir) {
+ /* The file has a path inside, don't use path */
+ result = path_search_walk_ext(
+ file, file_name_start - file,
+ file_name_start, file_len - (file_name_start - file),
+ cwd, cwd_len,
+ name_has_ext);
+
+ } else {
+ dir_end = path;
+
+ /* The file is really only a name; look in cwd first, then scan path */
+ result = path_search_walk_ext(L"", 0,
+ file, file_len,
+ cwd, cwd_len,
+ name_has_ext);
+
+ while (result == NULL) {
+ if (*dir_end == L'\0') {
+ break;
+ }
+
+ /* Skip the separator that dir_end now points to */
+ if (dir_end != path || *path == L';') {
+ dir_end++;
+ }
+
+ /* Next slice starts just after where the previous one ended */
+ dir_start = dir_end;
+
+ /* Slice until the next ; or \0 is found */
+ dir_end = wcschr(dir_start, L';');
+ if (dir_end == NULL) {
+ dir_end = wcschr(dir_start, L'\0');
+ }
+
+ /* If the slice is zero-length, don't bother */
+ if (dir_end - dir_start == 0) {
+ continue;
+ }
+
+ dir_path = dir_start;
+ dir_len = dir_end - dir_start;
+
+ /* Adjust if the path is quoted. */
+ if (dir_path[0] == '"' || dir_path[0] == '\'') {
+ ++dir_path;
+ --dir_len;
+ }
+
+ if (dir_path[dir_len - 1] == '"' || dir_path[dir_len - 1] == '\'') {
+ --dir_len;
+ }
+
+ result = path_search_walk_ext(dir_path, dir_len,
+ file, file_len,
+ cwd, cwd_len,
+ name_has_ext);
+ }
+ }
+
+ return result;
+}
+
+
+/*
+ * Quotes command line arguments
+ * Returns a pointer to the end (next char to be written) of the buffer
+ */
+WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) {
+ size_t len = wcslen(source);
+ size_t i;
+ int quote_hit;
+ WCHAR* start;
+
+ if (len == 0) {
+ /* Need double quotation for empty argument */
+ *(target++) = L'"';
+ *(target++) = L'"';
+ return target;
+ }
+
+ if (NULL == wcspbrk(source, L" \t\"")) {
+ /* No quotation needed */
+ wcsncpy(target, source, len);
+ target += len;
+ return target;
+ }
+
+ if (NULL == wcspbrk(source, L"\"\\")) {
+ /*
+ * No embedded double quotes or backlashes, so I can just wrap
+ * quote marks around the whole thing.
+ */
+ *(target++) = L'"';
+ wcsncpy(target, source, len);
+ target += len;
+ *(target++) = L'"';
+ return target;
+ }
+
+ /*
+ * Expected input/output:
+ * input : hello"world
+ * output: "hello\"world"
+ * input : hello""world
+ * output: "hello\"\"world"
+ * input : hello\world
+ * output: hello\world
+ * input : hello\\world
+ * output: hello\\world
+ * input : hello\"world
+ * output: "hello\\\"world"
+ * input : hello\\"world
+ * output: "hello\\\\\"world"
+ * input : hello world\
+ * output: "hello world\"
+ */
+
+ *(target++) = L'"';
+ start = target;
+ quote_hit = 1;
+
+ for (i = len; i > 0; --i) {
+ *(target++) = source[i - 1];
+
+ if (quote_hit && source[i - 1] == L'\\') {
+ *(target++) = L'\\';
+ } else if(source[i - 1] == L'"') {
+ quote_hit = 1;
+ *(target++) = L'\\';
+ } else {
+ quote_hit = 0;
+ }
+ }
+ target[0] = L'\0';
+ wcsrev(start);
+ *(target++) = L'"';
+ return target;
+}
+
+
+int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) {
+ char** arg;
+ WCHAR* dst = NULL;
+ WCHAR* temp_buffer = NULL;
+ size_t dst_len = 0;
+ size_t temp_buffer_len = 0;
+ WCHAR* pos;
+ int arg_count = 0;
+ int err = 0;
+
+ /* Count the required size. */
+ for (arg = args; *arg; arg++) {
+ DWORD arg_len;
+
+ arg_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ *arg,
+ -1,
+ NULL,
+ 0);
+ if (arg_len == 0) {
+ return GetLastError();
+ }
+
+ dst_len += arg_len;
+
+ if (arg_len > temp_buffer_len)
+ temp_buffer_len = arg_len;
+
+ arg_count++;
+ }
+
+ /* Adjust for potential quotes. Also assume the worst-case scenario */
+ /* that every character needs escaping, so we need twice as much space. */
+ dst_len = dst_len * 2 + arg_count * 2;
+
+ /* Allocate buffer for the final command line. */
+ dst = (WCHAR*) uv__malloc(dst_len * sizeof(WCHAR));
+ if (dst == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto error;
+ }
+
+ /* Allocate temporary working buffer. */
+ temp_buffer = (WCHAR*) uv__malloc(temp_buffer_len * sizeof(WCHAR));
+ if (temp_buffer == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto error;
+ }
+
+ pos = dst;
+ for (arg = args; *arg; arg++) {
+ DWORD arg_len;
+
+ /* Convert argument to wide char. */
+ arg_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ *arg,
+ -1,
+ temp_buffer,
+ (int) (dst + dst_len - pos));
+ if (arg_len == 0) {
+ err = GetLastError();
+ goto error;
+ }
+
+ if (verbatim_arguments) {
+ /* Copy verbatim. */
+ wcscpy(pos, temp_buffer);
+ pos += arg_len - 1;
+ } else {
+ /* Quote/escape, if needed. */
+ pos = quote_cmd_arg(temp_buffer, pos);
+ }
+
+ *pos++ = *(arg + 1) ? L' ' : L'\0';
+ }
+
+ uv__free(temp_buffer);
+
+ *dst_ptr = dst;
+ return 0;
+
+error:
+ uv__free(dst);
+ uv__free(temp_buffer);
+ return err;
+}
+
+
+int env_strncmp(const wchar_t* a, int na, const wchar_t* b) {
+ wchar_t* a_eq;
+ wchar_t* b_eq;
+ wchar_t* A;
+ wchar_t* B;
+ int nb;
+ int r;
+
+ if (na < 0) {
+ a_eq = wcschr(a, L'=');
+ assert(a_eq);
+ na = (int)(long)(a_eq - a);
+ } else {
+ na--;
+ }
+ b_eq = wcschr(b, L'=');
+ assert(b_eq);
+ nb = b_eq - b;
+
+ A = alloca((na+1) * sizeof(wchar_t));
+ B = alloca((nb+1) * sizeof(wchar_t));
+
+ r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, a, na, A, na);
+ assert(r==na);
+ A[na] = L'\0';
+ r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, b, nb, B, nb);
+ assert(r==nb);
+ B[nb] = L'\0';
+
+ while (1) {
+ wchar_t AA = *A++;
+ wchar_t BB = *B++;
+ if (AA < BB) {
+ return -1;
+ } else if (AA > BB) {
+ return 1;
+ } else if (!AA && !BB) {
+ return 0;
+ }
+ }
+}
+
+
+static int qsort_wcscmp(const void *a, const void *b) {
+ wchar_t* astr = *(wchar_t* const*)a;
+ wchar_t* bstr = *(wchar_t* const*)b;
+ return env_strncmp(astr, -1, bstr);
+}
+
+
+/*
+ * The way windows takes environment variables is different than what C does;
+ * Windows wants a contiguous block of null-terminated strings, terminated
+ * with an additional null.
+ *
+ * Windows has a few "essential" environment variables. winsock will fail
+ * to initialize if SYSTEMROOT is not defined; some APIs make reference to
+ * TEMP. SYSTEMDRIVE is probably also important. We therefore ensure that
+ * these get defined if the input environment block does not contain any
+ * values for them.
+ *
+ * Also add variables known to Cygwin to be required for correct
+ * subprocess operation in many cases:
+ * https://github.com/Alexpux/Cygwin/blob/b266b04fbbd3a595f02ea149e4306d3ab9b1fe3d/winsup/cygwin/environ.cc#L955
+ *
+ */
+int make_program_env(char* env_block[], WCHAR** dst_ptr) {
+ WCHAR* dst;
+ WCHAR* ptr;
+ char** env;
+ size_t env_len = 0;
+ int len;
+ size_t i;
+ DWORD var_size;
+ size_t env_block_count = 1; /* 1 for null-terminator */
+ WCHAR* dst_copy;
+ WCHAR** ptr_copy;
+ WCHAR** env_copy;
+ DWORD* required_vars_value_len = alloca(n_required_vars * sizeof(DWORD*));
+
+ /* first pass: determine size in UTF-16 */
+ for (env = env_block; *env; env++) {
+ int len;
+ if (strchr(*env, '=')) {
+ len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ *env,
+ -1,
+ NULL,
+ 0);
+ if (len <= 0) {
+ return GetLastError();
+ }
+ env_len += len;
+ env_block_count++;
+ }
+ }
+
+ /* second pass: copy to UTF-16 environment block */
+ dst_copy = (WCHAR*)uv__malloc(env_len * sizeof(WCHAR));
+ if (!dst_copy) {
+ return ERROR_OUTOFMEMORY;
+ }
+ env_copy = alloca(env_block_count * sizeof(WCHAR*));
+
+ ptr = dst_copy;
+ ptr_copy = env_copy;
+ for (env = env_block; *env; env++) {
+ if (strchr(*env, '=')) {
+ len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ *env,
+ -1,
+ ptr,
+ (int) (env_len - (ptr - dst_copy)));
+ if (len <= 0) {
+ DWORD err = GetLastError();
+ uv__free(dst_copy);
+ return err;
+ }
+ *ptr_copy++ = ptr;
+ ptr += len;
+ }
+ }
+ *ptr_copy = NULL;
+ assert(env_len == ptr - dst_copy);
+
+ /* sort our (UTF-16) copy */
+ qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp);
+
+ /* third pass: check for required variables */
+ for (ptr_copy = env_copy, i = 0; i < n_required_vars; ) {
+ int cmp;
+ if (!*ptr_copy) {
+ cmp = -1;
+ } else {
+ cmp = env_strncmp(required_vars[i].wide_eq,
+ required_vars[i].len,
+ *ptr_copy);
+ }
+ if (cmp < 0) {
+ /* missing required var */
+ var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0);
+ required_vars_value_len[i] = var_size;
+ if (var_size != 0) {
+ env_len += required_vars[i].len;
+ env_len += var_size;
+ }
+ i++;
+ } else {
+ ptr_copy++;
+ if (cmp == 0)
+ i++;
+ }
+ }
+
+ /* final pass: copy, in sort order, and inserting required variables */
+ dst = uv__malloc((1+env_len) * sizeof(WCHAR));
+ if (!dst) {
+ uv__free(dst_copy);
+ return ERROR_OUTOFMEMORY;
+ }
+
+ for (ptr = dst, ptr_copy = env_copy, i = 0;
+ *ptr_copy || i < n_required_vars;
+ ptr += len) {
+ int cmp;
+ if (i >= n_required_vars) {
+ cmp = 1;
+ } else if (!*ptr_copy) {
+ cmp = -1;
+ } else {
+ cmp = env_strncmp(required_vars[i].wide_eq,
+ required_vars[i].len,
+ *ptr_copy);
+ }
+ if (cmp < 0) {
+ /* missing required var */
+ len = required_vars_value_len[i];
+ if (len) {
+ wcscpy(ptr, required_vars[i].wide_eq);
+ ptr += required_vars[i].len;
+ var_size = GetEnvironmentVariableW(required_vars[i].wide,
+ ptr,
+ (int) (env_len - (ptr - dst)));
+ if (var_size != len-1) { /* race condition? */
+ uv_fatal_error(GetLastError(), "GetEnvironmentVariableW");
+ }
+ }
+ i++;
+ } else {
+ /* copy var from env_block */
+ len = wcslen(*ptr_copy) + 1;
+ wmemcpy(ptr, *ptr_copy, len);
+ ptr_copy++;
+ if (cmp == 0)
+ i++;
+ }
+ }
+
+ /* Terminate with an extra NULL. */
+ assert(env_len == (ptr - dst));
+ *ptr = L'\0';
+
+ uv__free(dst_copy);
+ *dst_ptr = dst;
+ return 0;
+}
+
+/*
+ * Attempt to find the value of the PATH environment variable in the child's
+ * preprocessed environment.
+ *
+ * If found, a pointer into `env` is returned. If not found, NULL is returned.
+ */
+static WCHAR* find_path(WCHAR *env) {
+ for (; env != NULL && *env != 0; env += wcslen(env) + 1) {
+ if (wcsncmp(env, L"PATH=", 5) == 0)
+ return &env[5];
+ }
+
+ return NULL;
+}
+
+/*
+ * Called on Windows thread-pool thread to indicate that
+ * a child process has exited.
+ */
+static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) {
+ uv_process_t* process = (uv_process_t*) data;
+ uv_loop_t* loop = process->loop;
+
+ assert(didTimeout == FALSE);
+ assert(process);
+ assert(!process->exit_cb_pending);
+
+ process->exit_cb_pending = 1;
+
+ /* Post completed */
+ POST_COMPLETION_FOR_REQ(loop, &process->exit_req);
+}
+
+
+/* Called on main thread after a child process has exited. */
+void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
+ int64_t exit_code;
+ DWORD status;
+
+ assert(handle->exit_cb_pending);
+ handle->exit_cb_pending = 0;
+
+ /* If we're closing, don't call the exit callback. Just schedule a close */
+ /* callback now. */
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ return;
+ }
+
+ /* Unregister from process notification. */
+ if (handle->wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(handle->wait_handle);
+ handle->wait_handle = INVALID_HANDLE_VALUE;
+ }
+
+ /* Set the handle to inactive: no callbacks will be made after the exit */
+ /* callback.*/
+ uv__handle_stop(handle);
+
+ if (GetExitCodeProcess(handle->process_handle, &status)) {
+ exit_code = status;
+ } else {
+ /* Unable to to obtain the exit code. This should never happen. */
+ exit_code = uv_translate_sys_error(GetLastError());
+ }
+
+ /* Fire the exit callback. */
+ if (handle->exit_cb) {
+ handle->exit_cb(handle, exit_code, handle->exit_signal);
+ }
+}
+
+
+void uv_process_close(uv_loop_t* loop, uv_process_t* handle) {
+ uv__handle_closing(handle);
+
+ if (handle->wait_handle != INVALID_HANDLE_VALUE) {
+ /* This blocks until either the wait was cancelled, or the callback has */
+ /* completed. */
+ BOOL r = UnregisterWaitEx(handle->wait_handle, INVALID_HANDLE_VALUE);
+ if (!r) {
+ /* This should never happen, and if it happens, we can't recover... */
+ uv_fatal_error(GetLastError(), "UnregisterWaitEx");
+ }
+
+ handle->wait_handle = INVALID_HANDLE_VALUE;
+ }
+
+ if (!handle->exit_cb_pending) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+}
+
+
+void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) {
+ assert(!handle->exit_cb_pending);
+ assert(handle->flags & UV__HANDLE_CLOSING);
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ /* Clean-up the process handle. */
+ CloseHandle(handle->process_handle);
+
+ uv__handle_close(handle);
+}
+
+
+int uv_spawn(uv_loop_t* loop,
+ uv_process_t* process,
+ const uv_process_options_t* options) {
+ int i;
+ int err = 0;
+ WCHAR* path = NULL, *alloc_path = NULL;
+ BOOL result;
+ WCHAR* application_path = NULL, *application = NULL, *arguments = NULL,
+ *env = NULL, *cwd = NULL;
+ STARTUPINFOW startup;
+ PROCESS_INFORMATION info;
+ DWORD process_flags;
+
+ uv_process_init(loop, process);
+ process->exit_cb = options->exit_cb;
+
+ if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) {
+ return UV_ENOTSUP;
+ }
+
+ if (options->file == NULL ||
+ options->args == NULL) {
+ return UV_EINVAL;
+ }
+
+ assert(options->file != NULL);
+ assert(!(options->flags & ~(UV_PROCESS_DETACHED |
+ UV_PROCESS_SETGID |
+ UV_PROCESS_SETUID |
+ UV_PROCESS_WINDOWS_HIDE |
+ UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
+
+ err = uv_utf8_to_utf16_alloc(options->file, &application);
+ if (err)
+ goto done;
+
+ err = make_program_args(
+ options->args,
+ options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
+ &arguments);
+ if (err)
+ goto done;
+
+ if (options->env) {
+ err = make_program_env(options->env, &env);
+ if (err)
+ goto done;
+ }
+
+ if (options->cwd) {
+ /* Explicit cwd */
+ err = uv_utf8_to_utf16_alloc(options->cwd, &cwd);
+ if (err)
+ goto done;
+
+ } else {
+ /* Inherit cwd */
+ DWORD cwd_len, r;
+
+ cwd_len = GetCurrentDirectoryW(0, NULL);
+ if (!cwd_len) {
+ err = GetLastError();
+ goto done;
+ }
+
+ cwd = (WCHAR*) uv__malloc(cwd_len * sizeof(WCHAR));
+ if (cwd == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto done;
+ }
+
+ r = GetCurrentDirectoryW(cwd_len, cwd);
+ if (r == 0 || r >= cwd_len) {
+ err = GetLastError();
+ goto done;
+ }
+ }
+
+ /* Get PATH environment variable. */
+ path = find_path(env);
+ if (path == NULL) {
+ DWORD path_len, r;
+
+ path_len = GetEnvironmentVariableW(L"PATH", NULL, 0);
+ if (path_len == 0) {
+ err = GetLastError();
+ goto done;
+ }
+
+ alloc_path = (WCHAR*) uv__malloc(path_len * sizeof(WCHAR));
+ if (alloc_path == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto done;
+ }
+ path = alloc_path;
+
+ r = GetEnvironmentVariableW(L"PATH", path, path_len);
+ if (r == 0 || r >= path_len) {
+ err = GetLastError();
+ goto done;
+ }
+ }
+
+ err = uv__stdio_create(loop, options, &process->child_stdio_buffer);
+ if (err)
+ goto done;
+
+ application_path = search_path(application,
+ cwd,
+ path);
+ if (application_path == NULL) {
+ /* Not found. */
+ err = ERROR_FILE_NOT_FOUND;
+ goto done;
+ }
+
+ startup.cb = sizeof(startup);
+ startup.lpReserved = NULL;
+ startup.lpDesktop = NULL;
+ startup.lpTitle = NULL;
+ startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+
+ startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer);
+ startup.lpReserved2 = (BYTE*) process->child_stdio_buffer;
+
+ startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0);
+ startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1);
+ startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2);
+
+ if (options->flags & UV_PROCESS_WINDOWS_HIDE) {
+ /* Use SW_HIDE to avoid any potential process window. */
+ startup.wShowWindow = SW_HIDE;
+ } else {
+ startup.wShowWindow = SW_SHOWDEFAULT;
+ }
+
+ process_flags = CREATE_UNICODE_ENVIRONMENT;
+
+ if (options->flags & UV_PROCESS_DETACHED) {
+ /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That
+ * means that libuv might not let you create a fully daemonized process
+ * when run under job control. However the type of job control that libuv
+ * itself creates doesn't trickle down to subprocesses so they can still
+ * daemonize.
+ *
+ * A reason to not do this is that CREATE_BREAKAWAY_FROM_JOB makes the
+ * CreateProcess call fail if we're under job control that doesn't allow
+ * breakaway.
+ */
+ process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP;
+ }
+
+ if (!CreateProcessW(application_path,
+ arguments,
+ NULL,
+ NULL,
+ 1,
+ process_flags,
+ env,
+ cwd,
+ &startup,
+ &info)) {
+ /* CreateProcessW failed. */
+ err = GetLastError();
+ goto done;
+ }
+
+ /* Spawn succeeded */
+ /* Beyond this point, failure is reported asynchronously. */
+
+ process->process_handle = info.hProcess;
+ process->pid = info.dwProcessId;
+
+ /* If the process isn't spawned as detached, assign to the global job */
+ /* object so windows will kill it when the parent process dies. */
+ if (!(options->flags & UV_PROCESS_DETACHED)) {
+ uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle);
+
+ if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) {
+ /* AssignProcessToJobObject might fail if this process is under job
+ * control and the job doesn't have the
+ * JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag set, on a Windows version
+ * that doesn't support nested jobs.
+ *
+ * When that happens we just swallow the error and continue without
+ * establishing a kill-child-on-parent-exit relationship, otherwise
+ * there would be no way for libuv applications run under job control
+ * to spawn processes at all.
+ */
+ DWORD err = GetLastError();
+ if (err != ERROR_ACCESS_DENIED)
+ uv_fatal_error(err, "AssignProcessToJobObject");
+ }
+ }
+
+ /* Set IPC pid to all IPC pipes. */
+ for (i = 0; i < options->stdio_count; i++) {
+ const uv_stdio_container_t* fdopt = &options->stdio[i];
+ if (fdopt->flags & UV_CREATE_PIPE &&
+ fdopt->data.stream->type == UV_NAMED_PIPE &&
+ ((uv_pipe_t*) fdopt->data.stream)->ipc) {
+ ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_pid = info.dwProcessId;
+ }
+ }
+
+ /* Setup notifications for when the child process exits. */
+ result = RegisterWaitForSingleObject(&process->wait_handle,
+ process->process_handle, exit_wait_callback, (void*)process, INFINITE,
+ WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
+ if (!result) {
+ uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject");
+ }
+
+ CloseHandle(info.hThread);
+
+ assert(!err);
+
+ /* Make the handle active. It will remain active until the exit callback */
+ /* is made or the handle is closed, whichever happens first. */
+ uv__handle_start(process);
+
+ /* Cleanup, whether we succeeded or failed. */
+ done:
+ uv__free(application);
+ uv__free(application_path);
+ uv__free(arguments);
+ uv__free(cwd);
+ uv__free(env);
+ uv__free(alloc_path);
+
+ if (process->child_stdio_buffer != NULL) {
+ /* Clean up child stdio handles. */
+ uv__stdio_destroy(process->child_stdio_buffer);
+ process->child_stdio_buffer = NULL;
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+static int uv__kill(HANDLE process_handle, int signum) {
+ switch (signum) {
+ case SIGTERM:
+ case SIGKILL:
+ case SIGINT: {
+ /* Unconditionally terminate the process. On Windows, killed processes */
+ /* normally return 1. */
+ DWORD status;
+ int err;
+
+ if (TerminateProcess(process_handle, 1))
+ return 0;
+
+ /* If the process already exited before TerminateProcess was called, */
+ /* TerminateProcess will fail with ERROR_ACCESS_DENIED. */
+ err = GetLastError();
+ if (err == ERROR_ACCESS_DENIED &&
+ GetExitCodeProcess(process_handle, &status) &&
+ status != STILL_ACTIVE) {
+ return UV_ESRCH;
+ }
+
+ return uv_translate_sys_error(err);
+ }
+
+ case 0: {
+ /* Health check: is the process still alive? */
+ DWORD status;
+
+ if (!GetExitCodeProcess(process_handle, &status))
+ return uv_translate_sys_error(GetLastError());
+
+ if (status != STILL_ACTIVE)
+ return UV_ESRCH;
+
+ return 0;
+ }
+
+ default:
+ /* Unsupported signal. */
+ return UV_ENOSYS;
+ }
+}
+
+
+int uv_process_kill(uv_process_t* process, int signum) {
+ int err;
+
+ if (process->process_handle == INVALID_HANDLE_VALUE) {
+ return UV_EINVAL;
+ }
+
+ err = uv__kill(process->process_handle, signum);
+ if (err) {
+ return err; /* err is already translated. */
+ }
+
+ process->exit_signal = signum;
+
+ return 0;
+}
+
+
+int uv_kill(int pid, int signum) {
+ int err;
+ HANDLE process_handle = OpenProcess(PROCESS_TERMINATE |
+ PROCESS_QUERY_INFORMATION, FALSE, pid);
+
+ if (process_handle == NULL) {
+ err = GetLastError();
+ if (err == ERROR_INVALID_PARAMETER) {
+ return UV_ESRCH;
+ } else {
+ return uv_translate_sys_error(err);
+ }
+ }
+
+ err = uv__kill(process_handle, signum);
+ CloseHandle(process_handle);
+
+ return err; /* err is already translated. */
+}
diff --git a/3rdparty/libuv/src/win/req-inl.h b/3rdparty/libuv/src/win/req-inl.h
new file mode 100644
index 00000000000..b5e502eef55
--- /dev/null
+++ b/3rdparty/libuv/src/win/req-inl.h
@@ -0,0 +1,224 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_REQ_INL_H_
+#define UV_WIN_REQ_INL_H_
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+#define SET_REQ_STATUS(req, status) \
+ (req)->u.io.overlapped.Internal = (ULONG_PTR) (status)
+
+#define SET_REQ_ERROR(req, error) \
+ SET_REQ_STATUS((req), NTSTATUS_FROM_WIN32((error)))
+
+#define SET_REQ_SUCCESS(req) \
+ SET_REQ_STATUS((req), STATUS_SUCCESS)
+
+#define GET_REQ_STATUS(req) \
+ ((NTSTATUS) (req)->u.io.overlapped.Internal)
+
+#define REQ_SUCCESS(req) \
+ (NT_SUCCESS(GET_REQ_STATUS((req))))
+
+#define GET_REQ_ERROR(req) \
+ (pRtlNtStatusToDosError(GET_REQ_STATUS((req))))
+
+#define GET_REQ_SOCK_ERROR(req) \
+ (uv_ntstatus_to_winsock_error(GET_REQ_STATUS((req))))
+
+
+#define REGISTER_HANDLE_REQ(loop, handle, req) \
+ do { \
+ INCREASE_ACTIVE_COUNT((loop), (handle)); \
+ uv__req_register((loop), (req)); \
+ } while (0)
+
+#define UNREGISTER_HANDLE_REQ(loop, handle, req) \
+ do { \
+ DECREASE_ACTIVE_COUNT((loop), (handle)); \
+ uv__req_unregister((loop), (req)); \
+ } while (0)
+
+
+#define UV_SUCCEEDED_WITHOUT_IOCP(result) \
+ ((result) && (handle->flags & UV_HANDLE_SYNC_BYPASS_IOCP))
+
+#define UV_SUCCEEDED_WITH_IOCP(result) \
+ ((result) || (GetLastError() == ERROR_IO_PENDING))
+
+
+#define POST_COMPLETION_FOR_REQ(loop, req) \
+ if (!PostQueuedCompletionStatus((loop)->iocp, \
+ 0, \
+ 0, \
+ &((req)->u.io.overlapped))) { \
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); \
+ }
+
+
+INLINE static void uv_req_init(uv_loop_t* loop, uv_req_t* req) {
+ req->type = UV_UNKNOWN_REQ;
+ SET_REQ_SUCCESS(req);
+}
+
+
+INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) {
+ return CONTAINING_RECORD(overlapped, uv_req_t, u.io.overlapped);
+}
+
+
+INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
+ req->next_req = NULL;
+ if (loop->pending_reqs_tail) {
+#ifdef _DEBUG
+ /* Ensure the request is not already in the queue, or the queue
+ * will get corrupted.
+ */
+ uv_req_t* current = loop->pending_reqs_tail;
+ do {
+ assert(req != current);
+ current = current->next_req;
+ } while(current != loop->pending_reqs_tail);
+#endif
+
+ req->next_req = loop->pending_reqs_tail->next_req;
+ loop->pending_reqs_tail->next_req = req;
+ loop->pending_reqs_tail = req;
+ } else {
+ req->next_req = req;
+ loop->pending_reqs_tail = req;
+ }
+}
+
+
+#define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \
+ do { \
+ switch (((uv_handle_t*) (req)->handle_at)->type) { \
+ case UV_TCP: \
+ uv_process_tcp_##method##_req(loop, \
+ (uv_tcp_t*) ((req)->handle_at), \
+ req); \
+ break; \
+ \
+ case UV_NAMED_PIPE: \
+ uv_process_pipe_##method##_req(loop, \
+ (uv_pipe_t*) ((req)->handle_at), \
+ req); \
+ break; \
+ \
+ case UV_TTY: \
+ uv_process_tty_##method##_req(loop, \
+ (uv_tty_t*) ((req)->handle_at), \
+ req); \
+ break; \
+ \
+ default: \
+ assert(0); \
+ } \
+ } while (0)
+
+
+INLINE static int uv_process_reqs(uv_loop_t* loop) {
+ uv_req_t* req;
+ uv_req_t* first;
+ uv_req_t* next;
+
+ if (loop->pending_reqs_tail == NULL)
+ return 0;
+
+ first = loop->pending_reqs_tail->next_req;
+ next = first;
+ loop->pending_reqs_tail = NULL;
+
+ while (next != NULL) {
+ req = next;
+ next = req->next_req != first ? req->next_req : NULL;
+
+ switch (req->type) {
+ case UV_READ:
+ DELEGATE_STREAM_REQ(loop, req, read, data);
+ break;
+
+ case UV_WRITE:
+ DELEGATE_STREAM_REQ(loop, (uv_write_t*) req, write, handle);
+ break;
+
+ case UV_ACCEPT:
+ DELEGATE_STREAM_REQ(loop, req, accept, data);
+ break;
+
+ case UV_CONNECT:
+ DELEGATE_STREAM_REQ(loop, (uv_connect_t*) req, connect, handle);
+ break;
+
+ case UV_SHUTDOWN:
+ /* Tcp shutdown requests don't come here. */
+ assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE);
+ uv_process_pipe_shutdown_req(
+ loop,
+ (uv_pipe_t*) ((uv_shutdown_t*) req)->handle,
+ (uv_shutdown_t*) req);
+ break;
+
+ case UV_UDP_RECV:
+ uv_process_udp_recv_req(loop, (uv_udp_t*) req->data, req);
+ break;
+
+ case UV_UDP_SEND:
+ uv_process_udp_send_req(loop,
+ ((uv_udp_send_t*) req)->handle,
+ (uv_udp_send_t*) req);
+ break;
+
+ case UV_WAKEUP:
+ uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req);
+ break;
+
+ case UV_SIGNAL_REQ:
+ uv_process_signal_req(loop, (uv_signal_t*) req->data, req);
+ break;
+
+ case UV_POLL_REQ:
+ uv_process_poll_req(loop, (uv_poll_t*) req->data, req);
+ break;
+
+ case UV_PROCESS_EXIT:
+ uv_process_proc_exit(loop, (uv_process_t*) req->data);
+ break;
+
+ case UV_FS_EVENT_REQ:
+ uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data);
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+
+ return 1;
+}
+
+#endif /* UV_WIN_REQ_INL_H_ */
diff --git a/3rdparty/libuv/src/win/req.c b/3rdparty/libuv/src/win/req.c
new file mode 100644
index 00000000000..111cc5e2893
--- /dev/null
+++ b/3rdparty/libuv/src/win/req.c
@@ -0,0 +1,25 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
diff --git a/3rdparty/libuv/src/win/signal.c b/3rdparty/libuv/src/win/signal.c
new file mode 100644
index 00000000000..2c64a55dc39
--- /dev/null
+++ b/3rdparty/libuv/src/win/signal.c
@@ -0,0 +1,356 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <signal.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+RB_HEAD(uv_signal_tree_s, uv_signal_s);
+
+static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree);
+static ssize_t volatile uv__signal_control_handler_refs = 0;
+static CRITICAL_SECTION uv__signal_lock;
+
+
+void uv_signals_init() {
+ InitializeCriticalSection(&uv__signal_lock);
+}
+
+
+static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
+ /* Compare signums first so all watchers with the same signnum end up */
+ /* adjacent. */
+ if (w1->signum < w2->signum) return -1;
+ if (w1->signum > w2->signum) return 1;
+
+ /* Sort by loop pointer, so we can easily look up the first item after */
+ /* { .signum = x, .loop = NULL } */
+ if ((uintptr_t) w1->loop < (uintptr_t) w2->loop) return -1;
+ if ((uintptr_t) w1->loop > (uintptr_t) w2->loop) return 1;
+
+ if ((uintptr_t) w1 < (uintptr_t) w2) return -1;
+ if ((uintptr_t) w1 > (uintptr_t) w2) return 1;
+
+ return 0;
+}
+
+
+RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare);
+
+
+/*
+ * Dispatches signal {signum} to all active uv_signal_t watchers in all loops.
+ * Returns 1 if the signal was dispatched to any watcher, or 0 if there were
+ * no active signal watchers observing this signal.
+ */
+int uv__signal_dispatch(int signum) {
+ uv_signal_t lookup;
+ uv_signal_t* handle;
+ int dispatched = 0;
+
+ EnterCriticalSection(&uv__signal_lock);
+
+ lookup.signum = signum;
+ lookup.loop = NULL;
+
+ for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup);
+ handle != NULL && handle->signum == signum;
+ handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) {
+ unsigned long previous = InterlockedExchange(
+ (volatile LONG*) &handle->pending_signum, signum);
+
+ if (!previous) {
+ POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req);
+ }
+
+ dispatched = 1;
+ }
+
+ LeaveCriticalSection(&uv__signal_lock);
+
+ return dispatched;
+}
+
+
+static BOOL WINAPI uv__signal_control_handler(DWORD type) {
+ switch (type) {
+ case CTRL_C_EVENT:
+ return uv__signal_dispatch(SIGINT);
+
+ case CTRL_BREAK_EVENT:
+ return uv__signal_dispatch(SIGBREAK);
+
+ case CTRL_CLOSE_EVENT:
+ if (uv__signal_dispatch(SIGHUP)) {
+ /* Windows will terminate the process after the control handler */
+ /* returns. After that it will just terminate our process. Therefore */
+ /* block the signal handler so the main loop has some time to pick */
+ /* up the signal and do something for a few seconds. */
+ Sleep(INFINITE);
+ return TRUE;
+ }
+ return FALSE;
+
+ case CTRL_LOGOFF_EVENT:
+ case CTRL_SHUTDOWN_EVENT:
+ /* These signals are only sent to services. Services have their own */
+ /* notification mechanism, so there's no point in handling these. */
+
+ default:
+ /* We don't handle these. */
+ return FALSE;
+ }
+}
+
+
+static int uv__signal_register_control_handler() {
+ /* When this function is called, the uv__signal_lock must be held. */
+
+ /* If the console control handler has already been hooked, just add a */
+ /* reference. */
+ if (uv__signal_control_handler_refs > 0) {
+ uv__signal_control_handler_refs++;
+ return 0;
+ }
+
+ if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
+ return GetLastError();
+
+ uv__signal_control_handler_refs++;
+
+ return 0;
+}
+
+
+static void uv__signal_unregister_control_handler() {
+ /* When this function is called, the uv__signal_lock must be held. */
+ BOOL r;
+
+ /* Don't unregister if the number of console control handlers exceeds one. */
+ /* Just remove a reference in that case. */
+ if (uv__signal_control_handler_refs > 1) {
+ uv__signal_control_handler_refs--;
+ return;
+ }
+
+ assert(uv__signal_control_handler_refs == 1);
+
+ r = SetConsoleCtrlHandler(uv__signal_control_handler, FALSE);
+ /* This should never fail; if it does it is probably a bug in libuv. */
+ assert(r);
+
+ uv__signal_control_handler_refs--;
+}
+
+
+static int uv__signal_register(int signum) {
+ switch (signum) {
+ case SIGINT:
+ case SIGBREAK:
+ case SIGHUP:
+ return uv__signal_register_control_handler();
+
+ case SIGWINCH:
+ /* SIGWINCH is generated in tty.c. No need to register anything. */
+ return 0;
+
+ case SIGILL:
+ case SIGABRT_COMPAT:
+ case SIGFPE:
+ case SIGSEGV:
+ case SIGTERM:
+ case SIGABRT:
+ /* Signal is never raised. */
+ return 0;
+
+ default:
+ /* Invalid signal. */
+ return ERROR_INVALID_PARAMETER;
+ }
+}
+
+
+static void uv__signal_unregister(int signum) {
+ switch (signum) {
+ case SIGINT:
+ case SIGBREAK:
+ case SIGHUP:
+ uv__signal_unregister_control_handler();
+ return;
+
+ case SIGWINCH:
+ /* SIGWINCH is generated in tty.c. No need to unregister anything. */
+ return;
+
+ case SIGILL:
+ case SIGABRT_COMPAT:
+ case SIGFPE:
+ case SIGSEGV:
+ case SIGTERM:
+ case SIGABRT:
+ /* Nothing is registered for this signal. */
+ return;
+
+ default:
+ /* Libuv bug. */
+ assert(0 && "Invalid signum");
+ return;
+ }
+}
+
+
+int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
+ uv_req_t* req;
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
+ handle->pending_signum = 0;
+ handle->signum = 0;
+ handle->signal_cb = NULL;
+
+ req = &handle->signal_req;
+ uv_req_init(loop, req);
+ req->type = UV_SIGNAL_REQ;
+ req->data = handle;
+
+ return 0;
+}
+
+
+int uv_signal_stop(uv_signal_t* handle) {
+ uv_signal_t* removed_handle;
+
+ /* If the watcher wasn't started, this is a no-op. */
+ if (handle->signum == 0)
+ return 0;
+
+ EnterCriticalSection(&uv__signal_lock);
+
+ uv__signal_unregister(handle->signum);
+
+ removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle);
+ assert(removed_handle == handle);
+
+ LeaveCriticalSection(&uv__signal_lock);
+
+ handle->signum = 0;
+ uv__handle_stop(handle);
+
+ return 0;
+}
+
+
+int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
+ int err;
+
+ /* If the user supplies signum == 0, then return an error already. If the */
+ /* signum is otherwise invalid then uv__signal_register will find out */
+ /* eventually. */
+ if (signum == 0) {
+ return UV_EINVAL;
+ }
+
+ /* Short circuit: if the signal watcher is already watching {signum} don't */
+ /* go through the process of deregistering and registering the handler. */
+ /* Additionally, this avoids pending signals getting lost in the (small) */
+ /* time frame that handle->signum == 0. */
+ if (signum == handle->signum) {
+ handle->signal_cb = signal_cb;
+ return 0;
+ }
+
+ /* If the signal handler was already active, stop it first. */
+ if (handle->signum != 0) {
+ int r = uv_signal_stop(handle);
+ /* uv_signal_stop is infallible. */
+ assert(r == 0);
+ }
+
+ EnterCriticalSection(&uv__signal_lock);
+
+ err = uv__signal_register(signum);
+ if (err) {
+ /* Uh-oh, didn't work. */
+ LeaveCriticalSection(&uv__signal_lock);
+ return uv_translate_sys_error(err);
+ }
+
+ handle->signum = signum;
+ RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);
+
+ LeaveCriticalSection(&uv__signal_lock);
+
+ handle->signal_cb = signal_cb;
+ uv__handle_start(handle);
+
+ return 0;
+}
+
+
+void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
+ uv_req_t* req) {
+ long dispatched_signum;
+
+ assert(handle->type == UV_SIGNAL);
+ assert(req->type == UV_SIGNAL_REQ);
+
+ dispatched_signum = InterlockedExchange(
+ (volatile LONG*) &handle->pending_signum, 0);
+ assert(dispatched_signum != 0);
+
+ /* Check if the pending signal equals the signum that we are watching for. */
+ /* These can get out of sync when the handler is stopped and restarted */
+ /* while the signal_req is pending. */
+ if (dispatched_signum == handle->signum)
+ handle->signal_cb(handle, dispatched_signum);
+
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ /* When it is closing, it must be stopped at this point. */
+ assert(handle->signum == 0);
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+}
+
+
+void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) {
+ uv_signal_stop(handle);
+ uv__handle_closing(handle);
+
+ if (handle->pending_signum == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+}
+
+
+void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) {
+ assert(handle->flags & UV__HANDLE_CLOSING);
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ assert(handle->signum == 0);
+ assert(handle->pending_signum == 0);
+
+ handle->flags |= UV_HANDLE_CLOSED;
+
+ uv__handle_close(handle);
+}
diff --git a/3rdparty/libuv/src/win/snprintf.c b/3rdparty/libuv/src/win/snprintf.c
new file mode 100644
index 00000000000..776c0e39217
--- /dev/null
+++ b/3rdparty/libuv/src/win/snprintf.c
@@ -0,0 +1,42 @@
+/* Copyright the libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+
+#include <stdio.h>
+#include <stdarg.h>
+
+/* Emulate snprintf() on MSVC<2015, _snprintf() doesn't zero-terminate the buffer
+ * on overflow...
+ */
+int snprintf(char* buf, size_t len, const char* fmt, ...) {
+ int n;
+ va_list ap;
+ va_start(ap, fmt);
+
+ n = _vscprintf(fmt, ap);
+ vsnprintf_s(buf, len, _TRUNCATE, fmt, ap);
+
+ va_end(ap);
+ return n;
+}
+
+#endif
diff --git a/3rdparty/libuv/src/win/stream-inl.h b/3rdparty/libuv/src/win/stream-inl.h
new file mode 100644
index 00000000000..b7a3c11958c
--- /dev/null
+++ b/3rdparty/libuv/src/win/stream-inl.h
@@ -0,0 +1,56 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_STREAM_INL_H_
+#define UV_WIN_STREAM_INL_H_
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+INLINE static void uv_stream_init(uv_loop_t* loop,
+ uv_stream_t* handle,
+ uv_handle_type type) {
+ uv__handle_init(loop, (uv_handle_t*) handle, type);
+ handle->write_queue_size = 0;
+ handle->activecnt = 0;
+}
+
+
+INLINE static void uv_connection_init(uv_stream_t* handle) {
+ handle->flags |= UV_HANDLE_CONNECTION;
+ handle->stream.conn.write_reqs_pending = 0;
+
+ uv_req_init(handle->loop, (uv_req_t*) &(handle->read_req));
+ handle->read_req.event_handle = NULL;
+ handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
+ handle->read_req.type = UV_READ;
+ handle->read_req.data = handle;
+
+ handle->stream.conn.shutdown_req = NULL;
+}
+
+
+#endif /* UV_WIN_STREAM_INL_H_ */
diff --git a/3rdparty/libuv/src/win/stream.c b/3rdparty/libuv/src/win/stream.c
new file mode 100644
index 00000000000..a2466e5e9db
--- /dev/null
+++ b/3rdparty/libuv/src/win/stream.c
@@ -0,0 +1,249 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
+ int err;
+
+ err = ERROR_INVALID_PARAMETER;
+ switch (stream->type) {
+ case UV_TCP:
+ err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
+ break;
+ case UV_NAMED_PIPE:
+ err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb);
+ break;
+ default:
+ assert(0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_accept(uv_stream_t* server, uv_stream_t* client) {
+ int err;
+
+ err = ERROR_INVALID_PARAMETER;
+ switch (server->type) {
+ case UV_TCP:
+ err = uv_tcp_accept((uv_tcp_t*)server, (uv_tcp_t*)client);
+ break;
+ case UV_NAMED_PIPE:
+ err = uv_pipe_accept((uv_pipe_t*)server, client);
+ break;
+ default:
+ assert(0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ int err;
+
+ if (handle->flags & UV_HANDLE_READING) {
+ return UV_EALREADY;
+ }
+
+ if (!(handle->flags & UV_HANDLE_READABLE)) {
+ return UV_ENOTCONN;
+ }
+
+ err = ERROR_INVALID_PARAMETER;
+ switch (handle->type) {
+ case UV_TCP:
+ err = uv_tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb);
+ break;
+ case UV_NAMED_PIPE:
+ err = uv_pipe_read_start((uv_pipe_t*)handle, alloc_cb, read_cb);
+ break;
+ case UV_TTY:
+ err = uv_tty_read_start((uv_tty_t*) handle, alloc_cb, read_cb);
+ break;
+ default:
+ assert(0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_read_stop(uv_stream_t* handle) {
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_READING))
+ return 0;
+
+ err = 0;
+ if (handle->type == UV_TTY) {
+ err = uv_tty_read_stop((uv_tty_t*) handle);
+ } else {
+ if (handle->type == UV_NAMED_PIPE) {
+ uv__pipe_stop_read((uv_pipe_t*) handle);
+ } else {
+ handle->flags &= ~UV_HANDLE_READING;
+ }
+ DECREASE_ACTIVE_COUNT(handle->loop, handle);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_write(uv_write_t* req,
+ uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_WRITABLE)) {
+ return UV_EPIPE;
+ }
+
+ err = ERROR_INVALID_PARAMETER;
+ switch (handle->type) {
+ case UV_TCP:
+ err = uv_tcp_write(loop, req, (uv_tcp_t*) handle, bufs, nbufs, cb);
+ break;
+ case UV_NAMED_PIPE:
+ err = uv_pipe_write(loop, req, (uv_pipe_t*) handle, bufs, nbufs, cb);
+ break;
+ case UV_TTY:
+ err = uv_tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb);
+ break;
+ default:
+ assert(0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_write2(uv_write_t* req,
+ uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle,
+ uv_write_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_WRITABLE)) {
+ return UV_EPIPE;
+ }
+
+ err = ERROR_INVALID_PARAMETER;
+ switch (handle->type) {
+ case UV_NAMED_PIPE:
+ err = uv_pipe_write2(loop,
+ req,
+ (uv_pipe_t*) handle,
+ bufs,
+ nbufs,
+ send_handle,
+ cb);
+ break;
+ default:
+ assert(0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_try_write(uv_stream_t* stream,
+ const uv_buf_t bufs[],
+ unsigned int nbufs) {
+ if (stream->flags & UV__HANDLE_CLOSING)
+ return UV_EBADF;
+ if (!(stream->flags & UV_HANDLE_WRITABLE))
+ return UV_EPIPE;
+
+ switch (stream->type) {
+ case UV_TCP:
+ return uv__tcp_try_write((uv_tcp_t*) stream, bufs, nbufs);
+ case UV_TTY:
+ return uv__tty_try_write((uv_tty_t*) stream, bufs, nbufs);
+ case UV_NAMED_PIPE:
+ return UV_EAGAIN;
+ default:
+ assert(0);
+ return UV_ENOSYS;
+ }
+}
+
+
+int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
+ uv_loop_t* loop = handle->loop;
+
+ if (!(handle->flags & UV_HANDLE_WRITABLE)) {
+ return UV_EPIPE;
+ }
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_SHUTDOWN;
+ req->handle = handle;
+ req->cb = cb;
+
+ handle->flags &= ~UV_HANDLE_WRITABLE;
+ handle->stream.conn.shutdown_req = req;
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+
+ return 0;
+}
+
+
+int uv_is_readable(const uv_stream_t* handle) {
+ return !!(handle->flags & UV_HANDLE_READABLE);
+}
+
+
+int uv_is_writable(const uv_stream_t* handle) {
+ return !!(handle->flags & UV_HANDLE_WRITABLE);
+}
+
+
+int uv_stream_set_blocking(uv_stream_t* handle, int blocking) {
+ if (handle->type != UV_NAMED_PIPE)
+ return UV_EINVAL;
+
+ if (blocking != 0)
+ handle->flags |= UV_HANDLE_BLOCKING_WRITES;
+ else
+ handle->flags &= ~UV_HANDLE_BLOCKING_WRITES;
+
+ return 0;
+}
diff --git a/3rdparty/libuv/src/win/tcp.c b/3rdparty/libuv/src/win/tcp.c
new file mode 100644
index 00000000000..0f5654863e9
--- /dev/null
+++ b/3rdparty/libuv/src/win/tcp.c
@@ -0,0 +1,1507 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "stream-inl.h"
+#include "req-inl.h"
+
+
+/*
+ * Threshold of active tcp streams for which to preallocate tcp read buffers.
+ * (Due to node slab allocator performing poorly under this pattern,
+ * the optimization is temporarily disabled (threshold=0). This will be
+ * revisited once node allocator is improved.)
+ */
+const unsigned int uv_active_tcp_streams_threshold = 0;
+
+/*
+ * Number of simultaneous pending AcceptEx calls.
+ */
+const unsigned int uv_simultaneous_server_accepts = 32;
+
+/* A zero-size buffer for use by uv_tcp_read */
+static char uv_zero_[] = "";
+
+static int uv__tcp_nodelay(uv_tcp_t* handle, SOCKET socket, int enable) {
+ if (setsockopt(socket,
+ IPPROTO_TCP,
+ TCP_NODELAY,
+ (const char*)&enable,
+ sizeof enable) == -1) {
+ return WSAGetLastError();
+ }
+ return 0;
+}
+
+
+static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsigned int delay) {
+ if (setsockopt(socket,
+ SOL_SOCKET,
+ SO_KEEPALIVE,
+ (const char*)&enable,
+ sizeof enable) == -1) {
+ return WSAGetLastError();
+ }
+
+ if (enable && setsockopt(socket,
+ IPPROTO_TCP,
+ TCP_KEEPALIVE,
+ (const char*)&delay,
+ sizeof delay) == -1) {
+ return WSAGetLastError();
+ }
+
+ return 0;
+}
+
+
+static int uv_tcp_set_socket(uv_loop_t* loop,
+ uv_tcp_t* handle,
+ SOCKET socket,
+ int family,
+ int imported) {
+ DWORD yes = 1;
+ int non_ifs_lsp;
+ int err;
+
+ if (handle->socket != INVALID_SOCKET)
+ return UV_EBUSY;
+
+ /* Set the socket to nonblocking mode */
+ if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) {
+ return WSAGetLastError();
+ }
+
+ /* Make the socket non-inheritable */
+ if (!SetHandleInformation((HANDLE) socket, HANDLE_FLAG_INHERIT, 0))
+ return GetLastError();
+
+ /* Associate it with the I/O completion port. */
+ /* Use uv_handle_t pointer as completion key. */
+ if (CreateIoCompletionPort((HANDLE)socket,
+ loop->iocp,
+ (ULONG_PTR)socket,
+ 0) == NULL) {
+ if (imported) {
+ handle->flags |= UV_HANDLE_EMULATE_IOCP;
+ } else {
+ return GetLastError();
+ }
+ }
+
+ if (family == AF_INET6) {
+ non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv6;
+ } else {
+ non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv4;
+ }
+
+ if (pSetFileCompletionNotificationModes &&
+ !(handle->flags & UV_HANDLE_EMULATE_IOCP) && !non_ifs_lsp) {
+ if (pSetFileCompletionNotificationModes((HANDLE) socket,
+ FILE_SKIP_SET_EVENT_ON_HANDLE |
+ FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
+ handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
+ } else if (GetLastError() != ERROR_INVALID_FUNCTION) {
+ return GetLastError();
+ }
+ }
+
+ if (handle->flags & UV_HANDLE_TCP_NODELAY) {
+ err = uv__tcp_nodelay(handle, socket, 1);
+ if (err)
+ return err;
+ }
+
+ /* TODO: Use stored delay. */
+ if (handle->flags & UV_HANDLE_TCP_KEEPALIVE) {
+ err = uv__tcp_keepalive(handle, socket, 1, 60);
+ if (err)
+ return err;
+ }
+
+ handle->socket = socket;
+
+ if (family == AF_INET6) {
+ handle->flags |= UV_HANDLE_IPV6;
+ } else {
+ assert(!(handle->flags & UV_HANDLE_IPV6));
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) {
+ int domain;
+
+ /* Use the lower 8 bits for the domain */
+ domain = flags & 0xFF;
+ if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
+ return UV_EINVAL;
+
+ if (flags & ~0xFF)
+ return UV_EINVAL;
+
+ uv_stream_init(loop, (uv_stream_t*) handle, UV_TCP);
+ handle->tcp.serv.accept_reqs = NULL;
+ handle->tcp.serv.pending_accepts = NULL;
+ handle->socket = INVALID_SOCKET;
+ handle->reqs_pending = 0;
+ handle->tcp.serv.func_acceptex = NULL;
+ handle->tcp.conn.func_connectex = NULL;
+ handle->tcp.serv.processed_accepts = 0;
+ handle->delayed_error = 0;
+
+ /* If anything fails beyond this point we need to remove the handle from
+ * the handle queue, since it was added by uv__handle_init in uv_stream_init.
+ */
+
+ if (domain != AF_UNSPEC) {
+ SOCKET sock;
+ DWORD err;
+
+ sock = socket(domain, SOCK_STREAM, 0);
+ if (sock == INVALID_SOCKET) {
+ err = WSAGetLastError();
+ QUEUE_REMOVE(&handle->handle_queue);
+ return uv_translate_sys_error(err);
+ }
+
+ err = uv_tcp_set_socket(handle->loop, handle, sock, domain, 0);
+ if (err) {
+ closesocket(sock);
+ QUEUE_REMOVE(&handle->handle_queue);
+ return uv_translate_sys_error(err);
+ }
+
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
+ return uv_tcp_init_ex(loop, handle, AF_UNSPEC);
+}
+
+
+void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
+ int err;
+ unsigned int i;
+ uv_tcp_accept_t* req;
+
+ if (handle->flags & UV_HANDLE_CONNECTION &&
+ handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+
+ UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
+
+ err = 0;
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ err = ERROR_OPERATION_ABORTED;
+ } else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) {
+ err = WSAGetLastError();
+ }
+
+ if (handle->stream.conn.shutdown_req->cb) {
+ handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req,
+ uv_translate_sys_error(err));
+ }
+
+ handle->stream.conn.shutdown_req = NULL;
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+
+ if (handle->flags & UV__HANDLE_CLOSING &&
+ handle->reqs_pending == 0) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) {
+ closesocket(handle->socket);
+ handle->socket = INVALID_SOCKET;
+ handle->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
+ }
+
+ if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) {
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ for (i = 0; i < uv_simultaneous_server_accepts; i++) {
+ req = &handle->tcp.serv.accept_reqs[i];
+ if (req->wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(req->wait_handle);
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ }
+ if (req->event_handle) {
+ CloseHandle(req->event_handle);
+ req->event_handle = NULL;
+ }
+ }
+ }
+
+ uv__free(handle->tcp.serv.accept_reqs);
+ handle->tcp.serv.accept_reqs = NULL;
+ }
+
+ if (handle->flags & UV_HANDLE_CONNECTION &&
+ handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(handle->read_req.wait_handle);
+ handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
+ }
+ if (handle->read_req.event_handle) {
+ CloseHandle(handle->read_req.event_handle);
+ handle->read_req.event_handle = NULL;
+ }
+ }
+
+ uv__handle_close(handle);
+ loop->active_tcp_streams--;
+ }
+}
+
+
+/* Unlike on Unix, here we don't set SO_REUSEADDR, because it doesn't just
+ * allow binding to addresses that are in use by sockets in TIME_WAIT, it
+ * effectively allows 'stealing' a port which is in use by another application.
+ *
+ * SO_EXCLUSIVEADDRUSE is also not good here because it does check all sockets,
+ * regardless of state, so we'd get an error even if the port is in use by a
+ * socket in TIME_WAIT state.
+ *
+ * See issue #1360.
+ *
+ */
+static int uv_tcp_try_bind(uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ DWORD err;
+ int r;
+
+ if (handle->socket == INVALID_SOCKET) {
+ SOCKET sock;
+
+ /* Cannot set IPv6-only mode on non-IPv6 socket. */
+ if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
+ return ERROR_INVALID_PARAMETER;
+
+ sock = socket(addr->sa_family, SOCK_STREAM, 0);
+ if (sock == INVALID_SOCKET) {
+ return WSAGetLastError();
+ }
+
+ err = uv_tcp_set_socket(handle->loop, handle, sock, addr->sa_family, 0);
+ if (err) {
+ closesocket(sock);
+ return err;
+ }
+ }
+
+#ifdef IPV6_V6ONLY
+ if (addr->sa_family == AF_INET6) {
+ int on;
+
+ on = (flags & UV_TCP_IPV6ONLY) != 0;
+
+ /* TODO: how to handle errors? This may fail if there is no ipv4 stack */
+ /* available, or when run on XP/2003 which have no support for dualstack */
+ /* sockets. For now we're silently ignoring the error. */
+ setsockopt(handle->socket,
+ IPPROTO_IPV6,
+ IPV6_V6ONLY,
+ (const char*)&on,
+ sizeof on);
+ }
+#endif
+
+ r = bind(handle->socket, addr, addrlen);
+
+ if (r == SOCKET_ERROR) {
+ err = WSAGetLastError();
+ if (err == WSAEADDRINUSE) {
+ /* Some errors are not to be reported until connect() or listen() */
+ handle->delayed_error = err;
+ } else {
+ return err;
+ }
+ }
+
+ handle->flags |= UV_HANDLE_BOUND;
+
+ return 0;
+}
+
+
+static void CALLBACK post_completion(void* context, BOOLEAN timed_out) {
+ uv_req_t* req;
+ uv_tcp_t* handle;
+
+ req = (uv_req_t*) context;
+ assert(req != NULL);
+ handle = (uv_tcp_t*)req->data;
+ assert(handle != NULL);
+ assert(!timed_out);
+
+ if (!PostQueuedCompletionStatus(handle->loop->iocp,
+ req->u.io.overlapped.InternalHigh,
+ 0,
+ &req->u.io.overlapped)) {
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+ }
+}
+
+
+static void CALLBACK post_write_completion(void* context, BOOLEAN timed_out) {
+ uv_write_t* req;
+ uv_tcp_t* handle;
+
+ req = (uv_write_t*) context;
+ assert(req != NULL);
+ handle = (uv_tcp_t*)req->handle;
+ assert(handle != NULL);
+ assert(!timed_out);
+
+ if (!PostQueuedCompletionStatus(handle->loop->iocp,
+ req->u.io.overlapped.InternalHigh,
+ 0,
+ &req->u.io.overlapped)) {
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+ }
+}
+
+
+static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
+ uv_loop_t* loop = handle->loop;
+ BOOL success;
+ DWORD bytes;
+ SOCKET accept_socket;
+ short family;
+
+ assert(handle->flags & UV_HANDLE_LISTENING);
+ assert(req->accept_socket == INVALID_SOCKET);
+
+ /* choose family and extension function */
+ if (handle->flags & UV_HANDLE_IPV6) {
+ family = AF_INET6;
+ } else {
+ family = AF_INET;
+ }
+
+ /* Open a socket for the accepted connection. */
+ accept_socket = socket(family, SOCK_STREAM, 0);
+ if (accept_socket == INVALID_SOCKET) {
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->reqs_pending++;
+ return;
+ }
+
+ /* Make the socket non-inheritable */
+ if (!SetHandleInformation((HANDLE) accept_socket, HANDLE_FLAG_INHERIT, 0)) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->reqs_pending++;
+ closesocket(accept_socket);
+ return;
+ }
+
+ /* Prepare the overlapped structure. */
+ memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
+ }
+
+ success = handle->tcp.serv.func_acceptex(handle->socket,
+ accept_socket,
+ (void*)req->accept_buffer,
+ 0,
+ sizeof(struct sockaddr_storage),
+ sizeof(struct sockaddr_storage),
+ &bytes,
+ &req->u.io.overlapped);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
+ /* Process the req without IOCP. */
+ req->accept_socket = accept_socket;
+ handle->reqs_pending++;
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(success)) {
+ /* The req will be processed with IOCP. */
+ req->accept_socket = accept_socket;
+ handle->reqs_pending++;
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
+ req->wait_handle == INVALID_HANDLE_VALUE &&
+ !RegisterWaitForSingleObject(&req->wait_handle,
+ req->event_handle, post_completion, (void*) req,
+ INFINITE, WT_EXECUTEINWAITTHREAD)) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->reqs_pending++;
+ return;
+ }
+ } else {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->reqs_pending++;
+ /* Destroy the preallocated client socket. */
+ closesocket(accept_socket);
+ /* Destroy the event handle */
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ CloseHandle(req->u.io.overlapped.hEvent);
+ req->event_handle = NULL;
+ }
+ }
+}
+
+
+static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
+ uv_read_t* req;
+ uv_buf_t buf;
+ int result;
+ DWORD bytes, flags;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+
+ req = &handle->read_req;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ /*
+ * Preallocate a read buffer if the number of active streams is below
+ * the threshold.
+ */
+ if (loop->active_tcp_streams < uv_active_tcp_streams_threshold) {
+ handle->flags &= ~UV_HANDLE_ZERO_READ;
+ handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->tcp.conn.read_buffer);
+ if (handle->tcp.conn.read_buffer.len == 0) {
+ handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &handle->tcp.conn.read_buffer);
+ return;
+ }
+ assert(handle->tcp.conn.read_buffer.base != NULL);
+ buf = handle->tcp.conn.read_buffer;
+ } else {
+ handle->flags |= UV_HANDLE_ZERO_READ;
+ buf.base = (char*) &uv_zero_;
+ buf.len = 0;
+ }
+
+ /* Prepare the overlapped structure. */
+ memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ assert(req->event_handle);
+ req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
+ }
+
+ flags = 0;
+ result = WSARecv(handle->socket,
+ (WSABUF*)&buf,
+ 1,
+ &bytes,
+ &flags,
+ &req->u.io.overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Process the req without IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ req->u.io.overlapped.InternalHigh = bytes;
+ handle->reqs_pending++;
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* The req will be processed with IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
+ req->wait_handle == INVALID_HANDLE_VALUE &&
+ !RegisterWaitForSingleObject(&req->wait_handle,
+ req->event_handle, post_completion, (void*) req,
+ INFINITE, WT_EXECUTEINWAITTHREAD)) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ }
+ } else {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->reqs_pending++;
+ }
+}
+
+
+int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ unsigned int i, simultaneous_accepts;
+ uv_tcp_accept_t* req;
+ int err;
+
+ assert(backlog > 0);
+
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ handle->stream.serv.connection_cb = cb;
+ }
+
+ if (handle->flags & UV_HANDLE_READING) {
+ return WSAEISCONN;
+ }
+
+ if (handle->delayed_error) {
+ return handle->delayed_error;
+ }
+
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ err = uv_tcp_try_bind(handle,
+ (const struct sockaddr*) &uv_addr_ip4_any_,
+ sizeof(uv_addr_ip4_any_),
+ 0);
+ if (err)
+ return err;
+ if (handle->delayed_error)
+ return handle->delayed_error;
+ }
+
+ if (!handle->tcp.serv.func_acceptex) {
+ if (!uv_get_acceptex_function(handle->socket, &handle->tcp.serv.func_acceptex)) {
+ return WSAEAFNOSUPPORT;
+ }
+ }
+
+ if (!(handle->flags & UV_HANDLE_SHARED_TCP_SOCKET) &&
+ listen(handle->socket, backlog) == SOCKET_ERROR) {
+ return WSAGetLastError();
+ }
+
+ handle->flags |= UV_HANDLE_LISTENING;
+ handle->stream.serv.connection_cb = cb;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+
+ simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1
+ : uv_simultaneous_server_accepts;
+
+ if(!handle->tcp.serv.accept_reqs) {
+ handle->tcp.serv.accept_reqs = (uv_tcp_accept_t*)
+ uv__malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t));
+ if (!handle->tcp.serv.accept_reqs) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ for (i = 0; i < simultaneous_accepts; i++) {
+ req = &handle->tcp.serv.accept_reqs[i];
+ uv_req_init(loop, (uv_req_t*)req);
+ req->type = UV_ACCEPT;
+ req->accept_socket = INVALID_SOCKET;
+ req->data = handle;
+
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ req->event_handle = CreateEvent(NULL, 0, 0, NULL);
+ if (!req->event_handle) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+ } else {
+ req->event_handle = NULL;
+ }
+
+ uv_tcp_queue_accept(handle, req);
+ }
+
+ /* Initialize other unused requests too, because uv_tcp_endgame */
+ /* doesn't know how how many requests were initialized, so it will */
+ /* try to clean up {uv_simultaneous_server_accepts} requests. */
+ for (i = simultaneous_accepts; i < uv_simultaneous_server_accepts; i++) {
+ req = &handle->tcp.serv.accept_reqs[i];
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_ACCEPT;
+ req->accept_socket = INVALID_SOCKET;
+ req->data = handle;
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ req->event_handle = NULL;
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
+ uv_loop_t* loop = server->loop;
+ int err = 0;
+ int family;
+
+ uv_tcp_accept_t* req = server->tcp.serv.pending_accepts;
+
+ if (!req) {
+ /* No valid connections found, so we error out. */
+ return WSAEWOULDBLOCK;
+ }
+
+ if (req->accept_socket == INVALID_SOCKET) {
+ return WSAENOTCONN;
+ }
+
+ if (server->flags & UV_HANDLE_IPV6) {
+ family = AF_INET6;
+ } else {
+ family = AF_INET;
+ }
+
+ err = uv_tcp_set_socket(client->loop,
+ client,
+ req->accept_socket,
+ family,
+ 0);
+ if (err) {
+ closesocket(req->accept_socket);
+ } else {
+ uv_connection_init((uv_stream_t*) client);
+ /* AcceptEx() implicitly binds the accepted socket. */
+ client->flags |= UV_HANDLE_BOUND | UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+ }
+
+ /* Prepare the req to pick up a new connection */
+ server->tcp.serv.pending_accepts = req->next_pending;
+ req->next_pending = NULL;
+ req->accept_socket = INVALID_SOCKET;
+
+ if (!(server->flags & UV__HANDLE_CLOSING)) {
+ /* Check if we're in a middle of changing the number of pending accepts. */
+ if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) {
+ uv_tcp_queue_accept(server, req);
+ } else {
+ /* We better be switching to a single pending accept. */
+ assert(server->flags & UV_HANDLE_TCP_SINGLE_ACCEPT);
+
+ server->tcp.serv.processed_accepts++;
+
+ if (server->tcp.serv.processed_accepts >= uv_simultaneous_server_accepts) {
+ server->tcp.serv.processed_accepts = 0;
+ /*
+ * All previously queued accept requests are now processed.
+ * We now switch to queueing just a single accept.
+ */
+ uv_tcp_queue_accept(server, &server->tcp.serv.accept_reqs[0]);
+ server->flags &= ~UV_HANDLE_TCP_ACCEPT_STATE_CHANGING;
+ server->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
+ }
+ }
+ }
+
+ loop->active_tcp_streams++;
+
+ return err;
+}
+
+
+int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ uv_loop_t* loop = handle->loop;
+
+ handle->flags |= UV_HANDLE_READING;
+ handle->read_cb = read_cb;
+ handle->alloc_cb = alloc_cb;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+
+ /* If reading was stopped and then started again, there could still be a */
+ /* read request pending. */
+ if (!(handle->flags & UV_HANDLE_READ_PENDING)) {
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
+ !handle->read_req.event_handle) {
+ handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL);
+ if (!handle->read_req.event_handle) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+ }
+ uv_tcp_queue_read(loop, handle);
+ }
+
+ return 0;
+}
+
+
+static int uv_tcp_try_connect(uv_connect_t* req,
+ uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_connect_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ const struct sockaddr* bind_addr;
+ BOOL success;
+ DWORD bytes;
+ int err;
+
+ if (handle->delayed_error) {
+ return handle->delayed_error;
+ }
+
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ if (addrlen == sizeof(uv_addr_ip4_any_)) {
+ bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
+ } else if (addrlen == sizeof(uv_addr_ip6_any_)) {
+ bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
+ } else {
+ abort();
+ }
+ err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0);
+ if (err)
+ return err;
+ if (handle->delayed_error)
+ return handle->delayed_error;
+ }
+
+ if (!handle->tcp.conn.func_connectex) {
+ if (!uv_get_connectex_function(handle->socket, &handle->tcp.conn.func_connectex)) {
+ return WSAEAFNOSUPPORT;
+ }
+ }
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_CONNECT;
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ success = handle->tcp.conn.func_connectex(handle->socket,
+ addr,
+ addrlen,
+ NULL,
+ 0,
+ &bytes,
+ &req->u.io.overlapped);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
+ /* Process the req without IOCP. */
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(success)) {
+ /* The req will be processed with IOCP. */
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ } else {
+ return WSAGetLastError();
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_getsockname(const uv_tcp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ int result;
+
+ if (handle->socket == INVALID_SOCKET) {
+ return UV_EINVAL;
+ }
+
+ if (handle->delayed_error) {
+ return uv_translate_sys_error(handle->delayed_error);
+ }
+
+ result = getsockname(handle->socket, name, namelen);
+ if (result != 0) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_getpeername(const uv_tcp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ int result;
+
+ if (handle->socket == INVALID_SOCKET) {
+ return UV_EINVAL;
+ }
+
+ if (handle->delayed_error) {
+ return uv_translate_sys_error(handle->delayed_error);
+ }
+
+ result = getpeername(handle->socket, name, namelen);
+ if (result != 0) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_write(uv_loop_t* loop,
+ uv_write_t* req,
+ uv_tcp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb) {
+ int result;
+ DWORD bytes;
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_WRITE;
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+
+ /* Prepare the overlapped structure. */
+ memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ req->event_handle = CreateEvent(NULL, 0, 0, NULL);
+ if (!req->event_handle) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+ req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ }
+
+ result = WSASend(handle->socket,
+ (WSABUF*) bufs,
+ nbufs,
+ &bytes,
+ 0,
+ &req->u.io.overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Request completed immediately. */
+ req->u.io.queued_bytes = 0;
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* Request queued by the kernel. */
+ req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ handle->write_queue_size += req->u.io.queued_bytes;
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
+ !RegisterWaitForSingleObject(&req->wait_handle,
+ req->event_handle, post_write_completion, (void*) req,
+ INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ }
+ } else {
+ /* Send failed due to an error, report it later */
+ req->u.io.queued_bytes = 0;
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ }
+
+ return 0;
+}
+
+
+int uv__tcp_try_write(uv_tcp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs) {
+ int result;
+ DWORD bytes;
+
+ if (handle->stream.conn.write_reqs_pending > 0)
+ return UV_EAGAIN;
+
+ result = WSASend(handle->socket,
+ (WSABUF*) bufs,
+ nbufs,
+ &bytes,
+ 0,
+ NULL,
+ NULL);
+
+ if (result == SOCKET_ERROR)
+ return uv_translate_sys_error(WSAGetLastError());
+ else
+ return bytes;
+}
+
+
+void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_req_t* req) {
+ DWORD bytes, flags, err;
+ uv_buf_t buf;
+
+ assert(handle->type == UV_TCP);
+
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+
+ if (!REQ_SUCCESS(req)) {
+ /* An error occurred doing the read. */
+ if ((handle->flags & UV_HANDLE_READING) ||
+ !(handle->flags & UV_HANDLE_ZERO_READ)) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
+ uv_buf_init(NULL, 0) : handle->tcp.conn.read_buffer;
+
+ err = GET_REQ_SOCK_ERROR(req);
+
+ if (err == WSAECONNABORTED) {
+ /*
+ * Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix.
+ */
+ err = WSAECONNRESET;
+ }
+
+ handle->read_cb((uv_stream_t*)handle,
+ uv_translate_sys_error(err),
+ &buf);
+ }
+ } else {
+ if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
+ /* The read was done with a non-zero buffer length. */
+ if (req->u.io.overlapped.InternalHigh > 0) {
+ /* Successful read */
+ handle->read_cb((uv_stream_t*)handle,
+ req->u.io.overlapped.InternalHigh,
+ &handle->tcp.conn.read_buffer);
+ /* Read again only if bytes == buf.len */
+ if (req->u.io.overlapped.InternalHigh < handle->tcp.conn.read_buffer.len) {
+ goto done;
+ }
+ } else {
+ /* Connection closed */
+ if (handle->flags & UV_HANDLE_READING) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ }
+ handle->flags &= ~UV_HANDLE_READABLE;
+
+ buf.base = 0;
+ buf.len = 0;
+ handle->read_cb((uv_stream_t*)handle, UV_EOF, &handle->tcp.conn.read_buffer);
+ goto done;
+ }
+ }
+
+ /* Do nonblocking reads until the buffer is empty */
+ while (handle->flags & UV_HANDLE_READING) {
+ handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
+ if (buf.len == 0) {
+ handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
+ break;
+ }
+ assert(buf.base != NULL);
+
+ flags = 0;
+ if (WSARecv(handle->socket,
+ (WSABUF*)&buf,
+ 1,
+ &bytes,
+ &flags,
+ NULL,
+ NULL) != SOCKET_ERROR) {
+ if (bytes > 0) {
+ /* Successful read */
+ handle->read_cb((uv_stream_t*)handle, bytes, &buf);
+ /* Read again only if bytes == buf.len */
+ if (bytes < buf.len) {
+ break;
+ }
+ } else {
+ /* Connection closed */
+ handle->flags &= ~(UV_HANDLE_READING | UV_HANDLE_READABLE);
+ DECREASE_ACTIVE_COUNT(loop, handle);
+
+ handle->read_cb((uv_stream_t*)handle, UV_EOF, &buf);
+ break;
+ }
+ } else {
+ err = WSAGetLastError();
+ if (err == WSAEWOULDBLOCK) {
+ /* Read buffer was completely empty, report a 0-byte read. */
+ handle->read_cb((uv_stream_t*)handle, 0, &buf);
+ } else {
+ /* Ouch! serious error. */
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+
+ if (err == WSAECONNABORTED) {
+ /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with */
+ /* Unix. */
+ err = WSAECONNRESET;
+ }
+
+ handle->read_cb((uv_stream_t*)handle,
+ uv_translate_sys_error(err),
+ &buf);
+ }
+ break;
+ }
+ }
+
+done:
+ /* Post another read if still reading and not closing. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_tcp_queue_read(loop, handle);
+ }
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_write_t* req) {
+ int err;
+
+ assert(handle->type == UV_TCP);
+
+ assert(handle->write_queue_size >= req->u.io.queued_bytes);
+ handle->write_queue_size -= req->u.io.queued_bytes;
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ if (req->wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(req->wait_handle);
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ }
+ if (req->event_handle) {
+ CloseHandle(req->event_handle);
+ req->event_handle = NULL;
+ }
+ }
+
+ if (req->cb) {
+ err = uv_translate_sys_error(GET_REQ_SOCK_ERROR(req));
+ if (err == UV_ECONNABORTED) {
+ /* use UV_ECANCELED for consistency with Unix */
+ err = UV_ECANCELED;
+ }
+ req->cb(req, err);
+ }
+
+ handle->stream.conn.write_reqs_pending--;
+ if (handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_req_t* raw_req) {
+ uv_tcp_accept_t* req = (uv_tcp_accept_t*) raw_req;
+ int err;
+
+ assert(handle->type == UV_TCP);
+
+ /* If handle->accepted_socket is not a valid socket, then */
+ /* uv_queue_accept must have failed. This is a serious error. We stop */
+ /* accepting connections and report this error to the connection */
+ /* callback. */
+ if (req->accept_socket == INVALID_SOCKET) {
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ handle->flags &= ~UV_HANDLE_LISTENING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ if (handle->stream.serv.connection_cb) {
+ err = GET_REQ_SOCK_ERROR(req);
+ handle->stream.serv.connection_cb((uv_stream_t*)handle,
+ uv_translate_sys_error(err));
+ }
+ }
+ } else if (REQ_SUCCESS(req) &&
+ setsockopt(req->accept_socket,
+ SOL_SOCKET,
+ SO_UPDATE_ACCEPT_CONTEXT,
+ (char*)&handle->socket,
+ sizeof(handle->socket)) == 0) {
+ req->next_pending = handle->tcp.serv.pending_accepts;
+ handle->tcp.serv.pending_accepts = req;
+
+ /* Accept and SO_UPDATE_ACCEPT_CONTEXT were successful. */
+ if (handle->stream.serv.connection_cb) {
+ handle->stream.serv.connection_cb((uv_stream_t*)handle, 0);
+ }
+ } else {
+ /* Error related to accepted socket is ignored because the server */
+ /* socket may still be healthy. If the server socket is broken */
+ /* uv_queue_accept will detect it. */
+ closesocket(req->accept_socket);
+ req->accept_socket = INVALID_SOCKET;
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ uv_tcp_queue_accept(handle, req);
+ }
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_connect_t* req) {
+ int err;
+
+ assert(handle->type == UV_TCP);
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ err = 0;
+ if (REQ_SUCCESS(req)) {
+ if (setsockopt(handle->socket,
+ SOL_SOCKET,
+ SO_UPDATE_CONNECT_CONTEXT,
+ NULL,
+ 0) == 0) {
+ uv_connection_init((uv_stream_t*)handle);
+ handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+ loop->active_tcp_streams++;
+ } else {
+ err = WSAGetLastError();
+ }
+ } else {
+ err = GET_REQ_SOCK_ERROR(req);
+ }
+ req->cb(req, uv_translate_sys_error(err));
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
+ int tcp_connection) {
+ int err;
+ SOCKET socket = WSASocketW(FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ &socket_info_ex->socket_info,
+ 0,
+ WSA_FLAG_OVERLAPPED);
+
+ if (socket == INVALID_SOCKET) {
+ return WSAGetLastError();
+ }
+
+ err = uv_tcp_set_socket(tcp->loop,
+ tcp,
+ socket,
+ socket_info_ex->socket_info.iAddressFamily,
+ 1);
+ if (err) {
+ closesocket(socket);
+ return err;
+ }
+
+ if (tcp_connection) {
+ uv_connection_init((uv_stream_t*)tcp);
+ tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+ }
+
+ tcp->flags |= UV_HANDLE_BOUND;
+ tcp->flags |= UV_HANDLE_SHARED_TCP_SOCKET;
+
+ tcp->delayed_error = socket_info_ex->delayed_error;
+
+ tcp->loop->active_tcp_streams++;
+ return 0;
+}
+
+
+int uv_tcp_nodelay(uv_tcp_t* handle, int enable) {
+ int err;
+
+ if (handle->socket != INVALID_SOCKET) {
+ err = uv__tcp_nodelay(handle, handle->socket, enable);
+ if (err)
+ return err;
+ }
+
+ if (enable) {
+ handle->flags |= UV_HANDLE_TCP_NODELAY;
+ } else {
+ handle->flags &= ~UV_HANDLE_TCP_NODELAY;
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) {
+ int err;
+
+ if (handle->socket != INVALID_SOCKET) {
+ err = uv__tcp_keepalive(handle, handle->socket, enable, delay);
+ if (err)
+ return err;
+ }
+
+ if (enable) {
+ handle->flags |= UV_HANDLE_TCP_KEEPALIVE;
+ } else {
+ handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE;
+ }
+
+ /* TODO: Store delay if handle->socket isn't created yet. */
+
+ return 0;
+}
+
+
+int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
+ LPWSAPROTOCOL_INFOW protocol_info) {
+ if (!(handle->flags & UV_HANDLE_CONNECTION)) {
+ /*
+ * We're about to share the socket with another process. Because
+ * this is a listening socket, we assume that the other process will
+ * be accepting connections on it. So, before sharing the socket
+ * with another process, we call listen here in the parent process.
+ */
+
+ if (!(handle->flags & UV_HANDLE_LISTENING)) {
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (!(handle->delayed_error)) {
+ if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) {
+ handle->delayed_error = WSAGetLastError();
+ }
+ }
+ }
+ }
+
+ if (WSADuplicateSocketW(handle->socket, pid, protocol_info)) {
+ return WSAGetLastError();
+ }
+
+ handle->flags |= UV_HANDLE_SHARED_TCP_SOCKET;
+
+ return 0;
+}
+
+
+int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
+ if (handle->flags & UV_HANDLE_CONNECTION) {
+ return UV_EINVAL;
+ }
+
+ /* Check if we're already in the desired mode. */
+ if ((enable && !(handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) ||
+ (!enable && handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) {
+ return 0;
+ }
+
+ /* Don't allow switching from single pending accept to many. */
+ if (enable) {
+ return UV_ENOTSUP;
+ }
+
+ /* Check if we're in a middle of changing the number of pending accepts. */
+ if (handle->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING) {
+ return 0;
+ }
+
+ handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
+
+ /* Flip the changing flag if we have already queued multiple accepts. */
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ handle->flags |= UV_HANDLE_TCP_ACCEPT_STATE_CHANGING;
+ }
+
+ return 0;
+}
+
+
+static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) {
+ SOCKET socket = tcp->socket;
+ int non_ifs_lsp;
+
+ /* Check if we have any non-IFS LSPs stacked on top of TCP */
+ non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 :
+ uv_tcp_non_ifs_lsp_ipv4;
+
+ /* If there are non-ifs LSPs then try to obtain a base handle for the */
+ /* socket. This will always fail on Windows XP/3k. */
+ if (non_ifs_lsp) {
+ DWORD bytes;
+ if (WSAIoctl(socket,
+ SIO_BASE_HANDLE,
+ NULL,
+ 0,
+ &socket,
+ sizeof socket,
+ &bytes,
+ NULL,
+ NULL) != 0) {
+ /* Failed. We can't do CancelIo. */
+ return -1;
+ }
+ }
+
+ assert(socket != 0 && socket != INVALID_SOCKET);
+
+ if (!CancelIo((HANDLE) socket)) {
+ return GetLastError();
+ }
+
+ /* It worked. */
+ return 0;
+}
+
+
+void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
+ int close_socket = 1;
+
+ if (tcp->flags & UV_HANDLE_READ_PENDING) {
+ /* In order for winsock to do a graceful close there must not be any */
+ /* any pending reads, or the socket must be shut down for writing */
+ if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) {
+ /* Just do shutdown on non-shared sockets, which ensures graceful close. */
+ shutdown(tcp->socket, SD_SEND);
+
+ } else if (uv_tcp_try_cancel_io(tcp) == 0) {
+ /* In case of a shared socket, we try to cancel all outstanding I/O, */
+ /* If that works, don't close the socket yet - wait for the read req to */
+ /* return and close the socket in uv_tcp_endgame. */
+ close_socket = 0;
+
+ } else {
+ /* When cancelling isn't possible - which could happen when an LSP is */
+ /* present on an old Windows version, we will have to close the socket */
+ /* with a read pending. That is not nice because trailing sent bytes */
+ /* may not make it to the other side. */
+ }
+
+ } else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) &&
+ tcp->tcp.serv.accept_reqs != NULL) {
+ /* Under normal circumstances closesocket() will ensure that all pending */
+ /* accept reqs are canceled. However, when the socket is shared the */
+ /* presence of another reference to the socket in another process will */
+ /* keep the accept reqs going, so we have to ensure that these are */
+ /* canceled. */
+ if (uv_tcp_try_cancel_io(tcp) != 0) {
+ /* When cancellation is not possible, there is another option: we can */
+ /* close the incoming sockets, which will also cancel the accept */
+ /* operations. However this is not cool because we might inadvertently */
+ /* close a socket that just accepted a new connection, which will */
+ /* cause the connection to be aborted. */
+ unsigned int i;
+ for (i = 0; i < uv_simultaneous_server_accepts; i++) {
+ uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i];
+ if (req->accept_socket != INVALID_SOCKET &&
+ !HasOverlappedIoCompleted(&req->u.io.overlapped)) {
+ closesocket(req->accept_socket);
+ req->accept_socket = INVALID_SOCKET;
+ }
+ }
+ }
+ }
+
+ if (tcp->flags & UV_HANDLE_READING) {
+ tcp->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, tcp);
+ }
+
+ if (tcp->flags & UV_HANDLE_LISTENING) {
+ tcp->flags &= ~UV_HANDLE_LISTENING;
+ DECREASE_ACTIVE_COUNT(loop, tcp);
+ }
+
+ if (close_socket) {
+ closesocket(tcp->socket);
+ tcp->socket = INVALID_SOCKET;
+ tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
+ }
+
+ tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
+ uv__handle_closing(tcp);
+
+ if (tcp->reqs_pending == 0) {
+ uv_want_endgame(tcp->loop, (uv_handle_t*)tcp);
+ }
+}
+
+
+int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
+ WSAPROTOCOL_INFOW protocol_info;
+ int opt_len;
+ int err;
+
+ /* Detect the address family of the socket. */
+ opt_len = (int) sizeof protocol_info;
+ if (getsockopt(sock,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &protocol_info,
+ &opt_len) == SOCKET_ERROR) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ err = uv_tcp_set_socket(handle->loop,
+ handle,
+ sock,
+ protocol_info.iAddressFamily,
+ 1);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ return 0;
+}
+
+
+/* This function is an egress point, i.e. it returns libuv errors rather than
+ * system errors.
+ */
+int uv__tcp_bind(uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ int err;
+
+ err = uv_tcp_try_bind(handle, addr, addrlen, flags);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ return 0;
+}
+
+
+/* This function is an egress point, i.e. it returns libuv errors rather than
+ * system errors.
+ */
+int uv__tcp_connect(uv_connect_t* req,
+ uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_connect_cb cb) {
+ int err;
+
+ err = uv_tcp_try_connect(req, handle, addr, addrlen, cb);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/src/win/thread.c b/3rdparty/libuv/src/win/thread.c
new file mode 100644
index 00000000000..91684e93875
--- /dev/null
+++ b/3rdparty/libuv/src/win/thread.c
@@ -0,0 +1,697 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+#define HAVE_CONDVAR_API() (pInitializeConditionVariable != NULL)
+
+static int uv_cond_fallback_init(uv_cond_t* cond);
+static void uv_cond_fallback_destroy(uv_cond_t* cond);
+static void uv_cond_fallback_signal(uv_cond_t* cond);
+static void uv_cond_fallback_broadcast(uv_cond_t* cond);
+static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex);
+static int uv_cond_fallback_timedwait(uv_cond_t* cond,
+ uv_mutex_t* mutex, uint64_t timeout);
+
+static int uv_cond_condvar_init(uv_cond_t* cond);
+static void uv_cond_condvar_destroy(uv_cond_t* cond);
+static void uv_cond_condvar_signal(uv_cond_t* cond);
+static void uv_cond_condvar_broadcast(uv_cond_t* cond);
+static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex);
+static int uv_cond_condvar_timedwait(uv_cond_t* cond,
+ uv_mutex_t* mutex, uint64_t timeout);
+
+
+static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) {
+ DWORD result;
+ HANDLE existing_event, created_event;
+
+ created_event = CreateEvent(NULL, 1, 0, NULL);
+ if (created_event == 0) {
+ /* Could fail in a low-memory situation? */
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+
+ existing_event = InterlockedCompareExchangePointer(&guard->event,
+ created_event,
+ NULL);
+
+ if (existing_event == NULL) {
+ /* We won the race */
+ callback();
+
+ result = SetEvent(created_event);
+ assert(result);
+ guard->ran = 1;
+
+ } else {
+ /* We lost the race. Destroy the event we created and wait for the */
+ /* existing one to become signaled. */
+ CloseHandle(created_event);
+ result = WaitForSingleObject(existing_event, INFINITE);
+ assert(result == WAIT_OBJECT_0);
+ }
+}
+
+
+void uv_once(uv_once_t* guard, void (*callback)(void)) {
+ /* Fast case - avoid WaitForSingleObject. */
+ if (guard->ran) {
+ return;
+ }
+
+ uv__once_inner(guard, callback);
+}
+
+
+/* Verify that uv_thread_t can be stored in a TLS slot. */
+STATIC_ASSERT(sizeof(uv_thread_t) <= sizeof(void*));
+
+static uv_key_t uv__current_thread_key;
+static uv_once_t uv__current_thread_init_guard = UV_ONCE_INIT;
+
+
+static void uv__init_current_thread_key(void) {
+ if (uv_key_create(&uv__current_thread_key))
+ abort();
+}
+
+
+struct thread_ctx {
+ void (*entry)(void* arg);
+ void* arg;
+ uv_thread_t self;
+};
+
+
+static UINT __stdcall uv__thread_start(void* arg) {
+ struct thread_ctx *ctx_p;
+ struct thread_ctx ctx;
+
+ ctx_p = arg;
+ ctx = *ctx_p;
+ uv__free(ctx_p);
+
+ uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
+ uv_key_set(&uv__current_thread_key, (void*) ctx.self);
+
+ ctx.entry(ctx.arg);
+
+ return 0;
+}
+
+
+int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
+ struct thread_ctx* ctx;
+ int err;
+ HANDLE thread;
+
+ ctx = uv__malloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return UV_ENOMEM;
+
+ ctx->entry = entry;
+ ctx->arg = arg;
+
+ /* Create the thread in suspended state so we have a chance to pass
+ * its own creation handle to it */
+ thread = (HANDLE) _beginthreadex(NULL,
+ 0,
+ uv__thread_start,
+ ctx,
+ CREATE_SUSPENDED,
+ NULL);
+ if (thread == NULL) {
+ err = errno;
+ uv__free(ctx);
+ } else {
+ err = 0;
+ *tid = thread;
+ ctx->self = thread;
+ ResumeThread(thread);
+ }
+
+ switch (err) {
+ case 0:
+ return 0;
+ case EACCES:
+ return UV_EACCES;
+ case EAGAIN:
+ return UV_EAGAIN;
+ case EINVAL:
+ return UV_EINVAL;
+ }
+
+ return UV_EIO;
+}
+
+
+uv_thread_t uv_thread_self(void) {
+ uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
+ return (uv_thread_t) uv_key_get(&uv__current_thread_key);
+}
+
+
+int uv_thread_join(uv_thread_t *tid) {
+ if (WaitForSingleObject(*tid, INFINITE))
+ return uv_translate_sys_error(GetLastError());
+ else {
+ CloseHandle(*tid);
+ *tid = 0;
+ return 0;
+ }
+}
+
+
+int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) {
+ return *t1 == *t2;
+}
+
+
+int uv_mutex_init(uv_mutex_t* mutex) {
+ InitializeCriticalSection(mutex);
+ return 0;
+}
+
+
+void uv_mutex_destroy(uv_mutex_t* mutex) {
+ DeleteCriticalSection(mutex);
+}
+
+
+void uv_mutex_lock(uv_mutex_t* mutex) {
+ EnterCriticalSection(mutex);
+}
+
+
+int uv_mutex_trylock(uv_mutex_t* mutex) {
+ if (TryEnterCriticalSection(mutex))
+ return 0;
+ else
+ return UV_EBUSY;
+}
+
+
+void uv_mutex_unlock(uv_mutex_t* mutex) {
+ LeaveCriticalSection(mutex);
+}
+
+
+int uv_rwlock_init(uv_rwlock_t* rwlock) {
+ /* Initialize the semaphore that acts as the write lock. */
+ HANDLE handle = CreateSemaphoreW(NULL, 1, 1, NULL);
+ if (handle == NULL)
+ return uv_translate_sys_error(GetLastError());
+ rwlock->state_.write_semaphore_ = handle;
+
+ /* Initialize the critical section protecting the reader count. */
+ InitializeCriticalSection(&rwlock->state_.num_readers_lock_);
+
+ /* Initialize the reader count. */
+ rwlock->state_.num_readers_ = 0;
+
+ return 0;
+}
+
+
+void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
+ DeleteCriticalSection(&rwlock->state_.num_readers_lock_);
+ CloseHandle(rwlock->state_.write_semaphore_);
+}
+
+
+void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
+ /* Acquire the lock that protects the reader count. */
+ EnterCriticalSection(&rwlock->state_.num_readers_lock_);
+
+ /* Increase the reader count, and lock for write if this is the first
+ * reader.
+ */
+ if (++rwlock->state_.num_readers_ == 1) {
+ DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
+ if (r != WAIT_OBJECT_0)
+ uv_fatal_error(GetLastError(), "WaitForSingleObject");
+ }
+
+ /* Release the lock that protects the reader count. */
+ LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
+}
+
+
+int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
+ int err;
+
+ if (!TryEnterCriticalSection(&rwlock->state_.num_readers_lock_))
+ return UV_EBUSY;
+
+ err = 0;
+
+ if (rwlock->state_.num_readers_ == 0) {
+ /* Currently there are no other readers, which means that the write lock
+ * needs to be acquired.
+ */
+ DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
+ if (r == WAIT_OBJECT_0)
+ rwlock->state_.num_readers_++;
+ else if (r == WAIT_TIMEOUT)
+ err = UV_EBUSY;
+ else if (r == WAIT_FAILED)
+ uv_fatal_error(GetLastError(), "WaitForSingleObject");
+
+ } else {
+ /* The write lock has already been acquired because there are other
+ * active readers.
+ */
+ rwlock->state_.num_readers_++;
+ }
+
+ LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
+ return err;
+}
+
+
+void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
+ EnterCriticalSection(&rwlock->state_.num_readers_lock_);
+
+ if (--rwlock->state_.num_readers_ == 0) {
+ if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
+ uv_fatal_error(GetLastError(), "ReleaseSemaphore");
+ }
+
+ LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
+}
+
+
+void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
+ DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
+ if (r != WAIT_OBJECT_0)
+ uv_fatal_error(GetLastError(), "WaitForSingleObject");
+}
+
+
+int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
+ DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
+ if (r == WAIT_OBJECT_0)
+ return 0;
+ else if (r == WAIT_TIMEOUT)
+ return UV_EBUSY;
+ else
+ uv_fatal_error(GetLastError(), "WaitForSingleObject");
+}
+
+
+void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
+ if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
+ uv_fatal_error(GetLastError(), "ReleaseSemaphore");
+}
+
+
+int uv_sem_init(uv_sem_t* sem, unsigned int value) {
+ *sem = CreateSemaphore(NULL, value, INT_MAX, NULL);
+ if (*sem == NULL)
+ return uv_translate_sys_error(GetLastError());
+ else
+ return 0;
+}
+
+
+void uv_sem_destroy(uv_sem_t* sem) {
+ if (!CloseHandle(*sem))
+ abort();
+}
+
+
+void uv_sem_post(uv_sem_t* sem) {
+ if (!ReleaseSemaphore(*sem, 1, NULL))
+ abort();
+}
+
+
+void uv_sem_wait(uv_sem_t* sem) {
+ if (WaitForSingleObject(*sem, INFINITE) != WAIT_OBJECT_0)
+ abort();
+}
+
+
+int uv_sem_trywait(uv_sem_t* sem) {
+ DWORD r = WaitForSingleObject(*sem, 0);
+
+ if (r == WAIT_OBJECT_0)
+ return 0;
+
+ if (r == WAIT_TIMEOUT)
+ return UV_EAGAIN;
+
+ abort();
+ return -1; /* Satisfy the compiler. */
+}
+
+
+/* This condition variable implementation is based on the SetEvent solution
+ * (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
+ * We could not use the SignalObjectAndWait solution (section 3.4) because
+ * it want the 2nd argument (type uv_mutex_t) of uv_cond_wait() and
+ * uv_cond_timedwait() to be HANDLEs, but we use CRITICAL_SECTIONs.
+ */
+
+static int uv_cond_fallback_init(uv_cond_t* cond) {
+ int err;
+
+ /* Initialize the count to 0. */
+ cond->fallback.waiters_count = 0;
+
+ InitializeCriticalSection(&cond->fallback.waiters_count_lock);
+
+ /* Create an auto-reset event. */
+ cond->fallback.signal_event = CreateEvent(NULL, /* no security */
+ FALSE, /* auto-reset event */
+ FALSE, /* non-signaled initially */
+ NULL); /* unnamed */
+ if (!cond->fallback.signal_event) {
+ err = GetLastError();
+ goto error2;
+ }
+
+ /* Create a manual-reset event. */
+ cond->fallback.broadcast_event = CreateEvent(NULL, /* no security */
+ TRUE, /* manual-reset */
+ FALSE, /* non-signaled */
+ NULL); /* unnamed */
+ if (!cond->fallback.broadcast_event) {
+ err = GetLastError();
+ goto error;
+ }
+
+ return 0;
+
+error:
+ CloseHandle(cond->fallback.signal_event);
+error2:
+ DeleteCriticalSection(&cond->fallback.waiters_count_lock);
+ return uv_translate_sys_error(err);
+}
+
+
+static int uv_cond_condvar_init(uv_cond_t* cond) {
+ pInitializeConditionVariable(&cond->cond_var);
+ return 0;
+}
+
+
+int uv_cond_init(uv_cond_t* cond) {
+ uv__once_init();
+
+ if (HAVE_CONDVAR_API())
+ return uv_cond_condvar_init(cond);
+ else
+ return uv_cond_fallback_init(cond);
+}
+
+
+static void uv_cond_fallback_destroy(uv_cond_t* cond) {
+ if (!CloseHandle(cond->fallback.broadcast_event))
+ abort();
+ if (!CloseHandle(cond->fallback.signal_event))
+ abort();
+ DeleteCriticalSection(&cond->fallback.waiters_count_lock);
+}
+
+
+static void uv_cond_condvar_destroy(uv_cond_t* cond) {
+ /* nothing to do */
+}
+
+
+void uv_cond_destroy(uv_cond_t* cond) {
+ if (HAVE_CONDVAR_API())
+ uv_cond_condvar_destroy(cond);
+ else
+ uv_cond_fallback_destroy(cond);
+}
+
+
+static void uv_cond_fallback_signal(uv_cond_t* cond) {
+ int have_waiters;
+
+ /* Avoid race conditions. */
+ EnterCriticalSection(&cond->fallback.waiters_count_lock);
+ have_waiters = cond->fallback.waiters_count > 0;
+ LeaveCriticalSection(&cond->fallback.waiters_count_lock);
+
+ if (have_waiters)
+ SetEvent(cond->fallback.signal_event);
+}
+
+
+static void uv_cond_condvar_signal(uv_cond_t* cond) {
+ pWakeConditionVariable(&cond->cond_var);
+}
+
+
+void uv_cond_signal(uv_cond_t* cond) {
+ if (HAVE_CONDVAR_API())
+ uv_cond_condvar_signal(cond);
+ else
+ uv_cond_fallback_signal(cond);
+}
+
+
+static void uv_cond_fallback_broadcast(uv_cond_t* cond) {
+ int have_waiters;
+
+ /* Avoid race conditions. */
+ EnterCriticalSection(&cond->fallback.waiters_count_lock);
+ have_waiters = cond->fallback.waiters_count > 0;
+ LeaveCriticalSection(&cond->fallback.waiters_count_lock);
+
+ if (have_waiters)
+ SetEvent(cond->fallback.broadcast_event);
+}
+
+
+static void uv_cond_condvar_broadcast(uv_cond_t* cond) {
+ pWakeAllConditionVariable(&cond->cond_var);
+}
+
+
+void uv_cond_broadcast(uv_cond_t* cond) {
+ if (HAVE_CONDVAR_API())
+ uv_cond_condvar_broadcast(cond);
+ else
+ uv_cond_fallback_broadcast(cond);
+}
+
+
+static int uv_cond_wait_helper(uv_cond_t* cond, uv_mutex_t* mutex,
+ DWORD dwMilliseconds) {
+ DWORD result;
+ int last_waiter;
+ HANDLE handles[2] = {
+ cond->fallback.signal_event,
+ cond->fallback.broadcast_event
+ };
+
+ /* Avoid race conditions. */
+ EnterCriticalSection(&cond->fallback.waiters_count_lock);
+ cond->fallback.waiters_count++;
+ LeaveCriticalSection(&cond->fallback.waiters_count_lock);
+
+ /* It's ok to release the <mutex> here since Win32 manual-reset events */
+ /* maintain state when used with <SetEvent>. This avoids the "lost wakeup" */
+ /* bug. */
+ uv_mutex_unlock(mutex);
+
+ /* Wait for either event to become signaled due to <uv_cond_signal> being */
+ /* called or <uv_cond_broadcast> being called. */
+ result = WaitForMultipleObjects(2, handles, FALSE, dwMilliseconds);
+
+ EnterCriticalSection(&cond->fallback.waiters_count_lock);
+ cond->fallback.waiters_count--;
+ last_waiter = result == WAIT_OBJECT_0 + 1
+ && cond->fallback.waiters_count == 0;
+ LeaveCriticalSection(&cond->fallback.waiters_count_lock);
+
+ /* Some thread called <pthread_cond_broadcast>. */
+ if (last_waiter) {
+ /* We're the last waiter to be notified or to stop waiting, so reset the */
+ /* the manual-reset event. */
+ ResetEvent(cond->fallback.broadcast_event);
+ }
+
+ /* Reacquire the <mutex>. */
+ uv_mutex_lock(mutex);
+
+ if (result == WAIT_OBJECT_0 || result == WAIT_OBJECT_0 + 1)
+ return 0;
+
+ if (result == WAIT_TIMEOUT)
+ return UV_ETIMEDOUT;
+
+ abort();
+ return -1; /* Satisfy the compiler. */
+}
+
+
+static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
+ if (uv_cond_wait_helper(cond, mutex, INFINITE))
+ abort();
+}
+
+
+static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
+ if (!pSleepConditionVariableCS(&cond->cond_var, mutex, INFINITE))
+ abort();
+}
+
+
+void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
+ if (HAVE_CONDVAR_API())
+ uv_cond_condvar_wait(cond, mutex);
+ else
+ uv_cond_fallback_wait(cond, mutex);
+}
+
+
+static int uv_cond_fallback_timedwait(uv_cond_t* cond,
+ uv_mutex_t* mutex, uint64_t timeout) {
+ return uv_cond_wait_helper(cond, mutex, (DWORD)(timeout / 1e6));
+}
+
+
+static int uv_cond_condvar_timedwait(uv_cond_t* cond,
+ uv_mutex_t* mutex, uint64_t timeout) {
+ if (pSleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6)))
+ return 0;
+ if (GetLastError() != ERROR_TIMEOUT)
+ abort();
+ return UV_ETIMEDOUT;
+}
+
+
+int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex,
+ uint64_t timeout) {
+ if (HAVE_CONDVAR_API())
+ return uv_cond_condvar_timedwait(cond, mutex, timeout);
+ else
+ return uv_cond_fallback_timedwait(cond, mutex, timeout);
+}
+
+
+int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
+ int err;
+
+ barrier->n = count;
+ barrier->count = 0;
+
+ err = uv_mutex_init(&barrier->mutex);
+ if (err)
+ return err;
+
+ err = uv_sem_init(&barrier->turnstile1, 0);
+ if (err)
+ goto error2;
+
+ err = uv_sem_init(&barrier->turnstile2, 1);
+ if (err)
+ goto error;
+
+ return 0;
+
+error:
+ uv_sem_destroy(&barrier->turnstile1);
+error2:
+ uv_mutex_destroy(&barrier->mutex);
+ return err;
+
+}
+
+
+void uv_barrier_destroy(uv_barrier_t* barrier) {
+ uv_sem_destroy(&barrier->turnstile2);
+ uv_sem_destroy(&barrier->turnstile1);
+ uv_mutex_destroy(&barrier->mutex);
+}
+
+
+int uv_barrier_wait(uv_barrier_t* barrier) {
+ int serial_thread;
+
+ uv_mutex_lock(&barrier->mutex);
+ if (++barrier->count == barrier->n) {
+ uv_sem_wait(&barrier->turnstile2);
+ uv_sem_post(&barrier->turnstile1);
+ }
+ uv_mutex_unlock(&barrier->mutex);
+
+ uv_sem_wait(&barrier->turnstile1);
+ uv_sem_post(&barrier->turnstile1);
+
+ uv_mutex_lock(&barrier->mutex);
+ serial_thread = (--barrier->count == 0);
+ if (serial_thread) {
+ uv_sem_wait(&barrier->turnstile1);
+ uv_sem_post(&barrier->turnstile2);
+ }
+ uv_mutex_unlock(&barrier->mutex);
+
+ uv_sem_wait(&barrier->turnstile2);
+ uv_sem_post(&barrier->turnstile2);
+ return serial_thread;
+}
+
+
+int uv_key_create(uv_key_t* key) {
+ key->tls_index = TlsAlloc();
+ if (key->tls_index == TLS_OUT_OF_INDEXES)
+ return UV_ENOMEM;
+ return 0;
+}
+
+
+void uv_key_delete(uv_key_t* key) {
+ if (TlsFree(key->tls_index) == FALSE)
+ abort();
+ key->tls_index = TLS_OUT_OF_INDEXES;
+}
+
+
+void* uv_key_get(uv_key_t* key) {
+ void* value;
+
+ value = TlsGetValue(key->tls_index);
+ if (value == NULL)
+ if (GetLastError() != ERROR_SUCCESS)
+ abort();
+
+ return value;
+}
+
+
+void uv_key_set(uv_key_t* key, void* value) {
+ if (TlsSetValue(key->tls_index, value) == FALSE)
+ abort();
+}
diff --git a/3rdparty/libuv/src/win/timer.c b/3rdparty/libuv/src/win/timer.c
new file mode 100644
index 00000000000..0da541a2c86
--- /dev/null
+++ b/3rdparty/libuv/src/win/timer.c
@@ -0,0 +1,200 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <limits.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "tree.h"
+#include "handle-inl.h"
+
+
+/* The number of milliseconds in one second. */
+#define UV__MILLISEC 1000
+
+
+void uv_update_time(uv_loop_t* loop) {
+ uint64_t new_time = uv__hrtime(UV__MILLISEC);
+ if (new_time > loop->time) {
+ loop->time = new_time;
+ }
+}
+
+void uv__time_forward(uv_loop_t* loop, uint64_t msecs) {
+ loop->time += msecs;
+}
+
+
+static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) {
+ if (a->due < b->due)
+ return -1;
+ if (a->due > b->due)
+ return 1;
+ /*
+ * compare start_id when both has the same due. start_id is
+ * allocated with loop->timer_counter in uv_timer_start().
+ */
+ if (a->start_id < b->start_id)
+ return -1;
+ if (a->start_id > b->start_id)
+ return 1;
+ return 0;
+}
+
+
+RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare);
+
+
+int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_TIMER);
+ handle->timer_cb = NULL;
+ handle->repeat = 0;
+
+ return 0;
+}
+
+
+void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle) {
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ uv__handle_close(handle);
+ }
+}
+
+
+static uint64_t get_clamped_due_time(uint64_t loop_time, uint64_t timeout) {
+ uint64_t clamped_timeout;
+
+ clamped_timeout = loop_time + timeout;
+ if (clamped_timeout < timeout)
+ clamped_timeout = (uint64_t) -1;
+
+ return clamped_timeout;
+}
+
+
+int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, uint64_t timeout,
+ uint64_t repeat) {
+ uv_loop_t* loop = handle->loop;
+ uv_timer_t* old;
+
+ if (timer_cb == NULL)
+ return UV_EINVAL;
+
+ if (uv__is_active(handle))
+ uv_timer_stop(handle);
+
+ handle->timer_cb = timer_cb;
+ handle->due = get_clamped_due_time(loop->time, timeout);
+ handle->repeat = repeat;
+ uv__handle_start(handle);
+
+ /* start_id is the second index to be compared in uv__timer_cmp() */
+ handle->start_id = handle->loop->timer_counter++;
+
+ old = RB_INSERT(uv_timer_tree_s, &loop->timers, handle);
+ assert(old == NULL);
+
+ return 0;
+}
+
+
+int uv_timer_stop(uv_timer_t* handle) {
+ uv_loop_t* loop = handle->loop;
+
+ if (!uv__is_active(handle))
+ return 0;
+
+ RB_REMOVE(uv_timer_tree_s, &loop->timers, handle);
+ uv__handle_stop(handle);
+
+ return 0;
+}
+
+
+int uv_timer_again(uv_timer_t* handle) {
+ /* If timer_cb is NULL that means that the timer was never started. */
+ if (!handle->timer_cb) {
+ return UV_EINVAL;
+ }
+
+ if (handle->repeat) {
+ uv_timer_stop(handle);
+ uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat);
+ }
+
+ return 0;
+}
+
+
+void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) {
+ assert(handle->type == UV_TIMER);
+ handle->repeat = repeat;
+}
+
+
+uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
+ assert(handle->type == UV_TIMER);
+ return handle->repeat;
+}
+
+
+DWORD uv__next_timeout(const uv_loop_t* loop) {
+ uv_timer_t* timer;
+ int64_t delta;
+
+ /* Check if there are any running timers
+ * Need to cast away const first, since RB_MIN doesn't know what we are
+ * going to do with this return value, it can't be marked const
+ */
+ timer = RB_MIN(uv_timer_tree_s, &((uv_loop_t*)loop)->timers);
+ if (timer) {
+ delta = timer->due - loop->time;
+ if (delta >= UINT_MAX - 1) {
+ /* A timeout value of UINT_MAX means infinite, so that's no good. */
+ return UINT_MAX - 1;
+ } else if (delta < 0) {
+ /* Negative timeout values are not allowed */
+ return 0;
+ } else {
+ return (DWORD)delta;
+ }
+ } else {
+ /* No timers */
+ return INFINITE;
+ }
+}
+
+
+void uv_process_timers(uv_loop_t* loop) {
+ uv_timer_t* timer;
+
+ /* Call timer callbacks */
+ for (timer = RB_MIN(uv_timer_tree_s, &loop->timers);
+ timer != NULL && timer->due <= loop->time;
+ timer = RB_MIN(uv_timer_tree_s, &loop->timers)) {
+
+ uv_timer_stop(timer);
+ uv_timer_again(timer);
+ timer->timer_cb((uv_timer_t*) timer);
+ }
+}
diff --git a/3rdparty/libuv/src/win/tty.c b/3rdparty/libuv/src/win/tty.c
new file mode 100644
index 00000000000..d87cc699097
--- /dev/null
+++ b/3rdparty/libuv/src/win/tty.c
@@ -0,0 +1,2084 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <io.h>
+#include <string.h>
+#include <stdlib.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+# include "stdint-msvc2008.h"
+#else
+# include <stdint.h>
+#endif
+
+#ifndef COMMON_LVB_REVERSE_VIDEO
+# define COMMON_LVB_REVERSE_VIDEO 0x4000
+#endif
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "stream-inl.h"
+#include "req-inl.h"
+
+
+#define UNICODE_REPLACEMENT_CHARACTER (0xfffd)
+
+#define ANSI_NORMAL 0x00
+#define ANSI_ESCAPE_SEEN 0x02
+#define ANSI_CSI 0x04
+#define ANSI_ST_CONTROL 0x08
+#define ANSI_IGNORE 0x10
+#define ANSI_IN_ARG 0x20
+#define ANSI_IN_STRING 0x40
+#define ANSI_BACKSLASH_SEEN 0x80
+
+#define MAX_INPUT_BUFFER_LENGTH 8192
+
+
+static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info);
+static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
+
+
+/* Null uv_buf_t */
+static const uv_buf_t uv_null_buf_ = { 0, NULL };
+
+
+/*
+ * The console virtual window.
+ *
+ * Normally cursor movement in windows is relative to the console screen buffer,
+ * e.g. the application is allowed to overwrite the 'history'. This is very
+ * inconvenient, it makes absolute cursor movement pretty useless. There is
+ * also the concept of 'client rect' which is defined by the actual size of
+ * the console window and the scroll position of the screen buffer, but it's
+ * very volatile because it changes when the user scrolls.
+ *
+ * To make cursor movement behave sensibly we define a virtual window to which
+ * cursor movement is confined. The virtual window is always as wide as the
+ * console screen buffer, but it's height is defined by the size of the
+ * console window. The top of the virtual window aligns with the position
+ * of the caret when the first stdout/err handle is created, unless that would
+ * mean that it would extend beyond the bottom of the screen buffer - in that
+ * that case it's located as far down as possible.
+ *
+ * When the user writes a long text or many newlines, such that the output
+ * reaches beyond the bottom of the virtual window, the virtual window is
+ * shifted downwards, but not resized.
+ *
+ * Since all tty i/o happens on the same console, this window is shared
+ * between all stdout/stderr handles.
+ */
+
+static int uv_tty_virtual_offset = -1;
+static int uv_tty_virtual_height = -1;
+static int uv_tty_virtual_width = -1;
+
+static CRITICAL_SECTION uv_tty_output_lock;
+
+static HANDLE uv_tty_output_handle = INVALID_HANDLE_VALUE;
+
+static WORD uv_tty_default_text_attributes =
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
+
+static char uv_tty_default_fg_color = 7;
+static char uv_tty_default_bg_color = 0;
+static char uv_tty_default_fg_bright = 0;
+static char uv_tty_default_bg_bright = 0;
+static char uv_tty_default_inverse = 0;
+
+
+void uv_console_init() {
+ InitializeCriticalSection(&uv_tty_output_lock);
+}
+
+
+int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
+ HANDLE handle;
+ CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
+
+ handle = (HANDLE) uv__get_osfhandle(fd);
+ if (handle == INVALID_HANDLE_VALUE)
+ return UV_EBADF;
+
+ if (fd <= 2) {
+ /* In order to avoid closing a stdio file descriptor 0-2, duplicate the
+ * underlying OS handle and forget about the original fd.
+ * We could also opt to use the original OS handle and just never close it,
+ * but then there would be no reliable way to cancel pending read operations
+ * upon close.
+ */
+ if (!DuplicateHandle(INVALID_HANDLE_VALUE,
+ handle,
+ INVALID_HANDLE_VALUE,
+ &handle,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS))
+ return uv_translate_sys_error(GetLastError());
+ fd = -1;
+ }
+
+ if (!readable) {
+ /* Obtain the screen buffer info with the output handle. */
+ if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ /* Obtain the the tty_output_lock because the virtual window state is */
+ /* shared between all uv_tty_t handles. */
+ EnterCriticalSection(&uv_tty_output_lock);
+
+ /* Store the global tty output handle. This handle is used by TTY read */
+ /* streams to update the virtual window when a CONSOLE_BUFFER_SIZE_EVENT */
+ /* is received. */
+ uv_tty_output_handle = handle;
+
+ /* Remember the original console text attributes. */
+ uv_tty_capture_initial_style(&screen_buffer_info);
+
+ uv_tty_update_virtual_window(&screen_buffer_info);
+
+ LeaveCriticalSection(&uv_tty_output_lock);
+ }
+
+
+ uv_stream_init(loop, (uv_stream_t*) tty, UV_TTY);
+ uv_connection_init((uv_stream_t*) tty);
+
+ tty->handle = handle;
+ tty->u.fd = fd;
+ tty->reqs_pending = 0;
+ tty->flags |= UV_HANDLE_BOUND;
+
+ if (readable) {
+ /* Initialize TTY input specific fields. */
+ tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE;
+ tty->tty.rd.read_line_handle = NULL;
+ tty->tty.rd.read_line_buffer = uv_null_buf_;
+ tty->tty.rd.read_raw_wait = NULL;
+
+ /* Init keycode-to-vt100 mapper state. */
+ tty->tty.rd.last_key_len = 0;
+ tty->tty.rd.last_key_offset = 0;
+ tty->tty.rd.last_utf16_high_surrogate = 0;
+ memset(&tty->tty.rd.last_input_record, 0, sizeof tty->tty.rd.last_input_record);
+ } else {
+ /* TTY output specific fields. */
+ tty->flags |= UV_HANDLE_WRITABLE;
+
+ /* Init utf8-to-utf16 conversion state. */
+ tty->tty.wr.utf8_bytes_left = 0;
+ tty->tty.wr.utf8_codepoint = 0;
+
+ /* Initialize eol conversion state */
+ tty->tty.wr.previous_eol = 0;
+
+ /* Init ANSI parser state. */
+ tty->tty.wr.ansi_parser_state = ANSI_NORMAL;
+ }
+
+ return 0;
+}
+
+
+/* Set the default console text attributes based on how the console was
+ * configured when libuv started.
+ */
+static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) {
+ static int style_captured = 0;
+
+ /* Only do this once.
+ Assumption: Caller has acquired uv_tty_output_lock. */
+ if (style_captured)
+ return;
+
+ /* Save raw win32 attributes. */
+ uv_tty_default_text_attributes = info->wAttributes;
+
+ /* Convert black text on black background to use white text. */
+ if (uv_tty_default_text_attributes == 0)
+ uv_tty_default_text_attributes = 7;
+
+ /* Convert Win32 attributes to ANSI colors. */
+ uv_tty_default_fg_color = 0;
+ uv_tty_default_bg_color = 0;
+ uv_tty_default_fg_bright = 0;
+ uv_tty_default_bg_bright = 0;
+ uv_tty_default_inverse = 0;
+
+ if (uv_tty_default_text_attributes & FOREGROUND_RED)
+ uv_tty_default_fg_color |= 1;
+
+ if (uv_tty_default_text_attributes & FOREGROUND_GREEN)
+ uv_tty_default_fg_color |= 2;
+
+ if (uv_tty_default_text_attributes & FOREGROUND_BLUE)
+ uv_tty_default_fg_color |= 4;
+
+ if (uv_tty_default_text_attributes & BACKGROUND_RED)
+ uv_tty_default_bg_color |= 1;
+
+ if (uv_tty_default_text_attributes & BACKGROUND_GREEN)
+ uv_tty_default_bg_color |= 2;
+
+ if (uv_tty_default_text_attributes & BACKGROUND_BLUE)
+ uv_tty_default_bg_color |= 4;
+
+ if (uv_tty_default_text_attributes & FOREGROUND_INTENSITY)
+ uv_tty_default_fg_bright = 1;
+
+ if (uv_tty_default_text_attributes & BACKGROUND_INTENSITY)
+ uv_tty_default_bg_bright = 1;
+
+ if (uv_tty_default_text_attributes & COMMON_LVB_REVERSE_VIDEO)
+ uv_tty_default_inverse = 1;
+
+ style_captured = 1;
+}
+
+
+int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
+ DWORD flags;
+ unsigned char was_reading;
+ uv_alloc_cb alloc_cb;
+ uv_read_cb read_cb;
+ int err;
+
+ if (!(tty->flags & UV_HANDLE_TTY_READABLE)) {
+ return UV_EINVAL;
+ }
+
+ if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) {
+ return 0;
+ }
+
+ switch (mode) {
+ case UV_TTY_MODE_NORMAL:
+ flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
+ break;
+ case UV_TTY_MODE_RAW:
+ flags = ENABLE_WINDOW_INPUT;
+ break;
+ case UV_TTY_MODE_IO:
+ return UV_ENOTSUP;
+ }
+
+ if (!SetConsoleMode(tty->handle, flags)) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ /* If currently reading, stop, and restart reading. */
+ if (tty->flags & UV_HANDLE_READING) {
+ was_reading = 1;
+ alloc_cb = tty->alloc_cb;
+ read_cb = tty->read_cb;
+
+ if (was_reading) {
+ err = uv_tty_read_stop(tty);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+ }
+ } else {
+ was_reading = 0;
+ }
+
+ /* Update flag. */
+ tty->flags &= ~UV_HANDLE_TTY_RAW;
+ tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0;
+
+ /* If we just stopped reading, restart. */
+ if (was_reading) {
+ err = uv_tty_read_start(tty, alloc_cb, read_cb);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_is_tty(uv_file file) {
+ DWORD result;
+ return GetConsoleMode((HANDLE) _get_osfhandle(file), &result) != 0;
+}
+
+
+int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+
+ if (!GetConsoleScreenBufferInfo(tty->handle, &info)) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ EnterCriticalSection(&uv_tty_output_lock);
+ uv_tty_update_virtual_window(&info);
+ LeaveCriticalSection(&uv_tty_output_lock);
+
+ *width = uv_tty_virtual_width;
+ *height = uv_tty_virtual_height;
+
+ return 0;
+}
+
+
+static void CALLBACK uv_tty_post_raw_read(void* data, BOOLEAN didTimeout) {
+ uv_loop_t* loop;
+ uv_tty_t* handle;
+ uv_req_t* req;
+
+ assert(data);
+ assert(!didTimeout);
+
+ req = (uv_req_t*) data;
+ handle = (uv_tty_t*) req->data;
+ loop = handle->loop;
+
+ UnregisterWait(handle->tty.rd.read_raw_wait);
+ handle->tty.rd.read_raw_wait = NULL;
+
+ SET_REQ_SUCCESS(req);
+ POST_COMPLETION_FOR_REQ(loop, req);
+}
+
+
+static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) {
+ uv_read_t* req;
+ BOOL r;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+
+ assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
+
+ handle->tty.rd.read_line_buffer = uv_null_buf_;
+
+ req = &handle->read_req;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ r = RegisterWaitForSingleObject(&handle->tty.rd.read_raw_wait,
+ handle->handle,
+ uv_tty_post_raw_read,
+ (void*) req,
+ INFINITE,
+ WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
+ if (!r) {
+ handle->tty.rd.read_raw_wait = NULL;
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ }
+
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+}
+
+
+static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
+ uv_loop_t* loop;
+ uv_tty_t* handle;
+ uv_req_t* req;
+ DWORD bytes, read_bytes;
+ WCHAR utf16[MAX_INPUT_BUFFER_LENGTH / 3];
+ DWORD chars, read_chars;
+
+ assert(data);
+
+ req = (uv_req_t*) data;
+ handle = (uv_tty_t*) req->data;
+ loop = handle->loop;
+
+ assert(handle->tty.rd.read_line_buffer.base != NULL);
+ assert(handle->tty.rd.read_line_buffer.len > 0);
+
+ /* ReadConsole can't handle big buffers. */
+ if (handle->tty.rd.read_line_buffer.len < MAX_INPUT_BUFFER_LENGTH) {
+ bytes = handle->tty.rd.read_line_buffer.len;
+ } else {
+ bytes = MAX_INPUT_BUFFER_LENGTH;
+ }
+
+ /* At last, unicode! */
+ /* One utf-16 codeunit never takes more than 3 utf-8 codeunits to encode */
+ chars = bytes / 3;
+
+ if (ReadConsoleW(handle->tty.rd.read_line_handle,
+ (void*) utf16,
+ chars,
+ &read_chars,
+ NULL)) {
+ read_bytes = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16,
+ read_chars,
+ handle->tty.rd.read_line_buffer.base,
+ bytes,
+ NULL,
+ NULL);
+ SET_REQ_SUCCESS(req);
+ req->u.io.overlapped.InternalHigh = read_bytes;
+ } else {
+ SET_REQ_ERROR(req, GetLastError());
+ }
+
+ POST_COMPLETION_FOR_REQ(loop, req);
+ return 0;
+}
+
+
+static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
+ uv_read_t* req;
+ BOOL r;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+ assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
+
+ req = &handle->read_req;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer);
+ if (handle->tty.rd.read_line_buffer.len == 0) {
+ handle->read_cb((uv_stream_t*) handle,
+ UV_ENOBUFS,
+ &handle->tty.rd.read_line_buffer);
+ return;
+ }
+ assert(handle->tty.rd.read_line_buffer.base != NULL);
+
+ /* Duplicate the console handle, so if we want to cancel the read, we can */
+ /* just close this handle duplicate. */
+ if (handle->tty.rd.read_line_handle == NULL) {
+ HANDLE this_process = GetCurrentProcess();
+ r = DuplicateHandle(this_process,
+ handle->handle,
+ this_process,
+ &handle->tty.rd.read_line_handle,
+ 0,
+ 0,
+ DUPLICATE_SAME_ACCESS);
+ if (!r) {
+ handle->tty.rd.read_line_handle = NULL;
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ goto out;
+ }
+ }
+
+ r = QueueUserWorkItem(uv_tty_line_read_thread,
+ (void*) req,
+ WT_EXECUTELONGFUNCTION);
+ if (!r) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ }
+
+ out:
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+}
+
+
+static void uv_tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) {
+ if (handle->flags & UV_HANDLE_TTY_RAW) {
+ uv_tty_queue_read_raw(loop, handle);
+ } else {
+ uv_tty_queue_read_line(loop, handle);
+ }
+}
+
+
+static const char* get_vt100_fn_key(DWORD code, char shift, char ctrl,
+ size_t* len) {
+#define VK_CASE(vk, normal_str, shift_str, ctrl_str, shift_ctrl_str) \
+ case (vk): \
+ if (shift && ctrl) { \
+ *len = sizeof shift_ctrl_str; \
+ return "\033" shift_ctrl_str; \
+ } else if (shift) { \
+ *len = sizeof shift_str ; \
+ return "\033" shift_str; \
+ } else if (ctrl) { \
+ *len = sizeof ctrl_str; \
+ return "\033" ctrl_str; \
+ } else { \
+ *len = sizeof normal_str; \
+ return "\033" normal_str; \
+ }
+
+ switch (code) {
+ /* These mappings are the same as Cygwin's. Unmodified and alt-modified */
+ /* keypad keys comply with linux console, modifiers comply with xterm */
+ /* modifier usage. F1..f12 and shift-f1..f10 comply with linux console, */
+ /* f6..f12 with and without modifiers comply with rxvt. */
+ VK_CASE(VK_INSERT, "[2~", "[2;2~", "[2;5~", "[2;6~")
+ VK_CASE(VK_END, "[4~", "[4;2~", "[4;5~", "[4;6~")
+ VK_CASE(VK_DOWN, "[B", "[1;2B", "[1;5B", "[1;6B")
+ VK_CASE(VK_NEXT, "[6~", "[6;2~", "[6;5~", "[6;6~")
+ VK_CASE(VK_LEFT, "[D", "[1;2D", "[1;5D", "[1;6D")
+ VK_CASE(VK_CLEAR, "[G", "[1;2G", "[1;5G", "[1;6G")
+ VK_CASE(VK_RIGHT, "[C", "[1;2C", "[1;5C", "[1;6C")
+ VK_CASE(VK_UP, "[A", "[1;2A", "[1;5A", "[1;6A")
+ VK_CASE(VK_HOME, "[1~", "[1;2~", "[1;5~", "[1;6~")
+ VK_CASE(VK_PRIOR, "[5~", "[5;2~", "[5;5~", "[5;6~")
+ VK_CASE(VK_DELETE, "[3~", "[3;2~", "[3;5~", "[3;6~")
+ VK_CASE(VK_NUMPAD0, "[2~", "[2;2~", "[2;5~", "[2;6~")
+ VK_CASE(VK_NUMPAD1, "[4~", "[4;2~", "[4;5~", "[4;6~")
+ VK_CASE(VK_NUMPAD2, "[B", "[1;2B", "[1;5B", "[1;6B")
+ VK_CASE(VK_NUMPAD3, "[6~", "[6;2~", "[6;5~", "[6;6~")
+ VK_CASE(VK_NUMPAD4, "[D", "[1;2D", "[1;5D", "[1;6D")
+ VK_CASE(VK_NUMPAD5, "[G", "[1;2G", "[1;5G", "[1;6G")
+ VK_CASE(VK_NUMPAD6, "[C", "[1;2C", "[1;5C", "[1;6C")
+ VK_CASE(VK_NUMPAD7, "[A", "[1;2A", "[1;5A", "[1;6A")
+ VK_CASE(VK_NUMPAD8, "[1~", "[1;2~", "[1;5~", "[1;6~")
+ VK_CASE(VK_NUMPAD9, "[5~", "[5;2~", "[5;5~", "[5;6~")
+ VK_CASE(VK_DECIMAL, "[3~", "[3;2~", "[3;5~", "[3;6~")
+ VK_CASE(VK_F1, "[[A", "[23~", "[11^", "[23^" )
+ VK_CASE(VK_F2, "[[B", "[24~", "[12^", "[24^" )
+ VK_CASE(VK_F3, "[[C", "[25~", "[13^", "[25^" )
+ VK_CASE(VK_F4, "[[D", "[26~", "[14^", "[26^" )
+ VK_CASE(VK_F5, "[[E", "[28~", "[15^", "[28^" )
+ VK_CASE(VK_F6, "[17~", "[29~", "[17^", "[29^" )
+ VK_CASE(VK_F7, "[18~", "[31~", "[18^", "[31^" )
+ VK_CASE(VK_F8, "[19~", "[32~", "[19^", "[32^" )
+ VK_CASE(VK_F9, "[20~", "[33~", "[20^", "[33^" )
+ VK_CASE(VK_F10, "[21~", "[34~", "[21^", "[34^" )
+ VK_CASE(VK_F11, "[23~", "[23$", "[23^", "[23@" )
+ VK_CASE(VK_F12, "[24~", "[24$", "[24^", "[24@" )
+
+ default:
+ *len = 0;
+ return NULL;
+ }
+#undef VK_CASE
+}
+
+
+void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* req) {
+ /* Shortcut for handle->tty.rd.last_input_record.Event.KeyEvent. */
+#define KEV handle->tty.rd.last_input_record.Event.KeyEvent
+
+ DWORD records_left, records_read;
+ uv_buf_t buf;
+ off_t buf_used;
+
+ assert(handle->type == UV_TTY);
+ assert(handle->flags & UV_HANDLE_TTY_READABLE);
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+
+ if (!(handle->flags & UV_HANDLE_READING) ||
+ !(handle->flags & UV_HANDLE_TTY_RAW)) {
+ goto out;
+ }
+
+ if (!REQ_SUCCESS(req)) {
+ /* An error occurred while waiting for the event. */
+ if ((handle->flags & UV_HANDLE_READING)) {
+ handle->flags &= ~UV_HANDLE_READING;
+ handle->read_cb((uv_stream_t*)handle,
+ uv_translate_sys_error(GET_REQ_ERROR(req)),
+ &uv_null_buf_);
+ }
+ goto out;
+ }
+
+ /* Fetch the number of events */
+ if (!GetNumberOfConsoleInputEvents(handle->handle, &records_left)) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb((uv_stream_t*)handle,
+ uv_translate_sys_error(GetLastError()),
+ &uv_null_buf_);
+ goto out;
+ }
+
+ /* Windows sends a lot of events that we're not interested in, so buf */
+ /* will be allocated on demand, when there's actually something to emit. */
+ buf = uv_null_buf_;
+ buf_used = 0;
+
+ while ((records_left > 0 || handle->tty.rd.last_key_len > 0) &&
+ (handle->flags & UV_HANDLE_READING)) {
+ if (handle->tty.rd.last_key_len == 0) {
+ /* Read the next input record */
+ if (!ReadConsoleInputW(handle->handle,
+ &handle->tty.rd.last_input_record,
+ 1,
+ &records_read)) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb((uv_stream_t*) handle,
+ uv_translate_sys_error(GetLastError()),
+ &buf);
+ goto out;
+ }
+ records_left--;
+
+ /* If the window was resized, recompute the virtual window size. This */
+ /* will trigger a SIGWINCH signal if the window size changed in an */
+ /* way that matters to libuv. */
+ if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+
+ EnterCriticalSection(&uv_tty_output_lock);
+
+ if (uv_tty_output_handle != INVALID_HANDLE_VALUE &&
+ GetConsoleScreenBufferInfo(uv_tty_output_handle, &info)) {
+ uv_tty_update_virtual_window(&info);
+ }
+
+ LeaveCriticalSection(&uv_tty_output_lock);
+
+ continue;
+ }
+
+ /* Ignore other events that are not key or resize events. */
+ if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) {
+ continue;
+ }
+
+ /* Ignore keyup events, unless the left alt key was held and a valid */
+ /* unicode character was emitted. */
+ if (!KEV.bKeyDown && !(((KEV.dwControlKeyState & LEFT_ALT_PRESSED) ||
+ KEV.wVirtualKeyCode==VK_MENU) && KEV.uChar.UnicodeChar != 0)) {
+ continue;
+ }
+
+ /* Ignore keypresses to numpad number keys if the left alt is held */
+ /* because the user is composing a character, or windows simulating */
+ /* this. */
+ if ((KEV.dwControlKeyState & LEFT_ALT_PRESSED) &&
+ !(KEV.dwControlKeyState & ENHANCED_KEY) &&
+ (KEV.wVirtualKeyCode == VK_INSERT ||
+ KEV.wVirtualKeyCode == VK_END ||
+ KEV.wVirtualKeyCode == VK_DOWN ||
+ KEV.wVirtualKeyCode == VK_NEXT ||
+ KEV.wVirtualKeyCode == VK_LEFT ||
+ KEV.wVirtualKeyCode == VK_CLEAR ||
+ KEV.wVirtualKeyCode == VK_RIGHT ||
+ KEV.wVirtualKeyCode == VK_HOME ||
+ KEV.wVirtualKeyCode == VK_UP ||
+ KEV.wVirtualKeyCode == VK_PRIOR ||
+ KEV.wVirtualKeyCode == VK_NUMPAD0 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD1 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD2 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD3 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD4 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD5 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD6 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD7 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD8 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD9)) {
+ continue;
+ }
+
+ if (KEV.uChar.UnicodeChar != 0) {
+ int prefix_len, char_len;
+
+ /* Character key pressed */
+ if (KEV.uChar.UnicodeChar >= 0xD800 &&
+ KEV.uChar.UnicodeChar < 0xDC00) {
+ /* UTF-16 high surrogate */
+ handle->tty.rd.last_utf16_high_surrogate = KEV.uChar.UnicodeChar;
+ continue;
+ }
+
+ /* Prefix with \u033 if alt was held, but alt was not used as part */
+ /* a compose sequence. */
+ if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
+ && !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED |
+ RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) {
+ handle->tty.rd.last_key[0] = '\033';
+ prefix_len = 1;
+ } else {
+ prefix_len = 0;
+ }
+
+ if (KEV.uChar.UnicodeChar >= 0xDC00 &&
+ KEV.uChar.UnicodeChar < 0xE000) {
+ /* UTF-16 surrogate pair */
+ WCHAR utf16_buffer[2] = { handle->tty.rd.last_utf16_high_surrogate,
+ KEV.uChar.UnicodeChar};
+ char_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16_buffer,
+ 2,
+ &handle->tty.rd.last_key[prefix_len],
+ sizeof handle->tty.rd.last_key,
+ NULL,
+ NULL);
+ } else {
+ /* Single UTF-16 character */
+ char_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ &KEV.uChar.UnicodeChar,
+ 1,
+ &handle->tty.rd.last_key[prefix_len],
+ sizeof handle->tty.rd.last_key,
+ NULL,
+ NULL);
+ }
+
+ /* Whatever happened, the last character wasn't a high surrogate. */
+ handle->tty.rd.last_utf16_high_surrogate = 0;
+
+ /* If the utf16 character(s) couldn't be converted something must */
+ /* be wrong. */
+ if (!char_len) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb((uv_stream_t*) handle,
+ uv_translate_sys_error(GetLastError()),
+ &buf);
+ goto out;
+ }
+
+ handle->tty.rd.last_key_len = (unsigned char) (prefix_len + char_len);
+ handle->tty.rd.last_key_offset = 0;
+ continue;
+
+ } else {
+ /* Function key pressed */
+ const char* vt100;
+ size_t prefix_len, vt100_len;
+
+ vt100 = get_vt100_fn_key(KEV.wVirtualKeyCode,
+ !!(KEV.dwControlKeyState & SHIFT_PRESSED),
+ !!(KEV.dwControlKeyState & (
+ LEFT_CTRL_PRESSED |
+ RIGHT_CTRL_PRESSED)),
+ &vt100_len);
+
+ /* If we were unable to map to a vt100 sequence, just ignore. */
+ if (!vt100) {
+ continue;
+ }
+
+ /* Prefix with \x033 when the alt key was held. */
+ if (KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
+ handle->tty.rd.last_key[0] = '\033';
+ prefix_len = 1;
+ } else {
+ prefix_len = 0;
+ }
+
+ /* Copy the vt100 sequence to the handle buffer. */
+ assert(prefix_len + vt100_len < sizeof handle->tty.rd.last_key);
+ memcpy(&handle->tty.rd.last_key[prefix_len], vt100, vt100_len);
+
+ handle->tty.rd.last_key_len = (unsigned char) (prefix_len + vt100_len);
+ handle->tty.rd.last_key_offset = 0;
+ continue;
+ }
+ } else {
+ /* Copy any bytes left from the last keypress to the user buffer. */
+ if (handle->tty.rd.last_key_offset < handle->tty.rd.last_key_len) {
+ /* Allocate a buffer if needed */
+ if (buf_used == 0) {
+ handle->alloc_cb((uv_handle_t*) handle, 1024, &buf);
+ if (buf.len == 0) {
+ handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
+ goto out;
+ }
+ assert(buf.base != NULL);
+ }
+
+ buf.base[buf_used++] = handle->tty.rd.last_key[handle->tty.rd.last_key_offset++];
+
+ /* If the buffer is full, emit it */
+ if ((size_t) buf_used == buf.len) {
+ handle->read_cb((uv_stream_t*) handle, buf_used, &buf);
+ buf = uv_null_buf_;
+ buf_used = 0;
+ }
+
+ continue;
+ }
+
+ /* Apply dwRepeat from the last input record. */
+ if (--KEV.wRepeatCount > 0) {
+ handle->tty.rd.last_key_offset = 0;
+ continue;
+ }
+
+ handle->tty.rd.last_key_len = 0;
+ continue;
+ }
+ }
+
+ /* Send the buffer back to the user */
+ if (buf_used > 0) {
+ handle->read_cb((uv_stream_t*) handle, buf_used, &buf);
+ }
+
+ out:
+ /* Wait for more input events. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_tty_queue_read(loop, handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+
+#undef KEV
+}
+
+
+
+void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* req) {
+ uv_buf_t buf;
+
+ assert(handle->type == UV_TTY);
+ assert(handle->flags & UV_HANDLE_TTY_READABLE);
+
+ buf = handle->tty.rd.read_line_buffer;
+
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+ handle->tty.rd.read_line_buffer = uv_null_buf_;
+
+ if (!REQ_SUCCESS(req)) {
+ /* Read was not successful */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ handle->tty.rd.read_line_handle != NULL) {
+ /* Real error */
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb((uv_stream_t*) handle,
+ uv_translate_sys_error(GET_REQ_ERROR(req)),
+ &buf);
+ } else {
+ /* The read was cancelled, or whatever we don't care */
+ handle->read_cb((uv_stream_t*) handle, 0, &buf);
+ }
+
+ } else {
+ /* Read successful */
+ /* TODO: read unicode, convert to utf-8 */
+ DWORD bytes = req->u.io.overlapped.InternalHigh;
+ handle->read_cb((uv_stream_t*) handle, bytes, &buf);
+ }
+
+ /* Wait for more input events. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_tty_queue_read(loop, handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* req) {
+ assert(handle->type == UV_TTY);
+ assert(handle->flags & UV_HANDLE_TTY_READABLE);
+
+ /* If the read_line_buffer member is zero, it must have been an raw read. */
+ /* Otherwise it was a line-buffered read. */
+ /* FIXME: This is quite obscure. Use a flag or something. */
+ if (handle->tty.rd.read_line_buffer.len == 0) {
+ uv_process_tty_read_raw_req(loop, handle, req);
+ } else {
+ uv_process_tty_read_line_req(loop, handle, req);
+ }
+}
+
+
+int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ uv_loop_t* loop = handle->loop;
+
+ if (!(handle->flags & UV_HANDLE_TTY_READABLE)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ handle->flags |= UV_HANDLE_READING;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb = read_cb;
+ handle->alloc_cb = alloc_cb;
+
+ /* If reading was stopped and then started again, there could still be a */
+ /* read request pending. */
+ if (handle->flags & UV_HANDLE_READ_PENDING) {
+ return 0;
+ }
+
+ /* Maybe the user stopped reading half-way while processing key events. */
+ /* Short-circuit if this could be the case. */
+ if (handle->tty.rd.last_key_len > 0) {
+ SET_REQ_SUCCESS(&handle->read_req);
+ uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
+ return 0;
+ }
+
+ uv_tty_queue_read(loop, handle);
+
+ return 0;
+}
+
+
+int uv_tty_read_stop(uv_tty_t* handle) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(handle->loop, handle);
+
+ /* Cancel raw read */
+ if ((handle->flags & UV_HANDLE_READ_PENDING) &&
+ (handle->flags & UV_HANDLE_TTY_RAW)) {
+ /* Write some bullshit event to force the console wait to return. */
+ INPUT_RECORD record;
+ DWORD written;
+ memset(&record, 0, sizeof record);
+ if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) {
+ return GetLastError();
+ }
+ }
+
+ /* Cancel line-buffered read */
+ if (handle->tty.rd.read_line_handle != NULL) {
+ /* Closing this handle will cancel the ReadConsole operation */
+ CloseHandle(handle->tty.rd.read_line_handle);
+ handle->tty.rd.read_line_handle = NULL;
+ }
+
+
+ return 0;
+}
+
+
+static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
+ int old_virtual_width = uv_tty_virtual_width;
+ int old_virtual_height = uv_tty_virtual_height;
+
+ uv_tty_virtual_width = info->dwSize.X;
+ uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1;
+
+ /* Recompute virtual window offset row. */
+ if (uv_tty_virtual_offset == -1) {
+ uv_tty_virtual_offset = info->dwCursorPosition.Y;
+ } else if (uv_tty_virtual_offset < info->dwCursorPosition.Y -
+ uv_tty_virtual_height + 1) {
+ /* If suddenly find the cursor outside of the virtual window, it must */
+ /* have somehow scrolled. Update the virtual window offset. */
+ uv_tty_virtual_offset = info->dwCursorPosition.Y -
+ uv_tty_virtual_height + 1;
+ }
+ if (uv_tty_virtual_offset + uv_tty_virtual_height > info->dwSize.Y) {
+ uv_tty_virtual_offset = info->dwSize.Y - uv_tty_virtual_height;
+ }
+ if (uv_tty_virtual_offset < 0) {
+ uv_tty_virtual_offset = 0;
+ }
+
+ /* If the virtual window size changed, emit a SIGWINCH signal. Don't emit */
+ /* if this was the first time the virtual window size was computed. */
+ if (old_virtual_width != -1 && old_virtual_height != -1 &&
+ (uv_tty_virtual_width != old_virtual_width ||
+ uv_tty_virtual_height != old_virtual_height)) {
+ uv__signal_dispatch(SIGWINCH);
+ }
+}
+
+
+static COORD uv_tty_make_real_coord(uv_tty_t* handle,
+ CONSOLE_SCREEN_BUFFER_INFO* info, int x, unsigned char x_relative, int y,
+ unsigned char y_relative) {
+ COORD result;
+
+ uv_tty_update_virtual_window(info);
+
+ /* Adjust y position */
+ if (y_relative) {
+ y = info->dwCursorPosition.Y + y;
+ } else {
+ y = uv_tty_virtual_offset + y;
+ }
+ /* Clip y to virtual client rectangle */
+ if (y < uv_tty_virtual_offset) {
+ y = uv_tty_virtual_offset;
+ } else if (y >= uv_tty_virtual_offset + uv_tty_virtual_height) {
+ y = uv_tty_virtual_offset + uv_tty_virtual_height - 1;
+ }
+
+ /* Adjust x */
+ if (x_relative) {
+ x = info->dwCursorPosition.X + x;
+ }
+ /* Clip x */
+ if (x < 0) {
+ x = 0;
+ } else if (x >= uv_tty_virtual_width) {
+ x = uv_tty_virtual_width - 1;
+ }
+
+ result.X = (unsigned short) x;
+ result.Y = (unsigned short) y;
+ return result;
+}
+
+
+static int uv_tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length,
+ DWORD* error) {
+ DWORD written;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ if (!WriteConsoleW(handle->handle,
+ (void*) buffer,
+ length,
+ &written,
+ NULL)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
+ int y, unsigned char y_relative, DWORD* error) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ COORD pos;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ retry:
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ }
+
+ pos = uv_tty_make_real_coord(handle, &info, x, x_relative, y, y_relative);
+
+ if (!SetConsoleCursorPosition(handle->handle, pos)) {
+ if (GetLastError() == ERROR_INVALID_PARAMETER) {
+ /* The console may be resized - retry */
+ goto retry;
+ } else {
+ *error = GetLastError();
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
+ const COORD origin = {0, 0};
+ const WORD char_attrs = uv_tty_default_text_attributes;
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ DWORD count, written;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ /* Reset original text attributes. */
+ if (!SetConsoleTextAttribute(handle->handle, char_attrs)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ /* Move the cursor position to (0, 0). */
+ if (!SetConsoleCursorPosition(handle->handle, origin)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ /* Clear the screen buffer. */
+ retry:
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ count = info.dwSize.X * info.dwSize.Y;
+
+ if (!(FillConsoleOutputCharacterW(handle->handle,
+ L'\x20',
+ count,
+ origin,
+ &written) &&
+ FillConsoleOutputAttribute(handle->handle,
+ char_attrs,
+ written,
+ origin,
+ &written))) {
+ if (GetLastError() == ERROR_INVALID_PARAMETER) {
+ /* The console may be resized - retry */
+ goto retry;
+ } else {
+ *error = GetLastError();
+ return -1;
+ }
+ }
+
+ /* Move the virtual window up to the top. */
+ uv_tty_virtual_offset = 0;
+ uv_tty_update_virtual_window(&info);
+
+ return 0;
+}
+
+
+static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
+ DWORD* error) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ COORD start, end;
+ DWORD count, written;
+
+ int x1, x2, y1, y2;
+ int x1r, x2r, y1r, y2r;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ if (dir == 0) {
+ /* Clear from current position */
+ x1 = 0;
+ x1r = 1;
+ } else {
+ /* Clear from column 0 */
+ x1 = 0;
+ x1r = 0;
+ }
+
+ if (dir == 1) {
+ /* Clear to current position */
+ x2 = 0;
+ x2r = 1;
+ } else {
+ /* Clear to end of row. We pretend the console is 65536 characters wide, */
+ /* uv_tty_make_real_coord will clip it to the actual console width. */
+ x2 = 0xffff;
+ x2r = 0;
+ }
+
+ if (!entire_screen) {
+ /* Stay on our own row */
+ y1 = y2 = 0;
+ y1r = y2r = 1;
+ } else {
+ /* Apply columns direction to row */
+ y1 = x1;
+ y1r = x1r;
+ y2 = x2;
+ y2r = x2r;
+ }
+
+ retry:
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ start = uv_tty_make_real_coord(handle, &info, x1, x1r, y1, y1r);
+ end = uv_tty_make_real_coord(handle, &info, x2, x2r, y2, y2r);
+ count = (end.Y * info.dwSize.X + end.X) -
+ (start.Y * info.dwSize.X + start.X) + 1;
+
+ if (!(FillConsoleOutputCharacterW(handle->handle,
+ L'\x20',
+ count,
+ start,
+ &written) &&
+ FillConsoleOutputAttribute(handle->handle,
+ info.wAttributes,
+ written,
+ start,
+ &written))) {
+ if (GetLastError() == ERROR_INVALID_PARAMETER) {
+ /* The console may be resized - retry */
+ goto retry;
+ } else {
+ *error = GetLastError();
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+#define FLIP_FGBG \
+ do { \
+ WORD fg = info.wAttributes & 0xF; \
+ WORD bg = info.wAttributes & 0xF0; \
+ info.wAttributes &= 0xFF00; \
+ info.wAttributes |= fg << 4; \
+ info.wAttributes |= bg >> 4; \
+ } while (0)
+
+static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
+ unsigned short argc = handle->tty.wr.ansi_csi_argc;
+ unsigned short* argv = handle->tty.wr.ansi_csi_argv;
+ int i;
+ CONSOLE_SCREEN_BUFFER_INFO info;
+
+ char fg_color = -1, bg_color = -1;
+ char fg_bright = -1, bg_bright = -1;
+ char inverse = -1;
+
+ if (argc == 0) {
+ /* Reset mode */
+ fg_color = uv_tty_default_fg_color;
+ bg_color = uv_tty_default_bg_color;
+ fg_bright = uv_tty_default_fg_bright;
+ bg_bright = uv_tty_default_bg_bright;
+ inverse = uv_tty_default_inverse;
+ }
+
+ for (i = 0; i < argc; i++) {
+ short arg = argv[i];
+
+ if (arg == 0) {
+ /* Reset mode */
+ fg_color = uv_tty_default_fg_color;
+ bg_color = uv_tty_default_bg_color;
+ fg_bright = uv_tty_default_fg_bright;
+ bg_bright = uv_tty_default_bg_bright;
+ inverse = uv_tty_default_inverse;
+
+ } else if (arg == 1) {
+ /* Foreground bright on */
+ fg_bright = 1;
+
+ } else if (arg == 2) {
+ /* Both bright off */
+ fg_bright = 0;
+ bg_bright = 0;
+
+ } else if (arg == 5) {
+ /* Background bright on */
+ bg_bright = 1;
+
+ } else if (arg == 7) {
+ /* Inverse: on */
+ inverse = 1;
+
+ } else if (arg == 21 || arg == 22) {
+ /* Foreground bright off */
+ fg_bright = 0;
+
+ } else if (arg == 25) {
+ /* Background bright off */
+ bg_bright = 0;
+
+ } else if (arg == 27) {
+ /* Inverse: off */
+ inverse = 0;
+
+ } else if (arg >= 30 && arg <= 37) {
+ /* Set foreground color */
+ fg_color = arg - 30;
+
+ } else if (arg == 39) {
+ /* Default text color */
+ fg_color = uv_tty_default_fg_color;
+ fg_bright = uv_tty_default_fg_bright;
+
+ } else if (arg >= 40 && arg <= 47) {
+ /* Set background color */
+ bg_color = arg - 40;
+
+ } else if (arg == 49) {
+ /* Default background color */
+ bg_color = uv_tty_default_bg_color;
+ bg_bright = uv_tty_default_bg_bright;
+
+ } else if (arg >= 90 && arg <= 97) {
+ /* Set bold foreground color */
+ fg_bright = 1;
+ fg_color = arg - 90;
+
+ } else if (arg >= 100 && arg <= 107) {
+ /* Set bold background color */
+ bg_bright = 1;
+ bg_color = arg - 100;
+
+ }
+ }
+
+ if (fg_color == -1 && bg_color == -1 && fg_bright == -1 &&
+ bg_bright == -1 && inverse == -1) {
+ /* Nothing changed */
+ return 0;
+ }
+
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
+ FLIP_FGBG;
+ }
+
+ if (fg_color != -1) {
+ info.wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+ if (fg_color & 1) info.wAttributes |= FOREGROUND_RED;
+ if (fg_color & 2) info.wAttributes |= FOREGROUND_GREEN;
+ if (fg_color & 4) info.wAttributes |= FOREGROUND_BLUE;
+ }
+
+ if (fg_bright != -1) {
+ if (fg_bright) {
+ info.wAttributes |= FOREGROUND_INTENSITY;
+ } else {
+ info.wAttributes &= ~FOREGROUND_INTENSITY;
+ }
+ }
+
+ if (bg_color != -1) {
+ info.wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
+ if (bg_color & 1) info.wAttributes |= BACKGROUND_RED;
+ if (bg_color & 2) info.wAttributes |= BACKGROUND_GREEN;
+ if (bg_color & 4) info.wAttributes |= BACKGROUND_BLUE;
+ }
+
+ if (bg_bright != -1) {
+ if (bg_bright) {
+ info.wAttributes |= BACKGROUND_INTENSITY;
+ } else {
+ info.wAttributes &= ~BACKGROUND_INTENSITY;
+ }
+ }
+
+ if (inverse != -1) {
+ if (inverse) {
+ info.wAttributes |= COMMON_LVB_REVERSE_VIDEO;
+ } else {
+ info.wAttributes &= ~COMMON_LVB_REVERSE_VIDEO;
+ }
+ }
+
+ if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
+ FLIP_FGBG;
+ }
+
+ if (!SetConsoleTextAttribute(handle->handle, info.wAttributes)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes,
+ DWORD* error) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ uv_tty_update_virtual_window(&info);
+
+ handle->tty.wr.saved_position.X = info.dwCursorPosition.X;
+ handle->tty.wr.saved_position.Y = info.dwCursorPosition.Y - uv_tty_virtual_offset;
+ handle->flags |= UV_HANDLE_TTY_SAVED_POSITION;
+
+ if (save_attributes) {
+ handle->tty.wr.saved_attributes = info.wAttributes &
+ (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
+ handle->flags |= UV_HANDLE_TTY_SAVED_ATTRIBUTES;
+ }
+
+ return 0;
+}
+
+
+static int uv_tty_restore_state(uv_tty_t* handle,
+ unsigned char restore_attributes, DWORD* error) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ WORD new_attributes;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ if (handle->flags & UV_HANDLE_TTY_SAVED_POSITION) {
+ if (uv_tty_move_caret(handle,
+ handle->tty.wr.saved_position.X,
+ 0,
+ handle->tty.wr.saved_position.Y,
+ 0,
+ error) != 0) {
+ return -1;
+ }
+ }
+
+ if (restore_attributes &&
+ (handle->flags & UV_HANDLE_TTY_SAVED_ATTRIBUTES)) {
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ new_attributes = info.wAttributes;
+ new_attributes &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
+ new_attributes |= handle->tty.wr.saved_attributes;
+
+ if (!SetConsoleTextAttribute(handle->handle, new_attributes)) {
+ *error = GetLastError();
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int uv_tty_set_cursor_visibility(uv_tty_t* handle,
+ BOOL visible,
+ DWORD* error) {
+ CONSOLE_CURSOR_INFO cursor_info;
+
+ if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ cursor_info.bVisible = visible;
+
+ if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ return 0;
+}
+
+static int uv_tty_write_bufs(uv_tty_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ DWORD* error) {
+ /* We can only write 8k characters at a time. Windows can't handle */
+ /* much more characters in a single console write anyway. */
+ WCHAR utf16_buf[8192];
+ DWORD utf16_buf_used = 0;
+ unsigned int i;
+
+#define FLUSH_TEXT() \
+ do { \
+ if (utf16_buf_used > 0) { \
+ uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error); \
+ utf16_buf_used = 0; \
+ } \
+ } while (0)
+
+#define ENSURE_BUFFER_SPACE(wchars_needed) \
+ if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) { \
+ FLUSH_TEXT(); \
+ }
+
+ /* Cache for fast access */
+ unsigned char utf8_bytes_left = handle->tty.wr.utf8_bytes_left;
+ unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint;
+ unsigned char previous_eol = handle->tty.wr.previous_eol;
+ unsigned char ansi_parser_state = handle->tty.wr.ansi_parser_state;
+
+ /* Store the error here. If we encounter an error, stop trying to do i/o */
+ /* but keep parsing the buffer so we leave the parser in a consistent */
+ /* state. */
+ *error = ERROR_SUCCESS;
+
+ EnterCriticalSection(&uv_tty_output_lock);
+
+ for (i = 0; i < nbufs; i++) {
+ uv_buf_t buf = bufs[i];
+ unsigned int j;
+
+ for (j = 0; j < buf.len; j++) {
+ unsigned char c = buf.base[j];
+
+ /* Run the character through the utf8 decoder We happily accept non */
+ /* shortest form encodings and invalid code points - there's no real */
+ /* harm that can be done. */
+ if (utf8_bytes_left == 0) {
+ /* Read utf-8 start byte */
+ DWORD first_zero_bit;
+ unsigned char not_c = ~c;
+#ifdef _MSC_VER /* msvc */
+ if (_BitScanReverse(&first_zero_bit, not_c)) {
+#else /* assume gcc */
+ if (c != 0) {
+ first_zero_bit = (sizeof(int) * 8) - 1 - __builtin_clz(not_c);
+#endif
+ if (first_zero_bit == 7) {
+ /* Ascii - pass right through */
+ utf8_codepoint = (unsigned int) c;
+
+ } else if (first_zero_bit <= 5) {
+ /* Multibyte sequence */
+ utf8_codepoint = (0xff >> (8 - first_zero_bit)) & c;
+ utf8_bytes_left = (char) (6 - first_zero_bit);
+
+ } else {
+ /* Invalid continuation */
+ utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
+ }
+
+ } else {
+ /* 0xff -- invalid */
+ utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
+ }
+
+ } else if ((c & 0xc0) == 0x80) {
+ /* Valid continuation of utf-8 multibyte sequence */
+ utf8_bytes_left--;
+ utf8_codepoint <<= 6;
+ utf8_codepoint |= ((unsigned int) c & 0x3f);
+
+ } else {
+ /* Start byte where continuation was expected. */
+ utf8_bytes_left = 0;
+ utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
+ /* Patch buf offset so this character will be parsed again as a */
+ /* start byte. */
+ j--;
+ }
+
+ /* Maybe we need to parse more bytes to find a character. */
+ if (utf8_bytes_left != 0) {
+ continue;
+ }
+
+ /* Parse vt100/ansi escape codes */
+ if (ansi_parser_state == ANSI_NORMAL) {
+ switch (utf8_codepoint) {
+ case '\033':
+ ansi_parser_state = ANSI_ESCAPE_SEEN;
+ continue;
+
+ case 0233:
+ ansi_parser_state = ANSI_CSI;
+ handle->tty.wr.ansi_csi_argc = 0;
+ continue;
+ }
+
+ } else if (ansi_parser_state == ANSI_ESCAPE_SEEN) {
+ switch (utf8_codepoint) {
+ case '[':
+ ansi_parser_state = ANSI_CSI;
+ handle->tty.wr.ansi_csi_argc = 0;
+ continue;
+
+ case '^':
+ case '_':
+ case 'P':
+ case ']':
+ /* Not supported, but we'll have to parse until we see a stop */
+ /* code, e.g. ESC \ or BEL. */
+ ansi_parser_state = ANSI_ST_CONTROL;
+ continue;
+
+ case '\033':
+ /* Ignore double escape. */
+ continue;
+
+ case 'c':
+ /* Full console reset. */
+ FLUSH_TEXT();
+ uv_tty_reset(handle, error);
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+
+ case '7':
+ /* Save the cursor position and text attributes. */
+ FLUSH_TEXT();
+ uv_tty_save_state(handle, 1, error);
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+
+ case '8':
+ /* Restore the cursor position and text attributes */
+ FLUSH_TEXT();
+ uv_tty_restore_state(handle, 1, error);
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+
+ default:
+ if (utf8_codepoint >= '@' && utf8_codepoint <= '_') {
+ /* Single-char control. */
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+ } else {
+ /* Invalid - proceed as normal, */
+ ansi_parser_state = ANSI_NORMAL;
+ }
+ }
+
+ } else if (ansi_parser_state & ANSI_CSI) {
+ if (!(ansi_parser_state & ANSI_IGNORE)) {
+ if (utf8_codepoint >= '0' && utf8_codepoint <= '9') {
+ /* Parsing a numerical argument */
+
+ if (!(ansi_parser_state & ANSI_IN_ARG)) {
+ /* We were not currently parsing a number */
+
+ /* Check for too many arguments */
+ if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
+ ansi_parser_state |= ANSI_IGNORE;
+ continue;
+ }
+
+ ansi_parser_state |= ANSI_IN_ARG;
+ handle->tty.wr.ansi_csi_argc++;
+ handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
+ (unsigned short) utf8_codepoint - '0';
+ continue;
+ } else {
+ /* We were already parsing a number. Parse next digit. */
+ uint32_t value = 10 *
+ handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1];
+
+ /* Check for overflow. */
+ if (value > UINT16_MAX) {
+ ansi_parser_state |= ANSI_IGNORE;
+ continue;
+ }
+
+ handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
+ (unsigned short) value + (utf8_codepoint - '0');
+ continue;
+ }
+
+ } else if (utf8_codepoint == ';') {
+ /* Denotes the end of an argument. */
+ if (ansi_parser_state & ANSI_IN_ARG) {
+ ansi_parser_state &= ~ANSI_IN_ARG;
+ continue;
+
+ } else {
+ /* If ANSI_IN_ARG is not set, add another argument and */
+ /* default it to 0. */
+ /* Check for too many arguments */
+ if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
+ ansi_parser_state |= ANSI_IGNORE;
+ continue;
+ }
+
+ handle->tty.wr.ansi_csi_argc++;
+ handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0;
+ continue;
+ }
+
+ } else if (utf8_codepoint == '?' && !(ansi_parser_state & ANSI_IN_ARG) &&
+ handle->tty.wr.ansi_csi_argc == 0) {
+ /* Ignores '?' if it is the first character after CSI[ */
+ /* This is an extension character from the VT100 codeset */
+ /* that is supported and used by most ANSI terminals today. */
+ continue;
+
+ } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' &&
+ (handle->tty.wr.ansi_csi_argc > 0 || utf8_codepoint != '[')) {
+ int x, y, d;
+
+ /* Command byte */
+ switch (utf8_codepoint) {
+ case 'A':
+ /* cursor up */
+ FLUSH_TEXT();
+ y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
+ uv_tty_move_caret(handle, 0, 1, y, 1, error);
+ break;
+
+ case 'B':
+ /* cursor down */
+ FLUSH_TEXT();
+ y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
+ uv_tty_move_caret(handle, 0, 1, y, 1, error);
+ break;
+
+ case 'C':
+ /* cursor forward */
+ FLUSH_TEXT();
+ x = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
+ uv_tty_move_caret(handle, x, 1, 0, 1, error);
+ break;
+
+ case 'D':
+ /* cursor back */
+ FLUSH_TEXT();
+ x = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
+ uv_tty_move_caret(handle, x, 1, 0, 1, error);
+ break;
+
+ case 'E':
+ /* cursor next line */
+ FLUSH_TEXT();
+ y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
+ uv_tty_move_caret(handle, 0, 0, y, 1, error);
+ break;
+
+ case 'F':
+ /* cursor previous line */
+ FLUSH_TEXT();
+ y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
+ uv_tty_move_caret(handle, 0, 0, y, 1, error);
+ break;
+
+ case 'G':
+ /* cursor horizontal move absolute */
+ FLUSH_TEXT();
+ x = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0])
+ ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
+ uv_tty_move_caret(handle, x, 0, 0, 1, error);
+ break;
+
+ case 'H':
+ case 'f':
+ /* cursor move absolute */
+ FLUSH_TEXT();
+ y = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0])
+ ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
+ x = (handle->tty.wr.ansi_csi_argc >= 2 && handle->tty.wr.ansi_csi_argv[1])
+ ? handle->tty.wr.ansi_csi_argv[1] - 1 : 0;
+ uv_tty_move_caret(handle, x, 0, y, 0, error);
+ break;
+
+ case 'J':
+ /* Erase screen */
+ FLUSH_TEXT();
+ d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0;
+ if (d >= 0 && d <= 2) {
+ uv_tty_clear(handle, d, 1, error);
+ }
+ break;
+
+ case 'K':
+ /* Erase line */
+ FLUSH_TEXT();
+ d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0;
+ if (d >= 0 && d <= 2) {
+ uv_tty_clear(handle, d, 0, error);
+ }
+ break;
+
+ case 'm':
+ /* Set style */
+ FLUSH_TEXT();
+ uv_tty_set_style(handle, error);
+ break;
+
+ case 's':
+ /* Save the cursor position. */
+ FLUSH_TEXT();
+ uv_tty_save_state(handle, 0, error);
+ break;
+
+ case 'u':
+ /* Restore the cursor position */
+ FLUSH_TEXT();
+ uv_tty_restore_state(handle, 0, error);
+ break;
+
+ case 'l':
+ /* Hide the cursor */
+ if (handle->tty.wr.ansi_csi_argc == 1 &&
+ handle->tty.wr.ansi_csi_argv[0] == 25) {
+ FLUSH_TEXT();
+ uv_tty_set_cursor_visibility(handle, 0, error);
+ }
+ break;
+
+ case 'h':
+ /* Show the cursor */
+ if (handle->tty.wr.ansi_csi_argc == 1 &&
+ handle->tty.wr.ansi_csi_argv[0] == 25) {
+ FLUSH_TEXT();
+ uv_tty_set_cursor_visibility(handle, 1, error);
+ }
+ break;
+ }
+
+ /* Sequence ended - go back to normal state. */
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+
+ } else {
+ /* We don't support commands that use private mode characters or */
+ /* intermediaries. Ignore the rest of the sequence. */
+ ansi_parser_state |= ANSI_IGNORE;
+ continue;
+ }
+ } else {
+ /* We're ignoring this command. Stop only on command character. */
+ if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
+ ansi_parser_state = ANSI_NORMAL;
+ }
+ continue;
+ }
+
+ } else if (ansi_parser_state & ANSI_ST_CONTROL) {
+ /* Unsupported control code */
+ /* Ignore everything until we see BEL or ESC \ */
+ if (ansi_parser_state & ANSI_IN_STRING) {
+ if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) {
+ if (utf8_codepoint == '"') {
+ ansi_parser_state &= ~ANSI_IN_STRING;
+ } else if (utf8_codepoint == '\\') {
+ ansi_parser_state |= ANSI_BACKSLASH_SEEN;
+ }
+ } else {
+ ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
+ }
+ } else {
+ if (utf8_codepoint == '\007' || (utf8_codepoint == '\\' &&
+ (ansi_parser_state & ANSI_ESCAPE_SEEN))) {
+ /* End of sequence */
+ ansi_parser_state = ANSI_NORMAL;
+ } else if (utf8_codepoint == '\033') {
+ /* Escape character */
+ ansi_parser_state |= ANSI_ESCAPE_SEEN;
+ } else if (utf8_codepoint == '"') {
+ /* String starting */
+ ansi_parser_state |= ANSI_IN_STRING;
+ ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
+ ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
+ } else {
+ ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
+ }
+ }
+ continue;
+ } else {
+ /* Inconsistent state */
+ abort();
+ }
+
+ /* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the */
+ /* windows console doesn't really support UTF-16, so just emit the */
+ /* replacement character. */
+ if (utf8_codepoint > 0xffff) {
+ utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
+ }
+
+ if (utf8_codepoint == 0x0a || utf8_codepoint == 0x0d) {
+ /* EOL conversion - emit \r\n when we see \n. */
+
+ if (utf8_codepoint == 0x0a && previous_eol != 0x0d) {
+ /* \n was not preceded by \r; print \r\n. */
+ ENSURE_BUFFER_SPACE(2);
+ utf16_buf[utf16_buf_used++] = L'\r';
+ utf16_buf[utf16_buf_used++] = L'\n';
+ } else if (utf8_codepoint == 0x0d && previous_eol == 0x0a) {
+ /* \n was followed by \r; do not print the \r, since */
+ /* the source was either \r\n\r (so the second \r is */
+ /* redundant) or was \n\r (so the \n was processed */
+ /* by the last case and an \r automatically inserted). */
+ } else {
+ /* \r without \n; print \r as-is. */
+ ENSURE_BUFFER_SPACE(1);
+ utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
+ }
+
+ previous_eol = (char) utf8_codepoint;
+
+ } else if (utf8_codepoint <= 0xffff) {
+ /* Encode character into utf-16 buffer. */
+ ENSURE_BUFFER_SPACE(1);
+ utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
+ previous_eol = 0;
+ }
+ }
+ }
+
+ /* Flush remaining characters */
+ FLUSH_TEXT();
+
+ /* Copy cached values back to struct. */
+ handle->tty.wr.utf8_bytes_left = utf8_bytes_left;
+ handle->tty.wr.utf8_codepoint = utf8_codepoint;
+ handle->tty.wr.previous_eol = previous_eol;
+ handle->tty.wr.ansi_parser_state = ansi_parser_state;
+
+ LeaveCriticalSection(&uv_tty_output_lock);
+
+ if (*error == STATUS_SUCCESS) {
+ return 0;
+ } else {
+ return -1;
+ }
+
+#undef FLUSH_TEXT
+}
+
+
+int uv_tty_write(uv_loop_t* loop,
+ uv_write_t* req,
+ uv_tty_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb) {
+ DWORD error;
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_WRITE;
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+
+ req->u.io.queued_bytes = 0;
+
+ if (!uv_tty_write_bufs(handle, bufs, nbufs, &error)) {
+ SET_REQ_SUCCESS(req);
+ } else {
+ SET_REQ_ERROR(req, error);
+ }
+
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+
+ return 0;
+}
+
+
+int uv__tty_try_write(uv_tty_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs) {
+ DWORD error;
+
+ if (handle->stream.conn.write_reqs_pending > 0)
+ return UV_EAGAIN;
+
+ if (uv_tty_write_bufs(handle, bufs, nbufs, &error))
+ return uv_translate_sys_error(error);
+
+ return uv__count_bufs(bufs, nbufs);
+}
+
+
+void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_write_t* req) {
+ int err;
+
+ handle->write_queue_size -= req->u.io.queued_bytes;
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (req->cb) {
+ err = GET_REQ_ERROR(req);
+ req->cb(req, uv_translate_sys_error(err));
+ }
+
+ handle->stream.conn.write_reqs_pending--;
+ if (handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_tty_close(uv_tty_t* handle) {
+ assert(handle->u.fd == -1 || handle->u.fd > 2);
+ if (handle->u.fd == -1)
+ CloseHandle(handle->handle);
+ else
+ close(handle->u.fd);
+
+ if (handle->flags & UV_HANDLE_READING)
+ uv_tty_read_stop(handle);
+
+ handle->u.fd = -1;
+ handle->handle = INVALID_HANDLE_VALUE;
+ handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
+ uv__handle_closing(handle);
+
+ if (handle->reqs_pending == 0) {
+ uv_want_endgame(handle->loop, (uv_handle_t*) handle);
+ }
+}
+
+
+void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
+ if (!(handle->flags & UV_HANDLE_TTY_READABLE) &&
+ handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+ UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
+
+ /* TTY shutdown is really just a no-op */
+ if (handle->stream.conn.shutdown_req->cb) {
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED);
+ } else {
+ handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0);
+ }
+ }
+
+ handle->stream.conn.shutdown_req = NULL;
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+
+ if (handle->flags & UV__HANDLE_CLOSING &&
+ handle->reqs_pending == 0) {
+ /* The console handle duplicate used for line reading should be destroyed */
+ /* by uv_tty_read_stop. */
+ assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
+ handle->tty.rd.read_line_handle == NULL);
+
+ /* The wait handle used for raw reading should be unregistered when the */
+ /* wait callback runs. */
+ assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
+ handle->tty.rd.read_raw_wait == NULL);
+
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ uv__handle_close(handle);
+ }
+}
+
+
+/* TODO: remove me */
+void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* raw_req) {
+ abort();
+}
+
+
+/* TODO: remove me */
+void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_connect_t* req) {
+ abort();
+}
+
+
+int uv_tty_reset_mode(void) {
+ /* Not necessary to do anything. */
+ return 0;
+}
diff --git a/3rdparty/libuv/src/win/udp.c b/3rdparty/libuv/src/win/udp.c
new file mode 100644
index 00000000000..24792ec067e
--- /dev/null
+++ b/3rdparty/libuv/src/win/udp.c
@@ -0,0 +1,926 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "stream-inl.h"
+#include "req-inl.h"
+
+
+/*
+ * Threshold of active udp streams for which to preallocate udp read buffers.
+ */
+const unsigned int uv_active_udp_streams_threshold = 0;
+
+/* A zero-size buffer for use by uv_udp_read */
+static char uv_zero_[] = "";
+
+int uv_udp_getsockname(const uv_udp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ int result;
+
+ if (handle->socket == INVALID_SOCKET) {
+ return UV_EINVAL;
+ }
+
+ result = getsockname(handle->socket, name, namelen);
+ if (result != 0) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
+ int family) {
+ DWORD yes = 1;
+ WSAPROTOCOL_INFOW info;
+ int opt_len;
+
+ if (handle->socket != INVALID_SOCKET)
+ return UV_EBUSY;
+
+ /* Set the socket to nonblocking mode */
+ if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) {
+ return WSAGetLastError();
+ }
+
+ /* Make the socket non-inheritable */
+ if (!SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0)) {
+ return GetLastError();
+ }
+
+ /* Associate it with the I/O completion port. */
+ /* Use uv_handle_t pointer as completion key. */
+ if (CreateIoCompletionPort((HANDLE)socket,
+ loop->iocp,
+ (ULONG_PTR)socket,
+ 0) == NULL) {
+ return GetLastError();
+ }
+
+ if (pSetFileCompletionNotificationModes) {
+ /* All known Windows that support SetFileCompletionNotificationModes */
+ /* have a bug that makes it impossible to use this function in */
+ /* conjunction with datagram sockets. We can work around that but only */
+ /* if the user is using the default UDP driver (AFD) and has no other */
+ /* LSPs stacked on top. Here we check whether that is the case. */
+ opt_len = (int) sizeof info;
+ if (getsockopt(socket,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &info,
+ &opt_len) == SOCKET_ERROR) {
+ return GetLastError();
+ }
+
+ if (info.ProtocolChain.ChainLen == 1) {
+ if (pSetFileCompletionNotificationModes((HANDLE)socket,
+ FILE_SKIP_SET_EVENT_ON_HANDLE |
+ FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
+ handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
+ handle->func_wsarecv = uv_wsarecv_workaround;
+ handle->func_wsarecvfrom = uv_wsarecvfrom_workaround;
+ } else if (GetLastError() != ERROR_INVALID_FUNCTION) {
+ return GetLastError();
+ }
+ }
+ }
+
+ handle->socket = socket;
+
+ if (family == AF_INET6) {
+ handle->flags |= UV_HANDLE_IPV6;
+ } else {
+ assert(!(handle->flags & UV_HANDLE_IPV6));
+ }
+
+ return 0;
+}
+
+
+int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
+ int domain;
+
+ /* Use the lower 8 bits for the domain */
+ domain = flags & 0xFF;
+ if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
+ return UV_EINVAL;
+
+ if (flags & ~0xFF)
+ return UV_EINVAL;
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_UDP);
+ handle->socket = INVALID_SOCKET;
+ handle->reqs_pending = 0;
+ handle->activecnt = 0;
+ handle->func_wsarecv = WSARecv;
+ handle->func_wsarecvfrom = WSARecvFrom;
+ handle->send_queue_size = 0;
+ handle->send_queue_count = 0;
+ uv_req_init(loop, (uv_req_t*) &(handle->recv_req));
+ handle->recv_req.type = UV_UDP_RECV;
+ handle->recv_req.data = handle;
+
+ /* If anything fails beyond this point we need to remove the handle from
+ * the handle queue, since it was added by uv__handle_init.
+ */
+
+ if (domain != AF_UNSPEC) {
+ SOCKET sock;
+ DWORD err;
+
+ sock = socket(domain, SOCK_DGRAM, 0);
+ if (sock == INVALID_SOCKET) {
+ err = WSAGetLastError();
+ QUEUE_REMOVE(&handle->handle_queue);
+ return uv_translate_sys_error(err);
+ }
+
+ err = uv_udp_set_socket(handle->loop, handle, sock, domain);
+ if (err) {
+ closesocket(sock);
+ QUEUE_REMOVE(&handle->handle_queue);
+ return uv_translate_sys_error(err);
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
+ return uv_udp_init_ex(loop, handle, AF_UNSPEC);
+}
+
+
+void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
+ uv_udp_recv_stop(handle);
+ closesocket(handle->socket);
+ handle->socket = INVALID_SOCKET;
+
+ uv__handle_closing(handle);
+
+ if (handle->reqs_pending == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+}
+
+
+void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) {
+ if (handle->flags & UV__HANDLE_CLOSING &&
+ handle->reqs_pending == 0) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ uv__handle_close(handle);
+ }
+}
+
+
+static int uv_udp_maybe_bind(uv_udp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ int r;
+ int err;
+ DWORD no = 0;
+
+ if (handle->flags & UV_HANDLE_BOUND)
+ return 0;
+
+ if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) {
+ /* UV_UDP_IPV6ONLY is supported only for IPV6 sockets */
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (handle->socket == INVALID_SOCKET) {
+ SOCKET sock = socket(addr->sa_family, SOCK_DGRAM, 0);
+ if (sock == INVALID_SOCKET) {
+ return WSAGetLastError();
+ }
+
+ err = uv_udp_set_socket(handle->loop, handle, sock, addr->sa_family);
+ if (err) {
+ closesocket(sock);
+ return err;
+ }
+ }
+
+ if (flags & UV_UDP_REUSEADDR) {
+ DWORD yes = 1;
+ /* Set SO_REUSEADDR on the socket. */
+ if (setsockopt(handle->socket,
+ SOL_SOCKET,
+ SO_REUSEADDR,
+ (char*) &yes,
+ sizeof yes) == SOCKET_ERROR) {
+ err = WSAGetLastError();
+ return err;
+ }
+ }
+
+ if (addr->sa_family == AF_INET6)
+ handle->flags |= UV_HANDLE_IPV6;
+
+ if (addr->sa_family == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) {
+ /* On windows IPV6ONLY is on by default. */
+ /* If the user doesn't specify it libuv turns it off. */
+
+ /* TODO: how to handle errors? This may fail if there is no ipv4 stack */
+ /* available, or when run on XP/2003 which have no support for dualstack */
+ /* sockets. For now we're silently ignoring the error. */
+ setsockopt(handle->socket,
+ IPPROTO_IPV6,
+ IPV6_V6ONLY,
+ (char*) &no,
+ sizeof no);
+ }
+
+ r = bind(handle->socket, addr, addrlen);
+ if (r == SOCKET_ERROR) {
+ return WSAGetLastError();
+ }
+
+ handle->flags |= UV_HANDLE_BOUND;
+
+ return 0;
+}
+
+
+static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
+ uv_req_t* req;
+ uv_buf_t buf;
+ DWORD bytes, flags;
+ int result;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+
+ req = &handle->recv_req;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ /*
+ * Preallocate a read buffer if the number of active streams is below
+ * the threshold.
+ */
+ if (loop->active_udp_streams < uv_active_udp_streams_threshold) {
+ handle->flags &= ~UV_HANDLE_ZERO_READ;
+
+ handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer);
+ if (handle->recv_buffer.len == 0) {
+ handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0);
+ return;
+ }
+ assert(handle->recv_buffer.base != NULL);
+
+ buf = handle->recv_buffer;
+ memset(&handle->recv_from, 0, sizeof handle->recv_from);
+ handle->recv_from_len = sizeof handle->recv_from;
+ flags = 0;
+
+ result = handle->func_wsarecvfrom(handle->socket,
+ (WSABUF*) &buf,
+ 1,
+ &bytes,
+ &flags,
+ (struct sockaddr*) &handle->recv_from,
+ &handle->recv_from_len,
+ &req->u.io.overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Process the req without IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ req->u.io.overlapped.InternalHigh = bytes;
+ handle->reqs_pending++;
+ uv_insert_pending_req(loop, req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* The req will be processed with IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+ } else {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, req);
+ handle->reqs_pending++;
+ }
+
+ } else {
+ handle->flags |= UV_HANDLE_ZERO_READ;
+
+ buf.base = (char*) uv_zero_;
+ buf.len = 0;
+ flags = MSG_PEEK;
+
+ result = handle->func_wsarecv(handle->socket,
+ (WSABUF*) &buf,
+ 1,
+ &bytes,
+ &flags,
+ &req->u.io.overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Process the req without IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ req->u.io.overlapped.InternalHigh = bytes;
+ handle->reqs_pending++;
+ uv_insert_pending_req(loop, req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* The req will be processed with IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+ } else {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, req);
+ handle->reqs_pending++;
+ }
+ }
+}
+
+
+int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
+ uv_udp_recv_cb recv_cb) {
+ uv_loop_t* loop = handle->loop;
+ int err;
+
+ if (handle->flags & UV_HANDLE_READING) {
+ return WSAEALREADY;
+ }
+
+ err = uv_udp_maybe_bind(handle,
+ (const struct sockaddr*) &uv_addr_ip4_any_,
+ sizeof(uv_addr_ip4_any_),
+ 0);
+ if (err)
+ return err;
+
+ handle->flags |= UV_HANDLE_READING;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+ loop->active_udp_streams++;
+
+ handle->recv_cb = recv_cb;
+ handle->alloc_cb = alloc_cb;
+
+ /* If reading was stopped and then started again, there could still be a */
+ /* recv request pending. */
+ if (!(handle->flags & UV_HANDLE_READ_PENDING))
+ uv_udp_queue_recv(loop, handle);
+
+ return 0;
+}
+
+
+int uv__udp_recv_stop(uv_udp_t* handle) {
+ if (handle->flags & UV_HANDLE_READING) {
+ handle->flags &= ~UV_HANDLE_READING;
+ handle->loop->active_udp_streams--;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ }
+
+ return 0;
+}
+
+
+static int uv__send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_udp_send_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ DWORD result, bytes;
+
+ uv_req_init(loop, (uv_req_t*) req);
+ req->type = UV_UDP_SEND;
+ req->handle = handle;
+ req->cb = cb;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ result = WSASendTo(handle->socket,
+ (WSABUF*)bufs,
+ nbufs,
+ &bytes,
+ 0,
+ addr,
+ addrlen,
+ &req->u.io.overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Request completed immediately. */
+ req->u.io.queued_bytes = 0;
+ handle->reqs_pending++;
+ handle->send_queue_size += req->u.io.queued_bytes;
+ handle->send_queue_count++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* Request queued by the kernel. */
+ req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
+ handle->reqs_pending++;
+ handle->send_queue_size += req->u.io.queued_bytes;
+ handle->send_queue_count++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ } else {
+ /* Send failed due to an error. */
+ return WSAGetLastError();
+ }
+
+ return 0;
+}
+
+
+void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
+ uv_req_t* req) {
+ uv_buf_t buf;
+ int partial;
+
+ assert(handle->type == UV_UDP);
+
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+
+ if (!REQ_SUCCESS(req)) {
+ DWORD err = GET_REQ_SOCK_ERROR(req);
+ if (err == WSAEMSGSIZE) {
+ /* Not a real error, it just indicates that the received packet */
+ /* was bigger than the receive buffer. */
+ } else if (err == WSAECONNRESET || err == WSAENETRESET) {
+ /* A previous sendto operation failed; ignore this error. If */
+ /* zero-reading we need to call WSARecv/WSARecvFrom _without_ the */
+ /* MSG_PEEK flag to clear out the error queue. For nonzero reads, */
+ /* immediately queue a new receive. */
+ if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
+ goto done;
+ }
+ } else {
+ /* A real error occurred. Report the error to the user only if we're */
+ /* currently reading. */
+ if (handle->flags & UV_HANDLE_READING) {
+ uv_udp_recv_stop(handle);
+ buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
+ uv_buf_init(NULL, 0) : handle->recv_buffer;
+ handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
+ }
+ goto done;
+ }
+ }
+
+ if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
+ /* Successful read */
+ partial = !REQ_SUCCESS(req);
+ handle->recv_cb(handle,
+ req->u.io.overlapped.InternalHigh,
+ &handle->recv_buffer,
+ (const struct sockaddr*) &handle->recv_from,
+ partial ? UV_UDP_PARTIAL : 0);
+ } else if (handle->flags & UV_HANDLE_READING) {
+ DWORD bytes, err, flags;
+ struct sockaddr_storage from;
+ int from_len;
+
+ /* Do a nonblocking receive */
+ /* TODO: try to read multiple datagrams at once. FIONREAD maybe? */
+ handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
+ if (buf.len == 0) {
+ handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
+ goto done;
+ }
+ assert(buf.base != NULL);
+
+ memset(&from, 0, sizeof from);
+ from_len = sizeof from;
+
+ flags = 0;
+
+ if (WSARecvFrom(handle->socket,
+ (WSABUF*)&buf,
+ 1,
+ &bytes,
+ &flags,
+ (struct sockaddr*) &from,
+ &from_len,
+ NULL,
+ NULL) != SOCKET_ERROR) {
+
+ /* Message received */
+ handle->recv_cb(handle, bytes, &buf, (const struct sockaddr*) &from, 0);
+ } else {
+ err = WSAGetLastError();
+ if (err == WSAEMSGSIZE) {
+ /* Message truncated */
+ handle->recv_cb(handle,
+ bytes,
+ &buf,
+ (const struct sockaddr*) &from,
+ UV_UDP_PARTIAL);
+ } else if (err == WSAEWOULDBLOCK) {
+ /* Kernel buffer empty */
+ handle->recv_cb(handle, 0, &buf, NULL, 0);
+ } else if (err == WSAECONNRESET || err == WSAENETRESET) {
+ /* WSAECONNRESET/WSANETRESET is ignored because this just indicates
+ * that a previous sendto operation failed.
+ */
+ handle->recv_cb(handle, 0, &buf, NULL, 0);
+ } else {
+ /* Any other error that we want to report back to the user. */
+ uv_udp_recv_stop(handle);
+ handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
+ }
+ }
+ }
+
+done:
+ /* Post another read if still reading and not closing. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_udp_queue_recv(loop, handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
+ uv_udp_send_t* req) {
+ int err;
+
+ assert(handle->type == UV_UDP);
+
+ assert(handle->send_queue_size >= req->u.io.queued_bytes);
+ assert(handle->send_queue_count >= 1);
+ handle->send_queue_size -= req->u.io.queued_bytes;
+ handle->send_queue_count--;
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (req->cb) {
+ err = 0;
+ if (!REQ_SUCCESS(req)) {
+ err = GET_REQ_SOCK_ERROR(req);
+ }
+ req->cb(req, uv_translate_sys_error(err));
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+static int uv__udp_set_membership4(uv_udp_t* handle,
+ const struct sockaddr_in* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ int err;
+ int optname;
+ struct ip_mreq mreq;
+
+ if (handle->flags & UV_HANDLE_IPV6)
+ return UV_EINVAL;
+
+ /* If the socket is unbound, bind to inaddr_any. */
+ err = uv_udp_maybe_bind(handle,
+ (const struct sockaddr*) &uv_addr_ip4_any_,
+ sizeof(uv_addr_ip4_any_),
+ UV_UDP_REUSEADDR);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ memset(&mreq, 0, sizeof mreq);
+
+ if (interface_addr) {
+ err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
+ if (err)
+ return err;
+ } else {
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ }
+
+ mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
+
+ switch (membership) {
+ case UV_JOIN_GROUP:
+ optname = IP_ADD_MEMBERSHIP;
+ break;
+ case UV_LEAVE_GROUP:
+ optname = IP_DROP_MEMBERSHIP;
+ break;
+ default:
+ return UV_EINVAL;
+ }
+
+ if (setsockopt(handle->socket,
+ IPPROTO_IP,
+ optname,
+ (char*) &mreq,
+ sizeof mreq) == SOCKET_ERROR) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+int uv__udp_set_membership6(uv_udp_t* handle,
+ const struct sockaddr_in6* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ int optname;
+ int err;
+ struct ipv6_mreq mreq;
+ struct sockaddr_in6 addr6;
+
+ if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6))
+ return UV_EINVAL;
+
+ err = uv_udp_maybe_bind(handle,
+ (const struct sockaddr*) &uv_addr_ip6_any_,
+ sizeof(uv_addr_ip6_any_),
+ UV_UDP_REUSEADDR);
+
+ if (err)
+ return uv_translate_sys_error(err);
+
+ memset(&mreq, 0, sizeof(mreq));
+
+ if (interface_addr) {
+ if (uv_ip6_addr(interface_addr, 0, &addr6))
+ return UV_EINVAL;
+ mreq.ipv6mr_interface = addr6.sin6_scope_id;
+ } else {
+ mreq.ipv6mr_interface = 0;
+ }
+
+ mreq.ipv6mr_multiaddr = multicast_addr->sin6_addr;
+
+ switch (membership) {
+ case UV_JOIN_GROUP:
+ optname = IPV6_ADD_MEMBERSHIP;
+ break;
+ case UV_LEAVE_GROUP:
+ optname = IPV6_DROP_MEMBERSHIP;
+ break;
+ default:
+ return UV_EINVAL;
+ }
+
+ if (setsockopt(handle->socket,
+ IPPROTO_IPV6,
+ optname,
+ (char*) &mreq,
+ sizeof mreq) == SOCKET_ERROR) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+int uv_udp_set_membership(uv_udp_t* handle,
+ const char* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+
+ if (uv_ip4_addr(multicast_addr, 0, &addr4) == 0)
+ return uv__udp_set_membership4(handle, &addr4, interface_addr, membership);
+ else if (uv_ip6_addr(multicast_addr, 0, &addr6) == 0)
+ return uv__udp_set_membership6(handle, &addr6, interface_addr, membership);
+ else
+ return UV_EINVAL;
+}
+
+
+int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
+ struct sockaddr_storage addr_st;
+ struct sockaddr_in* addr4;
+ struct sockaddr_in6* addr6;
+
+ addr4 = (struct sockaddr_in*) &addr_st;
+ addr6 = (struct sockaddr_in6*) &addr_st;
+
+ if (!interface_addr) {
+ memset(&addr_st, 0, sizeof addr_st);
+ if (handle->flags & UV_HANDLE_IPV6) {
+ addr_st.ss_family = AF_INET6;
+ addr6->sin6_scope_id = 0;
+ } else {
+ addr_st.ss_family = AF_INET;
+ addr4->sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+ } else if (uv_ip4_addr(interface_addr, 0, addr4) == 0) {
+ /* nothing, address was parsed */
+ } else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) {
+ /* nothing, address was parsed */
+ } else {
+ return UV_EINVAL;
+ }
+
+ if (!(handle->flags & UV_HANDLE_BOUND))
+ return UV_EBADF;
+
+ if (addr_st.ss_family == AF_INET) {
+ if (setsockopt(handle->socket,
+ IPPROTO_IP,
+ IP_MULTICAST_IF,
+ (char*) &addr4->sin_addr,
+ sizeof(addr4->sin_addr)) == SOCKET_ERROR) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+ } else if (addr_st.ss_family == AF_INET6) {
+ if (setsockopt(handle->socket,
+ IPPROTO_IPV6,
+ IPV6_MULTICAST_IF,
+ (char*) &addr6->sin6_scope_id,
+ sizeof(addr6->sin6_scope_id)) == SOCKET_ERROR) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+ } else {
+ assert(0 && "unexpected address family");
+ abort();
+ }
+
+ return 0;
+}
+
+
+int uv_udp_set_broadcast(uv_udp_t* handle, int value) {
+ BOOL optval = (BOOL) value;
+
+ if (!(handle->flags & UV_HANDLE_BOUND))
+ return UV_EBADF;
+
+ if (setsockopt(handle->socket,
+ SOL_SOCKET,
+ SO_BROADCAST,
+ (char*) &optval,
+ sizeof optval)) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
+ WSAPROTOCOL_INFOW protocol_info;
+ int opt_len;
+ int err;
+
+ /* Detect the address family of the socket. */
+ opt_len = (int) sizeof protocol_info;
+ if (getsockopt(sock,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &protocol_info,
+ &opt_len) == SOCKET_ERROR) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ err = uv_udp_set_socket(handle->loop,
+ handle,
+ sock,
+ protocol_info.iAddressFamily);
+ return uv_translate_sys_error(err);
+}
+
+
+#define SOCKOPT_SETTER(name, option4, option6, validate) \
+ int uv_udp_set_##name(uv_udp_t* handle, int value) { \
+ DWORD optval = (DWORD) value; \
+ \
+ if (!(validate(value))) { \
+ return UV_EINVAL; \
+ } \
+ \
+ if (!(handle->flags & UV_HANDLE_BOUND)) \
+ return UV_EBADF; \
+ \
+ if (!(handle->flags & UV_HANDLE_IPV6)) { \
+ /* Set IPv4 socket option */ \
+ if (setsockopt(handle->socket, \
+ IPPROTO_IP, \
+ option4, \
+ (char*) &optval, \
+ sizeof optval)) { \
+ return uv_translate_sys_error(WSAGetLastError()); \
+ } \
+ } else { \
+ /* Set IPv6 socket option */ \
+ if (setsockopt(handle->socket, \
+ IPPROTO_IPV6, \
+ option6, \
+ (char*) &optval, \
+ sizeof optval)) { \
+ return uv_translate_sys_error(WSAGetLastError()); \
+ } \
+ } \
+ return 0; \
+ }
+
+#define VALIDATE_TTL(value) ((value) >= 1 && (value) <= 255)
+#define VALIDATE_MULTICAST_TTL(value) ((value) >= -1 && (value) <= 255)
+#define VALIDATE_MULTICAST_LOOP(value) (1)
+
+SOCKOPT_SETTER(ttl,
+ IP_TTL,
+ IPV6_HOPLIMIT,
+ VALIDATE_TTL)
+SOCKOPT_SETTER(multicast_ttl,
+ IP_MULTICAST_TTL,
+ IPV6_MULTICAST_HOPS,
+ VALIDATE_MULTICAST_TTL)
+SOCKOPT_SETTER(multicast_loop,
+ IP_MULTICAST_LOOP,
+ IPV6_MULTICAST_LOOP,
+ VALIDATE_MULTICAST_LOOP)
+
+#undef SOCKOPT_SETTER
+#undef VALIDATE_TTL
+#undef VALIDATE_MULTICAST_TTL
+#undef VALIDATE_MULTICAST_LOOP
+
+
+/* This function is an egress point, i.e. it returns libuv errors rather than
+ * system errors.
+ */
+int uv__udp_bind(uv_udp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ int err;
+
+ err = uv_udp_maybe_bind(handle, addr, addrlen, flags);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ return 0;
+}
+
+
+/* This function is an egress point, i.e. it returns libuv errors rather than
+ * system errors.
+ */
+int uv__udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_udp_send_cb send_cb) {
+ const struct sockaddr* bind_addr;
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ if (addrlen == sizeof(uv_addr_ip4_any_)) {
+ bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
+ } else if (addrlen == sizeof(uv_addr_ip6_any_)) {
+ bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
+ } else {
+ abort();
+ }
+ err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
+ if (err)
+ return uv_translate_sys_error(err);
+ }
+
+ err = uv__send(req, handle, bufs, nbufs, addr, addrlen, send_cb);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ return 0;
+}
+
+
+int uv__udp_try_send(uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen) {
+ return UV_ENOSYS;
+}
diff --git a/3rdparty/libuv/src/win/util.c b/3rdparty/libuv/src/win/util.c
new file mode 100644
index 00000000000..cb247513046
--- /dev/null
+++ b/3rdparty/libuv/src/win/util.c
@@ -0,0 +1,1232 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <direct.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <wchar.h>
+
+#include "uv.h"
+#include "internal.h"
+
+#include <winsock2.h>
+#include <winperf.h>
+#include <iphlpapi.h>
+#include <psapi.h>
+#include <tlhelp32.h>
+#include <windows.h>
+#include <userenv.h>
+
+
+/*
+ * Max title length; the only thing MSDN tells us about the maximum length
+ * of the console title is that it is smaller than 64K. However in practice
+ * it is much smaller, and there is no way to figure out what the exact length
+ * of the title is or can be, at least not on XP. To make it even more
+ * annoying, GetConsoleTitle fails when the buffer to be read into is bigger
+ * than the actual maximum length. So we make a conservative guess here;
+ * just don't put the novel you're writing in the title, unless the plot
+ * survives truncation.
+ */
+#define MAX_TITLE_LENGTH 8192
+
+/* The number of nanoseconds in one second. */
+#define UV__NANOSEC 1000000000
+
+
+/* Cached copy of the process title, plus a mutex guarding it. */
+static char *process_title;
+static CRITICAL_SECTION process_title_lock;
+
+/* Cached copy of the process id, written once. */
+static DWORD current_pid = 0;
+
+
+/* Interval (in seconds) of the high-resolution clock. */
+static double hrtime_interval_ = 0;
+
+
+/*
+ * One-time initialization code for functionality defined in util.c.
+ */
+void uv__util_init() {
+ LARGE_INTEGER perf_frequency;
+
+ /* Initialize process title access mutex. */
+ InitializeCriticalSection(&process_title_lock);
+
+ /* Retrieve high-resolution timer frequency
+ * and precompute its reciprocal.
+ */
+ if (QueryPerformanceFrequency(&perf_frequency)) {
+ hrtime_interval_ = 1.0 / perf_frequency.QuadPart;
+ } else {
+ hrtime_interval_= 0;
+ }
+}
+
+
+int uv_utf16_to_utf8(const WCHAR* utf16Buffer, size_t utf16Size,
+ char* utf8Buffer, size_t utf8Size) {
+ return WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16Buffer,
+ utf16Size,
+ utf8Buffer,
+ utf8Size,
+ NULL,
+ NULL);
+}
+
+
+int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer,
+ size_t utf16Size) {
+ return MultiByteToWideChar(CP_UTF8,
+ 0,
+ utf8Buffer,
+ -1,
+ utf16Buffer,
+ utf16Size);
+}
+
+
+int uv_exepath(char* buffer, size_t* size_ptr) {
+ int utf8_len, utf16_buffer_len, utf16_len;
+ WCHAR* utf16_buffer;
+ int err;
+
+ if (buffer == NULL || size_ptr == NULL || *size_ptr == 0) {
+ return UV_EINVAL;
+ }
+
+ if (*size_ptr > 32768) {
+ /* Windows paths can never be longer than this. */
+ utf16_buffer_len = 32768;
+ } else {
+ utf16_buffer_len = (int) *size_ptr;
+ }
+
+ utf16_buffer = (WCHAR*) uv__malloc(sizeof(WCHAR) * utf16_buffer_len);
+ if (!utf16_buffer) {
+ return UV_ENOMEM;
+ }
+
+ /* Get the path as UTF-16. */
+ utf16_len = GetModuleFileNameW(NULL, utf16_buffer, utf16_buffer_len);
+ if (utf16_len <= 0) {
+ err = GetLastError();
+ goto error;
+ }
+
+ /* utf16_len contains the length, *not* including the terminating null. */
+ utf16_buffer[utf16_len] = L'\0';
+
+ /* Convert to UTF-8 */
+ utf8_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16_buffer,
+ -1,
+ buffer,
+ *size_ptr > INT_MAX ? INT_MAX : (int) *size_ptr,
+ NULL,
+ NULL);
+ if (utf8_len == 0) {
+ err = GetLastError();
+ goto error;
+ }
+
+ uv__free(utf16_buffer);
+
+ /* utf8_len *does* include the terminating null at this point, but the */
+ /* returned size shouldn't. */
+ *size_ptr = utf8_len - 1;
+ return 0;
+
+ error:
+ uv__free(utf16_buffer);
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_cwd(char* buffer, size_t* size) {
+ DWORD utf16_len;
+ WCHAR utf16_buffer[MAX_PATH];
+ int r;
+
+ if (buffer == NULL || size == NULL) {
+ return UV_EINVAL;
+ }
+
+ utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
+ if (utf16_len == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (utf16_len > MAX_PATH) {
+ /* This should be impossible; however the CRT has a code path to deal */
+ /* with this scenario, so I added a check anyway. */
+ return UV_EIO;
+ }
+
+ /* utf16_len contains the length, *not* including the terminating null. */
+ utf16_buffer[utf16_len] = L'\0';
+
+ /* The returned directory should not have a trailing slash, unless it */
+ /* points at a drive root, like c:\. Remove it if needed.*/
+ if (utf16_buffer[utf16_len - 1] == L'\\' &&
+ !(utf16_len == 3 && utf16_buffer[1] == L':')) {
+ utf16_len--;
+ utf16_buffer[utf16_len] = L'\0';
+ }
+
+ /* Check how much space we need */
+ r = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16_buffer,
+ -1,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ if (r == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (r > (int) *size) {
+ *size = r -1;
+ return UV_ENOBUFS;
+ }
+
+ /* Convert to UTF-8 */
+ r = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16_buffer,
+ -1,
+ buffer,
+ *size > INT_MAX ? INT_MAX : (int) *size,
+ NULL,
+ NULL);
+ if (r == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ *size = r - 1;
+ return 0;
+}
+
+
+int uv_chdir(const char* dir) {
+ WCHAR utf16_buffer[MAX_PATH];
+ size_t utf16_len;
+ WCHAR drive_letter, env_var[4];
+
+ if (dir == NULL) {
+ return UV_EINVAL;
+ }
+
+ if (MultiByteToWideChar(CP_UTF8,
+ 0,
+ dir,
+ -1,
+ utf16_buffer,
+ MAX_PATH) == 0) {
+ DWORD error = GetLastError();
+ /* The maximum length of the current working directory is 260 chars, */
+ /* including terminating null. If it doesn't fit, the path name must be */
+ /* too long. */
+ if (error == ERROR_INSUFFICIENT_BUFFER) {
+ return UV_ENAMETOOLONG;
+ } else {
+ return uv_translate_sys_error(error);
+ }
+ }
+
+ if (!SetCurrentDirectoryW(utf16_buffer)) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ /* Windows stores the drive-local path in an "hidden" environment variable, */
+ /* which has the form "=C:=C:\Windows". SetCurrentDirectory does not */
+ /* update this, so we'll have to do it. */
+ utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
+ if (utf16_len == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (utf16_len > MAX_PATH) {
+ return UV_EIO;
+ }
+
+ /* The returned directory should not have a trailing slash, unless it */
+ /* points at a drive root, like c:\. Remove it if needed. */
+ if (utf16_buffer[utf16_len - 1] == L'\\' &&
+ !(utf16_len == 3 && utf16_buffer[1] == L':')) {
+ utf16_len--;
+ utf16_buffer[utf16_len] = L'\0';
+ }
+
+ if (utf16_len < 2 || utf16_buffer[1] != L':') {
+ /* Doesn't look like a drive letter could be there - probably an UNC */
+ /* path. TODO: Need to handle win32 namespaces like \\?\C:\ ? */
+ drive_letter = 0;
+ } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') {
+ drive_letter = utf16_buffer[0];
+ } else if (utf16_buffer[0] >= L'a' && utf16_buffer[0] <= L'z') {
+ /* Convert to uppercase. */
+ drive_letter = utf16_buffer[0] - L'a' + L'A';
+ } else {
+ /* Not valid. */
+ drive_letter = 0;
+ }
+
+ if (drive_letter != 0) {
+ /* Construct the environment variable name and set it. */
+ env_var[0] = L'=';
+ env_var[1] = drive_letter;
+ env_var[2] = L':';
+ env_var[3] = L'\0';
+
+ if (!SetEnvironmentVariableW(env_var, utf16_buffer)) {
+ return uv_translate_sys_error(GetLastError());
+ }
+ }
+
+ return 0;
+}
+
+
+void uv_loadavg(double avg[3]) {
+ /* Can't be implemented */
+ avg[0] = avg[1] = avg[2] = 0;
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ MEMORYSTATUSEX memory_status;
+ memory_status.dwLength = sizeof(memory_status);
+
+ if (!GlobalMemoryStatusEx(&memory_status)) {
+ return -1;
+ }
+
+ return (uint64_t)memory_status.ullAvailPhys;
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ MEMORYSTATUSEX memory_status;
+ memory_status.dwLength = sizeof(memory_status);
+
+ if (!GlobalMemoryStatusEx(&memory_status)) {
+ return -1;
+ }
+
+ return (uint64_t)memory_status.ullTotalPhys;
+}
+
+
+int uv_parent_pid() {
+ int parent_pid = -1;
+ HANDLE handle;
+ PROCESSENTRY32 pe;
+ DWORD current_pid = GetCurrentProcessId();
+
+ pe.dwSize = sizeof(PROCESSENTRY32);
+ handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+
+ if (Process32First(handle, &pe)) {
+ do {
+ if (pe.th32ProcessID == current_pid) {
+ parent_pid = pe.th32ParentProcessID;
+ break;
+ }
+ } while( Process32Next(handle, &pe));
+ }
+
+ CloseHandle(handle);
+ return parent_pid;
+}
+
+
+int uv_current_pid() {
+ if (current_pid == 0) {
+ current_pid = GetCurrentProcessId();
+ }
+ return current_pid;
+}
+
+
+char** uv_setup_args(int argc, char** argv) {
+ return argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ int err;
+ int length;
+ WCHAR* title_w = NULL;
+
+ uv__once_init();
+
+ /* Find out how big the buffer for the wide-char title must be */
+ length = uv_utf8_to_utf16(title, NULL, 0);
+ if (!length) {
+ err = GetLastError();
+ goto done;
+ }
+
+ /* Convert to wide-char string */
+ title_w = (WCHAR*)uv__malloc(sizeof(WCHAR) * length);
+ if (!title_w) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ length = uv_utf8_to_utf16(title, title_w, length);
+ if (!length) {
+ err = GetLastError();
+ goto done;
+ }
+
+ /* If the title must be truncated insert a \0 terminator there */
+ if (length > MAX_TITLE_LENGTH) {
+ title_w[MAX_TITLE_LENGTH - 1] = L'\0';
+ }
+
+ if (!SetConsoleTitleW(title_w)) {
+ err = GetLastError();
+ goto done;
+ }
+
+ EnterCriticalSection(&process_title_lock);
+ uv__free(process_title);
+ process_title = uv__strdup(title);
+ LeaveCriticalSection(&process_title_lock);
+
+ err = 0;
+
+done:
+ uv__free(title_w);
+ return uv_translate_sys_error(err);
+}
+
+
+static int uv__get_process_title() {
+ WCHAR title_w[MAX_TITLE_LENGTH];
+ int length;
+
+ if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) {
+ return -1;
+ }
+
+ /* Find out what the size of the buffer is that we need */
+ length = uv_utf16_to_utf8(title_w, -1, NULL, 0);
+ if (!length) {
+ return -1;
+ }
+
+ assert(!process_title);
+ process_title = (char*)uv__malloc(length);
+ if (!process_title) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ /* Do utf16 -> utf8 conversion here */
+ if (!uv_utf16_to_utf8(title_w, -1, process_title, length)) {
+ uv__free(process_title);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ uv__once_init();
+
+ EnterCriticalSection(&process_title_lock);
+ /*
+ * If the process_title was never read before nor explicitly set,
+ * we must query it with getConsoleTitleW
+ */
+ if (!process_title && uv__get_process_title() == -1) {
+ LeaveCriticalSection(&process_title_lock);
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ assert(process_title);
+ strncpy(buffer, process_title, size);
+ LeaveCriticalSection(&process_title_lock);
+
+ return 0;
+}
+
+
+uint64_t uv_hrtime(void) {
+ uv__once_init();
+ return uv__hrtime(UV__NANOSEC);
+}
+
+uint64_t uv__hrtime(double scale) {
+ LARGE_INTEGER counter;
+
+ /* If the performance interval is zero, there's no support. */
+ if (hrtime_interval_ == 0) {
+ return 0;
+ }
+
+ if (!QueryPerformanceCounter(&counter)) {
+ return 0;
+ }
+
+ /* Because we have no guarantee about the order of magnitude of the
+ * performance counter interval, integer math could cause this computation
+ * to overflow. Therefore we resort to floating point math.
+ */
+ return (uint64_t) ((double) counter.QuadPart * hrtime_interval_ * scale);
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ HANDLE current_process;
+ PROCESS_MEMORY_COUNTERS pmc;
+
+ current_process = GetCurrentProcess();
+
+ if (!GetProcessMemoryInfo(current_process, &pmc, sizeof(pmc))) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ *rss = pmc.WorkingSetSize;
+
+ return 0;
+}
+
+
+int uv_uptime(double* uptime) {
+ BYTE stack_buffer[4096];
+ BYTE* malloced_buffer = NULL;
+ BYTE* buffer = (BYTE*) stack_buffer;
+ size_t buffer_size = sizeof(stack_buffer);
+ DWORD data_size;
+
+ PERF_DATA_BLOCK* data_block;
+ PERF_OBJECT_TYPE* object_type;
+ PERF_COUNTER_DEFINITION* counter_definition;
+
+ DWORD i;
+
+ for (;;) {
+ LONG result;
+
+ data_size = (DWORD) buffer_size;
+ result = RegQueryValueExW(HKEY_PERFORMANCE_DATA,
+ L"2",
+ NULL,
+ NULL,
+ buffer,
+ &data_size);
+ if (result == ERROR_SUCCESS) {
+ break;
+ } else if (result != ERROR_MORE_DATA) {
+ *uptime = 0;
+ return uv_translate_sys_error(result);
+ }
+
+ buffer_size *= 2;
+ /* Don't let the buffer grow infinitely. */
+ if (buffer_size > 1 << 20) {
+ goto internalError;
+ }
+
+ uv__free(malloced_buffer);
+
+ buffer = malloced_buffer = (BYTE*) uv__malloc(buffer_size);
+ if (malloced_buffer == NULL) {
+ *uptime = 0;
+ return UV_ENOMEM;
+ }
+ }
+
+ if (data_size < sizeof(*data_block))
+ goto internalError;
+
+ data_block = (PERF_DATA_BLOCK*) buffer;
+
+ if (wmemcmp(data_block->Signature, L"PERF", 4) != 0)
+ goto internalError;
+
+ if (data_size < data_block->HeaderLength + sizeof(*object_type))
+ goto internalError;
+
+ object_type = (PERF_OBJECT_TYPE*) (buffer + data_block->HeaderLength);
+
+ if (object_type->NumInstances != PERF_NO_INSTANCES)
+ goto internalError;
+
+ counter_definition = (PERF_COUNTER_DEFINITION*) (buffer +
+ data_block->HeaderLength + object_type->HeaderLength);
+ for (i = 0; i < object_type->NumCounters; i++) {
+ if ((BYTE*) counter_definition + sizeof(*counter_definition) >
+ buffer + data_size) {
+ break;
+ }
+
+ if (counter_definition->CounterNameTitleIndex == 674 &&
+ counter_definition->CounterSize == sizeof(uint64_t)) {
+ if (counter_definition->CounterOffset + sizeof(uint64_t) > data_size ||
+ !(counter_definition->CounterType & PERF_OBJECT_TIMER)) {
+ goto internalError;
+ } else {
+ BYTE* address = (BYTE*) object_type + object_type->DefinitionLength +
+ counter_definition->CounterOffset;
+ uint64_t value = *((uint64_t*) address);
+ *uptime = (double) (object_type->PerfTime.QuadPart - value) /
+ (double) object_type->PerfFreq.QuadPart;
+ uv__free(malloced_buffer);
+ return 0;
+ }
+ }
+
+ counter_definition = (PERF_COUNTER_DEFINITION*)
+ ((BYTE*) counter_definition + counter_definition->ByteLength);
+ }
+
+ /* If we get here, the uptime value was not found. */
+ uv__free(malloced_buffer);
+ *uptime = 0;
+ return UV_ENOSYS;
+
+ internalError:
+ uv__free(malloced_buffer);
+ *uptime = 0;
+ return UV_EIO;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
+ uv_cpu_info_t* cpu_infos;
+ SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi;
+ DWORD sppi_size;
+ SYSTEM_INFO system_info;
+ DWORD cpu_count, r, i;
+ NTSTATUS status;
+ ULONG result_size;
+ int err;
+ uv_cpu_info_t* cpu_info;
+
+ cpu_infos = NULL;
+ cpu_count = 0;
+ sppi = NULL;
+
+ uv__once_init();
+
+ GetSystemInfo(&system_info);
+ cpu_count = system_info.dwNumberOfProcessors;
+
+ cpu_infos = uv__calloc(cpu_count, sizeof *cpu_infos);
+ if (cpu_infos == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto error;
+ }
+
+ sppi_size = cpu_count * sizeof(*sppi);
+ sppi = uv__malloc(sppi_size);
+ if (sppi == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto error;
+ }
+
+ status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation,
+ sppi,
+ sppi_size,
+ &result_size);
+ if (!NT_SUCCESS(status)) {
+ err = pRtlNtStatusToDosError(status);
+ goto error;
+ }
+
+ assert(result_size == sppi_size);
+
+ for (i = 0; i < cpu_count; i++) {
+ WCHAR key_name[128];
+ HKEY processor_key;
+ DWORD cpu_speed;
+ DWORD cpu_speed_size = sizeof(cpu_speed);
+ WCHAR cpu_brand[256];
+ DWORD cpu_brand_size = sizeof(cpu_brand);
+ size_t len;
+
+ len = _snwprintf(key_name,
+ ARRAY_SIZE(key_name),
+ L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d",
+ i);
+
+ assert(len > 0 && len < ARRAY_SIZE(key_name));
+
+ r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ key_name,
+ 0,
+ KEY_QUERY_VALUE,
+ &processor_key);
+ if (r != ERROR_SUCCESS) {
+ err = GetLastError();
+ goto error;
+ }
+
+ if (RegQueryValueExW(processor_key,
+ L"~MHz",
+ NULL,
+ NULL,
+ (BYTE*) &cpu_speed,
+ &cpu_speed_size) != ERROR_SUCCESS) {
+ err = GetLastError();
+ RegCloseKey(processor_key);
+ goto error;
+ }
+
+ if (RegQueryValueExW(processor_key,
+ L"ProcessorNameString",
+ NULL,
+ NULL,
+ (BYTE*) &cpu_brand,
+ &cpu_brand_size) != ERROR_SUCCESS) {
+ err = GetLastError();
+ RegCloseKey(processor_key);
+ goto error;
+ }
+
+ RegCloseKey(processor_key);
+
+ cpu_info = &cpu_infos[i];
+ cpu_info->speed = cpu_speed;
+ cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000;
+ cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart -
+ sppi[i].IdleTime.QuadPart) / 10000;
+ cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000;
+ cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000;
+ cpu_info->cpu_times.nice = 0;
+
+
+ len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ cpu_brand,
+ cpu_brand_size / sizeof(WCHAR),
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ if (len == 0) {
+ err = GetLastError();
+ goto error;
+ }
+
+ assert(len > 0);
+
+ /* Allocate 1 extra byte for the null terminator. */
+ cpu_info->model = uv__malloc(len + 1);
+ if (cpu_info->model == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto error;
+ }
+
+ if (WideCharToMultiByte(CP_UTF8,
+ 0,
+ cpu_brand,
+ cpu_brand_size / sizeof(WCHAR),
+ cpu_info->model,
+ len,
+ NULL,
+ NULL) == 0) {
+ err = GetLastError();
+ goto error;
+ }
+
+ /* Ensure that cpu_info->model is null terminated. */
+ cpu_info->model[len] = '\0';
+ }
+
+ uv__free(sppi);
+
+ *cpu_count_ptr = cpu_count;
+ *cpu_infos_ptr = cpu_infos;
+
+ return 0;
+
+ error:
+ /* This is safe because the cpu_infos array is zeroed on allocation. */
+ for (i = 0; i < cpu_count; i++)
+ uv__free(cpu_infos[i].model);
+
+ uv__free(cpu_infos);
+ uv__free(sppi);
+
+ return uv_translate_sys_error(err);
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+static int is_windows_version_or_greater(DWORD os_major,
+ DWORD os_minor,
+ WORD service_pack_major,
+ WORD service_pack_minor) {
+ OSVERSIONINFOEX osvi;
+ DWORDLONG condition_mask = 0;
+ int op = VER_GREATER_EQUAL;
+
+ /* Initialize the OSVERSIONINFOEX structure. */
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ osvi.dwMajorVersion = os_major;
+ osvi.dwMinorVersion = os_minor;
+ osvi.wServicePackMajor = service_pack_major;
+ osvi.wServicePackMinor = service_pack_minor;
+
+ /* Initialize the condition mask. */
+ VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, op);
+ VER_SET_CONDITION(condition_mask, VER_MINORVERSION, op);
+ VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, op);
+ VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, op);
+
+ /* Perform the test. */
+ return (int) VerifyVersionInfo(
+ &osvi,
+ VER_MAJORVERSION | VER_MINORVERSION |
+ VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
+ condition_mask);
+}
+
+
+static int address_prefix_match(int family,
+ struct sockaddr* address,
+ struct sockaddr* prefix_address,
+ int prefix_len) {
+ uint8_t* address_data;
+ uint8_t* prefix_address_data;
+ int i;
+
+ assert(address->sa_family == family);
+ assert(prefix_address->sa_family == family);
+
+ if (family == AF_INET6) {
+ address_data = (uint8_t*) &(((struct sockaddr_in6 *) address)->sin6_addr);
+ prefix_address_data =
+ (uint8_t*) &(((struct sockaddr_in6 *) prefix_address)->sin6_addr);
+ } else {
+ address_data = (uint8_t*) &(((struct sockaddr_in *) address)->sin_addr);
+ prefix_address_data =
+ (uint8_t*) &(((struct sockaddr_in *) prefix_address)->sin_addr);
+ }
+
+ for (i = 0; i < prefix_len >> 3; i++) {
+ if (address_data[i] != prefix_address_data[i])
+ return 0;
+ }
+
+ if (prefix_len % 8)
+ return prefix_address_data[i] ==
+ (address_data[i] & (0xff << (8 - prefix_len % 8)));
+
+ return 1;
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
+ int* count_ptr) {
+ IP_ADAPTER_ADDRESSES* win_address_buf;
+ ULONG win_address_buf_size;
+ IP_ADAPTER_ADDRESSES* adapter;
+
+ uv_interface_address_t* uv_address_buf;
+ char* name_buf;
+ size_t uv_address_buf_size;
+ uv_interface_address_t* uv_address;
+
+ int count;
+
+ int is_vista_or_greater;
+ ULONG flags;
+
+ is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0);
+ if (is_vista_or_greater) {
+ flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
+ GAA_FLAG_SKIP_DNS_SERVER;
+ } else {
+ /* We need at least XP SP1. */
+ if (!is_windows_version_or_greater(5, 1, 1, 0))
+ return UV_ENOTSUP;
+
+ flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
+ GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX;
+ }
+
+
+ /* Fetch the size of the adapters reported by windows, and then get the */
+ /* list itself. */
+ win_address_buf_size = 0;
+ win_address_buf = NULL;
+
+ for (;;) {
+ ULONG r;
+
+ /* If win_address_buf is 0, then GetAdaptersAddresses will fail with */
+ /* ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in */
+ /* win_address_buf_size. */
+ r = GetAdaptersAddresses(AF_UNSPEC,
+ flags,
+ NULL,
+ win_address_buf,
+ &win_address_buf_size);
+
+ if (r == ERROR_SUCCESS)
+ break;
+
+ uv__free(win_address_buf);
+
+ switch (r) {
+ case ERROR_BUFFER_OVERFLOW:
+ /* This happens when win_address_buf is NULL or too small to hold */
+ /* all adapters. */
+ win_address_buf = uv__malloc(win_address_buf_size);
+ if (win_address_buf == NULL)
+ return UV_ENOMEM;
+
+ continue;
+
+ case ERROR_NO_DATA: {
+ /* No adapters were found. */
+ uv_address_buf = uv__malloc(1);
+ if (uv_address_buf == NULL)
+ return UV_ENOMEM;
+
+ *count_ptr = 0;
+ *addresses_ptr = uv_address_buf;
+
+ return 0;
+ }
+
+ case ERROR_ADDRESS_NOT_ASSOCIATED:
+ return UV_EAGAIN;
+
+ case ERROR_INVALID_PARAMETER:
+ /* MSDN says:
+ * "This error is returned for any of the following conditions: the
+ * SizePointer parameter is NULL, the Address parameter is not
+ * AF_INET, AF_INET6, or AF_UNSPEC, or the address information for
+ * the parameters requested is greater than ULONG_MAX."
+ * Since the first two conditions are not met, it must be that the
+ * adapter data is too big.
+ */
+ return UV_ENOBUFS;
+
+ default:
+ /* Other (unspecified) errors can happen, but we don't have any */
+ /* special meaning for them. */
+ assert(r != ERROR_SUCCESS);
+ return uv_translate_sys_error(r);
+ }
+ }
+
+ /* Count the number of enabled interfaces and compute how much space is */
+ /* needed to store their info. */
+ count = 0;
+ uv_address_buf_size = 0;
+
+ for (adapter = win_address_buf;
+ adapter != NULL;
+ adapter = adapter->Next) {
+ IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
+ int name_size;
+
+ /* Interfaces that are not 'up' should not be reported. Also skip */
+ /* interfaces that have no associated unicast address, as to avoid */
+ /* allocating space for the name for this interface. */
+ if (adapter->OperStatus != IfOperStatusUp ||
+ adapter->FirstUnicastAddress == NULL)
+ continue;
+
+ /* Compute the size of the interface name. */
+ name_size = WideCharToMultiByte(CP_UTF8,
+ 0,
+ adapter->FriendlyName,
+ -1,
+ NULL,
+ 0,
+ NULL,
+ FALSE);
+ if (name_size <= 0) {
+ uv__free(win_address_buf);
+ return uv_translate_sys_error(GetLastError());
+ }
+ uv_address_buf_size += name_size;
+
+ /* Count the number of addresses associated with this interface, and */
+ /* compute the size. */
+ for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
+ adapter->FirstUnicastAddress;
+ unicast_address != NULL;
+ unicast_address = unicast_address->Next) {
+ count++;
+ uv_address_buf_size += sizeof(uv_interface_address_t);
+ }
+ }
+
+ /* Allocate space to store interface data plus adapter names. */
+ uv_address_buf = uv__malloc(uv_address_buf_size);
+ if (uv_address_buf == NULL) {
+ uv__free(win_address_buf);
+ return UV_ENOMEM;
+ }
+
+ /* Compute the start of the uv_interface_address_t array, and the place in */
+ /* the buffer where the interface names will be stored. */
+ uv_address = uv_address_buf;
+ name_buf = (char*) (uv_address_buf + count);
+
+ /* Fill out the output buffer. */
+ for (adapter = win_address_buf;
+ adapter != NULL;
+ adapter = adapter->Next) {
+ IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
+ int name_size;
+ size_t max_name_size;
+
+ if (adapter->OperStatus != IfOperStatusUp ||
+ adapter->FirstUnicastAddress == NULL)
+ continue;
+
+ /* Convert the interface name to UTF8. */
+ max_name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf;
+ if (max_name_size > (size_t) INT_MAX)
+ max_name_size = INT_MAX;
+ name_size = WideCharToMultiByte(CP_UTF8,
+ 0,
+ adapter->FriendlyName,
+ -1,
+ name_buf,
+ (int) max_name_size,
+ NULL,
+ FALSE);
+ if (name_size <= 0) {
+ uv__free(win_address_buf);
+ uv__free(uv_address_buf);
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ /* Add an uv_interface_address_t element for every unicast address. */
+ for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
+ adapter->FirstUnicastAddress;
+ unicast_address != NULL;
+ unicast_address = unicast_address->Next) {
+ struct sockaddr* sa;
+ ULONG prefix_len;
+
+ sa = unicast_address->Address.lpSockaddr;
+
+ /* XP has no OnLinkPrefixLength field. */
+ if (is_vista_or_greater) {
+ prefix_len =
+ ((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength;
+ } else {
+ /* Prior to Windows Vista the FirstPrefix pointed to the list with
+ * single prefix for each IP address assigned to the adapter.
+ * Order of FirstPrefix does not match order of FirstUnicastAddress,
+ * so we need to find corresponding prefix.
+ */
+ IP_ADAPTER_PREFIX* prefix;
+ prefix_len = 0;
+
+ for (prefix = adapter->FirstPrefix; prefix; prefix = prefix->Next) {
+ /* We want the longest matching prefix. */
+ if (prefix->Address.lpSockaddr->sa_family != sa->sa_family ||
+ prefix->PrefixLength <= prefix_len)
+ continue;
+
+ if (address_prefix_match(sa->sa_family, sa,
+ prefix->Address.lpSockaddr, prefix->PrefixLength)) {
+ prefix_len = prefix->PrefixLength;
+ }
+ }
+
+ /* If there is no matching prefix information, return a single-host
+ * subnet mask (e.g. 255.255.255.255 for IPv4).
+ */
+ if (!prefix_len)
+ prefix_len = (sa->sa_family == AF_INET6) ? 128 : 32;
+ }
+
+ memset(uv_address, 0, sizeof *uv_address);
+
+ uv_address->name = name_buf;
+
+ if (adapter->PhysicalAddressLength == sizeof(uv_address->phys_addr)) {
+ memcpy(uv_address->phys_addr,
+ adapter->PhysicalAddress,
+ sizeof(uv_address->phys_addr));
+ }
+
+ uv_address->is_internal =
+ (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK);
+
+ if (sa->sa_family == AF_INET6) {
+ uv_address->address.address6 = *((struct sockaddr_in6 *) sa);
+
+ uv_address->netmask.netmask6.sin6_family = AF_INET6;
+ memset(uv_address->netmask.netmask6.sin6_addr.s6_addr, 0xff, prefix_len >> 3);
+ /* This check ensures that we don't write past the size of the data. */
+ if (prefix_len % 8) {
+ uv_address->netmask.netmask6.sin6_addr.s6_addr[prefix_len >> 3] =
+ 0xff << (8 - prefix_len % 8);
+ }
+
+ } else {
+ uv_address->address.address4 = *((struct sockaddr_in *) sa);
+
+ uv_address->netmask.netmask4.sin_family = AF_INET;
+ uv_address->netmask.netmask4.sin_addr.s_addr = (prefix_len > 0) ?
+ htonl(0xffffffff << (32 - prefix_len)) : 0;
+ }
+
+ uv_address++;
+ }
+
+ name_buf += name_size;
+ }
+
+ uv__free(win_address_buf);
+
+ *addresses_ptr = uv_address_buf;
+ *count_ptr = count;
+
+ return 0;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ uv__free(addresses);
+}
+
+
+int uv_getrusage(uv_rusage_t *uv_rusage) {
+ FILETIME createTime, exitTime, kernelTime, userTime;
+ SYSTEMTIME kernelSystemTime, userSystemTime;
+ int ret;
+
+ ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime);
+ if (ret == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ ret = FileTimeToSystemTime(&kernelTime, &kernelSystemTime);
+ if (ret == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ ret = FileTimeToSystemTime(&userTime, &userSystemTime);
+ if (ret == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ memset(uv_rusage, 0, sizeof(*uv_rusage));
+
+ uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 +
+ userSystemTime.wMinute * 60 +
+ userSystemTime.wSecond;
+ uv_rusage->ru_utime.tv_usec = userSystemTime.wMilliseconds * 1000;
+
+ uv_rusage->ru_stime.tv_sec = kernelSystemTime.wHour * 3600 +
+ kernelSystemTime.wMinute * 60 +
+ kernelSystemTime.wSecond;
+ uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000;
+
+ return 0;
+}
+
+
+int uv_os_homedir(char* buffer, size_t* size) {
+ HANDLE token;
+ wchar_t path[MAX_PATH];
+ DWORD bufsize;
+ size_t len;
+ int r;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return UV_EINVAL;
+
+ /* Check if the USERPROFILE environment variable is set first */
+ len = GetEnvironmentVariableW(L"USERPROFILE", path, MAX_PATH);
+
+ if (len == 0) {
+ r = GetLastError();
+ /* Don't return an error if USERPROFILE was not found */
+ if (r != ERROR_ENVVAR_NOT_FOUND)
+ return uv_translate_sys_error(r);
+ } else if (len > MAX_PATH) {
+ /* This should not be possible */
+ return UV_EIO;
+ } else {
+ goto convert_buffer;
+ }
+
+ /* USERPROFILE is not set, so call GetUserProfileDirectoryW() */
+ if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
+ return uv_translate_sys_error(GetLastError());
+
+ bufsize = MAX_PATH;
+ if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
+ r = GetLastError();
+ CloseHandle(token);
+
+ /* This should not be possible */
+ if (r == ERROR_INSUFFICIENT_BUFFER)
+ return UV_EIO;
+
+ return uv_translate_sys_error(r);
+ }
+
+ CloseHandle(token);
+
+convert_buffer:
+
+ /* Check how much space we need */
+ bufsize = uv_utf16_to_utf8(path, -1, NULL, 0);
+ if (bufsize == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (bufsize > *size) {
+ *size = bufsize - 1;
+ return UV_ENOBUFS;
+ }
+
+ /* Convert to UTF-8 */
+ bufsize = uv_utf16_to_utf8(path, -1, buffer, *size);
+ if (bufsize == 0)
+ return uv_translate_sys_error(GetLastError());
+
+ *size = bufsize - 1;
+ return 0;
+}
diff --git a/3rdparty/libuv/src/win/winapi.c b/3rdparty/libuv/src/win/winapi.c
new file mode 100644
index 00000000000..26bd0648668
--- /dev/null
+++ b/3rdparty/libuv/src/win/winapi.c
@@ -0,0 +1,146 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+/* Ntdll function pointers */
+sRtlNtStatusToDosError pRtlNtStatusToDosError;
+sNtDeviceIoControlFile pNtDeviceIoControlFile;
+sNtQueryInformationFile pNtQueryInformationFile;
+sNtSetInformationFile pNtSetInformationFile;
+sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
+sNtQueryDirectoryFile pNtQueryDirectoryFile;
+sNtQuerySystemInformation pNtQuerySystemInformation;
+
+
+/* Kernel32 function pointers */
+sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
+sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
+sCreateSymbolicLinkW pCreateSymbolicLinkW;
+sCancelIoEx pCancelIoEx;
+sInitializeConditionVariable pInitializeConditionVariable;
+sSleepConditionVariableCS pSleepConditionVariableCS;
+sSleepConditionVariableSRW pSleepConditionVariableSRW;
+sWakeAllConditionVariable pWakeAllConditionVariable;
+sWakeConditionVariable pWakeConditionVariable;
+sCancelSynchronousIo pCancelSynchronousIo;
+sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
+
+
+void uv_winapi_init() {
+ HMODULE ntdll_module;
+ HMODULE kernel32_module;
+
+ ntdll_module = GetModuleHandleA("ntdll.dll");
+ if (ntdll_module == NULL) {
+ uv_fatal_error(GetLastError(), "GetModuleHandleA");
+ }
+
+ pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress(
+ ntdll_module,
+ "RtlNtStatusToDosError");
+ if (pRtlNtStatusToDosError == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtDeviceIoControlFile = (sNtDeviceIoControlFile) GetProcAddress(
+ ntdll_module,
+ "NtDeviceIoControlFile");
+ if (pNtDeviceIoControlFile == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtQueryInformationFile = (sNtQueryInformationFile) GetProcAddress(
+ ntdll_module,
+ "NtQueryInformationFile");
+ if (pNtQueryInformationFile == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtSetInformationFile = (sNtSetInformationFile) GetProcAddress(
+ ntdll_module,
+ "NtSetInformationFile");
+ if (pNtSetInformationFile == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtQueryVolumeInformationFile = (sNtQueryVolumeInformationFile)
+ GetProcAddress(ntdll_module, "NtQueryVolumeInformationFile");
+ if (pNtQueryVolumeInformationFile == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtQueryDirectoryFile = (sNtQueryDirectoryFile)
+ GetProcAddress(ntdll_module, "NtQueryDirectoryFile");
+ if (pNtQueryVolumeInformationFile == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtQuerySystemInformation = (sNtQuerySystemInformation) GetProcAddress(
+ ntdll_module,
+ "NtQuerySystemInformation");
+ if (pNtQuerySystemInformation == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ kernel32_module = GetModuleHandleA("kernel32.dll");
+ if (kernel32_module == NULL) {
+ uv_fatal_error(GetLastError(), "GetModuleHandleA");
+ }
+
+ pGetQueuedCompletionStatusEx = (sGetQueuedCompletionStatusEx) GetProcAddress(
+ kernel32_module,
+ "GetQueuedCompletionStatusEx");
+
+ pSetFileCompletionNotificationModes = (sSetFileCompletionNotificationModes)
+ GetProcAddress(kernel32_module, "SetFileCompletionNotificationModes");
+
+ pCreateSymbolicLinkW = (sCreateSymbolicLinkW)
+ GetProcAddress(kernel32_module, "CreateSymbolicLinkW");
+
+ pCancelIoEx = (sCancelIoEx)
+ GetProcAddress(kernel32_module, "CancelIoEx");
+
+ pInitializeConditionVariable = (sInitializeConditionVariable)
+ GetProcAddress(kernel32_module, "InitializeConditionVariable");
+
+ pSleepConditionVariableCS = (sSleepConditionVariableCS)
+ GetProcAddress(kernel32_module, "SleepConditionVariableCS");
+
+ pSleepConditionVariableSRW = (sSleepConditionVariableSRW)
+ GetProcAddress(kernel32_module, "SleepConditionVariableSRW");
+
+ pWakeAllConditionVariable = (sWakeAllConditionVariable)
+ GetProcAddress(kernel32_module, "WakeAllConditionVariable");
+
+ pWakeConditionVariable = (sWakeConditionVariable)
+ GetProcAddress(kernel32_module, "WakeConditionVariable");
+
+ pCancelSynchronousIo = (sCancelSynchronousIo)
+ GetProcAddress(kernel32_module, "CancelSynchronousIo");
+
+ pGetFinalPathNameByHandleW = (sGetFinalPathNameByHandleW)
+ GetProcAddress(kernel32_module, "GetFinalPathNameByHandleW");
+}
diff --git a/3rdparty/libuv/src/win/winapi.h b/3rdparty/libuv/src/win/winapi.h
new file mode 100644
index 00000000000..122198a6d48
--- /dev/null
+++ b/3rdparty/libuv/src/win/winapi.h
@@ -0,0 +1,4710 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_WINAPI_H_
+#define UV_WIN_WINAPI_H_
+
+#include <windows.h>
+
+
+/*
+ * Ntdll headers
+ */
+#ifndef STATUS_SEVERITY_SUCCESS
+# define STATUS_SEVERITY_SUCCESS 0x0
+#endif
+
+#ifndef STATUS_SEVERITY_INFORMATIONAL
+# define STATUS_SEVERITY_INFORMATIONAL 0x1
+#endif
+
+#ifndef STATUS_SEVERITY_WARNING
+# define STATUS_SEVERITY_WARNING 0x2
+#endif
+
+#ifndef STATUS_SEVERITY_ERROR
+# define STATUS_SEVERITY_ERROR 0x3
+#endif
+
+#ifndef FACILITY_NTWIN32
+# define FACILITY_NTWIN32 0x7
+#endif
+
+#ifndef NT_SUCCESS
+# define NT_SUCCESS(status) (((NTSTATUS) (status)) >= 0)
+#endif
+
+#ifndef NT_INFORMATION
+# define NT_INFORMATION(status) ((((ULONG) (status)) >> 30) == 1)
+#endif
+
+#ifndef NT_WARNING
+# define NT_WARNING(status) ((((ULONG) (status)) >> 30) == 2)
+#endif
+
+#ifndef NT_ERROR
+# define NT_ERROR(status) ((((ULONG) (status)) >> 30) == 3)
+#endif
+
+#ifndef STATUS_SUCCESS
+# define STATUS_SUCCESS ((NTSTATUS) 0x00000000L)
+#endif
+
+#ifndef STATUS_WAIT_0
+# define STATUS_WAIT_0 ((NTSTATUS) 0x00000000L)
+#endif
+
+#ifndef STATUS_WAIT_1
+# define STATUS_WAIT_1 ((NTSTATUS) 0x00000001L)
+#endif
+
+#ifndef STATUS_WAIT_2
+# define STATUS_WAIT_2 ((NTSTATUS) 0x00000002L)
+#endif
+
+#ifndef STATUS_WAIT_3
+# define STATUS_WAIT_3 ((NTSTATUS) 0x00000003L)
+#endif
+
+#ifndef STATUS_WAIT_63
+# define STATUS_WAIT_63 ((NTSTATUS) 0x0000003FL)
+#endif
+
+#ifndef STATUS_ABANDONED
+# define STATUS_ABANDONED ((NTSTATUS) 0x00000080L)
+#endif
+
+#ifndef STATUS_ABANDONED_WAIT_0
+# define STATUS_ABANDONED_WAIT_0 ((NTSTATUS) 0x00000080L)
+#endif
+
+#ifndef STATUS_ABANDONED_WAIT_63
+# define STATUS_ABANDONED_WAIT_63 ((NTSTATUS) 0x000000BFL)
+#endif
+
+#ifndef STATUS_USER_APC
+# define STATUS_USER_APC ((NTSTATUS) 0x000000C0L)
+#endif
+
+#ifndef STATUS_KERNEL_APC
+# define STATUS_KERNEL_APC ((NTSTATUS) 0x00000100L)
+#endif
+
+#ifndef STATUS_ALERTED
+# define STATUS_ALERTED ((NTSTATUS) 0x00000101L)
+#endif
+
+#ifndef STATUS_TIMEOUT
+# define STATUS_TIMEOUT ((NTSTATUS) 0x00000102L)
+#endif
+
+#ifndef STATUS_PENDING
+# define STATUS_PENDING ((NTSTATUS) 0x00000103L)
+#endif
+
+#ifndef STATUS_REPARSE
+# define STATUS_REPARSE ((NTSTATUS) 0x00000104L)
+#endif
+
+#ifndef STATUS_MORE_ENTRIES
+# define STATUS_MORE_ENTRIES ((NTSTATUS) 0x00000105L)
+#endif
+
+#ifndef STATUS_NOT_ALL_ASSIGNED
+# define STATUS_NOT_ALL_ASSIGNED ((NTSTATUS) 0x00000106L)
+#endif
+
+#ifndef STATUS_SOME_NOT_MAPPED
+# define STATUS_SOME_NOT_MAPPED ((NTSTATUS) 0x00000107L)
+#endif
+
+#ifndef STATUS_OPLOCK_BREAK_IN_PROGRESS
+# define STATUS_OPLOCK_BREAK_IN_PROGRESS ((NTSTATUS) 0x00000108L)
+#endif
+
+#ifndef STATUS_VOLUME_MOUNTED
+# define STATUS_VOLUME_MOUNTED ((NTSTATUS) 0x00000109L)
+#endif
+
+#ifndef STATUS_RXACT_COMMITTED
+# define STATUS_RXACT_COMMITTED ((NTSTATUS) 0x0000010AL)
+#endif
+
+#ifndef STATUS_NOTIFY_CLEANUP
+# define STATUS_NOTIFY_CLEANUP ((NTSTATUS) 0x0000010BL)
+#endif
+
+#ifndef STATUS_NOTIFY_ENUM_DIR
+# define STATUS_NOTIFY_ENUM_DIR ((NTSTATUS) 0x0000010CL)
+#endif
+
+#ifndef STATUS_NO_QUOTAS_FOR_ACCOUNT
+# define STATUS_NO_QUOTAS_FOR_ACCOUNT ((NTSTATUS) 0x0000010DL)
+#endif
+
+#ifndef STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED
+# define STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED ((NTSTATUS) 0x0000010EL)
+#endif
+
+#ifndef STATUS_PAGE_FAULT_TRANSITION
+# define STATUS_PAGE_FAULT_TRANSITION ((NTSTATUS) 0x00000110L)
+#endif
+
+#ifndef STATUS_PAGE_FAULT_DEMAND_ZERO
+# define STATUS_PAGE_FAULT_DEMAND_ZERO ((NTSTATUS) 0x00000111L)
+#endif
+
+#ifndef STATUS_PAGE_FAULT_COPY_ON_WRITE
+# define STATUS_PAGE_FAULT_COPY_ON_WRITE ((NTSTATUS) 0x00000112L)
+#endif
+
+#ifndef STATUS_PAGE_FAULT_GUARD_PAGE
+# define STATUS_PAGE_FAULT_GUARD_PAGE ((NTSTATUS) 0x00000113L)
+#endif
+
+#ifndef STATUS_PAGE_FAULT_PAGING_FILE
+# define STATUS_PAGE_FAULT_PAGING_FILE ((NTSTATUS) 0x00000114L)
+#endif
+
+#ifndef STATUS_CACHE_PAGE_LOCKED
+# define STATUS_CACHE_PAGE_LOCKED ((NTSTATUS) 0x00000115L)
+#endif
+
+#ifndef STATUS_CRASH_DUMP
+# define STATUS_CRASH_DUMP ((NTSTATUS) 0x00000116L)
+#endif
+
+#ifndef STATUS_BUFFER_ALL_ZEROS
+# define STATUS_BUFFER_ALL_ZEROS ((NTSTATUS) 0x00000117L)
+#endif
+
+#ifndef STATUS_REPARSE_OBJECT
+# define STATUS_REPARSE_OBJECT ((NTSTATUS) 0x00000118L)
+#endif
+
+#ifndef STATUS_RESOURCE_REQUIREMENTS_CHANGED
+# define STATUS_RESOURCE_REQUIREMENTS_CHANGED ((NTSTATUS) 0x00000119L)
+#endif
+
+#ifndef STATUS_TRANSLATION_COMPLETE
+# define STATUS_TRANSLATION_COMPLETE ((NTSTATUS) 0x00000120L)
+#endif
+
+#ifndef STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY
+# define STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY ((NTSTATUS) 0x00000121L)
+#endif
+
+#ifndef STATUS_NOTHING_TO_TERMINATE
+# define STATUS_NOTHING_TO_TERMINATE ((NTSTATUS) 0x00000122L)
+#endif
+
+#ifndef STATUS_PROCESS_NOT_IN_JOB
+# define STATUS_PROCESS_NOT_IN_JOB ((NTSTATUS) 0x00000123L)
+#endif
+
+#ifndef STATUS_PROCESS_IN_JOB
+# define STATUS_PROCESS_IN_JOB ((NTSTATUS) 0x00000124L)
+#endif
+
+#ifndef STATUS_VOLSNAP_HIBERNATE_READY
+# define STATUS_VOLSNAP_HIBERNATE_READY ((NTSTATUS) 0x00000125L)
+#endif
+
+#ifndef STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY
+# define STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY ((NTSTATUS) 0x00000126L)
+#endif
+
+#ifndef STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED
+# define STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED ((NTSTATUS) 0x00000127L)
+#endif
+
+#ifndef STATUS_INTERRUPT_STILL_CONNECTED
+# define STATUS_INTERRUPT_STILL_CONNECTED ((NTSTATUS) 0x00000128L)
+#endif
+
+#ifndef STATUS_PROCESS_CLONED
+# define STATUS_PROCESS_CLONED ((NTSTATUS) 0x00000129L)
+#endif
+
+#ifndef STATUS_FILE_LOCKED_WITH_ONLY_READERS
+# define STATUS_FILE_LOCKED_WITH_ONLY_READERS ((NTSTATUS) 0x0000012AL)
+#endif
+
+#ifndef STATUS_FILE_LOCKED_WITH_WRITERS
+# define STATUS_FILE_LOCKED_WITH_WRITERS ((NTSTATUS) 0x0000012BL)
+#endif
+
+#ifndef STATUS_RESOURCEMANAGER_READ_ONLY
+# define STATUS_RESOURCEMANAGER_READ_ONLY ((NTSTATUS) 0x00000202L)
+#endif
+
+#ifndef STATUS_RING_PREVIOUSLY_EMPTY
+# define STATUS_RING_PREVIOUSLY_EMPTY ((NTSTATUS) 0x00000210L)
+#endif
+
+#ifndef STATUS_RING_PREVIOUSLY_FULL
+# define STATUS_RING_PREVIOUSLY_FULL ((NTSTATUS) 0x00000211L)
+#endif
+
+#ifndef STATUS_RING_PREVIOUSLY_ABOVE_QUOTA
+# define STATUS_RING_PREVIOUSLY_ABOVE_QUOTA ((NTSTATUS) 0x00000212L)
+#endif
+
+#ifndef STATUS_RING_NEWLY_EMPTY
+# define STATUS_RING_NEWLY_EMPTY ((NTSTATUS) 0x00000213L)
+#endif
+
+#ifndef STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT
+# define STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT ((NTSTATUS) 0x00000214L)
+#endif
+
+#ifndef STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE
+# define STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE ((NTSTATUS) 0x00000215L)
+#endif
+
+#ifndef STATUS_OPLOCK_HANDLE_CLOSED
+# define STATUS_OPLOCK_HANDLE_CLOSED ((NTSTATUS) 0x00000216L)
+#endif
+
+#ifndef STATUS_WAIT_FOR_OPLOCK
+# define STATUS_WAIT_FOR_OPLOCK ((NTSTATUS) 0x00000367L)
+#endif
+
+#ifndef STATUS_OBJECT_NAME_EXISTS
+# define STATUS_OBJECT_NAME_EXISTS ((NTSTATUS) 0x40000000L)
+#endif
+
+#ifndef STATUS_THREAD_WAS_SUSPENDED
+# define STATUS_THREAD_WAS_SUSPENDED ((NTSTATUS) 0x40000001L)
+#endif
+
+#ifndef STATUS_WORKING_SET_LIMIT_RANGE
+# define STATUS_WORKING_SET_LIMIT_RANGE ((NTSTATUS) 0x40000002L)
+#endif
+
+#ifndef STATUS_IMAGE_NOT_AT_BASE
+# define STATUS_IMAGE_NOT_AT_BASE ((NTSTATUS) 0x40000003L)
+#endif
+
+#ifndef STATUS_RXACT_STATE_CREATED
+# define STATUS_RXACT_STATE_CREATED ((NTSTATUS) 0x40000004L)
+#endif
+
+#ifndef STATUS_SEGMENT_NOTIFICATION
+# define STATUS_SEGMENT_NOTIFICATION ((NTSTATUS) 0x40000005L)
+#endif
+
+#ifndef STATUS_LOCAL_USER_SESSION_KEY
+# define STATUS_LOCAL_USER_SESSION_KEY ((NTSTATUS) 0x40000006L)
+#endif
+
+#ifndef STATUS_BAD_CURRENT_DIRECTORY
+# define STATUS_BAD_CURRENT_DIRECTORY ((NTSTATUS) 0x40000007L)
+#endif
+
+#ifndef STATUS_SERIAL_MORE_WRITES
+# define STATUS_SERIAL_MORE_WRITES ((NTSTATUS) 0x40000008L)
+#endif
+
+#ifndef STATUS_REGISTRY_RECOVERED
+# define STATUS_REGISTRY_RECOVERED ((NTSTATUS) 0x40000009L)
+#endif
+
+#ifndef STATUS_FT_READ_RECOVERY_FROM_BACKUP
+# define STATUS_FT_READ_RECOVERY_FROM_BACKUP ((NTSTATUS) 0x4000000AL)
+#endif
+
+#ifndef STATUS_FT_WRITE_RECOVERY
+# define STATUS_FT_WRITE_RECOVERY ((NTSTATUS) 0x4000000BL)
+#endif
+
+#ifndef STATUS_SERIAL_COUNTER_TIMEOUT
+# define STATUS_SERIAL_COUNTER_TIMEOUT ((NTSTATUS) 0x4000000CL)
+#endif
+
+#ifndef STATUS_NULL_LM_PASSWORD
+# define STATUS_NULL_LM_PASSWORD ((NTSTATUS) 0x4000000DL)
+#endif
+
+#ifndef STATUS_IMAGE_MACHINE_TYPE_MISMATCH
+# define STATUS_IMAGE_MACHINE_TYPE_MISMATCH ((NTSTATUS) 0x4000000EL)
+#endif
+
+#ifndef STATUS_RECEIVE_PARTIAL
+# define STATUS_RECEIVE_PARTIAL ((NTSTATUS) 0x4000000FL)
+#endif
+
+#ifndef STATUS_RECEIVE_EXPEDITED
+# define STATUS_RECEIVE_EXPEDITED ((NTSTATUS) 0x40000010L)
+#endif
+
+#ifndef STATUS_RECEIVE_PARTIAL_EXPEDITED
+# define STATUS_RECEIVE_PARTIAL_EXPEDITED ((NTSTATUS) 0x40000011L)
+#endif
+
+#ifndef STATUS_EVENT_DONE
+# define STATUS_EVENT_DONE ((NTSTATUS) 0x40000012L)
+#endif
+
+#ifndef STATUS_EVENT_PENDING
+# define STATUS_EVENT_PENDING ((NTSTATUS) 0x40000013L)
+#endif
+
+#ifndef STATUS_CHECKING_FILE_SYSTEM
+# define STATUS_CHECKING_FILE_SYSTEM ((NTSTATUS) 0x40000014L)
+#endif
+
+#ifndef STATUS_FATAL_APP_EXIT
+# define STATUS_FATAL_APP_EXIT ((NTSTATUS) 0x40000015L)
+#endif
+
+#ifndef STATUS_PREDEFINED_HANDLE
+# define STATUS_PREDEFINED_HANDLE ((NTSTATUS) 0x40000016L)
+#endif
+
+#ifndef STATUS_WAS_UNLOCKED
+# define STATUS_WAS_UNLOCKED ((NTSTATUS) 0x40000017L)
+#endif
+
+#ifndef STATUS_SERVICE_NOTIFICATION
+# define STATUS_SERVICE_NOTIFICATION ((NTSTATUS) 0x40000018L)
+#endif
+
+#ifndef STATUS_WAS_LOCKED
+# define STATUS_WAS_LOCKED ((NTSTATUS) 0x40000019L)
+#endif
+
+#ifndef STATUS_LOG_HARD_ERROR
+# define STATUS_LOG_HARD_ERROR ((NTSTATUS) 0x4000001AL)
+#endif
+
+#ifndef STATUS_ALREADY_WIN32
+# define STATUS_ALREADY_WIN32 ((NTSTATUS) 0x4000001BL)
+#endif
+
+#ifndef STATUS_WX86_UNSIMULATE
+# define STATUS_WX86_UNSIMULATE ((NTSTATUS) 0x4000001CL)
+#endif
+
+#ifndef STATUS_WX86_CONTINUE
+# define STATUS_WX86_CONTINUE ((NTSTATUS) 0x4000001DL)
+#endif
+
+#ifndef STATUS_WX86_SINGLE_STEP
+# define STATUS_WX86_SINGLE_STEP ((NTSTATUS) 0x4000001EL)
+#endif
+
+#ifndef STATUS_WX86_BREAKPOINT
+# define STATUS_WX86_BREAKPOINT ((NTSTATUS) 0x4000001FL)
+#endif
+
+#ifndef STATUS_WX86_EXCEPTION_CONTINUE
+# define STATUS_WX86_EXCEPTION_CONTINUE ((NTSTATUS) 0x40000020L)
+#endif
+
+#ifndef STATUS_WX86_EXCEPTION_LASTCHANCE
+# define STATUS_WX86_EXCEPTION_LASTCHANCE ((NTSTATUS) 0x40000021L)
+#endif
+
+#ifndef STATUS_WX86_EXCEPTION_CHAIN
+# define STATUS_WX86_EXCEPTION_CHAIN ((NTSTATUS) 0x40000022L)
+#endif
+
+#ifndef STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE
+# define STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE ((NTSTATUS) 0x40000023L)
+#endif
+
+#ifndef STATUS_NO_YIELD_PERFORMED
+# define STATUS_NO_YIELD_PERFORMED ((NTSTATUS) 0x40000024L)
+#endif
+
+#ifndef STATUS_TIMER_RESUME_IGNORED
+# define STATUS_TIMER_RESUME_IGNORED ((NTSTATUS) 0x40000025L)
+#endif
+
+#ifndef STATUS_ARBITRATION_UNHANDLED
+# define STATUS_ARBITRATION_UNHANDLED ((NTSTATUS) 0x40000026L)
+#endif
+
+#ifndef STATUS_CARDBUS_NOT_SUPPORTED
+# define STATUS_CARDBUS_NOT_SUPPORTED ((NTSTATUS) 0x40000027L)
+#endif
+
+#ifndef STATUS_WX86_CREATEWX86TIB
+# define STATUS_WX86_CREATEWX86TIB ((NTSTATUS) 0x40000028L)
+#endif
+
+#ifndef STATUS_MP_PROCESSOR_MISMATCH
+# define STATUS_MP_PROCESSOR_MISMATCH ((NTSTATUS) 0x40000029L)
+#endif
+
+#ifndef STATUS_HIBERNATED
+# define STATUS_HIBERNATED ((NTSTATUS) 0x4000002AL)
+#endif
+
+#ifndef STATUS_RESUME_HIBERNATION
+# define STATUS_RESUME_HIBERNATION ((NTSTATUS) 0x4000002BL)
+#endif
+
+#ifndef STATUS_FIRMWARE_UPDATED
+# define STATUS_FIRMWARE_UPDATED ((NTSTATUS) 0x4000002CL)
+#endif
+
+#ifndef STATUS_DRIVERS_LEAKING_LOCKED_PAGES
+# define STATUS_DRIVERS_LEAKING_LOCKED_PAGES ((NTSTATUS) 0x4000002DL)
+#endif
+
+#ifndef STATUS_MESSAGE_RETRIEVED
+# define STATUS_MESSAGE_RETRIEVED ((NTSTATUS) 0x4000002EL)
+#endif
+
+#ifndef STATUS_SYSTEM_POWERSTATE_TRANSITION
+# define STATUS_SYSTEM_POWERSTATE_TRANSITION ((NTSTATUS) 0x4000002FL)
+#endif
+
+#ifndef STATUS_ALPC_CHECK_COMPLETION_LIST
+# define STATUS_ALPC_CHECK_COMPLETION_LIST ((NTSTATUS) 0x40000030L)
+#endif
+
+#ifndef STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION
+# define STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION ((NTSTATUS) 0x40000031L)
+#endif
+
+#ifndef STATUS_ACCESS_AUDIT_BY_POLICY
+# define STATUS_ACCESS_AUDIT_BY_POLICY ((NTSTATUS) 0x40000032L)
+#endif
+
+#ifndef STATUS_ABANDON_HIBERFILE
+# define STATUS_ABANDON_HIBERFILE ((NTSTATUS) 0x40000033L)
+#endif
+
+#ifndef STATUS_BIZRULES_NOT_ENABLED
+# define STATUS_BIZRULES_NOT_ENABLED ((NTSTATUS) 0x40000034L)
+#endif
+
+#ifndef STATUS_GUARD_PAGE_VIOLATION
+# define STATUS_GUARD_PAGE_VIOLATION ((NTSTATUS) 0x80000001L)
+#endif
+
+#ifndef STATUS_DATATYPE_MISALIGNMENT
+# define STATUS_DATATYPE_MISALIGNMENT ((NTSTATUS) 0x80000002L)
+#endif
+
+#ifndef STATUS_BREAKPOINT
+# define STATUS_BREAKPOINT ((NTSTATUS) 0x80000003L)
+#endif
+
+#ifndef STATUS_SINGLE_STEP
+# define STATUS_SINGLE_STEP ((NTSTATUS) 0x80000004L)
+#endif
+
+#ifndef STATUS_BUFFER_OVERFLOW
+# define STATUS_BUFFER_OVERFLOW ((NTSTATUS) 0x80000005L)
+#endif
+
+#ifndef STATUS_NO_MORE_FILES
+# define STATUS_NO_MORE_FILES ((NTSTATUS) 0x80000006L)
+#endif
+
+#ifndef STATUS_WAKE_SYSTEM_DEBUGGER
+# define STATUS_WAKE_SYSTEM_DEBUGGER ((NTSTATUS) 0x80000007L)
+#endif
+
+#ifndef STATUS_HANDLES_CLOSED
+# define STATUS_HANDLES_CLOSED ((NTSTATUS) 0x8000000AL)
+#endif
+
+#ifndef STATUS_NO_INHERITANCE
+# define STATUS_NO_INHERITANCE ((NTSTATUS) 0x8000000BL)
+#endif
+
+#ifndef STATUS_GUID_SUBSTITUTION_MADE
+# define STATUS_GUID_SUBSTITUTION_MADE ((NTSTATUS) 0x8000000CL)
+#endif
+
+#ifndef STATUS_PARTIAL_COPY
+# define STATUS_PARTIAL_COPY ((NTSTATUS) 0x8000000DL)
+#endif
+
+#ifndef STATUS_DEVICE_PAPER_EMPTY
+# define STATUS_DEVICE_PAPER_EMPTY ((NTSTATUS) 0x8000000EL)
+#endif
+
+#ifndef STATUS_DEVICE_POWERED_OFF
+# define STATUS_DEVICE_POWERED_OFF ((NTSTATUS) 0x8000000FL)
+#endif
+
+#ifndef STATUS_DEVICE_OFF_LINE
+# define STATUS_DEVICE_OFF_LINE ((NTSTATUS) 0x80000010L)
+#endif
+
+#ifndef STATUS_DEVICE_BUSY
+# define STATUS_DEVICE_BUSY ((NTSTATUS) 0x80000011L)
+#endif
+
+#ifndef STATUS_NO_MORE_EAS
+# define STATUS_NO_MORE_EAS ((NTSTATUS) 0x80000012L)
+#endif
+
+#ifndef STATUS_INVALID_EA_NAME
+# define STATUS_INVALID_EA_NAME ((NTSTATUS) 0x80000013L)
+#endif
+
+#ifndef STATUS_EA_LIST_INCONSISTENT
+# define STATUS_EA_LIST_INCONSISTENT ((NTSTATUS) 0x80000014L)
+#endif
+
+#ifndef STATUS_INVALID_EA_FLAG
+# define STATUS_INVALID_EA_FLAG ((NTSTATUS) 0x80000015L)
+#endif
+
+#ifndef STATUS_VERIFY_REQUIRED
+# define STATUS_VERIFY_REQUIRED ((NTSTATUS) 0x80000016L)
+#endif
+
+#ifndef STATUS_EXTRANEOUS_INFORMATION
+# define STATUS_EXTRANEOUS_INFORMATION ((NTSTATUS) 0x80000017L)
+#endif
+
+#ifndef STATUS_RXACT_COMMIT_NECESSARY
+# define STATUS_RXACT_COMMIT_NECESSARY ((NTSTATUS) 0x80000018L)
+#endif
+
+#ifndef STATUS_NO_MORE_ENTRIES
+# define STATUS_NO_MORE_ENTRIES ((NTSTATUS) 0x8000001AL)
+#endif
+
+#ifndef STATUS_FILEMARK_DETECTED
+# define STATUS_FILEMARK_DETECTED ((NTSTATUS) 0x8000001BL)
+#endif
+
+#ifndef STATUS_MEDIA_CHANGED
+# define STATUS_MEDIA_CHANGED ((NTSTATUS) 0x8000001CL)
+#endif
+
+#ifndef STATUS_BUS_RESET
+# define STATUS_BUS_RESET ((NTSTATUS) 0x8000001DL)
+#endif
+
+#ifndef STATUS_END_OF_MEDIA
+# define STATUS_END_OF_MEDIA ((NTSTATUS) 0x8000001EL)
+#endif
+
+#ifndef STATUS_BEGINNING_OF_MEDIA
+# define STATUS_BEGINNING_OF_MEDIA ((NTSTATUS) 0x8000001FL)
+#endif
+
+#ifndef STATUS_MEDIA_CHECK
+# define STATUS_MEDIA_CHECK ((NTSTATUS) 0x80000020L)
+#endif
+
+#ifndef STATUS_SETMARK_DETECTED
+# define STATUS_SETMARK_DETECTED ((NTSTATUS) 0x80000021L)
+#endif
+
+#ifndef STATUS_NO_DATA_DETECTED
+# define STATUS_NO_DATA_DETECTED ((NTSTATUS) 0x80000022L)
+#endif
+
+#ifndef STATUS_REDIRECTOR_HAS_OPEN_HANDLES
+# define STATUS_REDIRECTOR_HAS_OPEN_HANDLES ((NTSTATUS) 0x80000023L)
+#endif
+
+#ifndef STATUS_SERVER_HAS_OPEN_HANDLES
+# define STATUS_SERVER_HAS_OPEN_HANDLES ((NTSTATUS) 0x80000024L)
+#endif
+
+#ifndef STATUS_ALREADY_DISCONNECTED
+# define STATUS_ALREADY_DISCONNECTED ((NTSTATUS) 0x80000025L)
+#endif
+
+#ifndef STATUS_LONGJUMP
+# define STATUS_LONGJUMP ((NTSTATUS) 0x80000026L)
+#endif
+
+#ifndef STATUS_CLEANER_CARTRIDGE_INSTALLED
+# define STATUS_CLEANER_CARTRIDGE_INSTALLED ((NTSTATUS) 0x80000027L)
+#endif
+
+#ifndef STATUS_PLUGPLAY_QUERY_VETOED
+# define STATUS_PLUGPLAY_QUERY_VETOED ((NTSTATUS) 0x80000028L)
+#endif
+
+#ifndef STATUS_UNWIND_CONSOLIDATE
+# define STATUS_UNWIND_CONSOLIDATE ((NTSTATUS) 0x80000029L)
+#endif
+
+#ifndef STATUS_REGISTRY_HIVE_RECOVERED
+# define STATUS_REGISTRY_HIVE_RECOVERED ((NTSTATUS) 0x8000002AL)
+#endif
+
+#ifndef STATUS_DLL_MIGHT_BE_INSECURE
+# define STATUS_DLL_MIGHT_BE_INSECURE ((NTSTATUS) 0x8000002BL)
+#endif
+
+#ifndef STATUS_DLL_MIGHT_BE_INCOMPATIBLE
+# define STATUS_DLL_MIGHT_BE_INCOMPATIBLE ((NTSTATUS) 0x8000002CL)
+#endif
+
+#ifndef STATUS_STOPPED_ON_SYMLINK
+# define STATUS_STOPPED_ON_SYMLINK ((NTSTATUS) 0x8000002DL)
+#endif
+
+#ifndef STATUS_CANNOT_GRANT_REQUESTED_OPLOCK
+# define STATUS_CANNOT_GRANT_REQUESTED_OPLOCK ((NTSTATUS) 0x8000002EL)
+#endif
+
+#ifndef STATUS_NO_ACE_CONDITION
+# define STATUS_NO_ACE_CONDITION ((NTSTATUS) 0x8000002FL)
+#endif
+
+#ifndef STATUS_UNSUCCESSFUL
+# define STATUS_UNSUCCESSFUL ((NTSTATUS) 0xC0000001L)
+#endif
+
+#ifndef STATUS_NOT_IMPLEMENTED
+# define STATUS_NOT_IMPLEMENTED ((NTSTATUS) 0xC0000002L)
+#endif
+
+#ifndef STATUS_INVALID_INFO_CLASS
+# define STATUS_INVALID_INFO_CLASS ((NTSTATUS) 0xC0000003L)
+#endif
+
+#ifndef STATUS_INFO_LENGTH_MISMATCH
+# define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xC0000004L)
+#endif
+
+#ifndef STATUS_ACCESS_VIOLATION
+# define STATUS_ACCESS_VIOLATION ((NTSTATUS) 0xC0000005L)
+#endif
+
+#ifndef STATUS_IN_PAGE_ERROR
+# define STATUS_IN_PAGE_ERROR ((NTSTATUS) 0xC0000006L)
+#endif
+
+#ifndef STATUS_PAGEFILE_QUOTA
+# define STATUS_PAGEFILE_QUOTA ((NTSTATUS) 0xC0000007L)
+#endif
+
+#ifndef STATUS_INVALID_HANDLE
+# define STATUS_INVALID_HANDLE ((NTSTATUS) 0xC0000008L)
+#endif
+
+#ifndef STATUS_BAD_INITIAL_STACK
+# define STATUS_BAD_INITIAL_STACK ((NTSTATUS) 0xC0000009L)
+#endif
+
+#ifndef STATUS_BAD_INITIAL_PC
+# define STATUS_BAD_INITIAL_PC ((NTSTATUS) 0xC000000AL)
+#endif
+
+#ifndef STATUS_INVALID_CID
+# define STATUS_INVALID_CID ((NTSTATUS) 0xC000000BL)
+#endif
+
+#ifndef STATUS_TIMER_NOT_CANCELED
+# define STATUS_TIMER_NOT_CANCELED ((NTSTATUS) 0xC000000CL)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER
+# define STATUS_INVALID_PARAMETER ((NTSTATUS) 0xC000000DL)
+#endif
+
+#ifndef STATUS_NO_SUCH_DEVICE
+# define STATUS_NO_SUCH_DEVICE ((NTSTATUS) 0xC000000EL)
+#endif
+
+#ifndef STATUS_NO_SUCH_FILE
+# define STATUS_NO_SUCH_FILE ((NTSTATUS) 0xC000000FL)
+#endif
+
+#ifndef STATUS_INVALID_DEVICE_REQUEST
+# define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS) 0xC0000010L)
+#endif
+
+#ifndef STATUS_END_OF_FILE
+# define STATUS_END_OF_FILE ((NTSTATUS) 0xC0000011L)
+#endif
+
+#ifndef STATUS_WRONG_VOLUME
+# define STATUS_WRONG_VOLUME ((NTSTATUS) 0xC0000012L)
+#endif
+
+#ifndef STATUS_NO_MEDIA_IN_DEVICE
+# define STATUS_NO_MEDIA_IN_DEVICE ((NTSTATUS) 0xC0000013L)
+#endif
+
+#ifndef STATUS_UNRECOGNIZED_MEDIA
+# define STATUS_UNRECOGNIZED_MEDIA ((NTSTATUS) 0xC0000014L)
+#endif
+
+#ifndef STATUS_NONEXISTENT_SECTOR
+# define STATUS_NONEXISTENT_SECTOR ((NTSTATUS) 0xC0000015L)
+#endif
+
+#ifndef STATUS_MORE_PROCESSING_REQUIRED
+# define STATUS_MORE_PROCESSING_REQUIRED ((NTSTATUS) 0xC0000016L)
+#endif
+
+#ifndef STATUS_NO_MEMORY
+# define STATUS_NO_MEMORY ((NTSTATUS) 0xC0000017L)
+#endif
+
+#ifndef STATUS_CONFLICTING_ADDRESSES
+# define STATUS_CONFLICTING_ADDRESSES ((NTSTATUS) 0xC0000018L)
+#endif
+
+#ifndef STATUS_NOT_MAPPED_VIEW
+# define STATUS_NOT_MAPPED_VIEW ((NTSTATUS) 0xC0000019L)
+#endif
+
+#ifndef STATUS_UNABLE_TO_FREE_VM
+# define STATUS_UNABLE_TO_FREE_VM ((NTSTATUS) 0xC000001AL)
+#endif
+
+#ifndef STATUS_UNABLE_TO_DELETE_SECTION
+# define STATUS_UNABLE_TO_DELETE_SECTION ((NTSTATUS) 0xC000001BL)
+#endif
+
+#ifndef STATUS_INVALID_SYSTEM_SERVICE
+# define STATUS_INVALID_SYSTEM_SERVICE ((NTSTATUS) 0xC000001CL)
+#endif
+
+#ifndef STATUS_ILLEGAL_INSTRUCTION
+# define STATUS_ILLEGAL_INSTRUCTION ((NTSTATUS) 0xC000001DL)
+#endif
+
+#ifndef STATUS_INVALID_LOCK_SEQUENCE
+# define STATUS_INVALID_LOCK_SEQUENCE ((NTSTATUS) 0xC000001EL)
+#endif
+
+#ifndef STATUS_INVALID_VIEW_SIZE
+# define STATUS_INVALID_VIEW_SIZE ((NTSTATUS) 0xC000001FL)
+#endif
+
+#ifndef STATUS_INVALID_FILE_FOR_SECTION
+# define STATUS_INVALID_FILE_FOR_SECTION ((NTSTATUS) 0xC0000020L)
+#endif
+
+#ifndef STATUS_ALREADY_COMMITTED
+# define STATUS_ALREADY_COMMITTED ((NTSTATUS) 0xC0000021L)
+#endif
+
+#ifndef STATUS_ACCESS_DENIED
+# define STATUS_ACCESS_DENIED ((NTSTATUS) 0xC0000022L)
+#endif
+
+#ifndef STATUS_BUFFER_TOO_SMALL
+# define STATUS_BUFFER_TOO_SMALL ((NTSTATUS) 0xC0000023L)
+#endif
+
+#ifndef STATUS_OBJECT_TYPE_MISMATCH
+# define STATUS_OBJECT_TYPE_MISMATCH ((NTSTATUS) 0xC0000024L)
+#endif
+
+#ifndef STATUS_NONCONTINUABLE_EXCEPTION
+# define STATUS_NONCONTINUABLE_EXCEPTION ((NTSTATUS) 0xC0000025L)
+#endif
+
+#ifndef STATUS_INVALID_DISPOSITION
+# define STATUS_INVALID_DISPOSITION ((NTSTATUS) 0xC0000026L)
+#endif
+
+#ifndef STATUS_UNWIND
+# define STATUS_UNWIND ((NTSTATUS) 0xC0000027L)
+#endif
+
+#ifndef STATUS_BAD_STACK
+# define STATUS_BAD_STACK ((NTSTATUS) 0xC0000028L)
+#endif
+
+#ifndef STATUS_INVALID_UNWIND_TARGET
+# define STATUS_INVALID_UNWIND_TARGET ((NTSTATUS) 0xC0000029L)
+#endif
+
+#ifndef STATUS_NOT_LOCKED
+# define STATUS_NOT_LOCKED ((NTSTATUS) 0xC000002AL)
+#endif
+
+#ifndef STATUS_PARITY_ERROR
+# define STATUS_PARITY_ERROR ((NTSTATUS) 0xC000002BL)
+#endif
+
+#ifndef STATUS_UNABLE_TO_DECOMMIT_VM
+# define STATUS_UNABLE_TO_DECOMMIT_VM ((NTSTATUS) 0xC000002CL)
+#endif
+
+#ifndef STATUS_NOT_COMMITTED
+# define STATUS_NOT_COMMITTED ((NTSTATUS) 0xC000002DL)
+#endif
+
+#ifndef STATUS_INVALID_PORT_ATTRIBUTES
+# define STATUS_INVALID_PORT_ATTRIBUTES ((NTSTATUS) 0xC000002EL)
+#endif
+
+#ifndef STATUS_PORT_MESSAGE_TOO_LONG
+# define STATUS_PORT_MESSAGE_TOO_LONG ((NTSTATUS) 0xC000002FL)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_MIX
+# define STATUS_INVALID_PARAMETER_MIX ((NTSTATUS) 0xC0000030L)
+#endif
+
+#ifndef STATUS_INVALID_QUOTA_LOWER
+# define STATUS_INVALID_QUOTA_LOWER ((NTSTATUS) 0xC0000031L)
+#endif
+
+#ifndef STATUS_DISK_CORRUPT_ERROR
+# define STATUS_DISK_CORRUPT_ERROR ((NTSTATUS) 0xC0000032L)
+#endif
+
+#ifndef STATUS_OBJECT_NAME_INVALID
+# define STATUS_OBJECT_NAME_INVALID ((NTSTATUS) 0xC0000033L)
+#endif
+
+#ifndef STATUS_OBJECT_NAME_NOT_FOUND
+# define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS) 0xC0000034L)
+#endif
+
+#ifndef STATUS_OBJECT_NAME_COLLISION
+# define STATUS_OBJECT_NAME_COLLISION ((NTSTATUS) 0xC0000035L)
+#endif
+
+#ifndef STATUS_PORT_DISCONNECTED
+# define STATUS_PORT_DISCONNECTED ((NTSTATUS) 0xC0000037L)
+#endif
+
+#ifndef STATUS_DEVICE_ALREADY_ATTACHED
+# define STATUS_DEVICE_ALREADY_ATTACHED ((NTSTATUS) 0xC0000038L)
+#endif
+
+#ifndef STATUS_OBJECT_PATH_INVALID
+# define STATUS_OBJECT_PATH_INVALID ((NTSTATUS) 0xC0000039L)
+#endif
+
+#ifndef STATUS_OBJECT_PATH_NOT_FOUND
+# define STATUS_OBJECT_PATH_NOT_FOUND ((NTSTATUS) 0xC000003AL)
+#endif
+
+#ifndef STATUS_OBJECT_PATH_SYNTAX_BAD
+# define STATUS_OBJECT_PATH_SYNTAX_BAD ((NTSTATUS) 0xC000003BL)
+#endif
+
+#ifndef STATUS_DATA_OVERRUN
+# define STATUS_DATA_OVERRUN ((NTSTATUS) 0xC000003CL)
+#endif
+
+#ifndef STATUS_DATA_LATE_ERROR
+# define STATUS_DATA_LATE_ERROR ((NTSTATUS) 0xC000003DL)
+#endif
+
+#ifndef STATUS_DATA_ERROR
+# define STATUS_DATA_ERROR ((NTSTATUS) 0xC000003EL)
+#endif
+
+#ifndef STATUS_CRC_ERROR
+# define STATUS_CRC_ERROR ((NTSTATUS) 0xC000003FL)
+#endif
+
+#ifndef STATUS_SECTION_TOO_BIG
+# define STATUS_SECTION_TOO_BIG ((NTSTATUS) 0xC0000040L)
+#endif
+
+#ifndef STATUS_PORT_CONNECTION_REFUSED
+# define STATUS_PORT_CONNECTION_REFUSED ((NTSTATUS) 0xC0000041L)
+#endif
+
+#ifndef STATUS_INVALID_PORT_HANDLE
+# define STATUS_INVALID_PORT_HANDLE ((NTSTATUS) 0xC0000042L)
+#endif
+
+#ifndef STATUS_SHARING_VIOLATION
+# define STATUS_SHARING_VIOLATION ((NTSTATUS) 0xC0000043L)
+#endif
+
+#ifndef STATUS_QUOTA_EXCEEDED
+# define STATUS_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000044L)
+#endif
+
+#ifndef STATUS_INVALID_PAGE_PROTECTION
+# define STATUS_INVALID_PAGE_PROTECTION ((NTSTATUS) 0xC0000045L)
+#endif
+
+#ifndef STATUS_MUTANT_NOT_OWNED
+# define STATUS_MUTANT_NOT_OWNED ((NTSTATUS) 0xC0000046L)
+#endif
+
+#ifndef STATUS_SEMAPHORE_LIMIT_EXCEEDED
+# define STATUS_SEMAPHORE_LIMIT_EXCEEDED ((NTSTATUS) 0xC0000047L)
+#endif
+
+#ifndef STATUS_PORT_ALREADY_SET
+# define STATUS_PORT_ALREADY_SET ((NTSTATUS) 0xC0000048L)
+#endif
+
+#ifndef STATUS_SECTION_NOT_IMAGE
+# define STATUS_SECTION_NOT_IMAGE ((NTSTATUS) 0xC0000049L)
+#endif
+
+#ifndef STATUS_SUSPEND_COUNT_EXCEEDED
+# define STATUS_SUSPEND_COUNT_EXCEEDED ((NTSTATUS) 0xC000004AL)
+#endif
+
+#ifndef STATUS_THREAD_IS_TERMINATING
+# define STATUS_THREAD_IS_TERMINATING ((NTSTATUS) 0xC000004BL)
+#endif
+
+#ifndef STATUS_BAD_WORKING_SET_LIMIT
+# define STATUS_BAD_WORKING_SET_LIMIT ((NTSTATUS) 0xC000004CL)
+#endif
+
+#ifndef STATUS_INCOMPATIBLE_FILE_MAP
+# define STATUS_INCOMPATIBLE_FILE_MAP ((NTSTATUS) 0xC000004DL)
+#endif
+
+#ifndef STATUS_SECTION_PROTECTION
+# define STATUS_SECTION_PROTECTION ((NTSTATUS) 0xC000004EL)
+#endif
+
+#ifndef STATUS_EAS_NOT_SUPPORTED
+# define STATUS_EAS_NOT_SUPPORTED ((NTSTATUS) 0xC000004FL)
+#endif
+
+#ifndef STATUS_EA_TOO_LARGE
+# define STATUS_EA_TOO_LARGE ((NTSTATUS) 0xC0000050L)
+#endif
+
+#ifndef STATUS_NONEXISTENT_EA_ENTRY
+# define STATUS_NONEXISTENT_EA_ENTRY ((NTSTATUS) 0xC0000051L)
+#endif
+
+#ifndef STATUS_NO_EAS_ON_FILE
+# define STATUS_NO_EAS_ON_FILE ((NTSTATUS) 0xC0000052L)
+#endif
+
+#ifndef STATUS_EA_CORRUPT_ERROR
+# define STATUS_EA_CORRUPT_ERROR ((NTSTATUS) 0xC0000053L)
+#endif
+
+#ifndef STATUS_FILE_LOCK_CONFLICT
+# define STATUS_FILE_LOCK_CONFLICT ((NTSTATUS) 0xC0000054L)
+#endif
+
+#ifndef STATUS_LOCK_NOT_GRANTED
+# define STATUS_LOCK_NOT_GRANTED ((NTSTATUS) 0xC0000055L)
+#endif
+
+#ifndef STATUS_DELETE_PENDING
+# define STATUS_DELETE_PENDING ((NTSTATUS) 0xC0000056L)
+#endif
+
+#ifndef STATUS_CTL_FILE_NOT_SUPPORTED
+# define STATUS_CTL_FILE_NOT_SUPPORTED ((NTSTATUS) 0xC0000057L)
+#endif
+
+#ifndef STATUS_UNKNOWN_REVISION
+# define STATUS_UNKNOWN_REVISION ((NTSTATUS) 0xC0000058L)
+#endif
+
+#ifndef STATUS_REVISION_MISMATCH
+# define STATUS_REVISION_MISMATCH ((NTSTATUS) 0xC0000059L)
+#endif
+
+#ifndef STATUS_INVALID_OWNER
+# define STATUS_INVALID_OWNER ((NTSTATUS) 0xC000005AL)
+#endif
+
+#ifndef STATUS_INVALID_PRIMARY_GROUP
+# define STATUS_INVALID_PRIMARY_GROUP ((NTSTATUS) 0xC000005BL)
+#endif
+
+#ifndef STATUS_NO_IMPERSONATION_TOKEN
+# define STATUS_NO_IMPERSONATION_TOKEN ((NTSTATUS) 0xC000005CL)
+#endif
+
+#ifndef STATUS_CANT_DISABLE_MANDATORY
+# define STATUS_CANT_DISABLE_MANDATORY ((NTSTATUS) 0xC000005DL)
+#endif
+
+#ifndef STATUS_NO_LOGON_SERVERS
+# define STATUS_NO_LOGON_SERVERS ((NTSTATUS) 0xC000005EL)
+#endif
+
+#ifndef STATUS_NO_SUCH_LOGON_SESSION
+# define STATUS_NO_SUCH_LOGON_SESSION ((NTSTATUS) 0xC000005FL)
+#endif
+
+#ifndef STATUS_NO_SUCH_PRIVILEGE
+# define STATUS_NO_SUCH_PRIVILEGE ((NTSTATUS) 0xC0000060L)
+#endif
+
+#ifndef STATUS_PRIVILEGE_NOT_HELD
+# define STATUS_PRIVILEGE_NOT_HELD ((NTSTATUS) 0xC0000061L)
+#endif
+
+#ifndef STATUS_INVALID_ACCOUNT_NAME
+# define STATUS_INVALID_ACCOUNT_NAME ((NTSTATUS) 0xC0000062L)
+#endif
+
+#ifndef STATUS_USER_EXISTS
+# define STATUS_USER_EXISTS ((NTSTATUS) 0xC0000063L)
+#endif
+
+#ifndef STATUS_NO_SUCH_USER
+# define STATUS_NO_SUCH_USER ((NTSTATUS) 0xC0000064L)
+#endif
+
+#ifndef STATUS_GROUP_EXISTS
+# define STATUS_GROUP_EXISTS ((NTSTATUS) 0xC0000065L)
+#endif
+
+#ifndef STATUS_NO_SUCH_GROUP
+# define STATUS_NO_SUCH_GROUP ((NTSTATUS) 0xC0000066L)
+#endif
+
+#ifndef STATUS_MEMBER_IN_GROUP
+# define STATUS_MEMBER_IN_GROUP ((NTSTATUS) 0xC0000067L)
+#endif
+
+#ifndef STATUS_MEMBER_NOT_IN_GROUP
+# define STATUS_MEMBER_NOT_IN_GROUP ((NTSTATUS) 0xC0000068L)
+#endif
+
+#ifndef STATUS_LAST_ADMIN
+# define STATUS_LAST_ADMIN ((NTSTATUS) 0xC0000069L)
+#endif
+
+#ifndef STATUS_WRONG_PASSWORD
+# define STATUS_WRONG_PASSWORD ((NTSTATUS) 0xC000006AL)
+#endif
+
+#ifndef STATUS_ILL_FORMED_PASSWORD
+# define STATUS_ILL_FORMED_PASSWORD ((NTSTATUS) 0xC000006BL)
+#endif
+
+#ifndef STATUS_PASSWORD_RESTRICTION
+# define STATUS_PASSWORD_RESTRICTION ((NTSTATUS) 0xC000006CL)
+#endif
+
+#ifndef STATUS_LOGON_FAILURE
+# define STATUS_LOGON_FAILURE ((NTSTATUS) 0xC000006DL)
+#endif
+
+#ifndef STATUS_ACCOUNT_RESTRICTION
+# define STATUS_ACCOUNT_RESTRICTION ((NTSTATUS) 0xC000006EL)
+#endif
+
+#ifndef STATUS_INVALID_LOGON_HOURS
+# define STATUS_INVALID_LOGON_HOURS ((NTSTATUS) 0xC000006FL)
+#endif
+
+#ifndef STATUS_INVALID_WORKSTATION
+# define STATUS_INVALID_WORKSTATION ((NTSTATUS) 0xC0000070L)
+#endif
+
+#ifndef STATUS_PASSWORD_EXPIRED
+# define STATUS_PASSWORD_EXPIRED ((NTSTATUS) 0xC0000071L)
+#endif
+
+#ifndef STATUS_ACCOUNT_DISABLED
+# define STATUS_ACCOUNT_DISABLED ((NTSTATUS) 0xC0000072L)
+#endif
+
+#ifndef STATUS_NONE_MAPPED
+# define STATUS_NONE_MAPPED ((NTSTATUS) 0xC0000073L)
+#endif
+
+#ifndef STATUS_TOO_MANY_LUIDS_REQUESTED
+# define STATUS_TOO_MANY_LUIDS_REQUESTED ((NTSTATUS) 0xC0000074L)
+#endif
+
+#ifndef STATUS_LUIDS_EXHAUSTED
+# define STATUS_LUIDS_EXHAUSTED ((NTSTATUS) 0xC0000075L)
+#endif
+
+#ifndef STATUS_INVALID_SUB_AUTHORITY
+# define STATUS_INVALID_SUB_AUTHORITY ((NTSTATUS) 0xC0000076L)
+#endif
+
+#ifndef STATUS_INVALID_ACL
+# define STATUS_INVALID_ACL ((NTSTATUS) 0xC0000077L)
+#endif
+
+#ifndef STATUS_INVALID_SID
+# define STATUS_INVALID_SID ((NTSTATUS) 0xC0000078L)
+#endif
+
+#ifndef STATUS_INVALID_SECURITY_DESCR
+# define STATUS_INVALID_SECURITY_DESCR ((NTSTATUS) 0xC0000079L)
+#endif
+
+#ifndef STATUS_PROCEDURE_NOT_FOUND
+# define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS) 0xC000007AL)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_FORMAT
+# define STATUS_INVALID_IMAGE_FORMAT ((NTSTATUS) 0xC000007BL)
+#endif
+
+#ifndef STATUS_NO_TOKEN
+# define STATUS_NO_TOKEN ((NTSTATUS) 0xC000007CL)
+#endif
+
+#ifndef STATUS_BAD_INHERITANCE_ACL
+# define STATUS_BAD_INHERITANCE_ACL ((NTSTATUS) 0xC000007DL)
+#endif
+
+#ifndef STATUS_RANGE_NOT_LOCKED
+# define STATUS_RANGE_NOT_LOCKED ((NTSTATUS) 0xC000007EL)
+#endif
+
+#ifndef STATUS_DISK_FULL
+# define STATUS_DISK_FULL ((NTSTATUS) 0xC000007FL)
+#endif
+
+#ifndef STATUS_SERVER_DISABLED
+# define STATUS_SERVER_DISABLED ((NTSTATUS) 0xC0000080L)
+#endif
+
+#ifndef STATUS_SERVER_NOT_DISABLED
+# define STATUS_SERVER_NOT_DISABLED ((NTSTATUS) 0xC0000081L)
+#endif
+
+#ifndef STATUS_TOO_MANY_GUIDS_REQUESTED
+# define STATUS_TOO_MANY_GUIDS_REQUESTED ((NTSTATUS) 0xC0000082L)
+#endif
+
+#ifndef STATUS_GUIDS_EXHAUSTED
+# define STATUS_GUIDS_EXHAUSTED ((NTSTATUS) 0xC0000083L)
+#endif
+
+#ifndef STATUS_INVALID_ID_AUTHORITY
+# define STATUS_INVALID_ID_AUTHORITY ((NTSTATUS) 0xC0000084L)
+#endif
+
+#ifndef STATUS_AGENTS_EXHAUSTED
+# define STATUS_AGENTS_EXHAUSTED ((NTSTATUS) 0xC0000085L)
+#endif
+
+#ifndef STATUS_INVALID_VOLUME_LABEL
+# define STATUS_INVALID_VOLUME_LABEL ((NTSTATUS) 0xC0000086L)
+#endif
+
+#ifndef STATUS_SECTION_NOT_EXTENDED
+# define STATUS_SECTION_NOT_EXTENDED ((NTSTATUS) 0xC0000087L)
+#endif
+
+#ifndef STATUS_NOT_MAPPED_DATA
+# define STATUS_NOT_MAPPED_DATA ((NTSTATUS) 0xC0000088L)
+#endif
+
+#ifndef STATUS_RESOURCE_DATA_NOT_FOUND
+# define STATUS_RESOURCE_DATA_NOT_FOUND ((NTSTATUS) 0xC0000089L)
+#endif
+
+#ifndef STATUS_RESOURCE_TYPE_NOT_FOUND
+# define STATUS_RESOURCE_TYPE_NOT_FOUND ((NTSTATUS) 0xC000008AL)
+#endif
+
+#ifndef STATUS_RESOURCE_NAME_NOT_FOUND
+# define STATUS_RESOURCE_NAME_NOT_FOUND ((NTSTATUS) 0xC000008BL)
+#endif
+
+#ifndef STATUS_ARRAY_BOUNDS_EXCEEDED
+# define STATUS_ARRAY_BOUNDS_EXCEEDED ((NTSTATUS) 0xC000008CL)
+#endif
+
+#ifndef STATUS_FLOAT_DENORMAL_OPERAND
+# define STATUS_FLOAT_DENORMAL_OPERAND ((NTSTATUS) 0xC000008DL)
+#endif
+
+#ifndef STATUS_FLOAT_DIVIDE_BY_ZERO
+# define STATUS_FLOAT_DIVIDE_BY_ZERO ((NTSTATUS) 0xC000008EL)
+#endif
+
+#ifndef STATUS_FLOAT_INEXACT_RESULT
+# define STATUS_FLOAT_INEXACT_RESULT ((NTSTATUS) 0xC000008FL)
+#endif
+
+#ifndef STATUS_FLOAT_INVALID_OPERATION
+# define STATUS_FLOAT_INVALID_OPERATION ((NTSTATUS) 0xC0000090L)
+#endif
+
+#ifndef STATUS_FLOAT_OVERFLOW
+# define STATUS_FLOAT_OVERFLOW ((NTSTATUS) 0xC0000091L)
+#endif
+
+#ifndef STATUS_FLOAT_STACK_CHECK
+# define STATUS_FLOAT_STACK_CHECK ((NTSTATUS) 0xC0000092L)
+#endif
+
+#ifndef STATUS_FLOAT_UNDERFLOW
+# define STATUS_FLOAT_UNDERFLOW ((NTSTATUS) 0xC0000093L)
+#endif
+
+#ifndef STATUS_INTEGER_DIVIDE_BY_ZERO
+# define STATUS_INTEGER_DIVIDE_BY_ZERO ((NTSTATUS) 0xC0000094L)
+#endif
+
+#ifndef STATUS_INTEGER_OVERFLOW
+# define STATUS_INTEGER_OVERFLOW ((NTSTATUS) 0xC0000095L)
+#endif
+
+#ifndef STATUS_PRIVILEGED_INSTRUCTION
+# define STATUS_PRIVILEGED_INSTRUCTION ((NTSTATUS) 0xC0000096L)
+#endif
+
+#ifndef STATUS_TOO_MANY_PAGING_FILES
+# define STATUS_TOO_MANY_PAGING_FILES ((NTSTATUS) 0xC0000097L)
+#endif
+
+#ifndef STATUS_FILE_INVALID
+# define STATUS_FILE_INVALID ((NTSTATUS) 0xC0000098L)
+#endif
+
+#ifndef STATUS_ALLOTTED_SPACE_EXCEEDED
+# define STATUS_ALLOTTED_SPACE_EXCEEDED ((NTSTATUS) 0xC0000099L)
+#endif
+
+#ifndef STATUS_INSUFFICIENT_RESOURCES
+# define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS) 0xC000009AL)
+#endif
+
+#ifndef STATUS_DFS_EXIT_PATH_FOUND
+# define STATUS_DFS_EXIT_PATH_FOUND ((NTSTATUS) 0xC000009BL)
+#endif
+
+#ifndef STATUS_DEVICE_DATA_ERROR
+# define STATUS_DEVICE_DATA_ERROR ((NTSTATUS) 0xC000009CL)
+#endif
+
+#ifndef STATUS_DEVICE_NOT_CONNECTED
+# define STATUS_DEVICE_NOT_CONNECTED ((NTSTATUS) 0xC000009DL)
+#endif
+
+#ifndef STATUS_DEVICE_POWER_FAILURE
+# define STATUS_DEVICE_POWER_FAILURE ((NTSTATUS) 0xC000009EL)
+#endif
+
+#ifndef STATUS_FREE_VM_NOT_AT_BASE
+# define STATUS_FREE_VM_NOT_AT_BASE ((NTSTATUS) 0xC000009FL)
+#endif
+
+#ifndef STATUS_MEMORY_NOT_ALLOCATED
+# define STATUS_MEMORY_NOT_ALLOCATED ((NTSTATUS) 0xC00000A0L)
+#endif
+
+#ifndef STATUS_WORKING_SET_QUOTA
+# define STATUS_WORKING_SET_QUOTA ((NTSTATUS) 0xC00000A1L)
+#endif
+
+#ifndef STATUS_MEDIA_WRITE_PROTECTED
+# define STATUS_MEDIA_WRITE_PROTECTED ((NTSTATUS) 0xC00000A2L)
+#endif
+
+#ifndef STATUS_DEVICE_NOT_READY
+# define STATUS_DEVICE_NOT_READY ((NTSTATUS) 0xC00000A3L)
+#endif
+
+#ifndef STATUS_INVALID_GROUP_ATTRIBUTES
+# define STATUS_INVALID_GROUP_ATTRIBUTES ((NTSTATUS) 0xC00000A4L)
+#endif
+
+#ifndef STATUS_BAD_IMPERSONATION_LEVEL
+# define STATUS_BAD_IMPERSONATION_LEVEL ((NTSTATUS) 0xC00000A5L)
+#endif
+
+#ifndef STATUS_CANT_OPEN_ANONYMOUS
+# define STATUS_CANT_OPEN_ANONYMOUS ((NTSTATUS) 0xC00000A6L)
+#endif
+
+#ifndef STATUS_BAD_VALIDATION_CLASS
+# define STATUS_BAD_VALIDATION_CLASS ((NTSTATUS) 0xC00000A7L)
+#endif
+
+#ifndef STATUS_BAD_TOKEN_TYPE
+# define STATUS_BAD_TOKEN_TYPE ((NTSTATUS) 0xC00000A8L)
+#endif
+
+#ifndef STATUS_BAD_MASTER_BOOT_RECORD
+# define STATUS_BAD_MASTER_BOOT_RECORD ((NTSTATUS) 0xC00000A9L)
+#endif
+
+#ifndef STATUS_INSTRUCTION_MISALIGNMENT
+# define STATUS_INSTRUCTION_MISALIGNMENT ((NTSTATUS) 0xC00000AAL)
+#endif
+
+#ifndef STATUS_INSTANCE_NOT_AVAILABLE
+# define STATUS_INSTANCE_NOT_AVAILABLE ((NTSTATUS) 0xC00000ABL)
+#endif
+
+#ifndef STATUS_PIPE_NOT_AVAILABLE
+# define STATUS_PIPE_NOT_AVAILABLE ((NTSTATUS) 0xC00000ACL)
+#endif
+
+#ifndef STATUS_INVALID_PIPE_STATE
+# define STATUS_INVALID_PIPE_STATE ((NTSTATUS) 0xC00000ADL)
+#endif
+
+#ifndef STATUS_PIPE_BUSY
+# define STATUS_PIPE_BUSY ((NTSTATUS) 0xC00000AEL)
+#endif
+
+#ifndef STATUS_ILLEGAL_FUNCTION
+# define STATUS_ILLEGAL_FUNCTION ((NTSTATUS) 0xC00000AFL)
+#endif
+
+#ifndef STATUS_PIPE_DISCONNECTED
+# define STATUS_PIPE_DISCONNECTED ((NTSTATUS) 0xC00000B0L)
+#endif
+
+#ifndef STATUS_PIPE_CLOSING
+# define STATUS_PIPE_CLOSING ((NTSTATUS) 0xC00000B1L)
+#endif
+
+#ifndef STATUS_PIPE_CONNECTED
+# define STATUS_PIPE_CONNECTED ((NTSTATUS) 0xC00000B2L)
+#endif
+
+#ifndef STATUS_PIPE_LISTENING
+# define STATUS_PIPE_LISTENING ((NTSTATUS) 0xC00000B3L)
+#endif
+
+#ifndef STATUS_INVALID_READ_MODE
+# define STATUS_INVALID_READ_MODE ((NTSTATUS) 0xC00000B4L)
+#endif
+
+#ifndef STATUS_IO_TIMEOUT
+# define STATUS_IO_TIMEOUT ((NTSTATUS) 0xC00000B5L)
+#endif
+
+#ifndef STATUS_FILE_FORCED_CLOSED
+# define STATUS_FILE_FORCED_CLOSED ((NTSTATUS) 0xC00000B6L)
+#endif
+
+#ifndef STATUS_PROFILING_NOT_STARTED
+# define STATUS_PROFILING_NOT_STARTED ((NTSTATUS) 0xC00000B7L)
+#endif
+
+#ifndef STATUS_PROFILING_NOT_STOPPED
+# define STATUS_PROFILING_NOT_STOPPED ((NTSTATUS) 0xC00000B8L)
+#endif
+
+#ifndef STATUS_COULD_NOT_INTERPRET
+# define STATUS_COULD_NOT_INTERPRET ((NTSTATUS) 0xC00000B9L)
+#endif
+
+#ifndef STATUS_FILE_IS_A_DIRECTORY
+# define STATUS_FILE_IS_A_DIRECTORY ((NTSTATUS) 0xC00000BAL)
+#endif
+
+#ifndef STATUS_NOT_SUPPORTED
+# define STATUS_NOT_SUPPORTED ((NTSTATUS) 0xC00000BBL)
+#endif
+
+#ifndef STATUS_REMOTE_NOT_LISTENING
+# define STATUS_REMOTE_NOT_LISTENING ((NTSTATUS) 0xC00000BCL)
+#endif
+
+#ifndef STATUS_DUPLICATE_NAME
+# define STATUS_DUPLICATE_NAME ((NTSTATUS) 0xC00000BDL)
+#endif
+
+#ifndef STATUS_BAD_NETWORK_PATH
+# define STATUS_BAD_NETWORK_PATH ((NTSTATUS) 0xC00000BEL)
+#endif
+
+#ifndef STATUS_NETWORK_BUSY
+# define STATUS_NETWORK_BUSY ((NTSTATUS) 0xC00000BFL)
+#endif
+
+#ifndef STATUS_DEVICE_DOES_NOT_EXIST
+# define STATUS_DEVICE_DOES_NOT_EXIST ((NTSTATUS) 0xC00000C0L)
+#endif
+
+#ifndef STATUS_TOO_MANY_COMMANDS
+# define STATUS_TOO_MANY_COMMANDS ((NTSTATUS) 0xC00000C1L)
+#endif
+
+#ifndef STATUS_ADAPTER_HARDWARE_ERROR
+# define STATUS_ADAPTER_HARDWARE_ERROR ((NTSTATUS) 0xC00000C2L)
+#endif
+
+#ifndef STATUS_INVALID_NETWORK_RESPONSE
+# define STATUS_INVALID_NETWORK_RESPONSE ((NTSTATUS) 0xC00000C3L)
+#endif
+
+#ifndef STATUS_UNEXPECTED_NETWORK_ERROR
+# define STATUS_UNEXPECTED_NETWORK_ERROR ((NTSTATUS) 0xC00000C4L)
+#endif
+
+#ifndef STATUS_BAD_REMOTE_ADAPTER
+# define STATUS_BAD_REMOTE_ADAPTER ((NTSTATUS) 0xC00000C5L)
+#endif
+
+#ifndef STATUS_PRINT_QUEUE_FULL
+# define STATUS_PRINT_QUEUE_FULL ((NTSTATUS) 0xC00000C6L)
+#endif
+
+#ifndef STATUS_NO_SPOOL_SPACE
+# define STATUS_NO_SPOOL_SPACE ((NTSTATUS) 0xC00000C7L)
+#endif
+
+#ifndef STATUS_PRINT_CANCELLED
+# define STATUS_PRINT_CANCELLED ((NTSTATUS) 0xC00000C8L)
+#endif
+
+#ifndef STATUS_NETWORK_NAME_DELETED
+# define STATUS_NETWORK_NAME_DELETED ((NTSTATUS) 0xC00000C9L)
+#endif
+
+#ifndef STATUS_NETWORK_ACCESS_DENIED
+# define STATUS_NETWORK_ACCESS_DENIED ((NTSTATUS) 0xC00000CAL)
+#endif
+
+#ifndef STATUS_BAD_DEVICE_TYPE
+# define STATUS_BAD_DEVICE_TYPE ((NTSTATUS) 0xC00000CBL)
+#endif
+
+#ifndef STATUS_BAD_NETWORK_NAME
+# define STATUS_BAD_NETWORK_NAME ((NTSTATUS) 0xC00000CCL)
+#endif
+
+#ifndef STATUS_TOO_MANY_NAMES
+# define STATUS_TOO_MANY_NAMES ((NTSTATUS) 0xC00000CDL)
+#endif
+
+#ifndef STATUS_TOO_MANY_SESSIONS
+# define STATUS_TOO_MANY_SESSIONS ((NTSTATUS) 0xC00000CEL)
+#endif
+
+#ifndef STATUS_SHARING_PAUSED
+# define STATUS_SHARING_PAUSED ((NTSTATUS) 0xC00000CFL)
+#endif
+
+#ifndef STATUS_REQUEST_NOT_ACCEPTED
+# define STATUS_REQUEST_NOT_ACCEPTED ((NTSTATUS) 0xC00000D0L)
+#endif
+
+#ifndef STATUS_REDIRECTOR_PAUSED
+# define STATUS_REDIRECTOR_PAUSED ((NTSTATUS) 0xC00000D1L)
+#endif
+
+#ifndef STATUS_NET_WRITE_FAULT
+# define STATUS_NET_WRITE_FAULT ((NTSTATUS) 0xC00000D2L)
+#endif
+
+#ifndef STATUS_PROFILING_AT_LIMIT
+# define STATUS_PROFILING_AT_LIMIT ((NTSTATUS) 0xC00000D3L)
+#endif
+
+#ifndef STATUS_NOT_SAME_DEVICE
+# define STATUS_NOT_SAME_DEVICE ((NTSTATUS) 0xC00000D4L)
+#endif
+
+#ifndef STATUS_FILE_RENAMED
+# define STATUS_FILE_RENAMED ((NTSTATUS) 0xC00000D5L)
+#endif
+
+#ifndef STATUS_VIRTUAL_CIRCUIT_CLOSED
+# define STATUS_VIRTUAL_CIRCUIT_CLOSED ((NTSTATUS) 0xC00000D6L)
+#endif
+
+#ifndef STATUS_NO_SECURITY_ON_OBJECT
+# define STATUS_NO_SECURITY_ON_OBJECT ((NTSTATUS) 0xC00000D7L)
+#endif
+
+#ifndef STATUS_CANT_WAIT
+# define STATUS_CANT_WAIT ((NTSTATUS) 0xC00000D8L)
+#endif
+
+#ifndef STATUS_PIPE_EMPTY
+# define STATUS_PIPE_EMPTY ((NTSTATUS) 0xC00000D9L)
+#endif
+
+#ifndef STATUS_CANT_ACCESS_DOMAIN_INFO
+# define STATUS_CANT_ACCESS_DOMAIN_INFO ((NTSTATUS) 0xC00000DAL)
+#endif
+
+#ifndef STATUS_CANT_TERMINATE_SELF
+# define STATUS_CANT_TERMINATE_SELF ((NTSTATUS) 0xC00000DBL)
+#endif
+
+#ifndef STATUS_INVALID_SERVER_STATE
+# define STATUS_INVALID_SERVER_STATE ((NTSTATUS) 0xC00000DCL)
+#endif
+
+#ifndef STATUS_INVALID_DOMAIN_STATE
+# define STATUS_INVALID_DOMAIN_STATE ((NTSTATUS) 0xC00000DDL)
+#endif
+
+#ifndef STATUS_INVALID_DOMAIN_ROLE
+# define STATUS_INVALID_DOMAIN_ROLE ((NTSTATUS) 0xC00000DEL)
+#endif
+
+#ifndef STATUS_NO_SUCH_DOMAIN
+# define STATUS_NO_SUCH_DOMAIN ((NTSTATUS) 0xC00000DFL)
+#endif
+
+#ifndef STATUS_DOMAIN_EXISTS
+# define STATUS_DOMAIN_EXISTS ((NTSTATUS) 0xC00000E0L)
+#endif
+
+#ifndef STATUS_DOMAIN_LIMIT_EXCEEDED
+# define STATUS_DOMAIN_LIMIT_EXCEEDED ((NTSTATUS) 0xC00000E1L)
+#endif
+
+#ifndef STATUS_OPLOCK_NOT_GRANTED
+# define STATUS_OPLOCK_NOT_GRANTED ((NTSTATUS) 0xC00000E2L)
+#endif
+
+#ifndef STATUS_INVALID_OPLOCK_PROTOCOL
+# define STATUS_INVALID_OPLOCK_PROTOCOL ((NTSTATUS) 0xC00000E3L)
+#endif
+
+#ifndef STATUS_INTERNAL_DB_CORRUPTION
+# define STATUS_INTERNAL_DB_CORRUPTION ((NTSTATUS) 0xC00000E4L)
+#endif
+
+#ifndef STATUS_INTERNAL_ERROR
+# define STATUS_INTERNAL_ERROR ((NTSTATUS) 0xC00000E5L)
+#endif
+
+#ifndef STATUS_GENERIC_NOT_MAPPED
+# define STATUS_GENERIC_NOT_MAPPED ((NTSTATUS) 0xC00000E6L)
+#endif
+
+#ifndef STATUS_BAD_DESCRIPTOR_FORMAT
+# define STATUS_BAD_DESCRIPTOR_FORMAT ((NTSTATUS) 0xC00000E7L)
+#endif
+
+#ifndef STATUS_INVALID_USER_BUFFER
+# define STATUS_INVALID_USER_BUFFER ((NTSTATUS) 0xC00000E8L)
+#endif
+
+#ifndef STATUS_UNEXPECTED_IO_ERROR
+# define STATUS_UNEXPECTED_IO_ERROR ((NTSTATUS) 0xC00000E9L)
+#endif
+
+#ifndef STATUS_UNEXPECTED_MM_CREATE_ERR
+# define STATUS_UNEXPECTED_MM_CREATE_ERR ((NTSTATUS) 0xC00000EAL)
+#endif
+
+#ifndef STATUS_UNEXPECTED_MM_MAP_ERROR
+# define STATUS_UNEXPECTED_MM_MAP_ERROR ((NTSTATUS) 0xC00000EBL)
+#endif
+
+#ifndef STATUS_UNEXPECTED_MM_EXTEND_ERR
+# define STATUS_UNEXPECTED_MM_EXTEND_ERR ((NTSTATUS) 0xC00000ECL)
+#endif
+
+#ifndef STATUS_NOT_LOGON_PROCESS
+# define STATUS_NOT_LOGON_PROCESS ((NTSTATUS) 0xC00000EDL)
+#endif
+
+#ifndef STATUS_LOGON_SESSION_EXISTS
+# define STATUS_LOGON_SESSION_EXISTS ((NTSTATUS) 0xC00000EEL)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_1
+# define STATUS_INVALID_PARAMETER_1 ((NTSTATUS) 0xC00000EFL)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_2
+# define STATUS_INVALID_PARAMETER_2 ((NTSTATUS) 0xC00000F0L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_3
+# define STATUS_INVALID_PARAMETER_3 ((NTSTATUS) 0xC00000F1L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_4
+# define STATUS_INVALID_PARAMETER_4 ((NTSTATUS) 0xC00000F2L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_5
+# define STATUS_INVALID_PARAMETER_5 ((NTSTATUS) 0xC00000F3L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_6
+# define STATUS_INVALID_PARAMETER_6 ((NTSTATUS) 0xC00000F4L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_7
+# define STATUS_INVALID_PARAMETER_7 ((NTSTATUS) 0xC00000F5L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_8
+# define STATUS_INVALID_PARAMETER_8 ((NTSTATUS) 0xC00000F6L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_9
+# define STATUS_INVALID_PARAMETER_9 ((NTSTATUS) 0xC00000F7L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_10
+# define STATUS_INVALID_PARAMETER_10 ((NTSTATUS) 0xC00000F8L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_11
+# define STATUS_INVALID_PARAMETER_11 ((NTSTATUS) 0xC00000F9L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_12
+# define STATUS_INVALID_PARAMETER_12 ((NTSTATUS) 0xC00000FAL)
+#endif
+
+#ifndef STATUS_REDIRECTOR_NOT_STARTED
+# define STATUS_REDIRECTOR_NOT_STARTED ((NTSTATUS) 0xC00000FBL)
+#endif
+
+#ifndef STATUS_REDIRECTOR_STARTED
+# define STATUS_REDIRECTOR_STARTED ((NTSTATUS) 0xC00000FCL)
+#endif
+
+#ifndef STATUS_STACK_OVERFLOW
+# define STATUS_STACK_OVERFLOW ((NTSTATUS) 0xC00000FDL)
+#endif
+
+#ifndef STATUS_NO_SUCH_PACKAGE
+# define STATUS_NO_SUCH_PACKAGE ((NTSTATUS) 0xC00000FEL)
+#endif
+
+#ifndef STATUS_BAD_FUNCTION_TABLE
+# define STATUS_BAD_FUNCTION_TABLE ((NTSTATUS) 0xC00000FFL)
+#endif
+
+#ifndef STATUS_VARIABLE_NOT_FOUND
+# define STATUS_VARIABLE_NOT_FOUND ((NTSTATUS) 0xC0000100L)
+#endif
+
+#ifndef STATUS_DIRECTORY_NOT_EMPTY
+# define STATUS_DIRECTORY_NOT_EMPTY ((NTSTATUS) 0xC0000101L)
+#endif
+
+#ifndef STATUS_FILE_CORRUPT_ERROR
+# define STATUS_FILE_CORRUPT_ERROR ((NTSTATUS) 0xC0000102L)
+#endif
+
+#ifndef STATUS_NOT_A_DIRECTORY
+# define STATUS_NOT_A_DIRECTORY ((NTSTATUS) 0xC0000103L)
+#endif
+
+#ifndef STATUS_BAD_LOGON_SESSION_STATE
+# define STATUS_BAD_LOGON_SESSION_STATE ((NTSTATUS) 0xC0000104L)
+#endif
+
+#ifndef STATUS_LOGON_SESSION_COLLISION
+# define STATUS_LOGON_SESSION_COLLISION ((NTSTATUS) 0xC0000105L)
+#endif
+
+#ifndef STATUS_NAME_TOO_LONG
+# define STATUS_NAME_TOO_LONG ((NTSTATUS) 0xC0000106L)
+#endif
+
+#ifndef STATUS_FILES_OPEN
+# define STATUS_FILES_OPEN ((NTSTATUS) 0xC0000107L)
+#endif
+
+#ifndef STATUS_CONNECTION_IN_USE
+# define STATUS_CONNECTION_IN_USE ((NTSTATUS) 0xC0000108L)
+#endif
+
+#ifndef STATUS_MESSAGE_NOT_FOUND
+# define STATUS_MESSAGE_NOT_FOUND ((NTSTATUS) 0xC0000109L)
+#endif
+
+#ifndef STATUS_PROCESS_IS_TERMINATING
+# define STATUS_PROCESS_IS_TERMINATING ((NTSTATUS) 0xC000010AL)
+#endif
+
+#ifndef STATUS_INVALID_LOGON_TYPE
+# define STATUS_INVALID_LOGON_TYPE ((NTSTATUS) 0xC000010BL)
+#endif
+
+#ifndef STATUS_NO_GUID_TRANSLATION
+# define STATUS_NO_GUID_TRANSLATION ((NTSTATUS) 0xC000010CL)
+#endif
+
+#ifndef STATUS_CANNOT_IMPERSONATE
+# define STATUS_CANNOT_IMPERSONATE ((NTSTATUS) 0xC000010DL)
+#endif
+
+#ifndef STATUS_IMAGE_ALREADY_LOADED
+# define STATUS_IMAGE_ALREADY_LOADED ((NTSTATUS) 0xC000010EL)
+#endif
+
+#ifndef STATUS_ABIOS_NOT_PRESENT
+# define STATUS_ABIOS_NOT_PRESENT ((NTSTATUS) 0xC000010FL)
+#endif
+
+#ifndef STATUS_ABIOS_LID_NOT_EXIST
+# define STATUS_ABIOS_LID_NOT_EXIST ((NTSTATUS) 0xC0000110L)
+#endif
+
+#ifndef STATUS_ABIOS_LID_ALREADY_OWNED
+# define STATUS_ABIOS_LID_ALREADY_OWNED ((NTSTATUS) 0xC0000111L)
+#endif
+
+#ifndef STATUS_ABIOS_NOT_LID_OWNER
+# define STATUS_ABIOS_NOT_LID_OWNER ((NTSTATUS) 0xC0000112L)
+#endif
+
+#ifndef STATUS_ABIOS_INVALID_COMMAND
+# define STATUS_ABIOS_INVALID_COMMAND ((NTSTATUS) 0xC0000113L)
+#endif
+
+#ifndef STATUS_ABIOS_INVALID_LID
+# define STATUS_ABIOS_INVALID_LID ((NTSTATUS) 0xC0000114L)
+#endif
+
+#ifndef STATUS_ABIOS_SELECTOR_NOT_AVAILABLE
+# define STATUS_ABIOS_SELECTOR_NOT_AVAILABLE ((NTSTATUS) 0xC0000115L)
+#endif
+
+#ifndef STATUS_ABIOS_INVALID_SELECTOR
+# define STATUS_ABIOS_INVALID_SELECTOR ((NTSTATUS) 0xC0000116L)
+#endif
+
+#ifndef STATUS_NO_LDT
+# define STATUS_NO_LDT ((NTSTATUS) 0xC0000117L)
+#endif
+
+#ifndef STATUS_INVALID_LDT_SIZE
+# define STATUS_INVALID_LDT_SIZE ((NTSTATUS) 0xC0000118L)
+#endif
+
+#ifndef STATUS_INVALID_LDT_OFFSET
+# define STATUS_INVALID_LDT_OFFSET ((NTSTATUS) 0xC0000119L)
+#endif
+
+#ifndef STATUS_INVALID_LDT_DESCRIPTOR
+# define STATUS_INVALID_LDT_DESCRIPTOR ((NTSTATUS) 0xC000011AL)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_NE_FORMAT
+# define STATUS_INVALID_IMAGE_NE_FORMAT ((NTSTATUS) 0xC000011BL)
+#endif
+
+#ifndef STATUS_RXACT_INVALID_STATE
+# define STATUS_RXACT_INVALID_STATE ((NTSTATUS) 0xC000011CL)
+#endif
+
+#ifndef STATUS_RXACT_COMMIT_FAILURE
+# define STATUS_RXACT_COMMIT_FAILURE ((NTSTATUS) 0xC000011DL)
+#endif
+
+#ifndef STATUS_MAPPED_FILE_SIZE_ZERO
+# define STATUS_MAPPED_FILE_SIZE_ZERO ((NTSTATUS) 0xC000011EL)
+#endif
+
+#ifndef STATUS_TOO_MANY_OPENED_FILES
+# define STATUS_TOO_MANY_OPENED_FILES ((NTSTATUS) 0xC000011FL)
+#endif
+
+#ifndef STATUS_CANCELLED
+# define STATUS_CANCELLED ((NTSTATUS) 0xC0000120L)
+#endif
+
+#ifndef STATUS_CANNOT_DELETE
+# define STATUS_CANNOT_DELETE ((NTSTATUS) 0xC0000121L)
+#endif
+
+#ifndef STATUS_INVALID_COMPUTER_NAME
+# define STATUS_INVALID_COMPUTER_NAME ((NTSTATUS) 0xC0000122L)
+#endif
+
+#ifndef STATUS_FILE_DELETED
+# define STATUS_FILE_DELETED ((NTSTATUS) 0xC0000123L)
+#endif
+
+#ifndef STATUS_SPECIAL_ACCOUNT
+# define STATUS_SPECIAL_ACCOUNT ((NTSTATUS) 0xC0000124L)
+#endif
+
+#ifndef STATUS_SPECIAL_GROUP
+# define STATUS_SPECIAL_GROUP ((NTSTATUS) 0xC0000125L)
+#endif
+
+#ifndef STATUS_SPECIAL_USER
+# define STATUS_SPECIAL_USER ((NTSTATUS) 0xC0000126L)
+#endif
+
+#ifndef STATUS_MEMBERS_PRIMARY_GROUP
+# define STATUS_MEMBERS_PRIMARY_GROUP ((NTSTATUS) 0xC0000127L)
+#endif
+
+#ifndef STATUS_FILE_CLOSED
+# define STATUS_FILE_CLOSED ((NTSTATUS) 0xC0000128L)
+#endif
+
+#ifndef STATUS_TOO_MANY_THREADS
+# define STATUS_TOO_MANY_THREADS ((NTSTATUS) 0xC0000129L)
+#endif
+
+#ifndef STATUS_THREAD_NOT_IN_PROCESS
+# define STATUS_THREAD_NOT_IN_PROCESS ((NTSTATUS) 0xC000012AL)
+#endif
+
+#ifndef STATUS_TOKEN_ALREADY_IN_USE
+# define STATUS_TOKEN_ALREADY_IN_USE ((NTSTATUS) 0xC000012BL)
+#endif
+
+#ifndef STATUS_PAGEFILE_QUOTA_EXCEEDED
+# define STATUS_PAGEFILE_QUOTA_EXCEEDED ((NTSTATUS) 0xC000012CL)
+#endif
+
+#ifndef STATUS_COMMITMENT_LIMIT
+# define STATUS_COMMITMENT_LIMIT ((NTSTATUS) 0xC000012DL)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_LE_FORMAT
+# define STATUS_INVALID_IMAGE_LE_FORMAT ((NTSTATUS) 0xC000012EL)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_NOT_MZ
+# define STATUS_INVALID_IMAGE_NOT_MZ ((NTSTATUS) 0xC000012FL)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_PROTECT
+# define STATUS_INVALID_IMAGE_PROTECT ((NTSTATUS) 0xC0000130L)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_WIN_16
+# define STATUS_INVALID_IMAGE_WIN_16 ((NTSTATUS) 0xC0000131L)
+#endif
+
+#ifndef STATUS_LOGON_SERVER_CONFLICT
+# define STATUS_LOGON_SERVER_CONFLICT ((NTSTATUS) 0xC0000132L)
+#endif
+
+#ifndef STATUS_TIME_DIFFERENCE_AT_DC
+# define STATUS_TIME_DIFFERENCE_AT_DC ((NTSTATUS) 0xC0000133L)
+#endif
+
+#ifndef STATUS_SYNCHRONIZATION_REQUIRED
+# define STATUS_SYNCHRONIZATION_REQUIRED ((NTSTATUS) 0xC0000134L)
+#endif
+
+#ifndef STATUS_DLL_NOT_FOUND
+# define STATUS_DLL_NOT_FOUND ((NTSTATUS) 0xC0000135L)
+#endif
+
+#ifndef STATUS_OPEN_FAILED
+# define STATUS_OPEN_FAILED ((NTSTATUS) 0xC0000136L)
+#endif
+
+#ifndef STATUS_IO_PRIVILEGE_FAILED
+# define STATUS_IO_PRIVILEGE_FAILED ((NTSTATUS) 0xC0000137L)
+#endif
+
+#ifndef STATUS_ORDINAL_NOT_FOUND
+# define STATUS_ORDINAL_NOT_FOUND ((NTSTATUS) 0xC0000138L)
+#endif
+
+#ifndef STATUS_ENTRYPOINT_NOT_FOUND
+# define STATUS_ENTRYPOINT_NOT_FOUND ((NTSTATUS) 0xC0000139L)
+#endif
+
+#ifndef STATUS_CONTROL_C_EXIT
+# define STATUS_CONTROL_C_EXIT ((NTSTATUS) 0xC000013AL)
+#endif
+
+#ifndef STATUS_LOCAL_DISCONNECT
+# define STATUS_LOCAL_DISCONNECT ((NTSTATUS) 0xC000013BL)
+#endif
+
+#ifndef STATUS_REMOTE_DISCONNECT
+# define STATUS_REMOTE_DISCONNECT ((NTSTATUS) 0xC000013CL)
+#endif
+
+#ifndef STATUS_REMOTE_RESOURCES
+# define STATUS_REMOTE_RESOURCES ((NTSTATUS) 0xC000013DL)
+#endif
+
+#ifndef STATUS_LINK_FAILED
+# define STATUS_LINK_FAILED ((NTSTATUS) 0xC000013EL)
+#endif
+
+#ifndef STATUS_LINK_TIMEOUT
+# define STATUS_LINK_TIMEOUT ((NTSTATUS) 0xC000013FL)
+#endif
+
+#ifndef STATUS_INVALID_CONNECTION
+# define STATUS_INVALID_CONNECTION ((NTSTATUS) 0xC0000140L)
+#endif
+
+#ifndef STATUS_INVALID_ADDRESS
+# define STATUS_INVALID_ADDRESS ((NTSTATUS) 0xC0000141L)
+#endif
+
+#ifndef STATUS_DLL_INIT_FAILED
+# define STATUS_DLL_INIT_FAILED ((NTSTATUS) 0xC0000142L)
+#endif
+
+#ifndef STATUS_MISSING_SYSTEMFILE
+# define STATUS_MISSING_SYSTEMFILE ((NTSTATUS) 0xC0000143L)
+#endif
+
+#ifndef STATUS_UNHANDLED_EXCEPTION
+# define STATUS_UNHANDLED_EXCEPTION ((NTSTATUS) 0xC0000144L)
+#endif
+
+#ifndef STATUS_APP_INIT_FAILURE
+# define STATUS_APP_INIT_FAILURE ((NTSTATUS) 0xC0000145L)
+#endif
+
+#ifndef STATUS_PAGEFILE_CREATE_FAILED
+# define STATUS_PAGEFILE_CREATE_FAILED ((NTSTATUS) 0xC0000146L)
+#endif
+
+#ifndef STATUS_NO_PAGEFILE
+# define STATUS_NO_PAGEFILE ((NTSTATUS) 0xC0000147L)
+#endif
+
+#ifndef STATUS_INVALID_LEVEL
+# define STATUS_INVALID_LEVEL ((NTSTATUS) 0xC0000148L)
+#endif
+
+#ifndef STATUS_WRONG_PASSWORD_CORE
+# define STATUS_WRONG_PASSWORD_CORE ((NTSTATUS) 0xC0000149L)
+#endif
+
+#ifndef STATUS_ILLEGAL_FLOAT_CONTEXT
+# define STATUS_ILLEGAL_FLOAT_CONTEXT ((NTSTATUS) 0xC000014AL)
+#endif
+
+#ifndef STATUS_PIPE_BROKEN
+# define STATUS_PIPE_BROKEN ((NTSTATUS) 0xC000014BL)
+#endif
+
+#ifndef STATUS_REGISTRY_CORRUPT
+# define STATUS_REGISTRY_CORRUPT ((NTSTATUS) 0xC000014CL)
+#endif
+
+#ifndef STATUS_REGISTRY_IO_FAILED
+# define STATUS_REGISTRY_IO_FAILED ((NTSTATUS) 0xC000014DL)
+#endif
+
+#ifndef STATUS_NO_EVENT_PAIR
+# define STATUS_NO_EVENT_PAIR ((NTSTATUS) 0xC000014EL)
+#endif
+
+#ifndef STATUS_UNRECOGNIZED_VOLUME
+# define STATUS_UNRECOGNIZED_VOLUME ((NTSTATUS) 0xC000014FL)
+#endif
+
+#ifndef STATUS_SERIAL_NO_DEVICE_INITED
+# define STATUS_SERIAL_NO_DEVICE_INITED ((NTSTATUS) 0xC0000150L)
+#endif
+
+#ifndef STATUS_NO_SUCH_ALIAS
+# define STATUS_NO_SUCH_ALIAS ((NTSTATUS) 0xC0000151L)
+#endif
+
+#ifndef STATUS_MEMBER_NOT_IN_ALIAS
+# define STATUS_MEMBER_NOT_IN_ALIAS ((NTSTATUS) 0xC0000152L)
+#endif
+
+#ifndef STATUS_MEMBER_IN_ALIAS
+# define STATUS_MEMBER_IN_ALIAS ((NTSTATUS) 0xC0000153L)
+#endif
+
+#ifndef STATUS_ALIAS_EXISTS
+# define STATUS_ALIAS_EXISTS ((NTSTATUS) 0xC0000154L)
+#endif
+
+#ifndef STATUS_LOGON_NOT_GRANTED
+# define STATUS_LOGON_NOT_GRANTED ((NTSTATUS) 0xC0000155L)
+#endif
+
+#ifndef STATUS_TOO_MANY_SECRETS
+# define STATUS_TOO_MANY_SECRETS ((NTSTATUS) 0xC0000156L)
+#endif
+
+#ifndef STATUS_SECRET_TOO_LONG
+# define STATUS_SECRET_TOO_LONG ((NTSTATUS) 0xC0000157L)
+#endif
+
+#ifndef STATUS_INTERNAL_DB_ERROR
+# define STATUS_INTERNAL_DB_ERROR ((NTSTATUS) 0xC0000158L)
+#endif
+
+#ifndef STATUS_FULLSCREEN_MODE
+# define STATUS_FULLSCREEN_MODE ((NTSTATUS) 0xC0000159L)
+#endif
+
+#ifndef STATUS_TOO_MANY_CONTEXT_IDS
+# define STATUS_TOO_MANY_CONTEXT_IDS ((NTSTATUS) 0xC000015AL)
+#endif
+
+#ifndef STATUS_LOGON_TYPE_NOT_GRANTED
+# define STATUS_LOGON_TYPE_NOT_GRANTED ((NTSTATUS) 0xC000015BL)
+#endif
+
+#ifndef STATUS_NOT_REGISTRY_FILE
+# define STATUS_NOT_REGISTRY_FILE ((NTSTATUS) 0xC000015CL)
+#endif
+
+#ifndef STATUS_NT_CROSS_ENCRYPTION_REQUIRED
+# define STATUS_NT_CROSS_ENCRYPTION_REQUIRED ((NTSTATUS) 0xC000015DL)
+#endif
+
+#ifndef STATUS_DOMAIN_CTRLR_CONFIG_ERROR
+# define STATUS_DOMAIN_CTRLR_CONFIG_ERROR ((NTSTATUS) 0xC000015EL)
+#endif
+
+#ifndef STATUS_FT_MISSING_MEMBER
+# define STATUS_FT_MISSING_MEMBER ((NTSTATUS) 0xC000015FL)
+#endif
+
+#ifndef STATUS_ILL_FORMED_SERVICE_ENTRY
+# define STATUS_ILL_FORMED_SERVICE_ENTRY ((NTSTATUS) 0xC0000160L)
+#endif
+
+#ifndef STATUS_ILLEGAL_CHARACTER
+# define STATUS_ILLEGAL_CHARACTER ((NTSTATUS) 0xC0000161L)
+#endif
+
+#ifndef STATUS_UNMAPPABLE_CHARACTER
+# define STATUS_UNMAPPABLE_CHARACTER ((NTSTATUS) 0xC0000162L)
+#endif
+
+#ifndef STATUS_UNDEFINED_CHARACTER
+# define STATUS_UNDEFINED_CHARACTER ((NTSTATUS) 0xC0000163L)
+#endif
+
+#ifndef STATUS_FLOPPY_VOLUME
+# define STATUS_FLOPPY_VOLUME ((NTSTATUS) 0xC0000164L)
+#endif
+
+#ifndef STATUS_FLOPPY_ID_MARK_NOT_FOUND
+# define STATUS_FLOPPY_ID_MARK_NOT_FOUND ((NTSTATUS) 0xC0000165L)
+#endif
+
+#ifndef STATUS_FLOPPY_WRONG_CYLINDER
+# define STATUS_FLOPPY_WRONG_CYLINDER ((NTSTATUS) 0xC0000166L)
+#endif
+
+#ifndef STATUS_FLOPPY_UNKNOWN_ERROR
+# define STATUS_FLOPPY_UNKNOWN_ERROR ((NTSTATUS) 0xC0000167L)
+#endif
+
+#ifndef STATUS_FLOPPY_BAD_REGISTERS
+# define STATUS_FLOPPY_BAD_REGISTERS ((NTSTATUS) 0xC0000168L)
+#endif
+
+#ifndef STATUS_DISK_RECALIBRATE_FAILED
+# define STATUS_DISK_RECALIBRATE_FAILED ((NTSTATUS) 0xC0000169L)
+#endif
+
+#ifndef STATUS_DISK_OPERATION_FAILED
+# define STATUS_DISK_OPERATION_FAILED ((NTSTATUS) 0xC000016AL)
+#endif
+
+#ifndef STATUS_DISK_RESET_FAILED
+# define STATUS_DISK_RESET_FAILED ((NTSTATUS) 0xC000016BL)
+#endif
+
+#ifndef STATUS_SHARED_IRQ_BUSY
+# define STATUS_SHARED_IRQ_BUSY ((NTSTATUS) 0xC000016CL)
+#endif
+
+#ifndef STATUS_FT_ORPHANING
+# define STATUS_FT_ORPHANING ((NTSTATUS) 0xC000016DL)
+#endif
+
+#ifndef STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT
+# define STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT ((NTSTATUS) 0xC000016EL)
+#endif
+
+#ifndef STATUS_PARTITION_FAILURE
+# define STATUS_PARTITION_FAILURE ((NTSTATUS) 0xC0000172L)
+#endif
+
+#ifndef STATUS_INVALID_BLOCK_LENGTH
+# define STATUS_INVALID_BLOCK_LENGTH ((NTSTATUS) 0xC0000173L)
+#endif
+
+#ifndef STATUS_DEVICE_NOT_PARTITIONED
+# define STATUS_DEVICE_NOT_PARTITIONED ((NTSTATUS) 0xC0000174L)
+#endif
+
+#ifndef STATUS_UNABLE_TO_LOCK_MEDIA
+# define STATUS_UNABLE_TO_LOCK_MEDIA ((NTSTATUS) 0xC0000175L)
+#endif
+
+#ifndef STATUS_UNABLE_TO_UNLOAD_MEDIA
+# define STATUS_UNABLE_TO_UNLOAD_MEDIA ((NTSTATUS) 0xC0000176L)
+#endif
+
+#ifndef STATUS_EOM_OVERFLOW
+# define STATUS_EOM_OVERFLOW ((NTSTATUS) 0xC0000177L)
+#endif
+
+#ifndef STATUS_NO_MEDIA
+# define STATUS_NO_MEDIA ((NTSTATUS) 0xC0000178L)
+#endif
+
+#ifndef STATUS_NO_SUCH_MEMBER
+# define STATUS_NO_SUCH_MEMBER ((NTSTATUS) 0xC000017AL)
+#endif
+
+#ifndef STATUS_INVALID_MEMBER
+# define STATUS_INVALID_MEMBER ((NTSTATUS) 0xC000017BL)
+#endif
+
+#ifndef STATUS_KEY_DELETED
+# define STATUS_KEY_DELETED ((NTSTATUS) 0xC000017CL)
+#endif
+
+#ifndef STATUS_NO_LOG_SPACE
+# define STATUS_NO_LOG_SPACE ((NTSTATUS) 0xC000017DL)
+#endif
+
+#ifndef STATUS_TOO_MANY_SIDS
+# define STATUS_TOO_MANY_SIDS ((NTSTATUS) 0xC000017EL)
+#endif
+
+#ifndef STATUS_LM_CROSS_ENCRYPTION_REQUIRED
+# define STATUS_LM_CROSS_ENCRYPTION_REQUIRED ((NTSTATUS) 0xC000017FL)
+#endif
+
+#ifndef STATUS_KEY_HAS_CHILDREN
+# define STATUS_KEY_HAS_CHILDREN ((NTSTATUS) 0xC0000180L)
+#endif
+
+#ifndef STATUS_CHILD_MUST_BE_VOLATILE
+# define STATUS_CHILD_MUST_BE_VOLATILE ((NTSTATUS) 0xC0000181L)
+#endif
+
+#ifndef STATUS_DEVICE_CONFIGURATION_ERROR
+# define STATUS_DEVICE_CONFIGURATION_ERROR ((NTSTATUS) 0xC0000182L)
+#endif
+
+#ifndef STATUS_DRIVER_INTERNAL_ERROR
+# define STATUS_DRIVER_INTERNAL_ERROR ((NTSTATUS) 0xC0000183L)
+#endif
+
+#ifndef STATUS_INVALID_DEVICE_STATE
+# define STATUS_INVALID_DEVICE_STATE ((NTSTATUS) 0xC0000184L)
+#endif
+
+#ifndef STATUS_IO_DEVICE_ERROR
+# define STATUS_IO_DEVICE_ERROR ((NTSTATUS) 0xC0000185L)
+#endif
+
+#ifndef STATUS_DEVICE_PROTOCOL_ERROR
+# define STATUS_DEVICE_PROTOCOL_ERROR ((NTSTATUS) 0xC0000186L)
+#endif
+
+#ifndef STATUS_BACKUP_CONTROLLER
+# define STATUS_BACKUP_CONTROLLER ((NTSTATUS) 0xC0000187L)
+#endif
+
+#ifndef STATUS_LOG_FILE_FULL
+# define STATUS_LOG_FILE_FULL ((NTSTATUS) 0xC0000188L)
+#endif
+
+#ifndef STATUS_TOO_LATE
+# define STATUS_TOO_LATE ((NTSTATUS) 0xC0000189L)
+#endif
+
+#ifndef STATUS_NO_TRUST_LSA_SECRET
+# define STATUS_NO_TRUST_LSA_SECRET ((NTSTATUS) 0xC000018AL)
+#endif
+
+#ifndef STATUS_NO_TRUST_SAM_ACCOUNT
+# define STATUS_NO_TRUST_SAM_ACCOUNT ((NTSTATUS) 0xC000018BL)
+#endif
+
+#ifndef STATUS_TRUSTED_DOMAIN_FAILURE
+# define STATUS_TRUSTED_DOMAIN_FAILURE ((NTSTATUS) 0xC000018CL)
+#endif
+
+#ifndef STATUS_TRUSTED_RELATIONSHIP_FAILURE
+# define STATUS_TRUSTED_RELATIONSHIP_FAILURE ((NTSTATUS) 0xC000018DL)
+#endif
+
+#ifndef STATUS_EVENTLOG_FILE_CORRUPT
+# define STATUS_EVENTLOG_FILE_CORRUPT ((NTSTATUS) 0xC000018EL)
+#endif
+
+#ifndef STATUS_EVENTLOG_CANT_START
+# define STATUS_EVENTLOG_CANT_START ((NTSTATUS) 0xC000018FL)
+#endif
+
+#ifndef STATUS_TRUST_FAILURE
+# define STATUS_TRUST_FAILURE ((NTSTATUS) 0xC0000190L)
+#endif
+
+#ifndef STATUS_MUTANT_LIMIT_EXCEEDED
+# define STATUS_MUTANT_LIMIT_EXCEEDED ((NTSTATUS) 0xC0000191L)
+#endif
+
+#ifndef STATUS_NETLOGON_NOT_STARTED
+# define STATUS_NETLOGON_NOT_STARTED ((NTSTATUS) 0xC0000192L)
+#endif
+
+#ifndef STATUS_ACCOUNT_EXPIRED
+# define STATUS_ACCOUNT_EXPIRED ((NTSTATUS) 0xC0000193L)
+#endif
+
+#ifndef STATUS_POSSIBLE_DEADLOCK
+# define STATUS_POSSIBLE_DEADLOCK ((NTSTATUS) 0xC0000194L)
+#endif
+
+#ifndef STATUS_NETWORK_CREDENTIAL_CONFLICT
+# define STATUS_NETWORK_CREDENTIAL_CONFLICT ((NTSTATUS) 0xC0000195L)
+#endif
+
+#ifndef STATUS_REMOTE_SESSION_LIMIT
+# define STATUS_REMOTE_SESSION_LIMIT ((NTSTATUS) 0xC0000196L)
+#endif
+
+#ifndef STATUS_EVENTLOG_FILE_CHANGED
+# define STATUS_EVENTLOG_FILE_CHANGED ((NTSTATUS) 0xC0000197L)
+#endif
+
+#ifndef STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT
+# define STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT ((NTSTATUS) 0xC0000198L)
+#endif
+
+#ifndef STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
+# define STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT ((NTSTATUS) 0xC0000199L)
+#endif
+
+#ifndef STATUS_NOLOGON_SERVER_TRUST_ACCOUNT
+# define STATUS_NOLOGON_SERVER_TRUST_ACCOUNT ((NTSTATUS) 0xC000019AL)
+#endif
+
+#ifndef STATUS_DOMAIN_TRUST_INCONSISTENT
+# define STATUS_DOMAIN_TRUST_INCONSISTENT ((NTSTATUS) 0xC000019BL)
+#endif
+
+#ifndef STATUS_FS_DRIVER_REQUIRED
+# define STATUS_FS_DRIVER_REQUIRED ((NTSTATUS) 0xC000019CL)
+#endif
+
+#ifndef STATUS_IMAGE_ALREADY_LOADED_AS_DLL
+# define STATUS_IMAGE_ALREADY_LOADED_AS_DLL ((NTSTATUS) 0xC000019DL)
+#endif
+
+#ifndef STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING
+# define STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING ((NTSTATUS) 0xC000019EL)
+#endif
+
+#ifndef STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME
+# define STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME ((NTSTATUS) 0xC000019FL)
+#endif
+
+#ifndef STATUS_SECURITY_STREAM_IS_INCONSISTENT
+# define STATUS_SECURITY_STREAM_IS_INCONSISTENT ((NTSTATUS) 0xC00001A0L)
+#endif
+
+#ifndef STATUS_INVALID_LOCK_RANGE
+# define STATUS_INVALID_LOCK_RANGE ((NTSTATUS) 0xC00001A1L)
+#endif
+
+#ifndef STATUS_INVALID_ACE_CONDITION
+# define STATUS_INVALID_ACE_CONDITION ((NTSTATUS) 0xC00001A2L)
+#endif
+
+#ifndef STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT
+# define STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT ((NTSTATUS) 0xC00001A3L)
+#endif
+
+#ifndef STATUS_NOTIFICATION_GUID_ALREADY_DEFINED
+# define STATUS_NOTIFICATION_GUID_ALREADY_DEFINED ((NTSTATUS) 0xC00001A4L)
+#endif
+
+#ifndef STATUS_NETWORK_OPEN_RESTRICTION
+# define STATUS_NETWORK_OPEN_RESTRICTION ((NTSTATUS) 0xC0000201L)
+#endif
+
+#ifndef STATUS_NO_USER_SESSION_KEY
+# define STATUS_NO_USER_SESSION_KEY ((NTSTATUS) 0xC0000202L)
+#endif
+
+#ifndef STATUS_USER_SESSION_DELETED
+# define STATUS_USER_SESSION_DELETED ((NTSTATUS) 0xC0000203L)
+#endif
+
+#ifndef STATUS_RESOURCE_LANG_NOT_FOUND
+# define STATUS_RESOURCE_LANG_NOT_FOUND ((NTSTATUS) 0xC0000204L)
+#endif
+
+#ifndef STATUS_INSUFF_SERVER_RESOURCES
+# define STATUS_INSUFF_SERVER_RESOURCES ((NTSTATUS) 0xC0000205L)
+#endif
+
+#ifndef STATUS_INVALID_BUFFER_SIZE
+# define STATUS_INVALID_BUFFER_SIZE ((NTSTATUS) 0xC0000206L)
+#endif
+
+#ifndef STATUS_INVALID_ADDRESS_COMPONENT
+# define STATUS_INVALID_ADDRESS_COMPONENT ((NTSTATUS) 0xC0000207L)
+#endif
+
+#ifndef STATUS_INVALID_ADDRESS_WILDCARD
+# define STATUS_INVALID_ADDRESS_WILDCARD ((NTSTATUS) 0xC0000208L)
+#endif
+
+#ifndef STATUS_TOO_MANY_ADDRESSES
+# define STATUS_TOO_MANY_ADDRESSES ((NTSTATUS) 0xC0000209L)
+#endif
+
+#ifndef STATUS_ADDRESS_ALREADY_EXISTS
+# define STATUS_ADDRESS_ALREADY_EXISTS ((NTSTATUS) 0xC000020AL)
+#endif
+
+#ifndef STATUS_ADDRESS_CLOSED
+# define STATUS_ADDRESS_CLOSED ((NTSTATUS) 0xC000020BL)
+#endif
+
+#ifndef STATUS_CONNECTION_DISCONNECTED
+# define STATUS_CONNECTION_DISCONNECTED ((NTSTATUS) 0xC000020CL)
+#endif
+
+#ifndef STATUS_CONNECTION_RESET
+# define STATUS_CONNECTION_RESET ((NTSTATUS) 0xC000020DL)
+#endif
+
+#ifndef STATUS_TOO_MANY_NODES
+# define STATUS_TOO_MANY_NODES ((NTSTATUS) 0xC000020EL)
+#endif
+
+#ifndef STATUS_TRANSACTION_ABORTED
+# define STATUS_TRANSACTION_ABORTED ((NTSTATUS) 0xC000020FL)
+#endif
+
+#ifndef STATUS_TRANSACTION_TIMED_OUT
+# define STATUS_TRANSACTION_TIMED_OUT ((NTSTATUS) 0xC0000210L)
+#endif
+
+#ifndef STATUS_TRANSACTION_NO_RELEASE
+# define STATUS_TRANSACTION_NO_RELEASE ((NTSTATUS) 0xC0000211L)
+#endif
+
+#ifndef STATUS_TRANSACTION_NO_MATCH
+# define STATUS_TRANSACTION_NO_MATCH ((NTSTATUS) 0xC0000212L)
+#endif
+
+#ifndef STATUS_TRANSACTION_RESPONDED
+# define STATUS_TRANSACTION_RESPONDED ((NTSTATUS) 0xC0000213L)
+#endif
+
+#ifndef STATUS_TRANSACTION_INVALID_ID
+# define STATUS_TRANSACTION_INVALID_ID ((NTSTATUS) 0xC0000214L)
+#endif
+
+#ifndef STATUS_TRANSACTION_INVALID_TYPE
+# define STATUS_TRANSACTION_INVALID_TYPE ((NTSTATUS) 0xC0000215L)
+#endif
+
+#ifndef STATUS_NOT_SERVER_SESSION
+# define STATUS_NOT_SERVER_SESSION ((NTSTATUS) 0xC0000216L)
+#endif
+
+#ifndef STATUS_NOT_CLIENT_SESSION
+# define STATUS_NOT_CLIENT_SESSION ((NTSTATUS) 0xC0000217L)
+#endif
+
+#ifndef STATUS_CANNOT_LOAD_REGISTRY_FILE
+# define STATUS_CANNOT_LOAD_REGISTRY_FILE ((NTSTATUS) 0xC0000218L)
+#endif
+
+#ifndef STATUS_DEBUG_ATTACH_FAILED
+# define STATUS_DEBUG_ATTACH_FAILED ((NTSTATUS) 0xC0000219L)
+#endif
+
+#ifndef STATUS_SYSTEM_PROCESS_TERMINATED
+# define STATUS_SYSTEM_PROCESS_TERMINATED ((NTSTATUS) 0xC000021AL)
+#endif
+
+#ifndef STATUS_DATA_NOT_ACCEPTED
+# define STATUS_DATA_NOT_ACCEPTED ((NTSTATUS) 0xC000021BL)
+#endif
+
+#ifndef STATUS_NO_BROWSER_SERVERS_FOUND
+# define STATUS_NO_BROWSER_SERVERS_FOUND ((NTSTATUS) 0xC000021CL)
+#endif
+
+#ifndef STATUS_VDM_HARD_ERROR
+# define STATUS_VDM_HARD_ERROR ((NTSTATUS) 0xC000021DL)
+#endif
+
+#ifndef STATUS_DRIVER_CANCEL_TIMEOUT
+# define STATUS_DRIVER_CANCEL_TIMEOUT ((NTSTATUS) 0xC000021EL)
+#endif
+
+#ifndef STATUS_REPLY_MESSAGE_MISMATCH
+# define STATUS_REPLY_MESSAGE_MISMATCH ((NTSTATUS) 0xC000021FL)
+#endif
+
+#ifndef STATUS_MAPPED_ALIGNMENT
+# define STATUS_MAPPED_ALIGNMENT ((NTSTATUS) 0xC0000220L)
+#endif
+
+#ifndef STATUS_IMAGE_CHECKSUM_MISMATCH
+# define STATUS_IMAGE_CHECKSUM_MISMATCH ((NTSTATUS) 0xC0000221L)
+#endif
+
+#ifndef STATUS_LOST_WRITEBEHIND_DATA
+# define STATUS_LOST_WRITEBEHIND_DATA ((NTSTATUS) 0xC0000222L)
+#endif
+
+#ifndef STATUS_CLIENT_SERVER_PARAMETERS_INVALID
+# define STATUS_CLIENT_SERVER_PARAMETERS_INVALID ((NTSTATUS) 0xC0000223L)
+#endif
+
+#ifndef STATUS_PASSWORD_MUST_CHANGE
+# define STATUS_PASSWORD_MUST_CHANGE ((NTSTATUS) 0xC0000224L)
+#endif
+
+#ifndef STATUS_NOT_FOUND
+# define STATUS_NOT_FOUND ((NTSTATUS) 0xC0000225L)
+#endif
+
+#ifndef STATUS_NOT_TINY_STREAM
+# define STATUS_NOT_TINY_STREAM ((NTSTATUS) 0xC0000226L)
+#endif
+
+#ifndef STATUS_RECOVERY_FAILURE
+# define STATUS_RECOVERY_FAILURE ((NTSTATUS) 0xC0000227L)
+#endif
+
+#ifndef STATUS_STACK_OVERFLOW_READ
+# define STATUS_STACK_OVERFLOW_READ ((NTSTATUS) 0xC0000228L)
+#endif
+
+#ifndef STATUS_FAIL_CHECK
+# define STATUS_FAIL_CHECK ((NTSTATUS) 0xC0000229L)
+#endif
+
+#ifndef STATUS_DUPLICATE_OBJECTID
+# define STATUS_DUPLICATE_OBJECTID ((NTSTATUS) 0xC000022AL)
+#endif
+
+#ifndef STATUS_OBJECTID_EXISTS
+# define STATUS_OBJECTID_EXISTS ((NTSTATUS) 0xC000022BL)
+#endif
+
+#ifndef STATUS_CONVERT_TO_LARGE
+# define STATUS_CONVERT_TO_LARGE ((NTSTATUS) 0xC000022CL)
+#endif
+
+#ifndef STATUS_RETRY
+# define STATUS_RETRY ((NTSTATUS) 0xC000022DL)
+#endif
+
+#ifndef STATUS_FOUND_OUT_OF_SCOPE
+# define STATUS_FOUND_OUT_OF_SCOPE ((NTSTATUS) 0xC000022EL)
+#endif
+
+#ifndef STATUS_ALLOCATE_BUCKET
+# define STATUS_ALLOCATE_BUCKET ((NTSTATUS) 0xC000022FL)
+#endif
+
+#ifndef STATUS_PROPSET_NOT_FOUND
+# define STATUS_PROPSET_NOT_FOUND ((NTSTATUS) 0xC0000230L)
+#endif
+
+#ifndef STATUS_MARSHALL_OVERFLOW
+# define STATUS_MARSHALL_OVERFLOW ((NTSTATUS) 0xC0000231L)
+#endif
+
+#ifndef STATUS_INVALID_VARIANT
+# define STATUS_INVALID_VARIANT ((NTSTATUS) 0xC0000232L)
+#endif
+
+#ifndef STATUS_DOMAIN_CONTROLLER_NOT_FOUND
+# define STATUS_DOMAIN_CONTROLLER_NOT_FOUND ((NTSTATUS) 0xC0000233L)
+#endif
+
+#ifndef STATUS_ACCOUNT_LOCKED_OUT
+# define STATUS_ACCOUNT_LOCKED_OUT ((NTSTATUS) 0xC0000234L)
+#endif
+
+#ifndef STATUS_HANDLE_NOT_CLOSABLE
+# define STATUS_HANDLE_NOT_CLOSABLE ((NTSTATUS) 0xC0000235L)
+#endif
+
+#ifndef STATUS_CONNECTION_REFUSED
+# define STATUS_CONNECTION_REFUSED ((NTSTATUS) 0xC0000236L)
+#endif
+
+#ifndef STATUS_GRACEFUL_DISCONNECT
+# define STATUS_GRACEFUL_DISCONNECT ((NTSTATUS) 0xC0000237L)
+#endif
+
+#ifndef STATUS_ADDRESS_ALREADY_ASSOCIATED
+# define STATUS_ADDRESS_ALREADY_ASSOCIATED ((NTSTATUS) 0xC0000238L)
+#endif
+
+#ifndef STATUS_ADDRESS_NOT_ASSOCIATED
+# define STATUS_ADDRESS_NOT_ASSOCIATED ((NTSTATUS) 0xC0000239L)
+#endif
+
+#ifndef STATUS_CONNECTION_INVALID
+# define STATUS_CONNECTION_INVALID ((NTSTATUS) 0xC000023AL)
+#endif
+
+#ifndef STATUS_CONNECTION_ACTIVE
+# define STATUS_CONNECTION_ACTIVE ((NTSTATUS) 0xC000023BL)
+#endif
+
+#ifndef STATUS_NETWORK_UNREACHABLE
+# define STATUS_NETWORK_UNREACHABLE ((NTSTATUS) 0xC000023CL)
+#endif
+
+#ifndef STATUS_HOST_UNREACHABLE
+# define STATUS_HOST_UNREACHABLE ((NTSTATUS) 0xC000023DL)
+#endif
+
+#ifndef STATUS_PROTOCOL_UNREACHABLE
+# define STATUS_PROTOCOL_UNREACHABLE ((NTSTATUS) 0xC000023EL)
+#endif
+
+#ifndef STATUS_PORT_UNREACHABLE
+# define STATUS_PORT_UNREACHABLE ((NTSTATUS) 0xC000023FL)
+#endif
+
+#ifndef STATUS_REQUEST_ABORTED
+# define STATUS_REQUEST_ABORTED ((NTSTATUS) 0xC0000240L)
+#endif
+
+#ifndef STATUS_CONNECTION_ABORTED
+# define STATUS_CONNECTION_ABORTED ((NTSTATUS) 0xC0000241L)
+#endif
+
+#ifndef STATUS_BAD_COMPRESSION_BUFFER
+# define STATUS_BAD_COMPRESSION_BUFFER ((NTSTATUS) 0xC0000242L)
+#endif
+
+#ifndef STATUS_USER_MAPPED_FILE
+# define STATUS_USER_MAPPED_FILE ((NTSTATUS) 0xC0000243L)
+#endif
+
+#ifndef STATUS_AUDIT_FAILED
+# define STATUS_AUDIT_FAILED ((NTSTATUS) 0xC0000244L)
+#endif
+
+#ifndef STATUS_TIMER_RESOLUTION_NOT_SET
+# define STATUS_TIMER_RESOLUTION_NOT_SET ((NTSTATUS) 0xC0000245L)
+#endif
+
+#ifndef STATUS_CONNECTION_COUNT_LIMIT
+# define STATUS_CONNECTION_COUNT_LIMIT ((NTSTATUS) 0xC0000246L)
+#endif
+
+#ifndef STATUS_LOGIN_TIME_RESTRICTION
+# define STATUS_LOGIN_TIME_RESTRICTION ((NTSTATUS) 0xC0000247L)
+#endif
+
+#ifndef STATUS_LOGIN_WKSTA_RESTRICTION
+# define STATUS_LOGIN_WKSTA_RESTRICTION ((NTSTATUS) 0xC0000248L)
+#endif
+
+#ifndef STATUS_IMAGE_MP_UP_MISMATCH
+# define STATUS_IMAGE_MP_UP_MISMATCH ((NTSTATUS) 0xC0000249L)
+#endif
+
+#ifndef STATUS_INSUFFICIENT_LOGON_INFO
+# define STATUS_INSUFFICIENT_LOGON_INFO ((NTSTATUS) 0xC0000250L)
+#endif
+
+#ifndef STATUS_BAD_DLL_ENTRYPOINT
+# define STATUS_BAD_DLL_ENTRYPOINT ((NTSTATUS) 0xC0000251L)
+#endif
+
+#ifndef STATUS_BAD_SERVICE_ENTRYPOINT
+# define STATUS_BAD_SERVICE_ENTRYPOINT ((NTSTATUS) 0xC0000252L)
+#endif
+
+#ifndef STATUS_LPC_REPLY_LOST
+# define STATUS_LPC_REPLY_LOST ((NTSTATUS) 0xC0000253L)
+#endif
+
+#ifndef STATUS_IP_ADDRESS_CONFLICT1
+# define STATUS_IP_ADDRESS_CONFLICT1 ((NTSTATUS) 0xC0000254L)
+#endif
+
+#ifndef STATUS_IP_ADDRESS_CONFLICT2
+# define STATUS_IP_ADDRESS_CONFLICT2 ((NTSTATUS) 0xC0000255L)
+#endif
+
+#ifndef STATUS_REGISTRY_QUOTA_LIMIT
+# define STATUS_REGISTRY_QUOTA_LIMIT ((NTSTATUS) 0xC0000256L)
+#endif
+
+#ifndef STATUS_PATH_NOT_COVERED
+# define STATUS_PATH_NOT_COVERED ((NTSTATUS) 0xC0000257L)
+#endif
+
+#ifndef STATUS_NO_CALLBACK_ACTIVE
+# define STATUS_NO_CALLBACK_ACTIVE ((NTSTATUS) 0xC0000258L)
+#endif
+
+#ifndef STATUS_LICENSE_QUOTA_EXCEEDED
+# define STATUS_LICENSE_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000259L)
+#endif
+
+#ifndef STATUS_PWD_TOO_SHORT
+# define STATUS_PWD_TOO_SHORT ((NTSTATUS) 0xC000025AL)
+#endif
+
+#ifndef STATUS_PWD_TOO_RECENT
+# define STATUS_PWD_TOO_RECENT ((NTSTATUS) 0xC000025BL)
+#endif
+
+#ifndef STATUS_PWD_HISTORY_CONFLICT
+# define STATUS_PWD_HISTORY_CONFLICT ((NTSTATUS) 0xC000025CL)
+#endif
+
+#ifndef STATUS_PLUGPLAY_NO_DEVICE
+# define STATUS_PLUGPLAY_NO_DEVICE ((NTSTATUS) 0xC000025EL)
+#endif
+
+#ifndef STATUS_UNSUPPORTED_COMPRESSION
+# define STATUS_UNSUPPORTED_COMPRESSION ((NTSTATUS) 0xC000025FL)
+#endif
+
+#ifndef STATUS_INVALID_HW_PROFILE
+# define STATUS_INVALID_HW_PROFILE ((NTSTATUS) 0xC0000260L)
+#endif
+
+#ifndef STATUS_INVALID_PLUGPLAY_DEVICE_PATH
+# define STATUS_INVALID_PLUGPLAY_DEVICE_PATH ((NTSTATUS) 0xC0000261L)
+#endif
+
+#ifndef STATUS_DRIVER_ORDINAL_NOT_FOUND
+# define STATUS_DRIVER_ORDINAL_NOT_FOUND ((NTSTATUS) 0xC0000262L)
+#endif
+
+#ifndef STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
+# define STATUS_DRIVER_ENTRYPOINT_NOT_FOUND ((NTSTATUS) 0xC0000263L)
+#endif
+
+#ifndef STATUS_RESOURCE_NOT_OWNED
+# define STATUS_RESOURCE_NOT_OWNED ((NTSTATUS) 0xC0000264L)
+#endif
+
+#ifndef STATUS_TOO_MANY_LINKS
+# define STATUS_TOO_MANY_LINKS ((NTSTATUS) 0xC0000265L)
+#endif
+
+#ifndef STATUS_QUOTA_LIST_INCONSISTENT
+# define STATUS_QUOTA_LIST_INCONSISTENT ((NTSTATUS) 0xC0000266L)
+#endif
+
+#ifndef STATUS_FILE_IS_OFFLINE
+# define STATUS_FILE_IS_OFFLINE ((NTSTATUS) 0xC0000267L)
+#endif
+
+#ifndef STATUS_EVALUATION_EXPIRATION
+# define STATUS_EVALUATION_EXPIRATION ((NTSTATUS) 0xC0000268L)
+#endif
+
+#ifndef STATUS_ILLEGAL_DLL_RELOCATION
+# define STATUS_ILLEGAL_DLL_RELOCATION ((NTSTATUS) 0xC0000269L)
+#endif
+
+#ifndef STATUS_LICENSE_VIOLATION
+# define STATUS_LICENSE_VIOLATION ((NTSTATUS) 0xC000026AL)
+#endif
+
+#ifndef STATUS_DLL_INIT_FAILED_LOGOFF
+# define STATUS_DLL_INIT_FAILED_LOGOFF ((NTSTATUS) 0xC000026BL)
+#endif
+
+#ifndef STATUS_DRIVER_UNABLE_TO_LOAD
+# define STATUS_DRIVER_UNABLE_TO_LOAD ((NTSTATUS) 0xC000026CL)
+#endif
+
+#ifndef STATUS_DFS_UNAVAILABLE
+# define STATUS_DFS_UNAVAILABLE ((NTSTATUS) 0xC000026DL)
+#endif
+
+#ifndef STATUS_VOLUME_DISMOUNTED
+# define STATUS_VOLUME_DISMOUNTED ((NTSTATUS) 0xC000026EL)
+#endif
+
+#ifndef STATUS_WX86_INTERNAL_ERROR
+# define STATUS_WX86_INTERNAL_ERROR ((NTSTATUS) 0xC000026FL)
+#endif
+
+#ifndef STATUS_WX86_FLOAT_STACK_CHECK
+# define STATUS_WX86_FLOAT_STACK_CHECK ((NTSTATUS) 0xC0000270L)
+#endif
+
+#ifndef STATUS_VALIDATE_CONTINUE
+# define STATUS_VALIDATE_CONTINUE ((NTSTATUS) 0xC0000271L)
+#endif
+
+#ifndef STATUS_NO_MATCH
+# define STATUS_NO_MATCH ((NTSTATUS) 0xC0000272L)
+#endif
+
+#ifndef STATUS_NO_MORE_MATCHES
+# define STATUS_NO_MORE_MATCHES ((NTSTATUS) 0xC0000273L)
+#endif
+
+#ifndef STATUS_NOT_A_REPARSE_POINT
+# define STATUS_NOT_A_REPARSE_POINT ((NTSTATUS) 0xC0000275L)
+#endif
+
+#ifndef STATUS_IO_REPARSE_TAG_INVALID
+# define STATUS_IO_REPARSE_TAG_INVALID ((NTSTATUS) 0xC0000276L)
+#endif
+
+#ifndef STATUS_IO_REPARSE_TAG_MISMATCH
+# define STATUS_IO_REPARSE_TAG_MISMATCH ((NTSTATUS) 0xC0000277L)
+#endif
+
+#ifndef STATUS_IO_REPARSE_DATA_INVALID
+# define STATUS_IO_REPARSE_DATA_INVALID ((NTSTATUS) 0xC0000278L)
+#endif
+
+#ifndef STATUS_IO_REPARSE_TAG_NOT_HANDLED
+# define STATUS_IO_REPARSE_TAG_NOT_HANDLED ((NTSTATUS) 0xC0000279L)
+#endif
+
+#ifndef STATUS_REPARSE_POINT_NOT_RESOLVED
+# define STATUS_REPARSE_POINT_NOT_RESOLVED ((NTSTATUS) 0xC0000280L)
+#endif
+
+#ifndef STATUS_DIRECTORY_IS_A_REPARSE_POINT
+# define STATUS_DIRECTORY_IS_A_REPARSE_POINT ((NTSTATUS) 0xC0000281L)
+#endif
+
+#ifndef STATUS_RANGE_LIST_CONFLICT
+# define STATUS_RANGE_LIST_CONFLICT ((NTSTATUS) 0xC0000282L)
+#endif
+
+#ifndef STATUS_SOURCE_ELEMENT_EMPTY
+# define STATUS_SOURCE_ELEMENT_EMPTY ((NTSTATUS) 0xC0000283L)
+#endif
+
+#ifndef STATUS_DESTINATION_ELEMENT_FULL
+# define STATUS_DESTINATION_ELEMENT_FULL ((NTSTATUS) 0xC0000284L)
+#endif
+
+#ifndef STATUS_ILLEGAL_ELEMENT_ADDRESS
+# define STATUS_ILLEGAL_ELEMENT_ADDRESS ((NTSTATUS) 0xC0000285L)
+#endif
+
+#ifndef STATUS_MAGAZINE_NOT_PRESENT
+# define STATUS_MAGAZINE_NOT_PRESENT ((NTSTATUS) 0xC0000286L)
+#endif
+
+#ifndef STATUS_REINITIALIZATION_NEEDED
+# define STATUS_REINITIALIZATION_NEEDED ((NTSTATUS) 0xC0000287L)
+#endif
+
+#ifndef STATUS_DEVICE_REQUIRES_CLEANING
+# define STATUS_DEVICE_REQUIRES_CLEANING ((NTSTATUS) 0x80000288L)
+#endif
+
+#ifndef STATUS_DEVICE_DOOR_OPEN
+# define STATUS_DEVICE_DOOR_OPEN ((NTSTATUS) 0x80000289L)
+#endif
+
+#ifndef STATUS_ENCRYPTION_FAILED
+# define STATUS_ENCRYPTION_FAILED ((NTSTATUS) 0xC000028AL)
+#endif
+
+#ifndef STATUS_DECRYPTION_FAILED
+# define STATUS_DECRYPTION_FAILED ((NTSTATUS) 0xC000028BL)
+#endif
+
+#ifndef STATUS_RANGE_NOT_FOUND
+# define STATUS_RANGE_NOT_FOUND ((NTSTATUS) 0xC000028CL)
+#endif
+
+#ifndef STATUS_NO_RECOVERY_POLICY
+# define STATUS_NO_RECOVERY_POLICY ((NTSTATUS) 0xC000028DL)
+#endif
+
+#ifndef STATUS_NO_EFS
+# define STATUS_NO_EFS ((NTSTATUS) 0xC000028EL)
+#endif
+
+#ifndef STATUS_WRONG_EFS
+# define STATUS_WRONG_EFS ((NTSTATUS) 0xC000028FL)
+#endif
+
+#ifndef STATUS_NO_USER_KEYS
+# define STATUS_NO_USER_KEYS ((NTSTATUS) 0xC0000290L)
+#endif
+
+#ifndef STATUS_FILE_NOT_ENCRYPTED
+# define STATUS_FILE_NOT_ENCRYPTED ((NTSTATUS) 0xC0000291L)
+#endif
+
+#ifndef STATUS_NOT_EXPORT_FORMAT
+# define STATUS_NOT_EXPORT_FORMAT ((NTSTATUS) 0xC0000292L)
+#endif
+
+#ifndef STATUS_FILE_ENCRYPTED
+# define STATUS_FILE_ENCRYPTED ((NTSTATUS) 0xC0000293L)
+#endif
+
+#ifndef STATUS_WAKE_SYSTEM
+# define STATUS_WAKE_SYSTEM ((NTSTATUS) 0x40000294L)
+#endif
+
+#ifndef STATUS_WMI_GUID_NOT_FOUND
+# define STATUS_WMI_GUID_NOT_FOUND ((NTSTATUS) 0xC0000295L)
+#endif
+
+#ifndef STATUS_WMI_INSTANCE_NOT_FOUND
+# define STATUS_WMI_INSTANCE_NOT_FOUND ((NTSTATUS) 0xC0000296L)
+#endif
+
+#ifndef STATUS_WMI_ITEMID_NOT_FOUND
+# define STATUS_WMI_ITEMID_NOT_FOUND ((NTSTATUS) 0xC0000297L)
+#endif
+
+#ifndef STATUS_WMI_TRY_AGAIN
+# define STATUS_WMI_TRY_AGAIN ((NTSTATUS) 0xC0000298L)
+#endif
+
+#ifndef STATUS_SHARED_POLICY
+# define STATUS_SHARED_POLICY ((NTSTATUS) 0xC0000299L)
+#endif
+
+#ifndef STATUS_POLICY_OBJECT_NOT_FOUND
+# define STATUS_POLICY_OBJECT_NOT_FOUND ((NTSTATUS) 0xC000029AL)
+#endif
+
+#ifndef STATUS_POLICY_ONLY_IN_DS
+# define STATUS_POLICY_ONLY_IN_DS ((NTSTATUS) 0xC000029BL)
+#endif
+
+#ifndef STATUS_VOLUME_NOT_UPGRADED
+# define STATUS_VOLUME_NOT_UPGRADED ((NTSTATUS) 0xC000029CL)
+#endif
+
+#ifndef STATUS_REMOTE_STORAGE_NOT_ACTIVE
+# define STATUS_REMOTE_STORAGE_NOT_ACTIVE ((NTSTATUS) 0xC000029DL)
+#endif
+
+#ifndef STATUS_REMOTE_STORAGE_MEDIA_ERROR
+# define STATUS_REMOTE_STORAGE_MEDIA_ERROR ((NTSTATUS) 0xC000029EL)
+#endif
+
+#ifndef STATUS_NO_TRACKING_SERVICE
+# define STATUS_NO_TRACKING_SERVICE ((NTSTATUS) 0xC000029FL)
+#endif
+
+#ifndef STATUS_SERVER_SID_MISMATCH
+# define STATUS_SERVER_SID_MISMATCH ((NTSTATUS) 0xC00002A0L)
+#endif
+
+#ifndef STATUS_DS_NO_ATTRIBUTE_OR_VALUE
+# define STATUS_DS_NO_ATTRIBUTE_OR_VALUE ((NTSTATUS) 0xC00002A1L)
+#endif
+
+#ifndef STATUS_DS_INVALID_ATTRIBUTE_SYNTAX
+# define STATUS_DS_INVALID_ATTRIBUTE_SYNTAX ((NTSTATUS) 0xC00002A2L)
+#endif
+
+#ifndef STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED
+# define STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED ((NTSTATUS) 0xC00002A3L)
+#endif
+
+#ifndef STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS
+# define STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS ((NTSTATUS) 0xC00002A4L)
+#endif
+
+#ifndef STATUS_DS_BUSY
+# define STATUS_DS_BUSY ((NTSTATUS) 0xC00002A5L)
+#endif
+
+#ifndef STATUS_DS_UNAVAILABLE
+# define STATUS_DS_UNAVAILABLE ((NTSTATUS) 0xC00002A6L)
+#endif
+
+#ifndef STATUS_DS_NO_RIDS_ALLOCATED
+# define STATUS_DS_NO_RIDS_ALLOCATED ((NTSTATUS) 0xC00002A7L)
+#endif
+
+#ifndef STATUS_DS_NO_MORE_RIDS
+# define STATUS_DS_NO_MORE_RIDS ((NTSTATUS) 0xC00002A8L)
+#endif
+
+#ifndef STATUS_DS_INCORRECT_ROLE_OWNER
+# define STATUS_DS_INCORRECT_ROLE_OWNER ((NTSTATUS) 0xC00002A9L)
+#endif
+
+#ifndef STATUS_DS_RIDMGR_INIT_ERROR
+# define STATUS_DS_RIDMGR_INIT_ERROR ((NTSTATUS) 0xC00002AAL)
+#endif
+
+#ifndef STATUS_DS_OBJ_CLASS_VIOLATION
+# define STATUS_DS_OBJ_CLASS_VIOLATION ((NTSTATUS) 0xC00002ABL)
+#endif
+
+#ifndef STATUS_DS_CANT_ON_NON_LEAF
+# define STATUS_DS_CANT_ON_NON_LEAF ((NTSTATUS) 0xC00002ACL)
+#endif
+
+#ifndef STATUS_DS_CANT_ON_RDN
+# define STATUS_DS_CANT_ON_RDN ((NTSTATUS) 0xC00002ADL)
+#endif
+
+#ifndef STATUS_DS_CANT_MOD_OBJ_CLASS
+# define STATUS_DS_CANT_MOD_OBJ_CLASS ((NTSTATUS) 0xC00002AEL)
+#endif
+
+#ifndef STATUS_DS_CROSS_DOM_MOVE_FAILED
+# define STATUS_DS_CROSS_DOM_MOVE_FAILED ((NTSTATUS) 0xC00002AFL)
+#endif
+
+#ifndef STATUS_DS_GC_NOT_AVAILABLE
+# define STATUS_DS_GC_NOT_AVAILABLE ((NTSTATUS) 0xC00002B0L)
+#endif
+
+#ifndef STATUS_DIRECTORY_SERVICE_REQUIRED
+# define STATUS_DIRECTORY_SERVICE_REQUIRED ((NTSTATUS) 0xC00002B1L)
+#endif
+
+#ifndef STATUS_REPARSE_ATTRIBUTE_CONFLICT
+# define STATUS_REPARSE_ATTRIBUTE_CONFLICT ((NTSTATUS) 0xC00002B2L)
+#endif
+
+#ifndef STATUS_CANT_ENABLE_DENY_ONLY
+# define STATUS_CANT_ENABLE_DENY_ONLY ((NTSTATUS) 0xC00002B3L)
+#endif
+
+#ifndef STATUS_FLOAT_MULTIPLE_FAULTS
+# define STATUS_FLOAT_MULTIPLE_FAULTS ((NTSTATUS) 0xC00002B4L)
+#endif
+
+#ifndef STATUS_FLOAT_MULTIPLE_TRAPS
+# define STATUS_FLOAT_MULTIPLE_TRAPS ((NTSTATUS) 0xC00002B5L)
+#endif
+
+#ifndef STATUS_DEVICE_REMOVED
+# define STATUS_DEVICE_REMOVED ((NTSTATUS) 0xC00002B6L)
+#endif
+
+#ifndef STATUS_JOURNAL_DELETE_IN_PROGRESS
+# define STATUS_JOURNAL_DELETE_IN_PROGRESS ((NTSTATUS) 0xC00002B7L)
+#endif
+
+#ifndef STATUS_JOURNAL_NOT_ACTIVE
+# define STATUS_JOURNAL_NOT_ACTIVE ((NTSTATUS) 0xC00002B8L)
+#endif
+
+#ifndef STATUS_NOINTERFACE
+# define STATUS_NOINTERFACE ((NTSTATUS) 0xC00002B9L)
+#endif
+
+#ifndef STATUS_DS_ADMIN_LIMIT_EXCEEDED
+# define STATUS_DS_ADMIN_LIMIT_EXCEEDED ((NTSTATUS) 0xC00002C1L)
+#endif
+
+#ifndef STATUS_DRIVER_FAILED_SLEEP
+# define STATUS_DRIVER_FAILED_SLEEP ((NTSTATUS) 0xC00002C2L)
+#endif
+
+#ifndef STATUS_MUTUAL_AUTHENTICATION_FAILED
+# define STATUS_MUTUAL_AUTHENTICATION_FAILED ((NTSTATUS) 0xC00002C3L)
+#endif
+
+#ifndef STATUS_CORRUPT_SYSTEM_FILE
+# define STATUS_CORRUPT_SYSTEM_FILE ((NTSTATUS) 0xC00002C4L)
+#endif
+
+#ifndef STATUS_DATATYPE_MISALIGNMENT_ERROR
+# define STATUS_DATATYPE_MISALIGNMENT_ERROR ((NTSTATUS) 0xC00002C5L)
+#endif
+
+#ifndef STATUS_WMI_READ_ONLY
+# define STATUS_WMI_READ_ONLY ((NTSTATUS) 0xC00002C6L)
+#endif
+
+#ifndef STATUS_WMI_SET_FAILURE
+# define STATUS_WMI_SET_FAILURE ((NTSTATUS) 0xC00002C7L)
+#endif
+
+#ifndef STATUS_COMMITMENT_MINIMUM
+# define STATUS_COMMITMENT_MINIMUM ((NTSTATUS) 0xC00002C8L)
+#endif
+
+#ifndef STATUS_REG_NAT_CONSUMPTION
+# define STATUS_REG_NAT_CONSUMPTION ((NTSTATUS) 0xC00002C9L)
+#endif
+
+#ifndef STATUS_TRANSPORT_FULL
+# define STATUS_TRANSPORT_FULL ((NTSTATUS) 0xC00002CAL)
+#endif
+
+#ifndef STATUS_DS_SAM_INIT_FAILURE
+# define STATUS_DS_SAM_INIT_FAILURE ((NTSTATUS) 0xC00002CBL)
+#endif
+
+#ifndef STATUS_ONLY_IF_CONNECTED
+# define STATUS_ONLY_IF_CONNECTED ((NTSTATUS) 0xC00002CCL)
+#endif
+
+#ifndef STATUS_DS_SENSITIVE_GROUP_VIOLATION
+# define STATUS_DS_SENSITIVE_GROUP_VIOLATION ((NTSTATUS) 0xC00002CDL)
+#endif
+
+#ifndef STATUS_PNP_RESTART_ENUMERATION
+# define STATUS_PNP_RESTART_ENUMERATION ((NTSTATUS) 0xC00002CEL)
+#endif
+
+#ifndef STATUS_JOURNAL_ENTRY_DELETED
+# define STATUS_JOURNAL_ENTRY_DELETED ((NTSTATUS) 0xC00002CFL)
+#endif
+
+#ifndef STATUS_DS_CANT_MOD_PRIMARYGROUPID
+# define STATUS_DS_CANT_MOD_PRIMARYGROUPID ((NTSTATUS) 0xC00002D0L)
+#endif
+
+#ifndef STATUS_SYSTEM_IMAGE_BAD_SIGNATURE
+# define STATUS_SYSTEM_IMAGE_BAD_SIGNATURE ((NTSTATUS) 0xC00002D1L)
+#endif
+
+#ifndef STATUS_PNP_REBOOT_REQUIRED
+# define STATUS_PNP_REBOOT_REQUIRED ((NTSTATUS) 0xC00002D2L)
+#endif
+
+#ifndef STATUS_POWER_STATE_INVALID
+# define STATUS_POWER_STATE_INVALID ((NTSTATUS) 0xC00002D3L)
+#endif
+
+#ifndef STATUS_DS_INVALID_GROUP_TYPE
+# define STATUS_DS_INVALID_GROUP_TYPE ((NTSTATUS) 0xC00002D4L)
+#endif
+
+#ifndef STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN
+# define STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN ((NTSTATUS) 0xC00002D5L)
+#endif
+
+#ifndef STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN
+# define STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN ((NTSTATUS) 0xC00002D6L)
+#endif
+
+#ifndef STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER
+# define STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER ((NTSTATUS) 0xC00002D7L)
+#endif
+
+#ifndef STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER
+# define STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER ((NTSTATUS) 0xC00002D8L)
+#endif
+
+#ifndef STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER
+# define STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER ((NTSTATUS) 0xC00002D9L)
+#endif
+
+#ifndef STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER
+# define STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER ((NTSTATUS) 0xC00002DAL)
+#endif
+
+#ifndef STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER
+# define STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER ((NTSTATUS) 0xC00002DBL)
+#endif
+
+#ifndef STATUS_DS_HAVE_PRIMARY_MEMBERS
+# define STATUS_DS_HAVE_PRIMARY_MEMBERS ((NTSTATUS) 0xC00002DCL)
+#endif
+
+#ifndef STATUS_WMI_NOT_SUPPORTED
+# define STATUS_WMI_NOT_SUPPORTED ((NTSTATUS) 0xC00002DDL)
+#endif
+
+#ifndef STATUS_INSUFFICIENT_POWER
+# define STATUS_INSUFFICIENT_POWER ((NTSTATUS) 0xC00002DEL)
+#endif
+
+#ifndef STATUS_SAM_NEED_BOOTKEY_PASSWORD
+# define STATUS_SAM_NEED_BOOTKEY_PASSWORD ((NTSTATUS) 0xC00002DFL)
+#endif
+
+#ifndef STATUS_SAM_NEED_BOOTKEY_FLOPPY
+# define STATUS_SAM_NEED_BOOTKEY_FLOPPY ((NTSTATUS) 0xC00002E0L)
+#endif
+
+#ifndef STATUS_DS_CANT_START
+# define STATUS_DS_CANT_START ((NTSTATUS) 0xC00002E1L)
+#endif
+
+#ifndef STATUS_DS_INIT_FAILURE
+# define STATUS_DS_INIT_FAILURE ((NTSTATUS) 0xC00002E2L)
+#endif
+
+#ifndef STATUS_SAM_INIT_FAILURE
+# define STATUS_SAM_INIT_FAILURE ((NTSTATUS) 0xC00002E3L)
+#endif
+
+#ifndef STATUS_DS_GC_REQUIRED
+# define STATUS_DS_GC_REQUIRED ((NTSTATUS) 0xC00002E4L)
+#endif
+
+#ifndef STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY
+# define STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY ((NTSTATUS) 0xC00002E5L)
+#endif
+
+#ifndef STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS
+# define STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS ((NTSTATUS) 0xC00002E6L)
+#endif
+
+#ifndef STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED
+# define STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED ((NTSTATUS) 0xC00002E7L)
+#endif
+
+#ifndef STATUS_MULTIPLE_FAULT_VIOLATION
+# define STATUS_MULTIPLE_FAULT_VIOLATION ((NTSTATUS) 0xC00002E8L)
+#endif
+
+#ifndef STATUS_CURRENT_DOMAIN_NOT_ALLOWED
+# define STATUS_CURRENT_DOMAIN_NOT_ALLOWED ((NTSTATUS) 0xC00002E9L)
+#endif
+
+#ifndef STATUS_CANNOT_MAKE
+# define STATUS_CANNOT_MAKE ((NTSTATUS) 0xC00002EAL)
+#endif
+
+#ifndef STATUS_SYSTEM_SHUTDOWN
+# define STATUS_SYSTEM_SHUTDOWN ((NTSTATUS) 0xC00002EBL)
+#endif
+
+#ifndef STATUS_DS_INIT_FAILURE_CONSOLE
+# define STATUS_DS_INIT_FAILURE_CONSOLE ((NTSTATUS) 0xC00002ECL)
+#endif
+
+#ifndef STATUS_DS_SAM_INIT_FAILURE_CONSOLE
+# define STATUS_DS_SAM_INIT_FAILURE_CONSOLE ((NTSTATUS) 0xC00002EDL)
+#endif
+
+#ifndef STATUS_UNFINISHED_CONTEXT_DELETED
+# define STATUS_UNFINISHED_CONTEXT_DELETED ((NTSTATUS) 0xC00002EEL)
+#endif
+
+#ifndef STATUS_NO_TGT_REPLY
+# define STATUS_NO_TGT_REPLY ((NTSTATUS) 0xC00002EFL)
+#endif
+
+#ifndef STATUS_OBJECTID_NOT_FOUND
+# define STATUS_OBJECTID_NOT_FOUND ((NTSTATUS) 0xC00002F0L)
+#endif
+
+#ifndef STATUS_NO_IP_ADDRESSES
+# define STATUS_NO_IP_ADDRESSES ((NTSTATUS) 0xC00002F1L)
+#endif
+
+#ifndef STATUS_WRONG_CREDENTIAL_HANDLE
+# define STATUS_WRONG_CREDENTIAL_HANDLE ((NTSTATUS) 0xC00002F2L)
+#endif
+
+#ifndef STATUS_CRYPTO_SYSTEM_INVALID
+# define STATUS_CRYPTO_SYSTEM_INVALID ((NTSTATUS) 0xC00002F3L)
+#endif
+
+#ifndef STATUS_MAX_REFERRALS_EXCEEDED
+# define STATUS_MAX_REFERRALS_EXCEEDED ((NTSTATUS) 0xC00002F4L)
+#endif
+
+#ifndef STATUS_MUST_BE_KDC
+# define STATUS_MUST_BE_KDC ((NTSTATUS) 0xC00002F5L)
+#endif
+
+#ifndef STATUS_STRONG_CRYPTO_NOT_SUPPORTED
+# define STATUS_STRONG_CRYPTO_NOT_SUPPORTED ((NTSTATUS) 0xC00002F6L)
+#endif
+
+#ifndef STATUS_TOO_MANY_PRINCIPALS
+# define STATUS_TOO_MANY_PRINCIPALS ((NTSTATUS) 0xC00002F7L)
+#endif
+
+#ifndef STATUS_NO_PA_DATA
+# define STATUS_NO_PA_DATA ((NTSTATUS) 0xC00002F8L)
+#endif
+
+#ifndef STATUS_PKINIT_NAME_MISMATCH
+# define STATUS_PKINIT_NAME_MISMATCH ((NTSTATUS) 0xC00002F9L)
+#endif
+
+#ifndef STATUS_SMARTCARD_LOGON_REQUIRED
+# define STATUS_SMARTCARD_LOGON_REQUIRED ((NTSTATUS) 0xC00002FAL)
+#endif
+
+#ifndef STATUS_KDC_INVALID_REQUEST
+# define STATUS_KDC_INVALID_REQUEST ((NTSTATUS) 0xC00002FBL)
+#endif
+
+#ifndef STATUS_KDC_UNABLE_TO_REFER
+# define STATUS_KDC_UNABLE_TO_REFER ((NTSTATUS) 0xC00002FCL)
+#endif
+
+#ifndef STATUS_KDC_UNKNOWN_ETYPE
+# define STATUS_KDC_UNKNOWN_ETYPE ((NTSTATUS) 0xC00002FDL)
+#endif
+
+#ifndef STATUS_SHUTDOWN_IN_PROGRESS
+# define STATUS_SHUTDOWN_IN_PROGRESS ((NTSTATUS) 0xC00002FEL)
+#endif
+
+#ifndef STATUS_SERVER_SHUTDOWN_IN_PROGRESS
+# define STATUS_SERVER_SHUTDOWN_IN_PROGRESS ((NTSTATUS) 0xC00002FFL)
+#endif
+
+#ifndef STATUS_NOT_SUPPORTED_ON_SBS
+# define STATUS_NOT_SUPPORTED_ON_SBS ((NTSTATUS) 0xC0000300L)
+#endif
+
+#ifndef STATUS_WMI_GUID_DISCONNECTED
+# define STATUS_WMI_GUID_DISCONNECTED ((NTSTATUS) 0xC0000301L)
+#endif
+
+#ifndef STATUS_WMI_ALREADY_DISABLED
+# define STATUS_WMI_ALREADY_DISABLED ((NTSTATUS) 0xC0000302L)
+#endif
+
+#ifndef STATUS_WMI_ALREADY_ENABLED
+# define STATUS_WMI_ALREADY_ENABLED ((NTSTATUS) 0xC0000303L)
+#endif
+
+#ifndef STATUS_MFT_TOO_FRAGMENTED
+# define STATUS_MFT_TOO_FRAGMENTED ((NTSTATUS) 0xC0000304L)
+#endif
+
+#ifndef STATUS_COPY_PROTECTION_FAILURE
+# define STATUS_COPY_PROTECTION_FAILURE ((NTSTATUS) 0xC0000305L)
+#endif
+
+#ifndef STATUS_CSS_AUTHENTICATION_FAILURE
+# define STATUS_CSS_AUTHENTICATION_FAILURE ((NTSTATUS) 0xC0000306L)
+#endif
+
+#ifndef STATUS_CSS_KEY_NOT_PRESENT
+# define STATUS_CSS_KEY_NOT_PRESENT ((NTSTATUS) 0xC0000307L)
+#endif
+
+#ifndef STATUS_CSS_KEY_NOT_ESTABLISHED
+# define STATUS_CSS_KEY_NOT_ESTABLISHED ((NTSTATUS) 0xC0000308L)
+#endif
+
+#ifndef STATUS_CSS_SCRAMBLED_SECTOR
+# define STATUS_CSS_SCRAMBLED_SECTOR ((NTSTATUS) 0xC0000309L)
+#endif
+
+#ifndef STATUS_CSS_REGION_MISMATCH
+# define STATUS_CSS_REGION_MISMATCH ((NTSTATUS) 0xC000030AL)
+#endif
+
+#ifndef STATUS_CSS_RESETS_EXHAUSTED
+# define STATUS_CSS_RESETS_EXHAUSTED ((NTSTATUS) 0xC000030BL)
+#endif
+
+#ifndef STATUS_PKINIT_FAILURE
+# define STATUS_PKINIT_FAILURE ((NTSTATUS) 0xC0000320L)
+#endif
+
+#ifndef STATUS_SMARTCARD_SUBSYSTEM_FAILURE
+# define STATUS_SMARTCARD_SUBSYSTEM_FAILURE ((NTSTATUS) 0xC0000321L)
+#endif
+
+#ifndef STATUS_NO_KERB_KEY
+# define STATUS_NO_KERB_KEY ((NTSTATUS) 0xC0000322L)
+#endif
+
+#ifndef STATUS_HOST_DOWN
+# define STATUS_HOST_DOWN ((NTSTATUS) 0xC0000350L)
+#endif
+
+#ifndef STATUS_UNSUPPORTED_PREAUTH
+# define STATUS_UNSUPPORTED_PREAUTH ((NTSTATUS) 0xC0000351L)
+#endif
+
+#ifndef STATUS_EFS_ALG_BLOB_TOO_BIG
+# define STATUS_EFS_ALG_BLOB_TOO_BIG ((NTSTATUS) 0xC0000352L)
+#endif
+
+#ifndef STATUS_PORT_NOT_SET
+# define STATUS_PORT_NOT_SET ((NTSTATUS) 0xC0000353L)
+#endif
+
+#ifndef STATUS_DEBUGGER_INACTIVE
+# define STATUS_DEBUGGER_INACTIVE ((NTSTATUS) 0xC0000354L)
+#endif
+
+#ifndef STATUS_DS_VERSION_CHECK_FAILURE
+# define STATUS_DS_VERSION_CHECK_FAILURE ((NTSTATUS) 0xC0000355L)
+#endif
+
+#ifndef STATUS_AUDITING_DISABLED
+# define STATUS_AUDITING_DISABLED ((NTSTATUS) 0xC0000356L)
+#endif
+
+#ifndef STATUS_PRENT4_MACHINE_ACCOUNT
+# define STATUS_PRENT4_MACHINE_ACCOUNT ((NTSTATUS) 0xC0000357L)
+#endif
+
+#ifndef STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER
+# define STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER ((NTSTATUS) 0xC0000358L)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_WIN_32
+# define STATUS_INVALID_IMAGE_WIN_32 ((NTSTATUS) 0xC0000359L)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_WIN_64
+# define STATUS_INVALID_IMAGE_WIN_64 ((NTSTATUS) 0xC000035AL)
+#endif
+
+#ifndef STATUS_BAD_BINDINGS
+# define STATUS_BAD_BINDINGS ((NTSTATUS) 0xC000035BL)
+#endif
+
+#ifndef STATUS_NETWORK_SESSION_EXPIRED
+# define STATUS_NETWORK_SESSION_EXPIRED ((NTSTATUS) 0xC000035CL)
+#endif
+
+#ifndef STATUS_APPHELP_BLOCK
+# define STATUS_APPHELP_BLOCK ((NTSTATUS) 0xC000035DL)
+#endif
+
+#ifndef STATUS_ALL_SIDS_FILTERED
+# define STATUS_ALL_SIDS_FILTERED ((NTSTATUS) 0xC000035EL)
+#endif
+
+#ifndef STATUS_NOT_SAFE_MODE_DRIVER
+# define STATUS_NOT_SAFE_MODE_DRIVER ((NTSTATUS) 0xC000035FL)
+#endif
+
+#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT
+# define STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT ((NTSTATUS) 0xC0000361L)
+#endif
+
+#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_PATH
+# define STATUS_ACCESS_DISABLED_BY_POLICY_PATH ((NTSTATUS) 0xC0000362L)
+#endif
+
+#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER
+# define STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER ((NTSTATUS) 0xC0000363L)
+#endif
+
+#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
+# define STATUS_ACCESS_DISABLED_BY_POLICY_OTHER ((NTSTATUS) 0xC0000364L)
+#endif
+
+#ifndef STATUS_FAILED_DRIVER_ENTRY
+# define STATUS_FAILED_DRIVER_ENTRY ((NTSTATUS) 0xC0000365L)
+#endif
+
+#ifndef STATUS_DEVICE_ENUMERATION_ERROR
+# define STATUS_DEVICE_ENUMERATION_ERROR ((NTSTATUS) 0xC0000366L)
+#endif
+
+#ifndef STATUS_MOUNT_POINT_NOT_RESOLVED
+# define STATUS_MOUNT_POINT_NOT_RESOLVED ((NTSTATUS) 0xC0000368L)
+#endif
+
+#ifndef STATUS_INVALID_DEVICE_OBJECT_PARAMETER
+# define STATUS_INVALID_DEVICE_OBJECT_PARAMETER ((NTSTATUS) 0xC0000369L)
+#endif
+
+#ifndef STATUS_MCA_OCCURED
+# define STATUS_MCA_OCCURED ((NTSTATUS) 0xC000036AL)
+#endif
+
+#ifndef STATUS_DRIVER_BLOCKED_CRITICAL
+# define STATUS_DRIVER_BLOCKED_CRITICAL ((NTSTATUS) 0xC000036BL)
+#endif
+
+#ifndef STATUS_DRIVER_BLOCKED
+# define STATUS_DRIVER_BLOCKED ((NTSTATUS) 0xC000036CL)
+#endif
+
+#ifndef STATUS_DRIVER_DATABASE_ERROR
+# define STATUS_DRIVER_DATABASE_ERROR ((NTSTATUS) 0xC000036DL)
+#endif
+
+#ifndef STATUS_SYSTEM_HIVE_TOO_LARGE
+# define STATUS_SYSTEM_HIVE_TOO_LARGE ((NTSTATUS) 0xC000036EL)
+#endif
+
+#ifndef STATUS_INVALID_IMPORT_OF_NON_DLL
+# define STATUS_INVALID_IMPORT_OF_NON_DLL ((NTSTATUS) 0xC000036FL)
+#endif
+
+#ifndef STATUS_DS_SHUTTING_DOWN
+# define STATUS_DS_SHUTTING_DOWN ((NTSTATUS) 0x40000370L)
+#endif
+
+#ifndef STATUS_NO_SECRETS
+# define STATUS_NO_SECRETS ((NTSTATUS) 0xC0000371L)
+#endif
+
+#ifndef STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY
+# define STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY ((NTSTATUS) 0xC0000372L)
+#endif
+
+#ifndef STATUS_FAILED_STACK_SWITCH
+# define STATUS_FAILED_STACK_SWITCH ((NTSTATUS) 0xC0000373L)
+#endif
+
+#ifndef STATUS_HEAP_CORRUPTION
+# define STATUS_HEAP_CORRUPTION ((NTSTATUS) 0xC0000374L)
+#endif
+
+#ifndef STATUS_SMARTCARD_WRONG_PIN
+# define STATUS_SMARTCARD_WRONG_PIN ((NTSTATUS) 0xC0000380L)
+#endif
+
+#ifndef STATUS_SMARTCARD_CARD_BLOCKED
+# define STATUS_SMARTCARD_CARD_BLOCKED ((NTSTATUS) 0xC0000381L)
+#endif
+
+#ifndef STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED
+# define STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED ((NTSTATUS) 0xC0000382L)
+#endif
+
+#ifndef STATUS_SMARTCARD_NO_CARD
+# define STATUS_SMARTCARD_NO_CARD ((NTSTATUS) 0xC0000383L)
+#endif
+
+#ifndef STATUS_SMARTCARD_NO_KEY_CONTAINER
+# define STATUS_SMARTCARD_NO_KEY_CONTAINER ((NTSTATUS) 0xC0000384L)
+#endif
+
+#ifndef STATUS_SMARTCARD_NO_CERTIFICATE
+# define STATUS_SMARTCARD_NO_CERTIFICATE ((NTSTATUS) 0xC0000385L)
+#endif
+
+#ifndef STATUS_SMARTCARD_NO_KEYSET
+# define STATUS_SMARTCARD_NO_KEYSET ((NTSTATUS) 0xC0000386L)
+#endif
+
+#ifndef STATUS_SMARTCARD_IO_ERROR
+# define STATUS_SMARTCARD_IO_ERROR ((NTSTATUS) 0xC0000387L)
+#endif
+
+#ifndef STATUS_DOWNGRADE_DETECTED
+# define STATUS_DOWNGRADE_DETECTED ((NTSTATUS) 0xC0000388L)
+#endif
+
+#ifndef STATUS_SMARTCARD_CERT_REVOKED
+# define STATUS_SMARTCARD_CERT_REVOKED ((NTSTATUS) 0xC0000389L)
+#endif
+
+#ifndef STATUS_ISSUING_CA_UNTRUSTED
+# define STATUS_ISSUING_CA_UNTRUSTED ((NTSTATUS) 0xC000038AL)
+#endif
+
+#ifndef STATUS_REVOCATION_OFFLINE_C
+# define STATUS_REVOCATION_OFFLINE_C ((NTSTATUS) 0xC000038BL)
+#endif
+
+#ifndef STATUS_PKINIT_CLIENT_FAILURE
+# define STATUS_PKINIT_CLIENT_FAILURE ((NTSTATUS) 0xC000038CL)
+#endif
+
+#ifndef STATUS_SMARTCARD_CERT_EXPIRED
+# define STATUS_SMARTCARD_CERT_EXPIRED ((NTSTATUS) 0xC000038DL)
+#endif
+
+#ifndef STATUS_DRIVER_FAILED_PRIOR_UNLOAD
+# define STATUS_DRIVER_FAILED_PRIOR_UNLOAD ((NTSTATUS) 0xC000038EL)
+#endif
+
+#ifndef STATUS_SMARTCARD_SILENT_CONTEXT
+# define STATUS_SMARTCARD_SILENT_CONTEXT ((NTSTATUS) 0xC000038FL)
+#endif
+
+#ifndef STATUS_PER_USER_TRUST_QUOTA_EXCEEDED
+# define STATUS_PER_USER_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000401L)
+#endif
+
+#ifndef STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED
+# define STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000402L)
+#endif
+
+#ifndef STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED
+# define STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000403L)
+#endif
+
+#ifndef STATUS_DS_NAME_NOT_UNIQUE
+# define STATUS_DS_NAME_NOT_UNIQUE ((NTSTATUS) 0xC0000404L)
+#endif
+
+#ifndef STATUS_DS_DUPLICATE_ID_FOUND
+# define STATUS_DS_DUPLICATE_ID_FOUND ((NTSTATUS) 0xC0000405L)
+#endif
+
+#ifndef STATUS_DS_GROUP_CONVERSION_ERROR
+# define STATUS_DS_GROUP_CONVERSION_ERROR ((NTSTATUS) 0xC0000406L)
+#endif
+
+#ifndef STATUS_VOLSNAP_PREPARE_HIBERNATE
+# define STATUS_VOLSNAP_PREPARE_HIBERNATE ((NTSTATUS) 0xC0000407L)
+#endif
+
+#ifndef STATUS_USER2USER_REQUIRED
+# define STATUS_USER2USER_REQUIRED ((NTSTATUS) 0xC0000408L)
+#endif
+
+#ifndef STATUS_STACK_BUFFER_OVERRUN
+# define STATUS_STACK_BUFFER_OVERRUN ((NTSTATUS) 0xC0000409L)
+#endif
+
+#ifndef STATUS_NO_S4U_PROT_SUPPORT
+# define STATUS_NO_S4U_PROT_SUPPORT ((NTSTATUS) 0xC000040AL)
+#endif
+
+#ifndef STATUS_CROSSREALM_DELEGATION_FAILURE
+# define STATUS_CROSSREALM_DELEGATION_FAILURE ((NTSTATUS) 0xC000040BL)
+#endif
+
+#ifndef STATUS_REVOCATION_OFFLINE_KDC
+# define STATUS_REVOCATION_OFFLINE_KDC ((NTSTATUS) 0xC000040CL)
+#endif
+
+#ifndef STATUS_ISSUING_CA_UNTRUSTED_KDC
+# define STATUS_ISSUING_CA_UNTRUSTED_KDC ((NTSTATUS) 0xC000040DL)
+#endif
+
+#ifndef STATUS_KDC_CERT_EXPIRED
+# define STATUS_KDC_CERT_EXPIRED ((NTSTATUS) 0xC000040EL)
+#endif
+
+#ifndef STATUS_KDC_CERT_REVOKED
+# define STATUS_KDC_CERT_REVOKED ((NTSTATUS) 0xC000040FL)
+#endif
+
+#ifndef STATUS_PARAMETER_QUOTA_EXCEEDED
+# define STATUS_PARAMETER_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000410L)
+#endif
+
+#ifndef STATUS_HIBERNATION_FAILURE
+# define STATUS_HIBERNATION_FAILURE ((NTSTATUS) 0xC0000411L)
+#endif
+
+#ifndef STATUS_DELAY_LOAD_FAILED
+# define STATUS_DELAY_LOAD_FAILED ((NTSTATUS) 0xC0000412L)
+#endif
+
+#ifndef STATUS_AUTHENTICATION_FIREWALL_FAILED
+# define STATUS_AUTHENTICATION_FIREWALL_FAILED ((NTSTATUS) 0xC0000413L)
+#endif
+
+#ifndef STATUS_VDM_DISALLOWED
+# define STATUS_VDM_DISALLOWED ((NTSTATUS) 0xC0000414L)
+#endif
+
+#ifndef STATUS_HUNG_DISPLAY_DRIVER_THREAD
+# define STATUS_HUNG_DISPLAY_DRIVER_THREAD ((NTSTATUS) 0xC0000415L)
+#endif
+
+#ifndef STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE
+# define STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE ((NTSTATUS) 0xC0000416L)
+#endif
+
+#ifndef STATUS_INVALID_CRUNTIME_PARAMETER
+# define STATUS_INVALID_CRUNTIME_PARAMETER ((NTSTATUS) 0xC0000417L)
+#endif
+
+#ifndef STATUS_NTLM_BLOCKED
+# define STATUS_NTLM_BLOCKED ((NTSTATUS) 0xC0000418L)
+#endif
+
+#ifndef STATUS_DS_SRC_SID_EXISTS_IN_FOREST
+# define STATUS_DS_SRC_SID_EXISTS_IN_FOREST ((NTSTATUS) 0xC0000419L)
+#endif
+
+#ifndef STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST
+# define STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST ((NTSTATUS) 0xC000041AL)
+#endif
+
+#ifndef STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST
+# define STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST ((NTSTATUS) 0xC000041BL)
+#endif
+
+#ifndef STATUS_INVALID_USER_PRINCIPAL_NAME
+# define STATUS_INVALID_USER_PRINCIPAL_NAME ((NTSTATUS) 0xC000041CL)
+#endif
+
+#ifndef STATUS_FATAL_USER_CALLBACK_EXCEPTION
+# define STATUS_FATAL_USER_CALLBACK_EXCEPTION ((NTSTATUS) 0xC000041DL)
+#endif
+
+#ifndef STATUS_ASSERTION_FAILURE
+# define STATUS_ASSERTION_FAILURE ((NTSTATUS) 0xC0000420L)
+#endif
+
+#ifndef STATUS_VERIFIER_STOP
+# define STATUS_VERIFIER_STOP ((NTSTATUS) 0xC0000421L)
+#endif
+
+#ifndef STATUS_CALLBACK_POP_STACK
+# define STATUS_CALLBACK_POP_STACK ((NTSTATUS) 0xC0000423L)
+#endif
+
+#ifndef STATUS_INCOMPATIBLE_DRIVER_BLOCKED
+# define STATUS_INCOMPATIBLE_DRIVER_BLOCKED ((NTSTATUS) 0xC0000424L)
+#endif
+
+#ifndef STATUS_HIVE_UNLOADED
+# define STATUS_HIVE_UNLOADED ((NTSTATUS) 0xC0000425L)
+#endif
+
+#ifndef STATUS_COMPRESSION_DISABLED
+# define STATUS_COMPRESSION_DISABLED ((NTSTATUS) 0xC0000426L)
+#endif
+
+#ifndef STATUS_FILE_SYSTEM_LIMITATION
+# define STATUS_FILE_SYSTEM_LIMITATION ((NTSTATUS) 0xC0000427L)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_HASH
+# define STATUS_INVALID_IMAGE_HASH ((NTSTATUS) 0xC0000428L)
+#endif
+
+#ifndef STATUS_NOT_CAPABLE
+# define STATUS_NOT_CAPABLE ((NTSTATUS) 0xC0000429L)
+#endif
+
+#ifndef STATUS_REQUEST_OUT_OF_SEQUENCE
+# define STATUS_REQUEST_OUT_OF_SEQUENCE ((NTSTATUS) 0xC000042AL)
+#endif
+
+#ifndef STATUS_IMPLEMENTATION_LIMIT
+# define STATUS_IMPLEMENTATION_LIMIT ((NTSTATUS) 0xC000042BL)
+#endif
+
+#ifndef STATUS_ELEVATION_REQUIRED
+# define STATUS_ELEVATION_REQUIRED ((NTSTATUS) 0xC000042CL)
+#endif
+
+#ifndef STATUS_NO_SECURITY_CONTEXT
+# define STATUS_NO_SECURITY_CONTEXT ((NTSTATUS) 0xC000042DL)
+#endif
+
+#ifndef STATUS_PKU2U_CERT_FAILURE
+# define STATUS_PKU2U_CERT_FAILURE ((NTSTATUS) 0xC000042FL)
+#endif
+
+#ifndef STATUS_BEYOND_VDL
+# define STATUS_BEYOND_VDL ((NTSTATUS) 0xC0000432L)
+#endif
+
+#ifndef STATUS_ENCOUNTERED_WRITE_IN_PROGRESS
+# define STATUS_ENCOUNTERED_WRITE_IN_PROGRESS ((NTSTATUS) 0xC0000433L)
+#endif
+
+#ifndef STATUS_PTE_CHANGED
+# define STATUS_PTE_CHANGED ((NTSTATUS) 0xC0000434L)
+#endif
+
+#ifndef STATUS_PURGE_FAILED
+# define STATUS_PURGE_FAILED ((NTSTATUS) 0xC0000435L)
+#endif
+
+#ifndef STATUS_CRED_REQUIRES_CONFIRMATION
+# define STATUS_CRED_REQUIRES_CONFIRMATION ((NTSTATUS) 0xC0000440L)
+#endif
+
+#ifndef STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE
+# define STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE ((NTSTATUS) 0xC0000441L)
+#endif
+
+#ifndef STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER
+# define STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER ((NTSTATUS) 0xC0000442L)
+#endif
+
+#ifndef STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE
+# define STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE ((NTSTATUS) 0xC0000443L)
+#endif
+
+#ifndef STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE
+# define STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE ((NTSTATUS) 0xC0000444L)
+#endif
+
+#ifndef STATUS_CS_ENCRYPTION_FILE_NOT_CSE
+# define STATUS_CS_ENCRYPTION_FILE_NOT_CSE ((NTSTATUS) 0xC0000445L)
+#endif
+
+#ifndef STATUS_INVALID_LABEL
+# define STATUS_INVALID_LABEL ((NTSTATUS) 0xC0000446L)
+#endif
+
+#ifndef STATUS_DRIVER_PROCESS_TERMINATED
+# define STATUS_DRIVER_PROCESS_TERMINATED ((NTSTATUS) 0xC0000450L)
+#endif
+
+#ifndef STATUS_AMBIGUOUS_SYSTEM_DEVICE
+# define STATUS_AMBIGUOUS_SYSTEM_DEVICE ((NTSTATUS) 0xC0000451L)
+#endif
+
+#ifndef STATUS_SYSTEM_DEVICE_NOT_FOUND
+# define STATUS_SYSTEM_DEVICE_NOT_FOUND ((NTSTATUS) 0xC0000452L)
+#endif
+
+#ifndef STATUS_RESTART_BOOT_APPLICATION
+# define STATUS_RESTART_BOOT_APPLICATION ((NTSTATUS) 0xC0000453L)
+#endif
+
+#ifndef STATUS_INSUFFICIENT_NVRAM_RESOURCES
+# define STATUS_INSUFFICIENT_NVRAM_RESOURCES ((NTSTATUS) 0xC0000454L)
+#endif
+
+#ifndef STATUS_INVALID_TASK_NAME
+# define STATUS_INVALID_TASK_NAME ((NTSTATUS) 0xC0000500L)
+#endif
+
+#ifndef STATUS_INVALID_TASK_INDEX
+# define STATUS_INVALID_TASK_INDEX ((NTSTATUS) 0xC0000501L)
+#endif
+
+#ifndef STATUS_THREAD_ALREADY_IN_TASK
+# define STATUS_THREAD_ALREADY_IN_TASK ((NTSTATUS) 0xC0000502L)
+#endif
+
+#ifndef STATUS_CALLBACK_BYPASS
+# define STATUS_CALLBACK_BYPASS ((NTSTATUS) 0xC0000503L)
+#endif
+
+#ifndef STATUS_FAIL_FAST_EXCEPTION
+# define STATUS_FAIL_FAST_EXCEPTION ((NTSTATUS) 0xC0000602L)
+#endif
+
+#ifndef STATUS_IMAGE_CERT_REVOKED
+# define STATUS_IMAGE_CERT_REVOKED ((NTSTATUS) 0xC0000603L)
+#endif
+
+#ifndef STATUS_PORT_CLOSED
+# define STATUS_PORT_CLOSED ((NTSTATUS) 0xC0000700L)
+#endif
+
+#ifndef STATUS_MESSAGE_LOST
+# define STATUS_MESSAGE_LOST ((NTSTATUS) 0xC0000701L)
+#endif
+
+#ifndef STATUS_INVALID_MESSAGE
+# define STATUS_INVALID_MESSAGE ((NTSTATUS) 0xC0000702L)
+#endif
+
+#ifndef STATUS_REQUEST_CANCELED
+# define STATUS_REQUEST_CANCELED ((NTSTATUS) 0xC0000703L)
+#endif
+
+#ifndef STATUS_RECURSIVE_DISPATCH
+# define STATUS_RECURSIVE_DISPATCH ((NTSTATUS) 0xC0000704L)
+#endif
+
+#ifndef STATUS_LPC_RECEIVE_BUFFER_EXPECTED
+# define STATUS_LPC_RECEIVE_BUFFER_EXPECTED ((NTSTATUS) 0xC0000705L)
+#endif
+
+#ifndef STATUS_LPC_INVALID_CONNECTION_USAGE
+# define STATUS_LPC_INVALID_CONNECTION_USAGE ((NTSTATUS) 0xC0000706L)
+#endif
+
+#ifndef STATUS_LPC_REQUESTS_NOT_ALLOWED
+# define STATUS_LPC_REQUESTS_NOT_ALLOWED ((NTSTATUS) 0xC0000707L)
+#endif
+
+#ifndef STATUS_RESOURCE_IN_USE
+# define STATUS_RESOURCE_IN_USE ((NTSTATUS) 0xC0000708L)
+#endif
+
+#ifndef STATUS_HARDWARE_MEMORY_ERROR
+# define STATUS_HARDWARE_MEMORY_ERROR ((NTSTATUS) 0xC0000709L)
+#endif
+
+#ifndef STATUS_THREADPOOL_HANDLE_EXCEPTION
+# define STATUS_THREADPOOL_HANDLE_EXCEPTION ((NTSTATUS) 0xC000070AL)
+#endif
+
+#ifndef STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED
+# define STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070BL)
+#endif
+
+#ifndef STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED
+# define STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070CL)
+#endif
+
+#ifndef STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED
+# define STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070DL)
+#endif
+
+#ifndef STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED
+# define STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070EL)
+#endif
+
+#ifndef STATUS_THREADPOOL_RELEASED_DURING_OPERATION
+# define STATUS_THREADPOOL_RELEASED_DURING_OPERATION ((NTSTATUS) 0xC000070FL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING
+# define STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING ((NTSTATUS) 0xC0000710L)
+#endif
+
+#ifndef STATUS_APC_RETURNED_WHILE_IMPERSONATING
+# define STATUS_APC_RETURNED_WHILE_IMPERSONATING ((NTSTATUS) 0xC0000711L)
+#endif
+
+#ifndef STATUS_PROCESS_IS_PROTECTED
+# define STATUS_PROCESS_IS_PROTECTED ((NTSTATUS) 0xC0000712L)
+#endif
+
+#ifndef STATUS_MCA_EXCEPTION
+# define STATUS_MCA_EXCEPTION ((NTSTATUS) 0xC0000713L)
+#endif
+
+#ifndef STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE
+# define STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE ((NTSTATUS) 0xC0000714L)
+#endif
+
+#ifndef STATUS_SYMLINK_CLASS_DISABLED
+# define STATUS_SYMLINK_CLASS_DISABLED ((NTSTATUS) 0xC0000715L)
+#endif
+
+#ifndef STATUS_INVALID_IDN_NORMALIZATION
+# define STATUS_INVALID_IDN_NORMALIZATION ((NTSTATUS) 0xC0000716L)
+#endif
+
+#ifndef STATUS_NO_UNICODE_TRANSLATION
+# define STATUS_NO_UNICODE_TRANSLATION ((NTSTATUS) 0xC0000717L)
+#endif
+
+#ifndef STATUS_ALREADY_REGISTERED
+# define STATUS_ALREADY_REGISTERED ((NTSTATUS) 0xC0000718L)
+#endif
+
+#ifndef STATUS_CONTEXT_MISMATCH
+# define STATUS_CONTEXT_MISMATCH ((NTSTATUS) 0xC0000719L)
+#endif
+
+#ifndef STATUS_PORT_ALREADY_HAS_COMPLETION_LIST
+# define STATUS_PORT_ALREADY_HAS_COMPLETION_LIST ((NTSTATUS) 0xC000071AL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_THREAD_PRIORITY
+# define STATUS_CALLBACK_RETURNED_THREAD_PRIORITY ((NTSTATUS) 0xC000071BL)
+#endif
+
+#ifndef STATUS_INVALID_THREAD
+# define STATUS_INVALID_THREAD ((NTSTATUS) 0xC000071CL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_TRANSACTION
+# define STATUS_CALLBACK_RETURNED_TRANSACTION ((NTSTATUS) 0xC000071DL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_LDR_LOCK
+# define STATUS_CALLBACK_RETURNED_LDR_LOCK ((NTSTATUS) 0xC000071EL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_LANG
+# define STATUS_CALLBACK_RETURNED_LANG ((NTSTATUS) 0xC000071FL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_PRI_BACK
+# define STATUS_CALLBACK_RETURNED_PRI_BACK ((NTSTATUS) 0xC0000720L)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_THREAD_AFFINITY
+# define STATUS_CALLBACK_RETURNED_THREAD_AFFINITY ((NTSTATUS) 0xC0000721L)
+#endif
+
+#ifndef STATUS_DISK_REPAIR_DISABLED
+# define STATUS_DISK_REPAIR_DISABLED ((NTSTATUS) 0xC0000800L)
+#endif
+
+#ifndef STATUS_DS_DOMAIN_RENAME_IN_PROGRESS
+# define STATUS_DS_DOMAIN_RENAME_IN_PROGRESS ((NTSTATUS) 0xC0000801L)
+#endif
+
+#ifndef STATUS_DISK_QUOTA_EXCEEDED
+# define STATUS_DISK_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000802L)
+#endif
+
+#ifndef STATUS_DATA_LOST_REPAIR
+# define STATUS_DATA_LOST_REPAIR ((NTSTATUS) 0x80000803L)
+#endif
+
+#ifndef STATUS_CONTENT_BLOCKED
+# define STATUS_CONTENT_BLOCKED ((NTSTATUS) 0xC0000804L)
+#endif
+
+#ifndef STATUS_BAD_CLUSTERS
+# define STATUS_BAD_CLUSTERS ((NTSTATUS) 0xC0000805L)
+#endif
+
+#ifndef STATUS_VOLUME_DIRTY
+# define STATUS_VOLUME_DIRTY ((NTSTATUS) 0xC0000806L)
+#endif
+
+#ifndef STATUS_FILE_CHECKED_OUT
+# define STATUS_FILE_CHECKED_OUT ((NTSTATUS) 0xC0000901L)
+#endif
+
+#ifndef STATUS_CHECKOUT_REQUIRED
+# define STATUS_CHECKOUT_REQUIRED ((NTSTATUS) 0xC0000902L)
+#endif
+
+#ifndef STATUS_BAD_FILE_TYPE
+# define STATUS_BAD_FILE_TYPE ((NTSTATUS) 0xC0000903L)
+#endif
+
+#ifndef STATUS_FILE_TOO_LARGE
+# define STATUS_FILE_TOO_LARGE ((NTSTATUS) 0xC0000904L)
+#endif
+
+#ifndef STATUS_FORMS_AUTH_REQUIRED
+# define STATUS_FORMS_AUTH_REQUIRED ((NTSTATUS) 0xC0000905L)
+#endif
+
+#ifndef STATUS_VIRUS_INFECTED
+# define STATUS_VIRUS_INFECTED ((NTSTATUS) 0xC0000906L)
+#endif
+
+#ifndef STATUS_VIRUS_DELETED
+# define STATUS_VIRUS_DELETED ((NTSTATUS) 0xC0000907L)
+#endif
+
+#ifndef STATUS_BAD_MCFG_TABLE
+# define STATUS_BAD_MCFG_TABLE ((NTSTATUS) 0xC0000908L)
+#endif
+
+#ifndef STATUS_CANNOT_BREAK_OPLOCK
+# define STATUS_CANNOT_BREAK_OPLOCK ((NTSTATUS) 0xC0000909L)
+#endif
+
+#ifndef STATUS_WOW_ASSERTION
+# define STATUS_WOW_ASSERTION ((NTSTATUS) 0xC0009898L)
+#endif
+
+#ifndef STATUS_INVALID_SIGNATURE
+# define STATUS_INVALID_SIGNATURE ((NTSTATUS) 0xC000A000L)
+#endif
+
+#ifndef STATUS_HMAC_NOT_SUPPORTED
+# define STATUS_HMAC_NOT_SUPPORTED ((NTSTATUS) 0xC000A001L)
+#endif
+
+#ifndef STATUS_AUTH_TAG_MISMATCH
+# define STATUS_AUTH_TAG_MISMATCH ((NTSTATUS) 0xC000A002L)
+#endif
+
+#ifndef STATUS_IPSEC_QUEUE_OVERFLOW
+# define STATUS_IPSEC_QUEUE_OVERFLOW ((NTSTATUS) 0xC000A010L)
+#endif
+
+#ifndef STATUS_ND_QUEUE_OVERFLOW
+# define STATUS_ND_QUEUE_OVERFLOW ((NTSTATUS) 0xC000A011L)
+#endif
+
+#ifndef STATUS_HOPLIMIT_EXCEEDED
+# define STATUS_HOPLIMIT_EXCEEDED ((NTSTATUS) 0xC000A012L)
+#endif
+
+#ifndef STATUS_PROTOCOL_NOT_SUPPORTED
+# define STATUS_PROTOCOL_NOT_SUPPORTED ((NTSTATUS) 0xC000A013L)
+#endif
+
+#ifndef STATUS_FASTPATH_REJECTED
+# define STATUS_FASTPATH_REJECTED ((NTSTATUS) 0xC000A014L)
+#endif
+
+#ifndef STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED
+# define STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED ((NTSTATUS) 0xC000A080L)
+#endif
+
+#ifndef STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR
+# define STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR ((NTSTATUS) 0xC000A081L)
+#endif
+
+#ifndef STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR
+# define STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR ((NTSTATUS) 0xC000A082L)
+#endif
+
+#ifndef STATUS_XML_PARSE_ERROR
+# define STATUS_XML_PARSE_ERROR ((NTSTATUS) 0xC000A083L)
+#endif
+
+#ifndef STATUS_XMLDSIG_ERROR
+# define STATUS_XMLDSIG_ERROR ((NTSTATUS) 0xC000A084L)
+#endif
+
+#ifndef STATUS_WRONG_COMPARTMENT
+# define STATUS_WRONG_COMPARTMENT ((NTSTATUS) 0xC000A085L)
+#endif
+
+#ifndef STATUS_AUTHIP_FAILURE
+# define STATUS_AUTHIP_FAILURE ((NTSTATUS) 0xC000A086L)
+#endif
+
+#ifndef STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS
+# define STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS ((NTSTATUS) 0xC000A087L)
+#endif
+
+#ifndef STATUS_DS_OID_NOT_FOUND
+# define STATUS_DS_OID_NOT_FOUND ((NTSTATUS) 0xC000A088L)
+#endif
+
+#ifndef STATUS_HASH_NOT_SUPPORTED
+# define STATUS_HASH_NOT_SUPPORTED ((NTSTATUS) 0xC000A100L)
+#endif
+
+#ifndef STATUS_HASH_NOT_PRESENT
+# define STATUS_HASH_NOT_PRESENT ((NTSTATUS) 0xC000A101L)
+#endif
+
+/* This is not the NTSTATUS_FROM_WIN32 that the DDK provides, because the */
+/* DDK got it wrong! */
+#ifdef NTSTATUS_FROM_WIN32
+# undef NTSTATUS_FROM_WIN32
+#endif
+#define NTSTATUS_FROM_WIN32(error) ((NTSTATUS) (error) <= 0 ? \
+ ((NTSTATUS) (error)) : ((NTSTATUS) (((error) & 0x0000FFFF) | \
+ (FACILITY_NTWIN32 << 16) | ERROR_SEVERITY_WARNING)))
+
+#ifndef JOB_OBJECT_LIMIT_PROCESS_MEMORY
+# define JOB_OBJECT_LIMIT_PROCESS_MEMORY 0x00000100
+#endif
+#ifndef JOB_OBJECT_LIMIT_JOB_MEMORY
+# define JOB_OBJECT_LIMIT_JOB_MEMORY 0x00000200
+#endif
+#ifndef JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION
+# define JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION 0x00000400
+#endif
+#ifndef JOB_OBJECT_LIMIT_BREAKAWAY_OK
+# define JOB_OBJECT_LIMIT_BREAKAWAY_OK 0x00000800
+#endif
+#ifndef JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK
+# define JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK 0x00001000
+#endif
+#ifndef JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
+# define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000
+#endif
+
+/* from winternl.h */
+typedef struct _UNICODE_STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+ PWSTR Buffer;
+} UNICODE_STRING, *PUNICODE_STRING;
+
+typedef const UNICODE_STRING *PCUNICODE_STRING;
+
+/* from ntifs.h */
+#ifndef DEVICE_TYPE
+# define DEVICE_TYPE DWORD
+#endif
+
+/* MinGW already has a definition for REPARSE_DATA_BUFFER, but mingw-w64 does
+ * not.
+ */
+#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
+ typedef struct _REPARSE_DATA_BUFFER {
+ ULONG ReparseTag;
+ USHORT ReparseDataLength;
+ USHORT Reserved;
+ union {
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ ULONG Flags;
+ WCHAR PathBuffer[1];
+ } SymbolicLinkReparseBuffer;
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ WCHAR PathBuffer[1];
+ } MountPointReparseBuffer;
+ struct {
+ UCHAR DataBuffer[1];
+ } GenericReparseBuffer;
+ } DUMMYUNIONNAME;
+ } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
+#endif
+
+typedef struct _IO_STATUS_BLOCK {
+ union {
+ NTSTATUS Status;
+ PVOID Pointer;
+ } DUMMYUNIONNAME;
+ ULONG_PTR Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+
+typedef enum _FILE_INFORMATION_CLASS {
+ FileDirectoryInformation = 1,
+ FileFullDirectoryInformation,
+ FileBothDirectoryInformation,
+ FileBasicInformation,
+ FileStandardInformation,
+ FileInternalInformation,
+ FileEaInformation,
+ FileAccessInformation,
+ FileNameInformation,
+ FileRenameInformation,
+ FileLinkInformation,
+ FileNamesInformation,
+ FileDispositionInformation,
+ FilePositionInformation,
+ FileFullEaInformation,
+ FileModeInformation,
+ FileAlignmentInformation,
+ FileAllInformation,
+ FileAllocationInformation,
+ FileEndOfFileInformation,
+ FileAlternateNameInformation,
+ FileStreamInformation,
+ FilePipeInformation,
+ FilePipeLocalInformation,
+ FilePipeRemoteInformation,
+ FileMailslotQueryInformation,
+ FileMailslotSetInformation,
+ FileCompressionInformation,
+ FileObjectIdInformation,
+ FileCompletionInformation,
+ FileMoveClusterInformation,
+ FileQuotaInformation,
+ FileReparsePointInformation,
+ FileNetworkOpenInformation,
+ FileAttributeTagInformation,
+ FileTrackingInformation,
+ FileIdBothDirectoryInformation,
+ FileIdFullDirectoryInformation,
+ FileValidDataLengthInformation,
+ FileShortNameInformation,
+ FileIoCompletionNotificationInformation,
+ FileIoStatusBlockRangeInformation,
+ FileIoPriorityHintInformation,
+ FileSfioReserveInformation,
+ FileSfioVolumeInformation,
+ FileHardLinkInformation,
+ FileProcessIdsUsingFileInformation,
+ FileNormalizedNameInformation,
+ FileNetworkPhysicalNameInformation,
+ FileIdGlobalTxDirectoryInformation,
+ FileIsRemoteDeviceInformation,
+ FileAttributeCacheInformation,
+ FileNumaNodeInformation,
+ FileStandardLinkInformation,
+ FileRemoteProtocolInformation,
+ FileMaximumInformation
+} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
+
+typedef struct _FILE_DIRECTORY_INFORMATION {
+ ULONG NextEntryOffset;
+ ULONG FileIndex;
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ LARGE_INTEGER EndOfFile;
+ LARGE_INTEGER AllocationSize;
+ ULONG FileAttributes;
+ ULONG FileNameLength;
+ WCHAR FileName[1];
+} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;
+
+typedef struct _FILE_BOTH_DIR_INFORMATION {
+ ULONG NextEntryOffset;
+ ULONG FileIndex;
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ LARGE_INTEGER EndOfFile;
+ LARGE_INTEGER AllocationSize;
+ ULONG FileAttributes;
+ ULONG FileNameLength;
+ ULONG EaSize;
+ CCHAR ShortNameLength;
+ WCHAR ShortName[12];
+ WCHAR FileName[1];
+} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;
+
+typedef struct _FILE_BASIC_INFORMATION {
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ DWORD FileAttributes;
+} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
+
+typedef struct _FILE_STANDARD_INFORMATION {
+ LARGE_INTEGER AllocationSize;
+ LARGE_INTEGER EndOfFile;
+ ULONG NumberOfLinks;
+ BOOLEAN DeletePending;
+ BOOLEAN Directory;
+} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION;
+
+typedef struct _FILE_INTERNAL_INFORMATION {
+ LARGE_INTEGER IndexNumber;
+} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION;
+
+typedef struct _FILE_EA_INFORMATION {
+ ULONG EaSize;
+} FILE_EA_INFORMATION, *PFILE_EA_INFORMATION;
+
+typedef struct _FILE_ACCESS_INFORMATION {
+ ACCESS_MASK AccessFlags;
+} FILE_ACCESS_INFORMATION, *PFILE_ACCESS_INFORMATION;
+
+typedef struct _FILE_POSITION_INFORMATION {
+ LARGE_INTEGER CurrentByteOffset;
+} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION;
+
+typedef struct _FILE_MODE_INFORMATION {
+ ULONG Mode;
+} FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION;
+
+typedef struct _FILE_ALIGNMENT_INFORMATION {
+ ULONG AlignmentRequirement;
+} FILE_ALIGNMENT_INFORMATION, *PFILE_ALIGNMENT_INFORMATION;
+
+typedef struct _FILE_NAME_INFORMATION {
+ ULONG FileNameLength;
+ WCHAR FileName[1];
+} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
+
+typedef struct _FILE_END_OF_FILE_INFORMATION {
+ LARGE_INTEGER EndOfFile;
+} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION;
+
+typedef struct _FILE_ALL_INFORMATION {
+ FILE_BASIC_INFORMATION BasicInformation;
+ FILE_STANDARD_INFORMATION StandardInformation;
+ FILE_INTERNAL_INFORMATION InternalInformation;
+ FILE_EA_INFORMATION EaInformation;
+ FILE_ACCESS_INFORMATION AccessInformation;
+ FILE_POSITION_INFORMATION PositionInformation;
+ FILE_MODE_INFORMATION ModeInformation;
+ FILE_ALIGNMENT_INFORMATION AlignmentInformation;
+ FILE_NAME_INFORMATION NameInformation;
+} FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION;
+
+typedef struct _FILE_DISPOSITION_INFORMATION {
+ BOOLEAN DeleteFile;
+} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION;
+
+typedef struct _FILE_PIPE_LOCAL_INFORMATION {
+ ULONG NamedPipeType;
+ ULONG NamedPipeConfiguration;
+ ULONG MaximumInstances;
+ ULONG CurrentInstances;
+ ULONG InboundQuota;
+ ULONG ReadDataAvailable;
+ ULONG OutboundQuota;
+ ULONG WriteQuotaAvailable;
+ ULONG NamedPipeState;
+ ULONG NamedPipeEnd;
+} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
+
+#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010
+#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020
+
+typedef enum _FS_INFORMATION_CLASS {
+ FileFsVolumeInformation = 1,
+ FileFsLabelInformation = 2,
+ FileFsSizeInformation = 3,
+ FileFsDeviceInformation = 4,
+ FileFsAttributeInformation = 5,
+ FileFsControlInformation = 6,
+ FileFsFullSizeInformation = 7,
+ FileFsObjectIdInformation = 8,
+ FileFsDriverPathInformation = 9,
+ FileFsVolumeFlagsInformation = 10,
+ FileFsSectorSizeInformation = 11
+} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;
+
+typedef struct _FILE_FS_VOLUME_INFORMATION {
+ LARGE_INTEGER VolumeCreationTime;
+ ULONG VolumeSerialNumber;
+ ULONG VolumeLabelLength;
+ BOOLEAN SupportsObjects;
+ WCHAR VolumeLabel[1];
+} FILE_FS_VOLUME_INFORMATION, *PFILE_FS_VOLUME_INFORMATION;
+
+typedef struct _FILE_FS_LABEL_INFORMATION {
+ ULONG VolumeLabelLength;
+ WCHAR VolumeLabel[1];
+} FILE_FS_LABEL_INFORMATION, *PFILE_FS_LABEL_INFORMATION;
+
+typedef struct _FILE_FS_SIZE_INFORMATION {
+ LARGE_INTEGER TotalAllocationUnits;
+ LARGE_INTEGER AvailableAllocationUnits;
+ ULONG SectorsPerAllocationUnit;
+ ULONG BytesPerSector;
+} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION;
+
+typedef struct _FILE_FS_DEVICE_INFORMATION {
+ DEVICE_TYPE DeviceType;
+ ULONG Characteristics;
+} FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION;
+
+typedef struct _FILE_FS_ATTRIBUTE_INFORMATION {
+ ULONG FileSystemAttributes;
+ LONG MaximumComponentNameLength;
+ ULONG FileSystemNameLength;
+ WCHAR FileSystemName[1];
+} FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION;
+
+typedef struct _FILE_FS_CONTROL_INFORMATION {
+ LARGE_INTEGER FreeSpaceStartFiltering;
+ LARGE_INTEGER FreeSpaceThreshold;
+ LARGE_INTEGER FreeSpaceStopFiltering;
+ LARGE_INTEGER DefaultQuotaThreshold;
+ LARGE_INTEGER DefaultQuotaLimit;
+ ULONG FileSystemControlFlags;
+} FILE_FS_CONTROL_INFORMATION, *PFILE_FS_CONTROL_INFORMATION;
+
+typedef struct _FILE_FS_FULL_SIZE_INFORMATION {
+ LARGE_INTEGER TotalAllocationUnits;
+ LARGE_INTEGER CallerAvailableAllocationUnits;
+ LARGE_INTEGER ActualAvailableAllocationUnits;
+ ULONG SectorsPerAllocationUnit;
+ ULONG BytesPerSector;
+} FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION;
+
+typedef struct _FILE_FS_OBJECTID_INFORMATION {
+ UCHAR ObjectId[16];
+ UCHAR ExtendedInfo[48];
+} FILE_FS_OBJECTID_INFORMATION, *PFILE_FS_OBJECTID_INFORMATION;
+
+typedef struct _FILE_FS_DRIVER_PATH_INFORMATION {
+ BOOLEAN DriverInPath;
+ ULONG DriverNameLength;
+ WCHAR DriverName[1];
+} FILE_FS_DRIVER_PATH_INFORMATION, *PFILE_FS_DRIVER_PATH_INFORMATION;
+
+typedef struct _FILE_FS_VOLUME_FLAGS_INFORMATION {
+ ULONG Flags;
+} FILE_FS_VOLUME_FLAGS_INFORMATION, *PFILE_FS_VOLUME_FLAGS_INFORMATION;
+
+typedef struct _FILE_FS_SECTOR_SIZE_INFORMATION {
+ ULONG LogicalBytesPerSector;
+ ULONG PhysicalBytesPerSectorForAtomicity;
+ ULONG PhysicalBytesPerSectorForPerformance;
+ ULONG FileSystemEffectivePhysicalBytesPerSectorForAtomicity;
+ ULONG Flags;
+ ULONG ByteOffsetForSectorAlignment;
+ ULONG ByteOffsetForPartitionAlignment;
+} FILE_FS_SECTOR_SIZE_INFORMATION, *PFILE_FS_SECTOR_SIZE_INFORMATION;
+
+typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
+ LARGE_INTEGER IdleTime;
+ LARGE_INTEGER KernelTime;
+ LARGE_INTEGER UserTime;
+ LARGE_INTEGER DpcTime;
+ LARGE_INTEGER InterruptTime;
+ ULONG InterruptCount;
+} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
+
+#ifndef SystemProcessorPerformanceInformation
+# define SystemProcessorPerformanceInformation 8
+#endif
+
+#ifndef FILE_DEVICE_FILE_SYSTEM
+# define FILE_DEVICE_FILE_SYSTEM 0x00000009
+#endif
+
+#ifndef FILE_DEVICE_NETWORK
+# define FILE_DEVICE_NETWORK 0x00000012
+#endif
+
+#ifndef METHOD_BUFFERED
+# define METHOD_BUFFERED 0
+#endif
+
+#ifndef METHOD_IN_DIRECT
+# define METHOD_IN_DIRECT 1
+#endif
+
+#ifndef METHOD_OUT_DIRECT
+# define METHOD_OUT_DIRECT 2
+#endif
+
+#ifndef METHOD_NEITHER
+#define METHOD_NEITHER 3
+#endif
+
+#ifndef METHOD_DIRECT_TO_HARDWARE
+# define METHOD_DIRECT_TO_HARDWARE METHOD_IN_DIRECT
+#endif
+
+#ifndef METHOD_DIRECT_FROM_HARDWARE
+# define METHOD_DIRECT_FROM_HARDWARE METHOD_OUT_DIRECT
+#endif
+
+#ifndef FILE_ANY_ACCESS
+# define FILE_ANY_ACCESS 0
+#endif
+
+#ifndef FILE_SPECIAL_ACCESS
+# define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS)
+#endif
+
+#ifndef FILE_READ_ACCESS
+# define FILE_READ_ACCESS 0x0001
+#endif
+
+#ifndef FILE_WRITE_ACCESS
+# define FILE_WRITE_ACCESS 0x0002
+#endif
+
+#ifndef CTL_CODE
+# define CTL_CODE(device_type, function, method, access) \
+ (((device_type) << 16) | ((access) << 14) | ((function) << 2) | (method))
+#endif
+
+#ifndef FSCTL_SET_REPARSE_POINT
+# define FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \
+ 41, \
+ METHOD_BUFFERED, \
+ FILE_SPECIAL_ACCESS)
+#endif
+
+#ifndef FSCTL_GET_REPARSE_POINT
+# define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \
+ 42, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+#endif
+
+#ifndef FSCTL_DELETE_REPARSE_POINT
+# define FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \
+ 43, \
+ METHOD_BUFFERED, \
+ FILE_SPECIAL_ACCESS)
+#endif
+
+#ifndef IO_REPARSE_TAG_SYMLINK
+# define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
+#endif
+
+typedef VOID (NTAPI *PIO_APC_ROUTINE)
+ (PVOID ApcContext,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ ULONG Reserved);
+
+typedef ULONG (NTAPI *sRtlNtStatusToDosError)
+ (NTSTATUS Status);
+
+typedef NTSTATUS (NTAPI *sNtDeviceIoControlFile)
+ (HANDLE FileHandle,
+ HANDLE Event,
+ PIO_APC_ROUTINE ApcRoutine,
+ PVOID ApcContext,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ ULONG IoControlCode,
+ PVOID InputBuffer,
+ ULONG InputBufferLength,
+ PVOID OutputBuffer,
+ ULONG OutputBufferLength);
+
+typedef NTSTATUS (NTAPI *sNtQueryInformationFile)
+ (HANDLE FileHandle,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ PVOID FileInformation,
+ ULONG Length,
+ FILE_INFORMATION_CLASS FileInformationClass);
+
+typedef NTSTATUS (NTAPI *sNtSetInformationFile)
+ (HANDLE FileHandle,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ PVOID FileInformation,
+ ULONG Length,
+ FILE_INFORMATION_CLASS FileInformationClass);
+
+typedef NTSTATUS (NTAPI *sNtQueryVolumeInformationFile)
+ (HANDLE FileHandle,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ PVOID FsInformation,
+ ULONG Length,
+ FS_INFORMATION_CLASS FsInformationClass);
+
+typedef NTSTATUS (NTAPI *sNtQuerySystemInformation)
+ (UINT SystemInformationClass,
+ PVOID SystemInformation,
+ ULONG SystemInformationLength,
+ PULONG ReturnLength);
+
+typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile)
+ (HANDLE FileHandle,
+ HANDLE Event,
+ PIO_APC_ROUTINE ApcRoutine,
+ PVOID ApcContext,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ PVOID FileInformation,
+ ULONG Length,
+ FILE_INFORMATION_CLASS FileInformationClass,
+ BOOLEAN ReturnSingleEntry,
+ PUNICODE_STRING FileName,
+ BOOLEAN RestartScan
+ );
+
+/*
+ * Kernel32 headers
+ */
+#ifndef FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
+# define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1
+#endif
+
+#ifndef FILE_SKIP_SET_EVENT_ON_HANDLE
+# define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2
+#endif
+
+#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
+# define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
+#endif
+
+#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
+ typedef struct _OVERLAPPED_ENTRY {
+ ULONG_PTR lpCompletionKey;
+ LPOVERLAPPED lpOverlapped;
+ ULONG_PTR Internal;
+ DWORD dwNumberOfBytesTransferred;
+ } OVERLAPPED_ENTRY, *LPOVERLAPPED_ENTRY;
+#endif
+
+/* from wincon.h */
+#ifndef ENABLE_INSERT_MODE
+# define ENABLE_INSERT_MODE 0x20
+#endif
+
+#ifndef ENABLE_QUICK_EDIT_MODE
+# define ENABLE_QUICK_EDIT_MODE 0x40
+#endif
+
+#ifndef ENABLE_EXTENDED_FLAGS
+# define ENABLE_EXTENDED_FLAGS 0x80
+#endif
+
+/* from winerror.h */
+#ifndef ERROR_SYMLINK_NOT_SUPPORTED
+# define ERROR_SYMLINK_NOT_SUPPORTED 1464
+#endif
+
+#ifndef ERROR_MUI_FILE_NOT_FOUND
+# define ERROR_MUI_FILE_NOT_FOUND 15100
+#endif
+
+#ifndef ERROR_MUI_INVALID_FILE
+# define ERROR_MUI_INVALID_FILE 15101
+#endif
+
+#ifndef ERROR_MUI_INVALID_RC_CONFIG
+# define ERROR_MUI_INVALID_RC_CONFIG 15102
+#endif
+
+#ifndef ERROR_MUI_INVALID_LOCALE_NAME
+# define ERROR_MUI_INVALID_LOCALE_NAME 15103
+#endif
+
+#ifndef ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME
+# define ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME 15104
+#endif
+
+#ifndef ERROR_MUI_FILE_NOT_LOADED
+# define ERROR_MUI_FILE_NOT_LOADED 15105
+#endif
+
+typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx)
+ (HANDLE CompletionPort,
+ LPOVERLAPPED_ENTRY lpCompletionPortEntries,
+ ULONG ulCount,
+ PULONG ulNumEntriesRemoved,
+ DWORD dwMilliseconds,
+ BOOL fAlertable);
+
+typedef BOOL (WINAPI* sSetFileCompletionNotificationModes)
+ (HANDLE FileHandle,
+ UCHAR Flags);
+
+typedef BOOLEAN (WINAPI* sCreateSymbolicLinkW)
+ (LPCWSTR lpSymlinkFileName,
+ LPCWSTR lpTargetFileName,
+ DWORD dwFlags);
+
+typedef BOOL (WINAPI* sCancelIoEx)
+ (HANDLE hFile,
+ LPOVERLAPPED lpOverlapped);
+
+typedef VOID (WINAPI* sInitializeConditionVariable)
+ (PCONDITION_VARIABLE ConditionVariable);
+
+typedef BOOL (WINAPI* sSleepConditionVariableCS)
+ (PCONDITION_VARIABLE ConditionVariable,
+ PCRITICAL_SECTION CriticalSection,
+ DWORD dwMilliseconds);
+
+typedef BOOL (WINAPI* sSleepConditionVariableSRW)
+ (PCONDITION_VARIABLE ConditionVariable,
+ PSRWLOCK SRWLock,
+ DWORD dwMilliseconds,
+ ULONG Flags);
+
+typedef VOID (WINAPI* sWakeAllConditionVariable)
+ (PCONDITION_VARIABLE ConditionVariable);
+
+typedef VOID (WINAPI* sWakeConditionVariable)
+ (PCONDITION_VARIABLE ConditionVariable);
+
+typedef BOOL (WINAPI* sCancelSynchronousIo)
+ (HANDLE hThread);
+
+typedef DWORD (WINAPI* sGetFinalPathNameByHandleW)
+ (HANDLE hFile,
+ LPWSTR lpszFilePath,
+ DWORD cchFilePath,
+ DWORD dwFlags);
+
+/* Ntdll function pointers */
+extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
+extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
+extern sNtQueryInformationFile pNtQueryInformationFile;
+extern sNtSetInformationFile pNtSetInformationFile;
+extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
+extern sNtQueryDirectoryFile pNtQueryDirectoryFile;
+extern sNtQuerySystemInformation pNtQuerySystemInformation;
+
+
+/* Kernel32 function pointers */
+extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
+extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
+extern sCreateSymbolicLinkW pCreateSymbolicLinkW;
+extern sCancelIoEx pCancelIoEx;
+extern sInitializeConditionVariable pInitializeConditionVariable;
+extern sSleepConditionVariableCS pSleepConditionVariableCS;
+extern sSleepConditionVariableSRW pSleepConditionVariableSRW;
+extern sWakeAllConditionVariable pWakeAllConditionVariable;
+extern sWakeConditionVariable pWakeConditionVariable;
+extern sCancelSynchronousIo pCancelSynchronousIo;
+extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
+
+#endif /* UV_WIN_WINAPI_H_ */
diff --git a/3rdparty/libuv/src/win/winsock.c b/3rdparty/libuv/src/win/winsock.c
new file mode 100644
index 00000000000..d2e667e9f75
--- /dev/null
+++ b/3rdparty/libuv/src/win/winsock.c
@@ -0,0 +1,561 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+/* Whether there are any non-IFS LSPs stacked on TCP */
+int uv_tcp_non_ifs_lsp_ipv4;
+int uv_tcp_non_ifs_lsp_ipv6;
+
+/* Ip address used to bind to any port at any interface */
+struct sockaddr_in uv_addr_ip4_any_;
+struct sockaddr_in6 uv_addr_ip6_any_;
+
+
+/*
+ * Retrieves the pointer to a winsock extension function.
+ */
+static BOOL uv_get_extension_function(SOCKET socket, GUID guid,
+ void **target) {
+ int result;
+ DWORD bytes;
+
+ result = WSAIoctl(socket,
+ SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &guid,
+ sizeof(guid),
+ (void*)target,
+ sizeof(*target),
+ &bytes,
+ NULL,
+ NULL);
+
+ if (result == SOCKET_ERROR) {
+ *target = NULL;
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+
+BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) {
+ const GUID wsaid_acceptex = WSAID_ACCEPTEX;
+ return uv_get_extension_function(socket, wsaid_acceptex, (void**)target);
+}
+
+
+BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) {
+ const GUID wsaid_connectex = WSAID_CONNECTEX;
+ return uv_get_extension_function(socket, wsaid_connectex, (void**)target);
+}
+
+
+static int error_means_no_support(DWORD error) {
+ return error == WSAEPROTONOSUPPORT || error == WSAESOCKTNOSUPPORT ||
+ error == WSAEPFNOSUPPORT || error == WSAEAFNOSUPPORT;
+}
+
+
+void uv_winsock_init() {
+ WSADATA wsa_data;
+ int errorno;
+ SOCKET dummy;
+ WSAPROTOCOL_INFOW protocol_info;
+ int opt_len;
+
+ /* Initialize winsock */
+ errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ if (errorno != 0) {
+ uv_fatal_error(errorno, "WSAStartup");
+ }
+
+ /* Set implicit binding address used by connectEx */
+ if (uv_ip4_addr("0.0.0.0", 0, &uv_addr_ip4_any_)) {
+ abort();
+ }
+
+ if (uv_ip6_addr("::", 0, &uv_addr_ip6_any_)) {
+ abort();
+ }
+
+ /* Detect non-IFS LSPs */
+ dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+
+ if (dummy != INVALID_SOCKET) {
+ opt_len = (int) sizeof protocol_info;
+ if (getsockopt(dummy,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &protocol_info,
+ &opt_len) == SOCKET_ERROR)
+ uv_fatal_error(WSAGetLastError(), "getsockopt");
+
+ if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES))
+ uv_tcp_non_ifs_lsp_ipv4 = 1;
+
+ if (closesocket(dummy) == SOCKET_ERROR)
+ uv_fatal_error(WSAGetLastError(), "closesocket");
+
+ } else if (!error_means_no_support(WSAGetLastError())) {
+ /* Any error other than "socket type not supported" is fatal. */
+ uv_fatal_error(WSAGetLastError(), "socket");
+ }
+
+ /* Detect IPV6 support and non-IFS LSPs */
+ dummy = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP);
+
+ if (dummy != INVALID_SOCKET) {
+ opt_len = (int) sizeof protocol_info;
+ if (getsockopt(dummy,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &protocol_info,
+ &opt_len) == SOCKET_ERROR)
+ uv_fatal_error(WSAGetLastError(), "getsockopt");
+
+ if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES))
+ uv_tcp_non_ifs_lsp_ipv6 = 1;
+
+ if (closesocket(dummy) == SOCKET_ERROR)
+ uv_fatal_error(WSAGetLastError(), "closesocket");
+
+ } else if (!error_means_no_support(WSAGetLastError())) {
+ /* Any error other than "socket type not supported" is fatal. */
+ uv_fatal_error(WSAGetLastError(), "socket");
+ }
+}
+
+
+int uv_ntstatus_to_winsock_error(NTSTATUS status) {
+ switch (status) {
+ case STATUS_SUCCESS:
+ return ERROR_SUCCESS;
+
+ case STATUS_PENDING:
+ return ERROR_IO_PENDING;
+
+ case STATUS_INVALID_HANDLE:
+ case STATUS_OBJECT_TYPE_MISMATCH:
+ return WSAENOTSOCK;
+
+ case STATUS_INSUFFICIENT_RESOURCES:
+ case STATUS_PAGEFILE_QUOTA:
+ case STATUS_COMMITMENT_LIMIT:
+ case STATUS_WORKING_SET_QUOTA:
+ case STATUS_NO_MEMORY:
+ case STATUS_QUOTA_EXCEEDED:
+ case STATUS_TOO_MANY_PAGING_FILES:
+ case STATUS_REMOTE_RESOURCES:
+ return WSAENOBUFS;
+
+ case STATUS_TOO_MANY_ADDRESSES:
+ case STATUS_SHARING_VIOLATION:
+ case STATUS_ADDRESS_ALREADY_EXISTS:
+ return WSAEADDRINUSE;
+
+ case STATUS_LINK_TIMEOUT:
+ case STATUS_IO_TIMEOUT:
+ case STATUS_TIMEOUT:
+ return WSAETIMEDOUT;
+
+ case STATUS_GRACEFUL_DISCONNECT:
+ return WSAEDISCON;
+
+ case STATUS_REMOTE_DISCONNECT:
+ case STATUS_CONNECTION_RESET:
+ case STATUS_LINK_FAILED:
+ case STATUS_CONNECTION_DISCONNECTED:
+ case STATUS_PORT_UNREACHABLE:
+ case STATUS_HOPLIMIT_EXCEEDED:
+ return WSAECONNRESET;
+
+ case STATUS_LOCAL_DISCONNECT:
+ case STATUS_TRANSACTION_ABORTED:
+ case STATUS_CONNECTION_ABORTED:
+ return WSAECONNABORTED;
+
+ case STATUS_BAD_NETWORK_PATH:
+ case STATUS_NETWORK_UNREACHABLE:
+ case STATUS_PROTOCOL_UNREACHABLE:
+ return WSAENETUNREACH;
+
+ case STATUS_HOST_UNREACHABLE:
+ return WSAEHOSTUNREACH;
+
+ case STATUS_CANCELLED:
+ case STATUS_REQUEST_ABORTED:
+ return WSAEINTR;
+
+ case STATUS_BUFFER_OVERFLOW:
+ case STATUS_INVALID_BUFFER_SIZE:
+ return WSAEMSGSIZE;
+
+ case STATUS_BUFFER_TOO_SMALL:
+ case STATUS_ACCESS_VIOLATION:
+ return WSAEFAULT;
+
+ case STATUS_DEVICE_NOT_READY:
+ case STATUS_REQUEST_NOT_ACCEPTED:
+ return WSAEWOULDBLOCK;
+
+ case STATUS_INVALID_NETWORK_RESPONSE:
+ case STATUS_NETWORK_BUSY:
+ case STATUS_NO_SUCH_DEVICE:
+ case STATUS_NO_SUCH_FILE:
+ case STATUS_OBJECT_PATH_NOT_FOUND:
+ case STATUS_OBJECT_NAME_NOT_FOUND:
+ case STATUS_UNEXPECTED_NETWORK_ERROR:
+ return WSAENETDOWN;
+
+ case STATUS_INVALID_CONNECTION:
+ return WSAENOTCONN;
+
+ case STATUS_REMOTE_NOT_LISTENING:
+ case STATUS_CONNECTION_REFUSED:
+ return WSAECONNREFUSED;
+
+ case STATUS_PIPE_DISCONNECTED:
+ return WSAESHUTDOWN;
+
+ case STATUS_CONFLICTING_ADDRESSES:
+ case STATUS_INVALID_ADDRESS:
+ case STATUS_INVALID_ADDRESS_COMPONENT:
+ return WSAEADDRNOTAVAIL;
+
+ case STATUS_NOT_SUPPORTED:
+ case STATUS_NOT_IMPLEMENTED:
+ return WSAEOPNOTSUPP;
+
+ case STATUS_ACCESS_DENIED:
+ return WSAEACCES;
+
+ default:
+ if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) &&
+ (status & (ERROR_SEVERITY_ERROR | ERROR_SEVERITY_WARNING))) {
+ /* It's a windows error that has been previously mapped to an */
+ /* ntstatus code. */
+ return (DWORD) (status & 0xffff);
+ } else {
+ /* The default fallback for unmappable ntstatus codes. */
+ return WSAEINVAL;
+ }
+ }
+}
+
+
+/*
+ * This function provides a workaround for a bug in the winsock implementation
+ * of WSARecv. The problem is that when SetFileCompletionNotificationModes is
+ * used to avoid IOCP notifications of completed reads, WSARecv does not
+ * reliably indicate whether we can expect a completion package to be posted
+ * when the receive buffer is smaller than the received datagram.
+ *
+ * However it is desirable to use SetFileCompletionNotificationModes because
+ * it yields a massive performance increase.
+ *
+ * This function provides a workaround for that bug, but it only works for the
+ * specific case that we need it for. E.g. it assumes that the "avoid iocp"
+ * bit has been set, and supports only overlapped operation. It also requires
+ * the user to use the default msafd driver, doesn't work when other LSPs are
+ * stacked on top of it.
+ */
+int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
+ DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
+ NTSTATUS status;
+ void* apc_context;
+ IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
+ AFD_RECV_INFO info;
+ DWORD error;
+
+ if (overlapped == NULL || completion_routine != NULL) {
+ WSASetLastError(WSAEINVAL);
+ return SOCKET_ERROR;
+ }
+
+ info.BufferArray = buffers;
+ info.BufferCount = buffer_count;
+ info.AfdFlags = AFD_OVERLAPPED;
+ info.TdiFlags = TDI_RECEIVE_NORMAL;
+
+ if (*flags & MSG_PEEK) {
+ info.TdiFlags |= TDI_RECEIVE_PEEK;
+ }
+
+ if (*flags & MSG_PARTIAL) {
+ info.TdiFlags |= TDI_RECEIVE_PARTIAL;
+ }
+
+ if (!((intptr_t) overlapped->hEvent & 1)) {
+ apc_context = (void*) overlapped;
+ } else {
+ apc_context = NULL;
+ }
+
+ iosb->Status = STATUS_PENDING;
+ iosb->Pointer = 0;
+
+ status = pNtDeviceIoControlFile((HANDLE) socket,
+ overlapped->hEvent,
+ NULL,
+ apc_context,
+ iosb,
+ IOCTL_AFD_RECEIVE,
+ &info,
+ sizeof(info),
+ NULL,
+ 0);
+
+ *flags = 0;
+ *bytes = (DWORD) iosb->Information;
+
+ switch (status) {
+ case STATUS_SUCCESS:
+ error = ERROR_SUCCESS;
+ break;
+
+ case STATUS_PENDING:
+ error = WSA_IO_PENDING;
+ break;
+
+ case STATUS_BUFFER_OVERFLOW:
+ error = WSAEMSGSIZE;
+ break;
+
+ case STATUS_RECEIVE_EXPEDITED:
+ error = ERROR_SUCCESS;
+ *flags = MSG_OOB;
+ break;
+
+ case STATUS_RECEIVE_PARTIAL_EXPEDITED:
+ error = ERROR_SUCCESS;
+ *flags = MSG_PARTIAL | MSG_OOB;
+ break;
+
+ case STATUS_RECEIVE_PARTIAL:
+ error = ERROR_SUCCESS;
+ *flags = MSG_PARTIAL;
+ break;
+
+ default:
+ error = uv_ntstatus_to_winsock_error(status);
+ break;
+ }
+
+ WSASetLastError(error);
+
+ if (error == ERROR_SUCCESS) {
+ return 0;
+ } else {
+ return SOCKET_ERROR;
+ }
+}
+
+
+/* See description of uv_wsarecv_workaround. */
+int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
+ DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
+ int* addr_len, WSAOVERLAPPED *overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
+ NTSTATUS status;
+ void* apc_context;
+ IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
+ AFD_RECV_DATAGRAM_INFO info;
+ DWORD error;
+
+ if (overlapped == NULL || addr == NULL || addr_len == NULL ||
+ completion_routine != NULL) {
+ WSASetLastError(WSAEINVAL);
+ return SOCKET_ERROR;
+ }
+
+ info.BufferArray = buffers;
+ info.BufferCount = buffer_count;
+ info.AfdFlags = AFD_OVERLAPPED;
+ info.TdiFlags = TDI_RECEIVE_NORMAL;
+ info.Address = addr;
+ info.AddressLength = addr_len;
+
+ if (*flags & MSG_PEEK) {
+ info.TdiFlags |= TDI_RECEIVE_PEEK;
+ }
+
+ if (*flags & MSG_PARTIAL) {
+ info.TdiFlags |= TDI_RECEIVE_PARTIAL;
+ }
+
+ if (!((intptr_t) overlapped->hEvent & 1)) {
+ apc_context = (void*) overlapped;
+ } else {
+ apc_context = NULL;
+ }
+
+ iosb->Status = STATUS_PENDING;
+ iosb->Pointer = 0;
+
+ status = pNtDeviceIoControlFile((HANDLE) socket,
+ overlapped->hEvent,
+ NULL,
+ apc_context,
+ iosb,
+ IOCTL_AFD_RECEIVE_DATAGRAM,
+ &info,
+ sizeof(info),
+ NULL,
+ 0);
+
+ *flags = 0;
+ *bytes = (DWORD) iosb->Information;
+
+ switch (status) {
+ case STATUS_SUCCESS:
+ error = ERROR_SUCCESS;
+ break;
+
+ case STATUS_PENDING:
+ error = WSA_IO_PENDING;
+ break;
+
+ case STATUS_BUFFER_OVERFLOW:
+ error = WSAEMSGSIZE;
+ break;
+
+ case STATUS_RECEIVE_EXPEDITED:
+ error = ERROR_SUCCESS;
+ *flags = MSG_OOB;
+ break;
+
+ case STATUS_RECEIVE_PARTIAL_EXPEDITED:
+ error = ERROR_SUCCESS;
+ *flags = MSG_PARTIAL | MSG_OOB;
+ break;
+
+ case STATUS_RECEIVE_PARTIAL:
+ error = ERROR_SUCCESS;
+ *flags = MSG_PARTIAL;
+ break;
+
+ default:
+ error = uv_ntstatus_to_winsock_error(status);
+ break;
+ }
+
+ WSASetLastError(error);
+
+ if (error == ERROR_SUCCESS) {
+ return 0;
+ } else {
+ return SOCKET_ERROR;
+ }
+}
+
+
+int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
+ AFD_POLL_INFO* info_out, OVERLAPPED* overlapped) {
+ IO_STATUS_BLOCK iosb;
+ IO_STATUS_BLOCK* iosb_ptr;
+ HANDLE event = NULL;
+ void* apc_context;
+ NTSTATUS status;
+ DWORD error;
+
+ if (overlapped != NULL) {
+ /* Overlapped operation. */
+ iosb_ptr = (IO_STATUS_BLOCK*) &overlapped->Internal;
+ event = overlapped->hEvent;
+
+ /* Do not report iocp completion if hEvent is tagged. */
+ if ((uintptr_t) event & 1) {
+ event = (HANDLE)((uintptr_t) event & ~(uintptr_t) 1);
+ apc_context = NULL;
+ } else {
+ apc_context = overlapped;
+ }
+
+ } else {
+ /* Blocking operation. */
+ iosb_ptr = &iosb;
+ event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (event == NULL) {
+ return SOCKET_ERROR;
+ }
+ apc_context = NULL;
+ }
+
+ iosb_ptr->Status = STATUS_PENDING;
+ status = pNtDeviceIoControlFile((HANDLE) socket,
+ event,
+ NULL,
+ apc_context,
+ iosb_ptr,
+ IOCTL_AFD_POLL,
+ info_in,
+ sizeof *info_in,
+ info_out,
+ sizeof *info_out);
+
+ if (overlapped == NULL) {
+ /* If this is a blocking operation, wait for the event to become */
+ /* signaled, and then grab the real status from the io status block. */
+ if (status == STATUS_PENDING) {
+ DWORD r = WaitForSingleObject(event, INFINITE);
+
+ if (r == WAIT_FAILED) {
+ DWORD saved_error = GetLastError();
+ CloseHandle(event);
+ WSASetLastError(saved_error);
+ return SOCKET_ERROR;
+ }
+
+ status = iosb.Status;
+ }
+
+ CloseHandle(event);
+ }
+
+ switch (status) {
+ case STATUS_SUCCESS:
+ error = ERROR_SUCCESS;
+ break;
+
+ case STATUS_PENDING:
+ error = WSA_IO_PENDING;
+ break;
+
+ default:
+ error = uv_ntstatus_to_winsock_error(status);
+ break;
+ }
+
+ WSASetLastError(error);
+
+ if (error == ERROR_SUCCESS) {
+ return 0;
+ } else {
+ return SOCKET_ERROR;
+ }
+}
diff --git a/3rdparty/libuv/src/win/winsock.h b/3rdparty/libuv/src/win/winsock.h
new file mode 100644
index 00000000000..7c007ab4934
--- /dev/null
+++ b/3rdparty/libuv/src/win/winsock.h
@@ -0,0 +1,190 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_WINSOCK_H_
+#define UV_WIN_WINSOCK_H_
+
+#include <winsock2.h>
+#include <iptypes.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+
+#include "winapi.h"
+
+
+/*
+ * MinGW is missing these too
+ */
+#ifndef SO_UPDATE_CONNECT_CONTEXT
+# define SO_UPDATE_CONNECT_CONTEXT 0x7010
+#endif
+
+#ifndef TCP_KEEPALIVE
+# define TCP_KEEPALIVE 3
+#endif
+
+#ifndef IPV6_V6ONLY
+# define IPV6_V6ONLY 27
+#endif
+
+#ifndef IPV6_HOPLIMIT
+# define IPV6_HOPLIMIT 21
+#endif
+
+#ifndef SIO_BASE_HANDLE
+# define SIO_BASE_HANDLE 0x48000022
+#endif
+
+/*
+ * TDI defines that are only in the DDK.
+ * We only need receive flags so far.
+ */
+#ifndef TDI_RECEIVE_NORMAL
+ #define TDI_RECEIVE_BROADCAST 0x00000004
+ #define TDI_RECEIVE_MULTICAST 0x00000008
+ #define TDI_RECEIVE_PARTIAL 0x00000010
+ #define TDI_RECEIVE_NORMAL 0x00000020
+ #define TDI_RECEIVE_EXPEDITED 0x00000040
+ #define TDI_RECEIVE_PEEK 0x00000080
+ #define TDI_RECEIVE_NO_RESPONSE_EXP 0x00000100
+ #define TDI_RECEIVE_COPY_LOOKAHEAD 0x00000200
+ #define TDI_RECEIVE_ENTIRE_MESSAGE 0x00000400
+ #define TDI_RECEIVE_AT_DISPATCH_LEVEL 0x00000800
+ #define TDI_RECEIVE_CONTROL_INFO 0x00001000
+ #define TDI_RECEIVE_FORCE_INDICATION 0x00002000
+ #define TDI_RECEIVE_NO_PUSH 0x00004000
+#endif
+
+/*
+ * The "Auxiliary Function Driver" is the windows kernel-mode driver that does
+ * TCP, UDP etc. Winsock is just a layer that dispatches requests to it.
+ * Having these definitions allows us to bypass winsock and make an AFD kernel
+ * call directly, avoiding a bug in winsock's recvfrom implementation.
+ */
+
+#define AFD_NO_FAST_IO 0x00000001
+#define AFD_OVERLAPPED 0x00000002
+#define AFD_IMMEDIATE 0x00000004
+
+#define AFD_POLL_RECEIVE_BIT 0
+#define AFD_POLL_RECEIVE (1 << AFD_POLL_RECEIVE_BIT)
+#define AFD_POLL_RECEIVE_EXPEDITED_BIT 1
+#define AFD_POLL_RECEIVE_EXPEDITED (1 << AFD_POLL_RECEIVE_EXPEDITED_BIT)
+#define AFD_POLL_SEND_BIT 2
+#define AFD_POLL_SEND (1 << AFD_POLL_SEND_BIT)
+#define AFD_POLL_DISCONNECT_BIT 3
+#define AFD_POLL_DISCONNECT (1 << AFD_POLL_DISCONNECT_BIT)
+#define AFD_POLL_ABORT_BIT 4
+#define AFD_POLL_ABORT (1 << AFD_POLL_ABORT_BIT)
+#define AFD_POLL_LOCAL_CLOSE_BIT 5
+#define AFD_POLL_LOCAL_CLOSE (1 << AFD_POLL_LOCAL_CLOSE_BIT)
+#define AFD_POLL_CONNECT_BIT 6
+#define AFD_POLL_CONNECT (1 << AFD_POLL_CONNECT_BIT)
+#define AFD_POLL_ACCEPT_BIT 7
+#define AFD_POLL_ACCEPT (1 << AFD_POLL_ACCEPT_BIT)
+#define AFD_POLL_CONNECT_FAIL_BIT 8
+#define AFD_POLL_CONNECT_FAIL (1 << AFD_POLL_CONNECT_FAIL_BIT)
+#define AFD_POLL_QOS_BIT 9
+#define AFD_POLL_QOS (1 << AFD_POLL_QOS_BIT)
+#define AFD_POLL_GROUP_QOS_BIT 10
+#define AFD_POLL_GROUP_QOS (1 << AFD_POLL_GROUP_QOS_BIT)
+
+#define AFD_NUM_POLL_EVENTS 11
+#define AFD_POLL_ALL ((1 << AFD_NUM_POLL_EVENTS) - 1)
+
+typedef struct _AFD_RECV_DATAGRAM_INFO {
+ LPWSABUF BufferArray;
+ ULONG BufferCount;
+ ULONG AfdFlags;
+ ULONG TdiFlags;
+ struct sockaddr* Address;
+ int* AddressLength;
+} AFD_RECV_DATAGRAM_INFO, *PAFD_RECV_DATAGRAM_INFO;
+
+typedef struct _AFD_RECV_INFO {
+ LPWSABUF BufferArray;
+ ULONG BufferCount;
+ ULONG AfdFlags;
+ ULONG TdiFlags;
+} AFD_RECV_INFO, *PAFD_RECV_INFO;
+
+
+#define _AFD_CONTROL_CODE(operation, method) \
+ ((FSCTL_AFD_BASE) << 12 | (operation << 2) | method)
+
+#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK
+
+#define AFD_RECEIVE 5
+#define AFD_RECEIVE_DATAGRAM 6
+#define AFD_POLL 9
+
+#define IOCTL_AFD_RECEIVE \
+ _AFD_CONTROL_CODE(AFD_RECEIVE, METHOD_NEITHER)
+
+#define IOCTL_AFD_RECEIVE_DATAGRAM \
+ _AFD_CONTROL_CODE(AFD_RECEIVE_DATAGRAM, METHOD_NEITHER)
+
+#define IOCTL_AFD_POLL \
+ _AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED)
+
+#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
+typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP {
+ /* FIXME: __C89_NAMELESS was removed */
+ /* __C89_NAMELESS */ union {
+ ULONGLONG Alignment;
+ /* __C89_NAMELESS */ struct {
+ ULONG Length;
+ DWORD Flags;
+ };
+ };
+ struct _IP_ADAPTER_UNICAST_ADDRESS_XP *Next;
+ SOCKET_ADDRESS Address;
+ IP_PREFIX_ORIGIN PrefixOrigin;
+ IP_SUFFIX_ORIGIN SuffixOrigin;
+ IP_DAD_STATE DadState;
+ ULONG ValidLifetime;
+ ULONG PreferredLifetime;
+ ULONG LeaseLifetime;
+} IP_ADAPTER_UNICAST_ADDRESS_XP,*PIP_ADAPTER_UNICAST_ADDRESS_XP;
+
+typedef struct _IP_ADAPTER_UNICAST_ADDRESS_LH {
+ union {
+ ULONGLONG Alignment;
+ struct {
+ ULONG Length;
+ DWORD Flags;
+ };
+ };
+ struct _IP_ADAPTER_UNICAST_ADDRESS_LH *Next;
+ SOCKET_ADDRESS Address;
+ IP_PREFIX_ORIGIN PrefixOrigin;
+ IP_SUFFIX_ORIGIN SuffixOrigin;
+ IP_DAD_STATE DadState;
+ ULONG ValidLifetime;
+ ULONG PreferredLifetime;
+ ULONG LeaseLifetime;
+ UINT8 OnLinkPrefixLength;
+} IP_ADAPTER_UNICAST_ADDRESS_LH,*PIP_ADAPTER_UNICAST_ADDRESS_LH;
+
+#endif
+
+#endif /* UV_WIN_WINSOCK_H_ */
diff --git a/3rdparty/libuv/test/benchmark-async-pummel.c b/3rdparty/libuv/test/benchmark-async-pummel.c
new file mode 100644
index 00000000000..cca3de1062b
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-async-pummel.c
@@ -0,0 +1,119 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define NUM_PINGS (1000 * 1000)
+#define ACCESS_ONCE(type, var) (*(volatile type*) &(var))
+
+static unsigned int callbacks;
+static volatile int done;
+
+static const char running[] = "running";
+static const char stop[] = "stop";
+static const char stopped[] = "stopped";
+
+
+static void async_cb(uv_async_t* handle) {
+ if (++callbacks == NUM_PINGS) {
+ /* Tell the pummel thread to stop. */
+ ACCESS_ONCE(const char*, handle->data) = stop;
+
+ /* Wait for for the pummel thread to acknowledge that it has stoppped. */
+ while (ACCESS_ONCE(const char*, handle->data) != stopped)
+ uv_sleep(0);
+
+ uv_close((uv_handle_t*) handle, NULL);
+ }
+}
+
+
+static void pummel(void* arg) {
+ uv_async_t* handle = (uv_async_t*) arg;
+
+ while (ACCESS_ONCE(const char*, handle->data) == running)
+ uv_async_send(handle);
+
+ /* Acknowledge that we've seen handle->data change. */
+ ACCESS_ONCE(const char*, handle->data) = stopped;
+}
+
+
+static int test_async_pummel(int nthreads) {
+ uv_thread_t* tids;
+ uv_async_t handle;
+ uint64_t time;
+ int i;
+
+ tids = calloc(nthreads, sizeof(tids[0]));
+ ASSERT(tids != NULL);
+
+ ASSERT(0 == uv_async_init(uv_default_loop(), &handle, async_cb));
+ ACCESS_ONCE(const char*, handle.data) = running;
+
+ for (i = 0; i < nthreads; i++)
+ ASSERT(0 == uv_thread_create(tids + i, pummel, &handle));
+
+ time = uv_hrtime();
+
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ time = uv_hrtime() - time;
+ done = 1;
+
+ for (i = 0; i < nthreads; i++)
+ ASSERT(0 == uv_thread_join(tids + i));
+
+ printf("async_pummel_%d: %s callbacks in %.2f seconds (%s/sec)\n",
+ nthreads,
+ fmt(callbacks),
+ time / 1e9,
+ fmt(callbacks / (time / 1e9)));
+
+ free(tids);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+BENCHMARK_IMPL(async_pummel_1) {
+ return test_async_pummel(1);
+}
+
+
+BENCHMARK_IMPL(async_pummel_2) {
+ return test_async_pummel(2);
+}
+
+
+BENCHMARK_IMPL(async_pummel_4) {
+ return test_async_pummel(4);
+}
+
+
+BENCHMARK_IMPL(async_pummel_8) {
+ return test_async_pummel(8);
+}
diff --git a/3rdparty/libuv/test/benchmark-async.c b/3rdparty/libuv/test/benchmark-async.c
new file mode 100644
index 00000000000..e44165f2b81
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-async.c
@@ -0,0 +1,141 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define NUM_PINGS (1000 * 1000)
+
+struct ctx {
+ uv_loop_t loop;
+ uv_thread_t thread;
+ uv_async_t main_async; /* wake up main thread */
+ uv_async_t worker_async; /* wake up worker */
+ unsigned int nthreads;
+ unsigned int main_sent;
+ unsigned int main_seen;
+ unsigned int worker_sent;
+ unsigned int worker_seen;
+};
+
+
+static void worker_async_cb(uv_async_t* handle) {
+ struct ctx* ctx = container_of(handle, struct ctx, worker_async);
+
+ ASSERT(0 == uv_async_send(&ctx->main_async));
+ ctx->worker_sent++;
+ ctx->worker_seen++;
+
+ if (ctx->worker_sent >= NUM_PINGS)
+ uv_close((uv_handle_t*) &ctx->worker_async, NULL);
+}
+
+
+static void main_async_cb(uv_async_t* handle) {
+ struct ctx* ctx = container_of(handle, struct ctx, main_async);
+
+ ASSERT(0 == uv_async_send(&ctx->worker_async));
+ ctx->main_sent++;
+ ctx->main_seen++;
+
+ if (ctx->main_sent >= NUM_PINGS)
+ uv_close((uv_handle_t*) &ctx->main_async, NULL);
+}
+
+
+static void worker(void* arg) {
+ struct ctx* ctx = arg;
+ ASSERT(0 == uv_async_send(&ctx->main_async));
+ ASSERT(0 == uv_run(&ctx->loop, UV_RUN_DEFAULT));
+ uv_loop_close(&ctx->loop);
+}
+
+
+static int test_async(int nthreads) {
+ struct ctx* threads;
+ struct ctx* ctx;
+ uint64_t time;
+ int i;
+
+ threads = calloc(nthreads, sizeof(threads[0]));
+ ASSERT(threads != NULL);
+
+ for (i = 0; i < nthreads; i++) {
+ ctx = threads + i;
+ ctx->nthreads = nthreads;
+ ASSERT(0 == uv_loop_init(&ctx->loop));
+ ASSERT(0 == uv_async_init(&ctx->loop, &ctx->worker_async, worker_async_cb));
+ ASSERT(0 == uv_async_init(uv_default_loop(),
+ &ctx->main_async,
+ main_async_cb));
+ ASSERT(0 == uv_thread_create(&ctx->thread, worker, ctx));
+ }
+
+ time = uv_hrtime();
+
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ for (i = 0; i < nthreads; i++)
+ ASSERT(0 == uv_thread_join(&threads[i].thread));
+
+ time = uv_hrtime() - time;
+
+ for (i = 0; i < nthreads; i++) {
+ ctx = threads + i;
+ ASSERT(ctx->worker_sent == NUM_PINGS);
+ ASSERT(ctx->worker_seen == NUM_PINGS);
+ ASSERT(ctx->main_sent == (unsigned int) NUM_PINGS);
+ ASSERT(ctx->main_seen == (unsigned int) NUM_PINGS);
+ }
+
+ printf("async%d: %.2f sec (%s/sec)\n",
+ nthreads,
+ time / 1e9,
+ fmt(NUM_PINGS / (time / 1e9)));
+
+ free(threads);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+BENCHMARK_IMPL(async1) {
+ return test_async(1);
+}
+
+
+BENCHMARK_IMPL(async2) {
+ return test_async(2);
+}
+
+
+BENCHMARK_IMPL(async4) {
+ return test_async(4);
+}
+
+
+BENCHMARK_IMPL(async8) {
+ return test_async(8);
+}
diff --git a/3rdparty/libuv/test/benchmark-fs-stat.c b/3rdparty/libuv/test/benchmark-fs-stat.c
new file mode 100644
index 00000000000..32d2589586c
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-fs-stat.c
@@ -0,0 +1,136 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define NUM_SYNC_REQS (10 * 1e5)
+#define NUM_ASYNC_REQS (1 * (int) 1e5)
+#define MAX_CONCURRENT_REQS 32
+
+#define sync_stat(req, path) \
+ do { \
+ uv_fs_stat(NULL, (req), (path), NULL); \
+ uv_fs_req_cleanup((req)); \
+ } \
+ while (0)
+
+struct async_req {
+ const char* path;
+ uv_fs_t fs_req;
+ int* count;
+};
+
+
+static void warmup(const char* path) {
+ uv_fs_t reqs[MAX_CONCURRENT_REQS];
+ unsigned int i;
+
+ /* warm up the thread pool */
+ for (i = 0; i < ARRAY_SIZE(reqs); i++)
+ uv_fs_stat(uv_default_loop(), reqs + i, path, uv_fs_req_cleanup);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ /* warm up the OS dirent cache */
+ for (i = 0; i < 16; i++)
+ sync_stat(reqs + 0, path);
+}
+
+
+static void sync_bench(const char* path) {
+ uint64_t before;
+ uint64_t after;
+ uv_fs_t req;
+ int i;
+
+ /* do the sync benchmark */
+ before = uv_hrtime();
+
+ for (i = 0; i < NUM_SYNC_REQS; i++)
+ sync_stat(&req, path);
+
+ after = uv_hrtime();
+
+ printf("%s stats (sync): %.2fs (%s/s)\n",
+ fmt(1.0 * NUM_SYNC_REQS),
+ (after - before) / 1e9,
+ fmt((1.0 * NUM_SYNC_REQS) / ((after - before) / 1e9)));
+ fflush(stdout);
+}
+
+
+static void stat_cb(uv_fs_t* fs_req) {
+ struct async_req* req = container_of(fs_req, struct async_req, fs_req);
+ uv_fs_req_cleanup(&req->fs_req);
+ if (*req->count == 0) return;
+ uv_fs_stat(uv_default_loop(), &req->fs_req, req->path, stat_cb);
+ (*req->count)--;
+}
+
+
+static void async_bench(const char* path) {
+ struct async_req reqs[MAX_CONCURRENT_REQS];
+ struct async_req* req;
+ uint64_t before;
+ uint64_t after;
+ int count;
+ int i;
+
+ for (i = 1; i <= MAX_CONCURRENT_REQS; i++) {
+ count = NUM_ASYNC_REQS;
+
+ for (req = reqs; req < reqs + i; req++) {
+ req->path = path;
+ req->count = &count;
+ uv_fs_stat(uv_default_loop(), &req->fs_req, req->path, stat_cb);
+ }
+
+ before = uv_hrtime();
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ after = uv_hrtime();
+
+ printf("%s stats (%d concurrent): %.2fs (%s/s)\n",
+ fmt(1.0 * NUM_ASYNC_REQS),
+ i,
+ (after - before) / 1e9,
+ fmt((1.0 * NUM_ASYNC_REQS) / ((after - before) / 1e9)));
+ fflush(stdout);
+ }
+}
+
+
+/* This benchmark aims to measure the overhead of doing I/O syscalls from
+ * the thread pool. The stat() syscall was chosen because its results are
+ * easy for the operating system to cache, taking the actual I/O overhead
+ * out of the equation.
+ */
+BENCHMARK_IMPL(fs_stat) {
+ const char path[] = ".";
+ warmup(path);
+ sync_bench(path);
+ async_bench(path);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-getaddrinfo.c b/3rdparty/libuv/test/benchmark-getaddrinfo.c
new file mode 100644
index 00000000000..1dbc23ddba0
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-getaddrinfo.c
@@ -0,0 +1,92 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdlib.h>
+
+#define CONCURRENT_CALLS 10
+#define TOTAL_CALLS 10000
+
+static const char* name = "localhost";
+
+static uv_loop_t* loop;
+
+static uv_getaddrinfo_t handles[CONCURRENT_CALLS];
+
+static int calls_initiated = 0;
+static int calls_completed = 0;
+static int64_t start_time;
+static int64_t end_time;
+
+
+static void getaddrinfo_initiate(uv_getaddrinfo_t* handle);
+
+
+static void getaddrinfo_cb(uv_getaddrinfo_t* handle, int status,
+ struct addrinfo* res) {
+ ASSERT(status == 0);
+ calls_completed++;
+ if (calls_initiated < TOTAL_CALLS) {
+ getaddrinfo_initiate(handle);
+ }
+
+ uv_freeaddrinfo(res);
+}
+
+
+static void getaddrinfo_initiate(uv_getaddrinfo_t* handle) {
+ int r;
+
+ calls_initiated++;
+
+ r = uv_getaddrinfo(loop, handle, &getaddrinfo_cb, name, NULL, NULL);
+ ASSERT(r == 0);
+}
+
+
+BENCHMARK_IMPL(getaddrinfo) {
+ int i;
+
+ loop = uv_default_loop();
+
+ uv_update_time(loop);
+ start_time = uv_now(loop);
+
+ for (i = 0; i < CONCURRENT_CALLS; i++) {
+ getaddrinfo_initiate(&handles[i]);
+ }
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ uv_update_time(loop);
+ end_time = uv_now(loop);
+
+ ASSERT(calls_initiated == TOTAL_CALLS);
+ ASSERT(calls_completed == TOTAL_CALLS);
+
+ fprintf(stderr, "getaddrinfo: %.0f req/s\n",
+ (double) calls_completed / (double) (end_time - start_time) * 1000.0);
+ fflush(stderr);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-list.h b/3rdparty/libuv/test/benchmark-list.h
new file mode 100644
index 00000000000..1e843071c01
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-list.h
@@ -0,0 +1,163 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+BENCHMARK_DECLARE (sizes)
+BENCHMARK_DECLARE (loop_count)
+BENCHMARK_DECLARE (loop_count_timed)
+BENCHMARK_DECLARE (ping_pongs)
+BENCHMARK_DECLARE (tcp_write_batch)
+BENCHMARK_DECLARE (tcp4_pound_100)
+BENCHMARK_DECLARE (tcp4_pound_1000)
+BENCHMARK_DECLARE (pipe_pound_100)
+BENCHMARK_DECLARE (pipe_pound_1000)
+BENCHMARK_DECLARE (tcp_pump100_client)
+BENCHMARK_DECLARE (tcp_pump1_client)
+BENCHMARK_DECLARE (pipe_pump100_client)
+BENCHMARK_DECLARE (pipe_pump1_client)
+
+BENCHMARK_DECLARE (tcp_multi_accept2)
+BENCHMARK_DECLARE (tcp_multi_accept4)
+BENCHMARK_DECLARE (tcp_multi_accept8)
+
+/* Run until X packets have been sent/received. */
+BENCHMARK_DECLARE (udp_pummel_1v1)
+BENCHMARK_DECLARE (udp_pummel_1v10)
+BENCHMARK_DECLARE (udp_pummel_1v100)
+BENCHMARK_DECLARE (udp_pummel_1v1000)
+BENCHMARK_DECLARE (udp_pummel_10v10)
+BENCHMARK_DECLARE (udp_pummel_10v100)
+BENCHMARK_DECLARE (udp_pummel_10v1000)
+BENCHMARK_DECLARE (udp_pummel_100v100)
+BENCHMARK_DECLARE (udp_pummel_100v1000)
+BENCHMARK_DECLARE (udp_pummel_1000v1000)
+
+/* Run until X seconds have elapsed. */
+BENCHMARK_DECLARE (udp_timed_pummel_1v1)
+BENCHMARK_DECLARE (udp_timed_pummel_1v10)
+BENCHMARK_DECLARE (udp_timed_pummel_1v100)
+BENCHMARK_DECLARE (udp_timed_pummel_1v1000)
+BENCHMARK_DECLARE (udp_timed_pummel_10v10)
+BENCHMARK_DECLARE (udp_timed_pummel_10v100)
+BENCHMARK_DECLARE (udp_timed_pummel_10v1000)
+BENCHMARK_DECLARE (udp_timed_pummel_100v100)
+BENCHMARK_DECLARE (udp_timed_pummel_100v1000)
+BENCHMARK_DECLARE (udp_timed_pummel_1000v1000)
+
+BENCHMARK_DECLARE (getaddrinfo)
+BENCHMARK_DECLARE (fs_stat)
+BENCHMARK_DECLARE (async1)
+BENCHMARK_DECLARE (async2)
+BENCHMARK_DECLARE (async4)
+BENCHMARK_DECLARE (async8)
+BENCHMARK_DECLARE (async_pummel_1)
+BENCHMARK_DECLARE (async_pummel_2)
+BENCHMARK_DECLARE (async_pummel_4)
+BENCHMARK_DECLARE (async_pummel_8)
+BENCHMARK_DECLARE (spawn)
+BENCHMARK_DECLARE (thread_create)
+BENCHMARK_DECLARE (million_async)
+BENCHMARK_DECLARE (million_timers)
+HELPER_DECLARE (tcp4_blackhole_server)
+HELPER_DECLARE (tcp_pump_server)
+HELPER_DECLARE (pipe_pump_server)
+HELPER_DECLARE (tcp4_echo_server)
+HELPER_DECLARE (pipe_echo_server)
+HELPER_DECLARE (dns_server)
+
+TASK_LIST_START
+ BENCHMARK_ENTRY (sizes)
+ BENCHMARK_ENTRY (loop_count)
+ BENCHMARK_ENTRY (loop_count_timed)
+
+ BENCHMARK_ENTRY (ping_pongs)
+ BENCHMARK_HELPER (ping_pongs, tcp4_echo_server)
+
+ BENCHMARK_ENTRY (tcp_write_batch)
+ BENCHMARK_HELPER (tcp_write_batch, tcp4_blackhole_server)
+
+ BENCHMARK_ENTRY (tcp_pump100_client)
+ BENCHMARK_HELPER (tcp_pump100_client, tcp_pump_server)
+
+ BENCHMARK_ENTRY (tcp_pump1_client)
+ BENCHMARK_HELPER (tcp_pump1_client, tcp_pump_server)
+
+ BENCHMARK_ENTRY (tcp4_pound_100)
+ BENCHMARK_HELPER (tcp4_pound_100, tcp4_echo_server)
+
+ BENCHMARK_ENTRY (tcp4_pound_1000)
+ BENCHMARK_HELPER (tcp4_pound_1000, tcp4_echo_server)
+
+ BENCHMARK_ENTRY (pipe_pump100_client)
+ BENCHMARK_HELPER (pipe_pump100_client, pipe_pump_server)
+
+ BENCHMARK_ENTRY (pipe_pump1_client)
+ BENCHMARK_HELPER (pipe_pump1_client, pipe_pump_server)
+
+ BENCHMARK_ENTRY (pipe_pound_100)
+ BENCHMARK_HELPER (pipe_pound_100, pipe_echo_server)
+
+ BENCHMARK_ENTRY (pipe_pound_1000)
+ BENCHMARK_HELPER (pipe_pound_1000, pipe_echo_server)
+
+ BENCHMARK_ENTRY (tcp_multi_accept2)
+ BENCHMARK_ENTRY (tcp_multi_accept4)
+ BENCHMARK_ENTRY (tcp_multi_accept8)
+
+ BENCHMARK_ENTRY (udp_pummel_1v1)
+ BENCHMARK_ENTRY (udp_pummel_1v10)
+ BENCHMARK_ENTRY (udp_pummel_1v100)
+ BENCHMARK_ENTRY (udp_pummel_1v1000)
+ BENCHMARK_ENTRY (udp_pummel_10v10)
+ BENCHMARK_ENTRY (udp_pummel_10v100)
+ BENCHMARK_ENTRY (udp_pummel_10v1000)
+ BENCHMARK_ENTRY (udp_pummel_100v100)
+ BENCHMARK_ENTRY (udp_pummel_100v1000)
+ BENCHMARK_ENTRY (udp_pummel_1000v1000)
+
+ BENCHMARK_ENTRY (udp_timed_pummel_1v1)
+ BENCHMARK_ENTRY (udp_timed_pummel_1v10)
+ BENCHMARK_ENTRY (udp_timed_pummel_1v100)
+ BENCHMARK_ENTRY (udp_timed_pummel_1v1000)
+ BENCHMARK_ENTRY (udp_timed_pummel_10v10)
+ BENCHMARK_ENTRY (udp_timed_pummel_10v100)
+ BENCHMARK_ENTRY (udp_timed_pummel_10v1000)
+ BENCHMARK_ENTRY (udp_timed_pummel_100v100)
+ BENCHMARK_ENTRY (udp_timed_pummel_100v1000)
+ BENCHMARK_ENTRY (udp_timed_pummel_1000v1000)
+
+ BENCHMARK_ENTRY (getaddrinfo)
+
+ BENCHMARK_ENTRY (fs_stat)
+
+ BENCHMARK_ENTRY (async1)
+ BENCHMARK_ENTRY (async2)
+ BENCHMARK_ENTRY (async4)
+ BENCHMARK_ENTRY (async8)
+ BENCHMARK_ENTRY (async_pummel_1)
+ BENCHMARK_ENTRY (async_pummel_2)
+ BENCHMARK_ENTRY (async_pummel_4)
+ BENCHMARK_ENTRY (async_pummel_8)
+
+ BENCHMARK_ENTRY (spawn)
+ BENCHMARK_ENTRY (thread_create)
+ BENCHMARK_ENTRY (million_async)
+ BENCHMARK_ENTRY (million_timers)
+TASK_LIST_END
diff --git a/3rdparty/libuv/test/benchmark-loop-count.c b/3rdparty/libuv/test/benchmark-loop-count.c
new file mode 100644
index 00000000000..970a94c2fec
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-loop-count.c
@@ -0,0 +1,92 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define NUM_TICKS (2 * 1000 * 1000)
+
+static unsigned long ticks;
+static uv_idle_t idle_handle;
+static uv_timer_t timer_handle;
+
+
+static void idle_cb(uv_idle_t* handle) {
+ if (++ticks == NUM_TICKS)
+ uv_idle_stop(handle);
+}
+
+
+static void idle2_cb(uv_idle_t* handle) {
+ ticks++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ uv_idle_stop(&idle_handle);
+ uv_timer_stop(&timer_handle);
+}
+
+
+BENCHMARK_IMPL(loop_count) {
+ uv_loop_t* loop = uv_default_loop();
+ uint64_t ns;
+
+ uv_idle_init(loop, &idle_handle);
+ uv_idle_start(&idle_handle, idle_cb);
+
+ ns = uv_hrtime();
+ uv_run(loop, UV_RUN_DEFAULT);
+ ns = uv_hrtime() - ns;
+
+ ASSERT(ticks == NUM_TICKS);
+
+ fprintf(stderr, "loop_count: %d ticks in %.2fs (%.0f/s)\n",
+ NUM_TICKS,
+ ns / 1e9,
+ NUM_TICKS / (ns / 1e9));
+ fflush(stderr);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+BENCHMARK_IMPL(loop_count_timed) {
+ uv_loop_t* loop = uv_default_loop();
+
+ uv_idle_init(loop, &idle_handle);
+ uv_idle_start(&idle_handle, idle2_cb);
+
+ uv_timer_init(loop, &timer_handle);
+ uv_timer_start(&timer_handle, timer_cb, 5000, 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ fprintf(stderr, "loop_count: %lu ticks (%.0f ticks/s)\n", ticks, ticks / 5.0);
+ fflush(stderr);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-million-async.c b/3rdparty/libuv/test/benchmark-million-async.c
new file mode 100644
index 00000000000..5395ed54bab
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-million-async.c
@@ -0,0 +1,112 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+struct async_container {
+ unsigned async_events;
+ unsigned handles_seen;
+ uv_async_t async_handles[1024 * 1024];
+};
+
+static volatile int done;
+static uv_thread_t thread_id;
+static struct async_container* container;
+
+
+static unsigned fastrand(void) {
+ static unsigned g = 0;
+ g = g * 214013 + 2531011;
+ return g;
+}
+
+
+static void thread_cb(void* arg) {
+ unsigned i;
+
+ while (done == 0) {
+ i = fastrand() % ARRAY_SIZE(container->async_handles);
+ uv_async_send(container->async_handles + i);
+ }
+}
+
+
+static void async_cb(uv_async_t* handle) {
+ container->async_events++;
+ handle->data = handle;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ unsigned i;
+
+ done = 1;
+ ASSERT(0 == uv_thread_join(&thread_id));
+
+ for (i = 0; i < ARRAY_SIZE(container->async_handles); i++) {
+ uv_async_t* handle = container->async_handles + i;
+
+ if (handle->data != NULL)
+ container->handles_seen++;
+
+ uv_close((uv_handle_t*) handle, NULL);
+ }
+
+ uv_close((uv_handle_t*) handle, NULL);
+}
+
+
+BENCHMARK_IMPL(million_async) {
+ uv_timer_t timer_handle;
+ uv_async_t* handle;
+ uv_loop_t* loop;
+ int timeout;
+ unsigned i;
+
+ loop = uv_default_loop();
+ timeout = 5000;
+
+ container = malloc(sizeof(*container));
+ ASSERT(container != NULL);
+ container->async_events = 0;
+ container->handles_seen = 0;
+
+ for (i = 0; i < ARRAY_SIZE(container->async_handles); i++) {
+ handle = container->async_handles + i;
+ ASSERT(0 == uv_async_init(loop, handle, async_cb));
+ handle->data = NULL;
+ }
+
+ ASSERT(0 == uv_timer_init(loop, &timer_handle));
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, timeout, 0));
+ ASSERT(0 == uv_thread_create(&thread_id, thread_cb, NULL));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ printf("%s async events in %.1f seconds (%s/s, %s unique handles seen)\n",
+ fmt(container->async_events),
+ timeout / 1000.,
+ fmt(container->async_events / (timeout / 1000.)),
+ fmt(container->handles_seen));
+ free(container);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-million-timers.c b/3rdparty/libuv/test/benchmark-million-timers.c
new file mode 100644
index 00000000000..60a308bef13
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-million-timers.c
@@ -0,0 +1,86 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+#define NUM_TIMERS (10 * 1000 * 1000)
+
+static int timer_cb_called;
+static int close_cb_called;
+
+
+static void timer_cb(uv_timer_t* handle) {
+ timer_cb_called++;
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+BENCHMARK_IMPL(million_timers) {
+ uv_timer_t* timers;
+ uv_loop_t* loop;
+ uint64_t before_all;
+ uint64_t before_run;
+ uint64_t after_run;
+ uint64_t after_all;
+ int timeout;
+ int i;
+
+ timers = malloc(NUM_TIMERS * sizeof(timers[0]));
+ ASSERT(timers != NULL);
+
+ loop = uv_default_loop();
+ timeout = 0;
+
+ before_all = uv_hrtime();
+ for (i = 0; i < NUM_TIMERS; i++) {
+ if (i % 1000 == 0) timeout++;
+ ASSERT(0 == uv_timer_init(loop, timers + i));
+ ASSERT(0 == uv_timer_start(timers + i, timer_cb, timeout, 0));
+ }
+
+ before_run = uv_hrtime();
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ after_run = uv_hrtime();
+
+ for (i = 0; i < NUM_TIMERS; i++)
+ uv_close((uv_handle_t*) (timers + i), close_cb);
+
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ after_all = uv_hrtime();
+
+ ASSERT(timer_cb_called == NUM_TIMERS);
+ ASSERT(close_cb_called == NUM_TIMERS);
+ free(timers);
+
+ fprintf(stderr, "%.2f seconds total\n", (after_all - before_all) / 1e9);
+ fprintf(stderr, "%.2f seconds init\n", (before_run - before_all) / 1e9);
+ fprintf(stderr, "%.2f seconds dispatch\n", (after_run - before_run) / 1e9);
+ fprintf(stderr, "%.2f seconds cleanup\n", (after_all - after_run) / 1e9);
+ fflush(stderr);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-multi-accept.c b/3rdparty/libuv/test/benchmark-multi-accept.c
new file mode 100644
index 00000000000..2f32c0caf4a
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-multi-accept.c
@@ -0,0 +1,447 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+#define IPC_PIPE_NAME TEST_PIPENAME
+#define NUM_CONNECTS (250 * 1000)
+
+union stream_handle {
+ uv_pipe_t pipe;
+ uv_tcp_t tcp;
+};
+
+/* Use as (uv_stream_t *) &handle_storage -- it's kind of clunky but it
+ * avoids aliasing warnings.
+ */
+typedef unsigned char handle_storage_t[sizeof(union stream_handle)];
+
+/* Used for passing around the listen handle, not part of the benchmark proper.
+ * We have an overabundance of server types here. It works like this:
+ *
+ * 1. The main thread starts an IPC pipe server.
+ * 2. The worker threads connect to the IPC server and obtain a listen handle.
+ * 3. The worker threads start accepting requests on the listen handle.
+ * 4. The main thread starts connecting repeatedly.
+ *
+ * Step #4 should perhaps be farmed out over several threads.
+ */
+struct ipc_server_ctx {
+ handle_storage_t server_handle;
+ unsigned int num_connects;
+ uv_pipe_t ipc_pipe;
+};
+
+struct ipc_peer_ctx {
+ handle_storage_t peer_handle;
+ uv_write_t write_req;
+};
+
+struct ipc_client_ctx {
+ uv_connect_t connect_req;
+ uv_stream_t* server_handle;
+ uv_pipe_t ipc_pipe;
+ char scratch[16];
+};
+
+/* Used in the actual benchmark. */
+struct server_ctx {
+ handle_storage_t server_handle;
+ unsigned int num_connects;
+ uv_async_t async_handle;
+ uv_thread_t thread_id;
+ uv_sem_t semaphore;
+};
+
+struct client_ctx {
+ handle_storage_t client_handle;
+ unsigned int num_connects;
+ uv_connect_t connect_req;
+ uv_idle_t idle_handle;
+};
+
+static void ipc_connection_cb(uv_stream_t* ipc_pipe, int status);
+static void ipc_write_cb(uv_write_t* req, int status);
+static void ipc_close_cb(uv_handle_t* handle);
+static void ipc_connect_cb(uv_connect_t* req, int status);
+static void ipc_read_cb(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf);
+static void ipc_alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf);
+
+static void sv_async_cb(uv_async_t* handle);
+static void sv_connection_cb(uv_stream_t* server_handle, int status);
+static void sv_read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf);
+static void sv_alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf);
+
+static void cl_connect_cb(uv_connect_t* req, int status);
+static void cl_idle_cb(uv_idle_t* handle);
+static void cl_close_cb(uv_handle_t* handle);
+
+static struct sockaddr_in listen_addr;
+
+
+static void ipc_connection_cb(uv_stream_t* ipc_pipe, int status) {
+ struct ipc_server_ctx* sc;
+ struct ipc_peer_ctx* pc;
+ uv_loop_t* loop;
+ uv_buf_t buf;
+
+ loop = ipc_pipe->loop;
+ buf = uv_buf_init("PING", 4);
+ sc = container_of(ipc_pipe, struct ipc_server_ctx, ipc_pipe);
+ pc = calloc(1, sizeof(*pc));
+ ASSERT(pc != NULL);
+
+ if (ipc_pipe->type == UV_TCP)
+ ASSERT(0 == uv_tcp_init(loop, (uv_tcp_t*) &pc->peer_handle));
+ else if (ipc_pipe->type == UV_NAMED_PIPE)
+ ASSERT(0 == uv_pipe_init(loop, (uv_pipe_t*) &pc->peer_handle, 1));
+ else
+ ASSERT(0);
+
+ ASSERT(0 == uv_accept(ipc_pipe, (uv_stream_t*) &pc->peer_handle));
+ ASSERT(0 == uv_write2(&pc->write_req,
+ (uv_stream_t*) &pc->peer_handle,
+ &buf,
+ 1,
+ (uv_stream_t*) &sc->server_handle,
+ ipc_write_cb));
+
+ if (--sc->num_connects == 0)
+ uv_close((uv_handle_t*) ipc_pipe, NULL);
+}
+
+
+static void ipc_write_cb(uv_write_t* req, int status) {
+ struct ipc_peer_ctx* ctx;
+ ctx = container_of(req, struct ipc_peer_ctx, write_req);
+ uv_close((uv_handle_t*) &ctx->peer_handle, ipc_close_cb);
+}
+
+
+static void ipc_close_cb(uv_handle_t* handle) {
+ struct ipc_peer_ctx* ctx;
+ ctx = container_of(handle, struct ipc_peer_ctx, peer_handle);
+ free(ctx);
+}
+
+
+static void ipc_connect_cb(uv_connect_t* req, int status) {
+ struct ipc_client_ctx* ctx;
+ ctx = container_of(req, struct ipc_client_ctx, connect_req);
+ ASSERT(0 == status);
+ ASSERT(0 == uv_read_start((uv_stream_t*) &ctx->ipc_pipe,
+ ipc_alloc_cb,
+ ipc_read_cb));
+}
+
+
+static void ipc_alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ struct ipc_client_ctx* ctx;
+ ctx = container_of(handle, struct ipc_client_ctx, ipc_pipe);
+ buf->base = ctx->scratch;
+ buf->len = sizeof(ctx->scratch);
+}
+
+
+static void ipc_read_cb(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ struct ipc_client_ctx* ctx;
+ uv_loop_t* loop;
+ uv_handle_type type;
+ uv_pipe_t* ipc_pipe;
+
+ ipc_pipe = (uv_pipe_t*) handle;
+ ctx = container_of(ipc_pipe, struct ipc_client_ctx, ipc_pipe);
+ loop = ipc_pipe->loop;
+
+ ASSERT(1 == uv_pipe_pending_count(ipc_pipe));
+ type = uv_pipe_pending_type(ipc_pipe);
+ if (type == UV_TCP)
+ ASSERT(0 == uv_tcp_init(loop, (uv_tcp_t*) ctx->server_handle));
+ else if (type == UV_NAMED_PIPE)
+ ASSERT(0 == uv_pipe_init(loop, (uv_pipe_t*) ctx->server_handle, 0));
+ else
+ ASSERT(0);
+
+ ASSERT(0 == uv_accept(handle, ctx->server_handle));
+ uv_close((uv_handle_t*) &ctx->ipc_pipe, NULL);
+}
+
+
+/* Set up an IPC pipe server that hands out listen sockets to the worker
+ * threads. It's kind of cumbersome for such a simple operation, maybe we
+ * should revive uv_import() and uv_export().
+ */
+static void send_listen_handles(uv_handle_type type,
+ unsigned int num_servers,
+ struct server_ctx* servers) {
+ struct ipc_server_ctx ctx;
+ uv_loop_t* loop;
+ unsigned int i;
+
+ loop = uv_default_loop();
+ ctx.num_connects = num_servers;
+
+ if (type == UV_TCP) {
+ ASSERT(0 == uv_tcp_init(loop, (uv_tcp_t*) &ctx.server_handle));
+ ASSERT(0 == uv_tcp_bind((uv_tcp_t*) &ctx.server_handle,
+ (const struct sockaddr*) &listen_addr,
+ 0));
+ }
+ else
+ ASSERT(0);
+
+ ASSERT(0 == uv_pipe_init(loop, &ctx.ipc_pipe, 1));
+ ASSERT(0 == uv_pipe_bind(&ctx.ipc_pipe, IPC_PIPE_NAME));
+ ASSERT(0 == uv_listen((uv_stream_t*) &ctx.ipc_pipe, 128, ipc_connection_cb));
+
+ for (i = 0; i < num_servers; i++)
+ uv_sem_post(&servers[i].semaphore);
+
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ uv_close((uv_handle_t*) &ctx.server_handle, NULL);
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ for (i = 0; i < num_servers; i++)
+ uv_sem_wait(&servers[i].semaphore);
+}
+
+
+static void get_listen_handle(uv_loop_t* loop, uv_stream_t* server_handle) {
+ struct ipc_client_ctx ctx;
+
+ ctx.server_handle = server_handle;
+ ctx.server_handle->data = "server handle";
+
+ ASSERT(0 == uv_pipe_init(loop, &ctx.ipc_pipe, 1));
+ uv_pipe_connect(&ctx.connect_req,
+ &ctx.ipc_pipe,
+ IPC_PIPE_NAME,
+ ipc_connect_cb);
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+}
+
+
+static void server_cb(void *arg) {
+ struct server_ctx *ctx;
+ uv_loop_t loop;
+
+ ctx = arg;
+ ASSERT(0 == uv_loop_init(&loop));
+
+ ASSERT(0 == uv_async_init(&loop, &ctx->async_handle, sv_async_cb));
+ uv_unref((uv_handle_t*) &ctx->async_handle);
+
+ /* Wait until the main thread is ready. */
+ uv_sem_wait(&ctx->semaphore);
+ get_listen_handle(&loop, (uv_stream_t*) &ctx->server_handle);
+ uv_sem_post(&ctx->semaphore);
+
+ /* Now start the actual benchmark. */
+ ASSERT(0 == uv_listen((uv_stream_t*) &ctx->server_handle,
+ 128,
+ sv_connection_cb));
+ ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT));
+
+ uv_loop_close(&loop);
+}
+
+
+static void sv_async_cb(uv_async_t* handle) {
+ struct server_ctx* ctx;
+ ctx = container_of(handle, struct server_ctx, async_handle);
+ uv_close((uv_handle_t*) &ctx->server_handle, NULL);
+ uv_close((uv_handle_t*) &ctx->async_handle, NULL);
+}
+
+
+static void sv_connection_cb(uv_stream_t* server_handle, int status) {
+ handle_storage_t* storage;
+ struct server_ctx* ctx;
+
+ ctx = container_of(server_handle, struct server_ctx, server_handle);
+ ASSERT(status == 0);
+
+ storage = malloc(sizeof(*storage));
+ ASSERT(storage != NULL);
+
+ if (server_handle->type == UV_TCP)
+ ASSERT(0 == uv_tcp_init(server_handle->loop, (uv_tcp_t*) storage));
+ else if (server_handle->type == UV_NAMED_PIPE)
+ ASSERT(0 == uv_pipe_init(server_handle->loop, (uv_pipe_t*) storage, 0));
+ else
+ ASSERT(0);
+
+ ASSERT(0 == uv_accept(server_handle, (uv_stream_t*) storage));
+ ASSERT(0 == uv_read_start((uv_stream_t*) storage, sv_alloc_cb, sv_read_cb));
+ ctx->num_connects++;
+}
+
+
+static void sv_alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[32];
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void sv_read_cb(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ ASSERT(nread == UV_EOF);
+ uv_close((uv_handle_t*) handle, (uv_close_cb) free);
+}
+
+
+static void cl_connect_cb(uv_connect_t* req, int status) {
+ struct client_ctx* ctx = container_of(req, struct client_ctx, connect_req);
+ uv_idle_start(&ctx->idle_handle, cl_idle_cb);
+ ASSERT(0 == status);
+}
+
+
+static void cl_idle_cb(uv_idle_t* handle) {
+ struct client_ctx* ctx = container_of(handle, struct client_ctx, idle_handle);
+ uv_close((uv_handle_t*) &ctx->client_handle, cl_close_cb);
+ uv_idle_stop(&ctx->idle_handle);
+}
+
+
+static void cl_close_cb(uv_handle_t* handle) {
+ struct client_ctx* ctx;
+
+ ctx = container_of(handle, struct client_ctx, client_handle);
+
+ if (--ctx->num_connects == 0) {
+ uv_close((uv_handle_t*) &ctx->idle_handle, NULL);
+ return;
+ }
+
+ ASSERT(0 == uv_tcp_init(handle->loop, (uv_tcp_t*) &ctx->client_handle));
+ ASSERT(0 == uv_tcp_connect(&ctx->connect_req,
+ (uv_tcp_t*) &ctx->client_handle,
+ (const struct sockaddr*) &listen_addr,
+ cl_connect_cb));
+}
+
+
+static int test_tcp(unsigned int num_servers, unsigned int num_clients) {
+ struct server_ctx* servers;
+ struct client_ctx* clients;
+ uv_loop_t* loop;
+ uv_tcp_t* handle;
+ unsigned int i;
+ double time;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &listen_addr));
+ loop = uv_default_loop();
+
+ servers = calloc(num_servers, sizeof(servers[0]));
+ clients = calloc(num_clients, sizeof(clients[0]));
+ ASSERT(servers != NULL);
+ ASSERT(clients != NULL);
+
+ /* We're making the assumption here that from the perspective of the
+ * OS scheduler, threads are functionally equivalent to and interchangeable
+ * with full-blown processes.
+ */
+ for (i = 0; i < num_servers; i++) {
+ struct server_ctx* ctx = servers + i;
+ ASSERT(0 == uv_sem_init(&ctx->semaphore, 0));
+ ASSERT(0 == uv_thread_create(&ctx->thread_id, server_cb, ctx));
+ }
+
+ send_listen_handles(UV_TCP, num_servers, servers);
+
+ for (i = 0; i < num_clients; i++) {
+ struct client_ctx* ctx = clients + i;
+ ctx->num_connects = NUM_CONNECTS / num_clients;
+ handle = (uv_tcp_t*) &ctx->client_handle;
+ handle->data = "client handle";
+ ASSERT(0 == uv_tcp_init(loop, handle));
+ ASSERT(0 == uv_tcp_connect(&ctx->connect_req,
+ handle,
+ (const struct sockaddr*) &listen_addr,
+ cl_connect_cb));
+ ASSERT(0 == uv_idle_init(loop, &ctx->idle_handle));
+ }
+
+ {
+ uint64_t t = uv_hrtime();
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ t = uv_hrtime() - t;
+ time = t / 1e9;
+ }
+
+ for (i = 0; i < num_servers; i++) {
+ struct server_ctx* ctx = servers + i;
+ uv_async_send(&ctx->async_handle);
+ ASSERT(0 == uv_thread_join(&ctx->thread_id));
+ uv_sem_destroy(&ctx->semaphore);
+ }
+
+ printf("accept%u: %.0f accepts/sec (%u total)\n",
+ num_servers,
+ NUM_CONNECTS / time,
+ NUM_CONNECTS);
+
+ for (i = 0; i < num_servers; i++) {
+ struct server_ctx* ctx = servers + i;
+ printf(" thread #%u: %.0f accepts/sec (%u total, %.1f%%)\n",
+ i,
+ ctx->num_connects / time,
+ ctx->num_connects,
+ ctx->num_connects * 100.0 / NUM_CONNECTS);
+ }
+
+ free(clients);
+ free(servers);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+BENCHMARK_IMPL(tcp_multi_accept2) {
+ return test_tcp(2, 40);
+}
+
+
+BENCHMARK_IMPL(tcp_multi_accept4) {
+ return test_tcp(4, 40);
+}
+
+
+BENCHMARK_IMPL(tcp_multi_accept8) {
+ return test_tcp(8, 40);
+}
diff --git a/3rdparty/libuv/test/benchmark-ping-pongs.c b/3rdparty/libuv/test/benchmark-ping-pongs.c
new file mode 100644
index 00000000000..646a7df9447
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-ping-pongs.c
@@ -0,0 +1,221 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/* Run the benchmark for this many ms */
+#define TIME 5000
+
+
+typedef struct {
+ int pongs;
+ int state;
+ uv_tcp_t tcp;
+ uv_connect_t connect_req;
+ uv_shutdown_t shutdown_req;
+} pinger_t;
+
+typedef struct buf_s {
+ uv_buf_t uv_buf_t;
+ struct buf_s* next;
+} buf_t;
+
+
+static char PING[] = "PING\n";
+
+static uv_loop_t* loop;
+
+static buf_t* buf_freelist = NULL;
+static int pinger_shutdown_cb_called;
+static int completed_pingers = 0;
+static int64_t start_time;
+
+
+static void buf_alloc(uv_handle_t* tcp, size_t size, uv_buf_t* buf) {
+ buf_t* ab;
+
+ ab = buf_freelist;
+ if (ab != NULL)
+ buf_freelist = ab->next;
+ else {
+ ab = malloc(size + sizeof(*ab));
+ ab->uv_buf_t.len = size;
+ ab->uv_buf_t.base = (char*) (ab + 1);
+ }
+
+ *buf = ab->uv_buf_t;
+}
+
+
+static void buf_free(const uv_buf_t* buf) {
+ buf_t* ab = (buf_t*) buf->base - 1;
+ ab->next = buf_freelist;
+ buf_freelist = ab;
+}
+
+
+static void pinger_close_cb(uv_handle_t* handle) {
+ pinger_t* pinger;
+
+ pinger = (pinger_t*)handle->data;
+ fprintf(stderr, "ping_pongs: %d roundtrips/s\n", (1000 * pinger->pongs) / TIME);
+ fflush(stderr);
+
+ free(pinger);
+
+ completed_pingers++;
+}
+
+
+static void pinger_write_cb(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+
+ free(req);
+}
+
+
+static void pinger_write_ping(pinger_t* pinger) {
+ uv_write_t* req;
+ uv_buf_t buf;
+
+ buf = uv_buf_init(PING, sizeof(PING) - 1);
+
+ req = malloc(sizeof *req);
+ if (uv_write(req, (uv_stream_t*) &pinger->tcp, &buf, 1, pinger_write_cb)) {
+ FATAL("uv_write failed");
+ }
+}
+
+
+static void pinger_shutdown_cb(uv_shutdown_t* req, int status) {
+ ASSERT(status == 0);
+ pinger_shutdown_cb_called++;
+
+ /*
+ * The close callback has not been triggered yet. We must wait for EOF
+ * until we close the connection.
+ */
+ ASSERT(completed_pingers == 0);
+}
+
+
+static void pinger_read_cb(uv_stream_t* tcp,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ ssize_t i;
+ pinger_t* pinger;
+
+ pinger = (pinger_t*)tcp->data;
+
+ if (nread < 0) {
+ ASSERT(nread == UV_EOF);
+
+ if (buf->base) {
+ buf_free(buf);
+ }
+
+ ASSERT(pinger_shutdown_cb_called == 1);
+ uv_close((uv_handle_t*)tcp, pinger_close_cb);
+
+ return;
+ }
+
+ /* Now we count the pings */
+ for (i = 0; i < nread; i++) {
+ ASSERT(buf->base[i] == PING[pinger->state]);
+ pinger->state = (pinger->state + 1) % (sizeof(PING) - 1);
+ if (pinger->state == 0) {
+ pinger->pongs++;
+ if (uv_now(loop) - start_time > TIME) {
+ uv_shutdown(&pinger->shutdown_req,
+ (uv_stream_t*) tcp,
+ pinger_shutdown_cb);
+ break;
+ } else {
+ pinger_write_ping(pinger);
+ }
+ }
+ }
+
+ buf_free(buf);
+}
+
+
+static void pinger_connect_cb(uv_connect_t* req, int status) {
+ pinger_t *pinger = (pinger_t*)req->handle->data;
+
+ ASSERT(status == 0);
+
+ pinger_write_ping(pinger);
+
+ if (uv_read_start(req->handle, buf_alloc, pinger_read_cb)) {
+ FATAL("uv_read_start failed");
+ }
+}
+
+
+static void pinger_new(void) {
+ struct sockaddr_in client_addr;
+ struct sockaddr_in server_addr;
+ pinger_t *pinger;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &client_addr));
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
+ pinger = malloc(sizeof(*pinger));
+ pinger->state = 0;
+ pinger->pongs = 0;
+
+ /* Try to connect to the server and do NUM_PINGS ping-pongs. */
+ r = uv_tcp_init(loop, &pinger->tcp);
+ ASSERT(!r);
+
+ pinger->tcp.data = pinger;
+
+ ASSERT(0 == uv_tcp_bind(&pinger->tcp,
+ (const struct sockaddr*) &client_addr,
+ 0));
+
+ r = uv_tcp_connect(&pinger->connect_req,
+ &pinger->tcp,
+ (const struct sockaddr*) &server_addr,
+ pinger_connect_cb);
+ ASSERT(!r);
+}
+
+
+BENCHMARK_IMPL(ping_pongs) {
+ loop = uv_default_loop();
+
+ start_time = uv_now(loop);
+
+ pinger_new();
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(completed_pingers == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-pound.c b/3rdparty/libuv/test/benchmark-pound.c
new file mode 100644
index 00000000000..79f36345037
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-pound.c
@@ -0,0 +1,351 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+/* Update this is you're going to run > 1000 concurrent requests. */
+#define MAX_CONNS 1000
+
+#undef NANOSEC
+#define NANOSEC ((uint64_t) 1e9)
+
+#undef DEBUG
+#define DEBUG 0
+
+struct conn_rec_s;
+
+typedef void (*setup_fn)(int num, void* arg);
+typedef void (*make_connect_fn)(struct conn_rec_s* conn);
+typedef int (*connect_fn)(int num, make_connect_fn make_connect, void* arg);
+
+/* Base class for tcp_conn_rec and pipe_conn_rec.
+ * The ordering of fields matters!
+ */
+typedef struct conn_rec_s {
+ int i;
+ uv_connect_t conn_req;
+ uv_write_t write_req;
+ make_connect_fn make_connect;
+ uv_stream_t stream;
+} conn_rec;
+
+typedef struct {
+ int i;
+ uv_connect_t conn_req;
+ uv_write_t write_req;
+ make_connect_fn make_connect;
+ uv_tcp_t stream;
+} tcp_conn_rec;
+
+typedef struct {
+ int i;
+ uv_connect_t conn_req;
+ uv_write_t write_req;
+ make_connect_fn make_connect;
+ uv_pipe_t stream;
+} pipe_conn_rec;
+
+static char buffer[] = "QS";
+
+static uv_loop_t* loop;
+
+static tcp_conn_rec tcp_conns[MAX_CONNS];
+static pipe_conn_rec pipe_conns[MAX_CONNS];
+
+static uint64_t start; /* in ms */
+static int closed_streams;
+static int conns_failed;
+
+static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf);
+static void connect_cb(uv_connect_t* conn_req, int status);
+static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
+static void close_cb(uv_handle_t* handle);
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void after_write(uv_write_t* req, int status) {
+ if (status != 0) {
+ fprintf(stderr, "write error %s\n", uv_err_name(status));
+ uv_close((uv_handle_t*)req->handle, close_cb);
+ conns_failed++;
+ return;
+ }
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ conn_rec* conn;
+ uv_buf_t buf;
+ int r;
+
+ if (status != 0) {
+#if DEBUG
+ fprintf(stderr, "connect error %s\n", uv_err_name(status));
+#endif
+ uv_close((uv_handle_t*)req->handle, close_cb);
+ conns_failed++;
+ return;
+ }
+
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+
+ conn = (conn_rec*)req->data;
+ ASSERT(conn != NULL);
+
+#if DEBUG
+ printf("connect_cb %d\n", conn->i);
+#endif
+
+ r = uv_read_start(&conn->stream, alloc_cb, read_cb);
+ ASSERT(r == 0);
+
+ buf.base = buffer;
+ buf.len = sizeof(buffer) - 1;
+
+ r = uv_write(&conn->write_req, &conn->stream, &buf, 1, after_write);
+ ASSERT(r == 0);
+}
+
+
+static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
+
+ ASSERT(stream != NULL);
+
+#if DEBUG
+ printf("read_cb %d\n", p->i);
+#endif
+
+ uv_close((uv_handle_t*)stream, close_cb);
+
+ if (nread < 0) {
+ if (nread == UV_EOF) {
+ ;
+ } else if (nread == UV_ECONNRESET) {
+ conns_failed++;
+ } else {
+ fprintf(stderr, "read error %s\n", uv_err_name(nread));
+ ASSERT(0);
+ }
+ }
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ conn_rec* p = (conn_rec*)handle->data;
+
+ ASSERT(handle != NULL);
+ closed_streams++;
+
+#if DEBUG
+ printf("close_cb %d\n", p->i);
+#endif
+
+ if (uv_now(loop) - start < 10000) {
+ p->make_connect(p);
+ }
+}
+
+
+static void tcp_do_setup(int num, void* arg) {
+ int i;
+
+ for (i = 0; i < num; i++) {
+ tcp_conns[i].i = i;
+ }
+}
+
+
+static void pipe_do_setup(int num, void* arg) {
+ int i;
+
+ for (i = 0; i < num; i++) {
+ pipe_conns[i].i = i;
+ }
+}
+
+
+static void tcp_make_connect(conn_rec* p) {
+ struct sockaddr_in addr;
+ tcp_conn_rec* tp;
+ int r;
+
+ tp = (tcp_conn_rec*) p;
+
+ r = uv_tcp_init(loop, (uv_tcp_t*)&p->stream);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_connect(&tp->conn_req,
+ (uv_tcp_t*) &p->stream,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ if (r) {
+ fprintf(stderr, "uv_tcp_connect error %s\n", uv_err_name(r));
+ ASSERT(0);
+ }
+
+#if DEBUG
+ printf("make connect %d\n", p->i);
+#endif
+
+ p->conn_req.data = p;
+ p->write_req.data = p;
+ p->stream.data = p;
+}
+
+
+static void pipe_make_connect(conn_rec* p) {
+ int r;
+
+ r = uv_pipe_init(loop, (uv_pipe_t*)&p->stream, 0);
+ ASSERT(r == 0);
+
+ uv_pipe_connect(&((pipe_conn_rec*) p)->conn_req,
+ (uv_pipe_t*) &p->stream,
+ TEST_PIPENAME,
+ connect_cb);
+
+#if DEBUG
+ printf("make connect %d\n", p->i);
+#endif
+
+ p->conn_req.data = p;
+ p->write_req.data = p;
+ p->stream.data = p;
+}
+
+
+static int tcp_do_connect(int num, make_connect_fn make_connect, void* arg) {
+ int i;
+
+ for (i = 0; i < num; i++) {
+ tcp_make_connect((conn_rec*)&tcp_conns[i]);
+ tcp_conns[i].make_connect = make_connect;
+ }
+
+ return 0;
+}
+
+
+static int pipe_do_connect(int num, make_connect_fn make_connect, void* arg) {
+ int i;
+
+ for (i = 0; i < num; i++) {
+ pipe_make_connect((conn_rec*)&pipe_conns[i]);
+ pipe_conns[i].make_connect = make_connect;
+ }
+
+ return 0;
+}
+
+
+static int pound_it(int concurrency,
+ const char* type,
+ setup_fn do_setup,
+ connect_fn do_connect,
+ make_connect_fn make_connect,
+ void* arg) {
+ double secs;
+ int r;
+ uint64_t start_time; /* in ns */
+ uint64_t end_time;
+
+ loop = uv_default_loop();
+
+ uv_update_time(loop);
+ start = uv_now(loop);
+
+ /* Run benchmark for at least five seconds. */
+ start_time = uv_hrtime();
+
+ do_setup(concurrency, arg);
+
+ r = do_connect(concurrency, make_connect, arg);
+ ASSERT(!r);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ end_time = uv_hrtime();
+
+ /* Number of fractional seconds it took to run the benchmark. */
+ secs = (double)(end_time - start_time) / NANOSEC;
+
+ fprintf(stderr, "%s-conn-pound-%d: %.0f accepts/s (%d failed)\n",
+ type,
+ concurrency,
+ closed_streams / secs,
+ conns_failed);
+ fflush(stderr);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+BENCHMARK_IMPL(tcp4_pound_100) {
+ return pound_it(100,
+ "tcp",
+ tcp_do_setup,
+ tcp_do_connect,
+ tcp_make_connect,
+ NULL);
+}
+
+
+BENCHMARK_IMPL(tcp4_pound_1000) {
+ return pound_it(1000,
+ "tcp",
+ tcp_do_setup,
+ tcp_do_connect,
+ tcp_make_connect,
+ NULL);
+}
+
+
+BENCHMARK_IMPL(pipe_pound_100) {
+ return pound_it(100,
+ "pipe",
+ pipe_do_setup,
+ pipe_do_connect,
+ pipe_make_connect,
+ NULL);
+}
+
+
+BENCHMARK_IMPL(pipe_pound_1000) {
+ return pound_it(1000,
+ "pipe",
+ pipe_do_setup,
+ pipe_do_connect,
+ pipe_make_connect,
+ NULL);
+}
diff --git a/3rdparty/libuv/test/benchmark-pump.c b/3rdparty/libuv/test/benchmark-pump.c
new file mode 100644
index 00000000000..88f2dc5c658
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-pump.c
@@ -0,0 +1,476 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+#include <math.h>
+#include <stdio.h>
+
+
+static int TARGET_CONNECTIONS;
+#define WRITE_BUFFER_SIZE 8192
+#define MAX_SIMULTANEOUS_CONNECTS 100
+
+#define PRINT_STATS 0
+#define STATS_INTERVAL 1000 /* msec */
+#define STATS_COUNT 5
+
+
+static void do_write(uv_stream_t*);
+static void maybe_connect_some();
+
+static uv_req_t* req_alloc();
+static void req_free(uv_req_t* uv_req);
+
+static void buf_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf);
+static void buf_free(const uv_buf_t* buf);
+
+static uv_loop_t* loop;
+
+static uv_tcp_t tcpServer;
+static uv_pipe_t pipeServer;
+static uv_stream_t* server;
+static struct sockaddr_in listen_addr;
+static struct sockaddr_in connect_addr;
+
+static int64_t start_time;
+
+static int max_connect_socket = 0;
+static int max_read_sockets = 0;
+static int read_sockets = 0;
+static int write_sockets = 0;
+
+static int64_t nrecv = 0;
+static int64_t nrecv_total = 0;
+static int64_t nsent = 0;
+static int64_t nsent_total = 0;
+
+static int stats_left = 0;
+
+static char write_buffer[WRITE_BUFFER_SIZE];
+
+/* Make this as large as you need. */
+#define MAX_WRITE_HANDLES 1000
+
+static stream_type type;
+
+static uv_tcp_t tcp_write_handles[MAX_WRITE_HANDLES];
+static uv_pipe_t pipe_write_handles[MAX_WRITE_HANDLES];
+
+static uv_timer_t timer_handle;
+
+
+static double gbit(int64_t bytes, int64_t passed_ms) {
+ double gbits = ((double)bytes / (1024 * 1024 * 1024)) * 8;
+ return gbits / ((double)passed_ms / 1000);
+}
+
+
+static void show_stats(uv_timer_t* handle) {
+ int64_t diff;
+ int i;
+
+#if PRINT_STATS
+ fprintf(stderr, "connections: %d, write: %.1f gbit/s\n",
+ write_sockets,
+ gbit(nsent, STATS_INTERVAL));
+ fflush(stderr);
+#endif
+
+ /* Exit if the show is over */
+ if (!--stats_left) {
+
+ uv_update_time(loop);
+ diff = uv_now(loop) - start_time;
+
+ fprintf(stderr, "%s_pump%d_client: %.1f gbit/s\n",
+ type == TCP ? "tcp" : "pipe",
+ write_sockets,
+ gbit(nsent_total, diff));
+ fflush(stderr);
+
+ for (i = 0; i < write_sockets; i++) {
+ if (type == TCP)
+ uv_close((uv_handle_t*) &tcp_write_handles[i], NULL);
+ else
+ uv_close((uv_handle_t*) &pipe_write_handles[i], NULL);
+ }
+
+ exit(0);
+ }
+
+ /* Reset read and write counters */
+ nrecv = 0;
+ nsent = 0;
+}
+
+
+static void read_show_stats(void) {
+ int64_t diff;
+
+ uv_update_time(loop);
+ diff = uv_now(loop) - start_time;
+
+ fprintf(stderr, "%s_pump%d_server: %.1f gbit/s\n",
+ type == TCP ? "tcp" : "pipe",
+ max_read_sockets,
+ gbit(nrecv_total, diff));
+ fflush(stderr);
+}
+
+
+
+static void read_sockets_close_cb(uv_handle_t* handle) {
+ free(handle);
+ read_sockets--;
+
+ /* If it's past the first second and everyone has closed their connection
+ * Then print stats.
+ */
+ if (uv_now(loop) - start_time > 1000 && read_sockets == 0) {
+ read_show_stats();
+ uv_close((uv_handle_t*)server, NULL);
+ }
+}
+
+
+static void start_stats_collection(void) {
+ int r;
+
+ /* Show-stats timer */
+ stats_left = STATS_COUNT;
+ r = uv_timer_init(loop, &timer_handle);
+ ASSERT(r == 0);
+ r = uv_timer_start(&timer_handle, show_stats, STATS_INTERVAL, STATS_INTERVAL);
+ ASSERT(r == 0);
+
+ uv_update_time(loop);
+ start_time = uv_now(loop);
+}
+
+
+static void read_cb(uv_stream_t* stream, ssize_t bytes, const uv_buf_t* buf) {
+ if (nrecv_total == 0) {
+ ASSERT(start_time == 0);
+ uv_update_time(loop);
+ start_time = uv_now(loop);
+ }
+
+ if (bytes < 0) {
+ uv_close((uv_handle_t*)stream, read_sockets_close_cb);
+ return;
+ }
+
+ buf_free(buf);
+
+ nrecv += bytes;
+ nrecv_total += bytes;
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+
+ req_free((uv_req_t*) req);
+
+ nsent += sizeof write_buffer;
+ nsent_total += sizeof write_buffer;
+
+ do_write((uv_stream_t*) req->handle);
+}
+
+
+static void do_write(uv_stream_t* stream) {
+ uv_write_t* req;
+ uv_buf_t buf;
+ int r;
+
+ buf.base = (char*) &write_buffer;
+ buf.len = sizeof write_buffer;
+
+ req = (uv_write_t*) req_alloc();
+ r = uv_write(req, stream, &buf, 1, write_cb);
+ ASSERT(r == 0);
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ int i;
+
+ if (status) {
+ fprintf(stderr, "%s", uv_strerror(status));
+ fflush(stderr);
+ }
+ ASSERT(status == 0);
+
+ write_sockets++;
+ req_free((uv_req_t*) req);
+
+ maybe_connect_some();
+
+ if (write_sockets == TARGET_CONNECTIONS) {
+ start_stats_collection();
+
+ /* Yay! start writing */
+ for (i = 0; i < write_sockets; i++) {
+ if (type == TCP)
+ do_write((uv_stream_t*) &tcp_write_handles[i]);
+ else
+ do_write((uv_stream_t*) &pipe_write_handles[i]);
+ }
+ }
+}
+
+
+static void maybe_connect_some(void) {
+ uv_connect_t* req;
+ uv_tcp_t* tcp;
+ uv_pipe_t* pipe;
+ int r;
+
+ while (max_connect_socket < TARGET_CONNECTIONS &&
+ max_connect_socket < write_sockets + MAX_SIMULTANEOUS_CONNECTS) {
+ if (type == TCP) {
+ tcp = &tcp_write_handles[max_connect_socket++];
+
+ r = uv_tcp_init(loop, tcp);
+ ASSERT(r == 0);
+
+ req = (uv_connect_t*) req_alloc();
+ r = uv_tcp_connect(req,
+ tcp,
+ (const struct sockaddr*) &connect_addr,
+ connect_cb);
+ ASSERT(r == 0);
+ } else {
+ pipe = &pipe_write_handles[max_connect_socket++];
+
+ r = uv_pipe_init(loop, pipe, 0);
+ ASSERT(r == 0);
+
+ req = (uv_connect_t*) req_alloc();
+ uv_pipe_connect(req, pipe, TEST_PIPENAME, connect_cb);
+ }
+ }
+}
+
+
+static void connection_cb(uv_stream_t* s, int status) {
+ uv_stream_t* stream;
+ int r;
+
+ ASSERT(server == s);
+ ASSERT(status == 0);
+
+ if (type == TCP) {
+ stream = (uv_stream_t*)malloc(sizeof(uv_tcp_t));
+ r = uv_tcp_init(loop, (uv_tcp_t*)stream);
+ ASSERT(r == 0);
+ } else {
+ stream = (uv_stream_t*)malloc(sizeof(uv_pipe_t));
+ r = uv_pipe_init(loop, (uv_pipe_t*)stream, 0);
+ ASSERT(r == 0);
+ }
+
+ r = uv_accept(s, stream);
+ ASSERT(r == 0);
+
+ r = uv_read_start(stream, buf_alloc, read_cb);
+ ASSERT(r == 0);
+
+ read_sockets++;
+ max_read_sockets++;
+}
+
+
+/*
+ * Request allocator
+ */
+
+typedef struct req_list_s {
+ union uv_any_req uv_req;
+ struct req_list_s* next;
+} req_list_t;
+
+
+static req_list_t* req_freelist = NULL;
+
+
+static uv_req_t* req_alloc(void) {
+ req_list_t* req;
+
+ req = req_freelist;
+ if (req != NULL) {
+ req_freelist = req->next;
+ return (uv_req_t*) req;
+ }
+
+ req = (req_list_t*) malloc(sizeof *req);
+ return (uv_req_t*) req;
+}
+
+
+static void req_free(uv_req_t* uv_req) {
+ req_list_t* req = (req_list_t*) uv_req;
+
+ req->next = req_freelist;
+ req_freelist = req;
+}
+
+
+/*
+ * Buffer allocator
+ */
+
+typedef struct buf_list_s {
+ uv_buf_t uv_buf_t;
+ struct buf_list_s* next;
+} buf_list_t;
+
+
+static buf_list_t* buf_freelist = NULL;
+
+
+static void buf_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ buf_list_t* ab;
+
+ ab = buf_freelist;
+ if (ab != NULL)
+ buf_freelist = ab->next;
+ else {
+ ab = malloc(size + sizeof(*ab));
+ ab->uv_buf_t.len = size;
+ ab->uv_buf_t.base = (char*) (ab + 1);
+ }
+
+ *buf = ab->uv_buf_t;
+}
+
+
+static void buf_free(const uv_buf_t* buf) {
+ buf_list_t* ab = (buf_list_t*) buf->base - 1;
+ ab->next = buf_freelist;
+ buf_freelist = ab;
+}
+
+
+HELPER_IMPL(tcp_pump_server) {
+ int r;
+
+ type = TCP;
+ loop = uv_default_loop();
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &listen_addr));
+
+ /* Server */
+ server = (uv_stream_t*)&tcpServer;
+ r = uv_tcp_init(loop, &tcpServer);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &listen_addr, 0);
+ ASSERT(r == 0);
+ r = uv_listen((uv_stream_t*)&tcpServer, MAX_WRITE_HANDLES, connection_cb);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ return 0;
+}
+
+
+HELPER_IMPL(pipe_pump_server) {
+ int r;
+ type = PIPE;
+
+ loop = uv_default_loop();
+
+ /* Server */
+ server = (uv_stream_t*)&pipeServer;
+ r = uv_pipe_init(loop, &pipeServer, 0);
+ ASSERT(r == 0);
+ r = uv_pipe_bind(&pipeServer, TEST_PIPENAME);
+ ASSERT(r == 0);
+ r = uv_listen((uv_stream_t*)&pipeServer, MAX_WRITE_HANDLES, connection_cb);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+static void tcp_pump(int n) {
+ ASSERT(n <= MAX_WRITE_HANDLES);
+ TARGET_CONNECTIONS = n;
+ type = TCP;
+
+ loop = uv_default_loop();
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &connect_addr));
+
+ /* Start making connections */
+ maybe_connect_some();
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+}
+
+
+static void pipe_pump(int n) {
+ ASSERT(n <= MAX_WRITE_HANDLES);
+ TARGET_CONNECTIONS = n;
+ type = PIPE;
+
+ loop = uv_default_loop();
+
+ /* Start making connections */
+ maybe_connect_some();
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+}
+
+
+BENCHMARK_IMPL(tcp_pump100_client) {
+ tcp_pump(100);
+ return 0;
+}
+
+
+BENCHMARK_IMPL(tcp_pump1_client) {
+ tcp_pump(1);
+ return 0;
+}
+
+
+BENCHMARK_IMPL(pipe_pump100_client) {
+ pipe_pump(100);
+ return 0;
+}
+
+
+BENCHMARK_IMPL(pipe_pump1_client) {
+ pipe_pump(1);
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-sizes.c b/3rdparty/libuv/test/benchmark-sizes.c
new file mode 100644
index 00000000000..9bf42f91537
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-sizes.c
@@ -0,0 +1,46 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+
+BENCHMARK_IMPL(sizes) {
+ fprintf(stderr, "uv_shutdown_t: %u bytes\n", (unsigned int) sizeof(uv_shutdown_t));
+ fprintf(stderr, "uv_write_t: %u bytes\n", (unsigned int) sizeof(uv_write_t));
+ fprintf(stderr, "uv_connect_t: %u bytes\n", (unsigned int) sizeof(uv_connect_t));
+ fprintf(stderr, "uv_udp_send_t: %u bytes\n", (unsigned int) sizeof(uv_udp_send_t));
+ fprintf(stderr, "uv_tcp_t: %u bytes\n", (unsigned int) sizeof(uv_tcp_t));
+ fprintf(stderr, "uv_pipe_t: %u bytes\n", (unsigned int) sizeof(uv_pipe_t));
+ fprintf(stderr, "uv_tty_t: %u bytes\n", (unsigned int) sizeof(uv_tty_t));
+ fprintf(stderr, "uv_prepare_t: %u bytes\n", (unsigned int) sizeof(uv_prepare_t));
+ fprintf(stderr, "uv_check_t: %u bytes\n", (unsigned int) sizeof(uv_check_t));
+ fprintf(stderr, "uv_idle_t: %u bytes\n", (unsigned int) sizeof(uv_idle_t));
+ fprintf(stderr, "uv_async_t: %u bytes\n", (unsigned int) sizeof(uv_async_t));
+ fprintf(stderr, "uv_timer_t: %u bytes\n", (unsigned int) sizeof(uv_timer_t));
+ fprintf(stderr, "uv_fs_poll_t: %u bytes\n", (unsigned int) sizeof(uv_fs_poll_t));
+ fprintf(stderr, "uv_fs_event_t: %u bytes\n", (unsigned int) sizeof(uv_fs_event_t));
+ fprintf(stderr, "uv_process_t: %u bytes\n", (unsigned int) sizeof(uv_process_t));
+ fprintf(stderr, "uv_poll_t: %u bytes\n", (unsigned int) sizeof(uv_poll_t));
+ fprintf(stderr, "uv_loop_t: %u bytes\n", (unsigned int) sizeof(uv_loop_t));
+ fflush(stderr);
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-spawn.c b/3rdparty/libuv/test/benchmark-spawn.c
new file mode 100644
index 00000000000..ed9ad608f37
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-spawn.c
@@ -0,0 +1,164 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* This benchmark spawns itself 1000 times. */
+
+#include "task.h"
+#include "uv.h"
+
+static uv_loop_t* loop;
+
+static int N = 1000;
+static int done;
+
+static uv_process_t process;
+static uv_process_options_t options;
+static char exepath[1024];
+static size_t exepath_size = 1024;
+static char* args[3];
+static uv_pipe_t out;
+
+#define OUTPUT_SIZE 1024
+static char output[OUTPUT_SIZE];
+static int output_used;
+
+static int process_open;
+static int pipe_open;
+
+
+static void spawn(void);
+
+
+static void maybe_spawn(void) {
+ if (process_open == 0 && pipe_open == 0) {
+ done++;
+ if (done < N) {
+ spawn();
+ }
+ }
+}
+
+
+static void process_close_cb(uv_handle_t* handle) {
+ ASSERT(process_open == 1);
+ process_open = 0;
+ maybe_spawn();
+}
+
+
+static void exit_cb(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ ASSERT(exit_status == 42);
+ ASSERT(term_signal == 0);
+ uv_close((uv_handle_t*)process, process_close_cb);
+}
+
+
+static void on_alloc(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ buf->base = output + output_used;
+ buf->len = OUTPUT_SIZE - output_used;
+}
+
+
+static void pipe_close_cb(uv_handle_t* pipe) {
+ ASSERT(pipe_open == 1);
+ pipe_open = 0;
+ maybe_spawn();
+}
+
+
+static void on_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* buf) {
+ if (nread > 0) {
+ ASSERT(pipe_open == 1);
+ output_used += nread;
+ } else if (nread < 0) {
+ if (nread == UV_EOF) {
+ uv_close((uv_handle_t*)pipe, pipe_close_cb);
+ }
+ }
+}
+
+
+static void spawn(void) {
+ uv_stdio_container_t stdio[2];
+ int r;
+
+ ASSERT(process_open == 0);
+ ASSERT(pipe_open == 0);
+
+ args[0] = exepath;
+ args[1] = "spawn_helper";
+ args[2] = NULL;
+ options.file = exepath;
+ options.args = args;
+ options.exit_cb = exit_cb;
+
+ uv_pipe_init(loop, &out, 0);
+
+ options.stdio = stdio;
+ options.stdio_count = 2;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+
+ r = uv_spawn(loop, &process, &options);
+ ASSERT(r == 0);
+
+ process_open = 1;
+ pipe_open = 1;
+ output_used = 0;
+
+ r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
+ ASSERT(r == 0);
+}
+
+
+BENCHMARK_IMPL(spawn) {
+ int r;
+ static int64_t start_time, end_time;
+
+ loop = uv_default_loop();
+
+ r = uv_exepath(exepath, &exepath_size);
+ ASSERT(r == 0);
+ exepath[exepath_size] = '\0';
+
+ uv_update_time(loop);
+ start_time = uv_now(loop);
+
+ spawn();
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ uv_update_time(loop);
+ end_time = uv_now(loop);
+
+ fprintf(stderr, "spawn: %.0f spawns/s\n",
+ (double) N / (double) (end_time - start_time) * 1000.0);
+ fflush(stderr);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-tcp-write-batch.c b/3rdparty/libuv/test/benchmark-tcp-write-batch.c
new file mode 100644
index 00000000000..96921b70db5
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-tcp-write-batch.c
@@ -0,0 +1,144 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define WRITE_REQ_DATA "Hello, world."
+#define NUM_WRITE_REQS (1000 * 1000)
+
+typedef struct {
+ uv_write_t req;
+ uv_buf_t buf;
+} write_req;
+
+
+static write_req* write_reqs;
+static uv_tcp_t tcp_client;
+static uv_connect_t connect_req;
+static uv_shutdown_t shutdown_req;
+
+static int shutdown_cb_called = 0;
+static int connect_cb_called = 0;
+static int write_cb_called = 0;
+static int close_cb_called = 0;
+
+static void connect_cb(uv_connect_t* req, int status);
+static void write_cb(uv_write_t* req, int status);
+static void shutdown_cb(uv_shutdown_t* req, int status);
+static void close_cb(uv_handle_t* handle);
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ write_req* w;
+ int i;
+ int r;
+
+ ASSERT(req->handle == (uv_stream_t*)&tcp_client);
+
+ for (i = 0; i < NUM_WRITE_REQS; i++) {
+ w = &write_reqs[i];
+ r = uv_write(&w->req, req->handle, &w->buf, 1, write_cb);
+ ASSERT(r == 0);
+ }
+
+ r = uv_shutdown(&shutdown_req, req->handle, shutdown_cb);
+ ASSERT(r == 0);
+
+ connect_cb_called++;
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+ write_cb_called++;
+}
+
+
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+ ASSERT(req->handle == (uv_stream_t*)&tcp_client);
+ ASSERT(req->handle->write_queue_size == 0);
+
+ uv_close((uv_handle_t*)req->handle, close_cb);
+ free(write_reqs);
+
+ shutdown_cb_called++;
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle == (uv_handle_t*)&tcp_client);
+ close_cb_called++;
+}
+
+
+BENCHMARK_IMPL(tcp_write_batch) {
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+ uint64_t start;
+ uint64_t stop;
+ int i;
+ int r;
+
+ write_reqs = malloc(sizeof(*write_reqs) * NUM_WRITE_REQS);
+ ASSERT(write_reqs != NULL);
+
+ /* Prepare the data to write out. */
+ for (i = 0; i < NUM_WRITE_REQS; i++) {
+ write_reqs[i].buf = uv_buf_init(WRITE_REQ_DATA,
+ sizeof(WRITE_REQ_DATA) - 1);
+ }
+
+ loop = uv_default_loop();
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_init(loop, &tcp_client);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(&connect_req,
+ &tcp_client,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+
+ start = uv_hrtime();
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ stop = uv_hrtime();
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(write_cb_called == NUM_WRITE_REQS);
+ ASSERT(shutdown_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ printf("%ld write requests in %.2fs.\n",
+ (long)NUM_WRITE_REQS,
+ (stop - start) / 1e9);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-thread.c b/3rdparty/libuv/test/benchmark-thread.c
new file mode 100644
index 00000000000..b37a7fd6d01
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-thread.c
@@ -0,0 +1,64 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define NUM_THREADS (20 * 1000)
+
+static volatile int num_threads;
+
+
+static void thread_entry(void* arg) {
+ ASSERT(arg == (void *) 42);
+ num_threads++;
+ /* FIXME write barrier? */
+}
+
+
+BENCHMARK_IMPL(thread_create) {
+ uint64_t start_time;
+ double duration;
+ uv_thread_t tid;
+ int i, r;
+
+ start_time = uv_hrtime();
+
+ for (i = 0; i < NUM_THREADS; i++) {
+ r = uv_thread_create(&tid, thread_entry, (void *) 42);
+ ASSERT(r == 0);
+
+ r = uv_thread_join(&tid);
+ ASSERT(r == 0);
+ }
+
+ duration = (uv_hrtime() - start_time) / 1e9;
+
+ ASSERT(num_threads == NUM_THREADS);
+
+ printf("%d threads created in %.2f seconds (%.0f/s)\n",
+ NUM_THREADS, duration, NUM_THREADS / duration);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/benchmark-udp-pummel.c b/3rdparty/libuv/test/benchmark-udp-pummel.c
new file mode 100644
index 00000000000..68a2373d781
--- /dev/null
+++ b/3rdparty/libuv/test/benchmark-udp-pummel.c
@@ -0,0 +1,243 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+#include "uv.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define EXPECTED "RANG TANG DING DONG I AM THE JAPANESE SANDMAN"
+
+#define TEST_DURATION 5000 /* ms */
+
+#define BASE_PORT 12345
+
+struct sender_state {
+ struct sockaddr_in addr;
+ uv_udp_send_t send_req;
+ uv_udp_t udp_handle;
+};
+
+struct receiver_state {
+ struct sockaddr_in addr;
+ uv_udp_t udp_handle;
+};
+
+/* not used in timed mode */
+static unsigned int packet_counter = (unsigned int) 1e6;
+
+static int n_senders_;
+static int n_receivers_;
+static uv_buf_t bufs[5];
+static struct sender_state senders[1024];
+static struct receiver_state receivers[1024];
+
+static unsigned int send_cb_called;
+static unsigned int recv_cb_called;
+static unsigned int close_cb_called;
+static int timed;
+static int exiting;
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ ASSERT(suggested_size <= sizeof(slab));
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void send_cb(uv_udp_send_t* req, int status) {
+ struct sender_state* s;
+
+ ASSERT(req != NULL);
+
+ if (status != 0) {
+ ASSERT(status == UV_ECANCELED);
+ return;
+ }
+
+ if (exiting)
+ return;
+
+ s = container_of(req, struct sender_state, send_req);
+ ASSERT(req->handle == &s->udp_handle);
+
+ if (timed)
+ goto send;
+
+ if (packet_counter == 0) {
+ uv_close((uv_handle_t*)&s->udp_handle, NULL);
+ return;
+ }
+
+ packet_counter--;
+
+send:
+ ASSERT(0 == uv_udp_send(&s->send_req,
+ &s->udp_handle,
+ bufs,
+ ARRAY_SIZE(bufs),
+ (const struct sockaddr*) &s->addr,
+ send_cb));
+ send_cb_called++;
+}
+
+
+static void recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ if (nread == 0)
+ return;
+
+ if (nread < 0) {
+ ASSERT(nread == UV_ECANCELED);
+ return;
+ }
+
+ ASSERT(addr->sa_family == AF_INET);
+ ASSERT(!memcmp(buf->base, EXPECTED, nread));
+
+ recv_cb_called++;
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void timeout_cb(uv_timer_t* timer) {
+ int i;
+
+ exiting = 1;
+
+ for (i = 0; i < n_senders_; i++)
+ uv_close((uv_handle_t*)&senders[i].udp_handle, close_cb);
+
+ for (i = 0; i < n_receivers_; i++)
+ uv_close((uv_handle_t*)&receivers[i].udp_handle, close_cb);
+}
+
+
+static int pummel(unsigned int n_senders,
+ unsigned int n_receivers,
+ unsigned long timeout) {
+ uv_timer_t timer_handle;
+ uint64_t duration;
+ uv_loop_t* loop;
+ unsigned int i;
+
+ ASSERT(n_senders <= ARRAY_SIZE(senders));
+ ASSERT(n_receivers <= ARRAY_SIZE(receivers));
+
+ loop = uv_default_loop();
+
+ n_senders_ = n_senders;
+ n_receivers_ = n_receivers;
+
+ if (timeout) {
+ ASSERT(0 == uv_timer_init(loop, &timer_handle));
+ ASSERT(0 == uv_timer_start(&timer_handle, timeout_cb, timeout, 0));
+ /* Timer should not keep loop alive. */
+ uv_unref((uv_handle_t*)&timer_handle);
+ timed = 1;
+ }
+
+ for (i = 0; i < n_receivers; i++) {
+ struct receiver_state* s = receivers + i;
+ struct sockaddr_in addr;
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", BASE_PORT + i, &addr));
+ ASSERT(0 == uv_udp_init(loop, &s->udp_handle));
+ ASSERT(0 == uv_udp_bind(&s->udp_handle, (const struct sockaddr*) &addr, 0));
+ ASSERT(0 == uv_udp_recv_start(&s->udp_handle, alloc_cb, recv_cb));
+ uv_unref((uv_handle_t*)&s->udp_handle);
+ }
+
+ bufs[0] = uv_buf_init(EXPECTED + 0, 10);
+ bufs[1] = uv_buf_init(EXPECTED + 10, 10);
+ bufs[2] = uv_buf_init(EXPECTED + 20, 10);
+ bufs[3] = uv_buf_init(EXPECTED + 30, 10);
+ bufs[4] = uv_buf_init(EXPECTED + 40, 5);
+
+ for (i = 0; i < n_senders; i++) {
+ struct sender_state* s = senders + i;
+ ASSERT(0 == uv_ip4_addr("127.0.0.1",
+ BASE_PORT + (i % n_receivers),
+ &s->addr));
+ ASSERT(0 == uv_udp_init(loop, &s->udp_handle));
+ ASSERT(0 == uv_udp_send(&s->send_req,
+ &s->udp_handle,
+ bufs,
+ ARRAY_SIZE(bufs),
+ (const struct sockaddr*) &s->addr,
+ send_cb));
+ }
+
+ duration = uv_hrtime();
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ duration = uv_hrtime() - duration;
+ /* convert from nanoseconds to milliseconds */
+ duration = duration / (uint64_t) 1e6;
+
+ printf("udp_pummel_%dv%d: %.0f/s received, %.0f/s sent. "
+ "%u received, %u sent in %.1f seconds.\n",
+ n_receivers,
+ n_senders,
+ recv_cb_called / (duration / 1000.0),
+ send_cb_called / (duration / 1000.0),
+ recv_cb_called,
+ send_cb_called,
+ duration / 1000.0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+#define X(a, b) \
+ BENCHMARK_IMPL(udp_pummel_##a##v##b) { \
+ return pummel(a, b, 0); \
+ } \
+ BENCHMARK_IMPL(udp_timed_pummel_##a##v##b) { \
+ return pummel(a, b, TEST_DURATION); \
+ }
+
+X(1, 1)
+X(1, 10)
+X(1, 100)
+X(1, 1000)
+X(10, 10)
+X(10, 100)
+X(10, 1000)
+X(100, 10)
+X(100, 100)
+X(100, 1000)
+X(1000, 1000)
+
+#undef X
diff --git a/3rdparty/libuv/test/blackhole-server.c b/3rdparty/libuv/test/blackhole-server.c
new file mode 100644
index 00000000000..ad878b35c61
--- /dev/null
+++ b/3rdparty/libuv/test/blackhole-server.c
@@ -0,0 +1,121 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct {
+ uv_tcp_t handle;
+ uv_shutdown_t shutdown_req;
+} conn_rec;
+
+static uv_tcp_t tcp_server;
+
+static void connection_cb(uv_stream_t* stream, int status);
+static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf);
+static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
+static void shutdown_cb(uv_shutdown_t* req, int status);
+static void close_cb(uv_handle_t* handle);
+
+
+static void connection_cb(uv_stream_t* stream, int status) {
+ conn_rec* conn;
+ int r;
+
+ ASSERT(status == 0);
+ ASSERT(stream == (uv_stream_t*)&tcp_server);
+
+ conn = malloc(sizeof *conn);
+ ASSERT(conn != NULL);
+
+ r = uv_tcp_init(stream->loop, &conn->handle);
+ ASSERT(r == 0);
+
+ r = uv_accept(stream, (uv_stream_t*)&conn->handle);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)&conn->handle, alloc_cb, read_cb);
+ ASSERT(r == 0);
+}
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
+ conn_rec* conn;
+ int r;
+
+ if (nread >= 0)
+ return;
+
+ ASSERT(nread == UV_EOF);
+
+ conn = container_of(stream, conn_rec, handle);
+
+ r = uv_shutdown(&conn->shutdown_req, stream, shutdown_cb);
+ ASSERT(r == 0);
+}
+
+
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+ conn_rec* conn = container_of(req, conn_rec, shutdown_req);
+ uv_close((uv_handle_t*)&conn->handle, close_cb);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ conn_rec* conn = container_of(handle, conn_rec, handle);
+ free(conn);
+}
+
+
+HELPER_IMPL(tcp4_blackhole_server) {
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_init(loop, &tcp_server);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&tcp_server, 128, connection_cb);
+ ASSERT(r == 0);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(0 && "Blackhole server dropped out of event loop.");
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/dns-server.c b/3rdparty/libuv/test/dns-server.c
new file mode 100644
index 00000000000..80052c70398
--- /dev/null
+++ b/3rdparty/libuv/test/dns-server.c
@@ -0,0 +1,340 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+typedef struct {
+ uv_write_t req;
+ uv_buf_t buf;
+} write_req_t;
+
+
+/* used to track multiple DNS requests received */
+typedef struct {
+ char* prevbuf_ptr;
+ int prevbuf_pos;
+ int prevbuf_rem;
+} dnsstate;
+
+
+/* modify handle to append dnsstate */
+typedef struct {
+ uv_tcp_t handle;
+ dnsstate state;
+} dnshandle;
+
+
+static uv_loop_t* loop;
+
+
+static uv_tcp_t server;
+
+
+static void after_write(uv_write_t* req, int status);
+static void after_read(uv_stream_t*, ssize_t nread, const uv_buf_t* buf);
+static void on_close(uv_handle_t* peer);
+static void on_connection(uv_stream_t*, int status);
+
+#define WRITE_BUF_LEN (64*1024)
+#define DNSREC_LEN (4)
+
+#define LEN_OFFSET 0
+#define QUERYID_OFFSET 2
+
+static unsigned char DNSRsp[] = {
+ 0, 43, 0, 0, 0x81, 0x80, 0, 1, 0, 1, 0, 0, 0, 0
+};
+
+static unsigned char qrecord[] = {
+ 5, 'e', 'c', 'h', 'o', 's', 3, 's', 'r', 'v', 0, 0, 1, 0, 1
+};
+
+static unsigned char arecord[] = {
+ 0xc0, 0x0c, 0, 1, 0, 1, 0, 0, 5, 0xbd, 0, 4, 10, 0, 1, 1
+};
+
+
+static void after_write(uv_write_t* req, int status) {
+ write_req_t* wr;
+
+ if (status) {
+ fprintf(stderr, "uv_write error: %s\n", uv_strerror(status));
+ ASSERT(0);
+ }
+
+ wr = (write_req_t*) req;
+
+ /* Free the read/write buffer and the request */
+ free(wr->buf.base);
+ free(wr);
+}
+
+
+static void after_shutdown(uv_shutdown_t* req, int status) {
+ uv_close((uv_handle_t*) req->handle, on_close);
+ free(req);
+}
+
+
+static void addrsp(write_req_t* wr, char* hdr) {
+ char * dnsrsp;
+ short int rsplen;
+ short int* reclen;
+
+ rsplen = sizeof(DNSRsp) + sizeof(qrecord) + sizeof(arecord);
+
+ ASSERT (rsplen + wr->buf.len < WRITE_BUF_LEN);
+
+ dnsrsp = wr->buf.base + wr->buf.len;
+
+ /* copy stock response */
+ memcpy(dnsrsp, DNSRsp, sizeof(DNSRsp));
+ memcpy(dnsrsp + sizeof(DNSRsp), qrecord, sizeof(qrecord));
+ memcpy(dnsrsp + sizeof(DNSRsp) + sizeof(qrecord), arecord, sizeof(arecord));
+
+ /* overwrite with network order length and id from request header */
+ reclen = (short int*)dnsrsp;
+ *reclen = htons(rsplen-2);
+ dnsrsp[QUERYID_OFFSET] = hdr[QUERYID_OFFSET];
+ dnsrsp[QUERYID_OFFSET+1] = hdr[QUERYID_OFFSET+1];
+
+ wr->buf.len += rsplen;
+}
+
+static void process_req(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ write_req_t* wr;
+ dnshandle* dns = (dnshandle*)handle;
+ char hdrbuf[DNSREC_LEN];
+ int hdrbuf_remaining = DNSREC_LEN;
+ int rec_remaining = 0;
+ int readbuf_remaining;
+ char* dnsreq;
+ char* hdrstart;
+ int usingprev = 0;
+
+ wr = (write_req_t*) malloc(sizeof *wr);
+ wr->buf.base = (char*)malloc(WRITE_BUF_LEN);
+ wr->buf.len = 0;
+
+ if (dns->state.prevbuf_ptr != NULL) {
+ dnsreq = dns->state.prevbuf_ptr + dns->state.prevbuf_pos;
+ readbuf_remaining = dns->state.prevbuf_rem;
+ usingprev = 1;
+ } else {
+ dnsreq = buf->base;
+ readbuf_remaining = nread;
+ }
+ hdrstart = dnsreq;
+
+ while (dnsreq != NULL) {
+ /* something to process */
+ while (readbuf_remaining > 0) {
+ /* something to process in current buffer */
+ if (hdrbuf_remaining > 0) {
+ /* process len and id */
+ if (readbuf_remaining < hdrbuf_remaining) {
+ /* too little to get request header. save for next buffer */
+ memcpy(&hdrbuf[DNSREC_LEN - hdrbuf_remaining],
+ dnsreq,
+ readbuf_remaining);
+ hdrbuf_remaining = DNSREC_LEN - readbuf_remaining;
+ break;
+ } else {
+ /* save header */
+ memcpy(&hdrbuf[DNSREC_LEN - hdrbuf_remaining],
+ dnsreq,
+ hdrbuf_remaining);
+ dnsreq += hdrbuf_remaining;
+ readbuf_remaining -= hdrbuf_remaining;
+ hdrbuf_remaining = 0;
+
+ /* get record length */
+ rec_remaining = (unsigned) hdrbuf[0] * 256 + (unsigned) hdrbuf[1];
+ rec_remaining -= (DNSREC_LEN - 2);
+ }
+ }
+
+ if (rec_remaining <= readbuf_remaining) {
+ /* prepare reply */
+ addrsp(wr, hdrbuf);
+
+ /* move to next record */
+ dnsreq += rec_remaining;
+ hdrstart = dnsreq;
+ readbuf_remaining -= rec_remaining;
+ rec_remaining = 0;
+ hdrbuf_remaining = DNSREC_LEN;
+ } else {
+ /* otherwise this buffer is done. */
+ rec_remaining -= readbuf_remaining;
+ break;
+ }
+ }
+
+ /* If we had to use bytes from prev buffer, start processing the current
+ * one.
+ */
+ if (usingprev == 1) {
+ /* free previous buffer */
+ free(dns->state.prevbuf_ptr);
+ dnsreq = buf->base;
+ readbuf_remaining = nread;
+ usingprev = 0;
+ } else {
+ dnsreq = NULL;
+ }
+ }
+
+ /* send write buffer */
+ if (wr->buf.len > 0) {
+ if (uv_write((uv_write_t*) &wr->req, handle, &wr->buf, 1, after_write)) {
+ FATAL("uv_write failed");
+ }
+ }
+
+ if (readbuf_remaining > 0) {
+ /* save start of record position, so we can continue on next read */
+ dns->state.prevbuf_ptr = buf->base;
+ dns->state.prevbuf_pos = hdrstart - buf->base;
+ dns->state.prevbuf_rem = nread - dns->state.prevbuf_pos;
+ } else {
+ /* nothing left in this buffer */
+ dns->state.prevbuf_ptr = NULL;
+ dns->state.prevbuf_pos = 0;
+ dns->state.prevbuf_rem = 0;
+ free(buf->base);
+ }
+}
+
+static void after_read(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ uv_shutdown_t* req;
+
+ if (nread < 0) {
+ /* Error or EOF */
+ ASSERT(nread == UV_EOF);
+
+ if (buf->base) {
+ free(buf->base);
+ }
+
+ req = malloc(sizeof *req);
+ uv_shutdown(req, handle, after_shutdown);
+
+ return;
+ }
+
+ if (nread == 0) {
+ /* Everything OK, but nothing read. */
+ free(buf->base);
+ return;
+ }
+ /* process requests and send responses */
+ process_req(handle, nread, buf);
+}
+
+
+static void on_close(uv_handle_t* peer) {
+ free(peer);
+}
+
+
+static void buf_alloc(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ buf->base = malloc(suggested_size);
+ buf->len = suggested_size;
+}
+
+
+static void on_connection(uv_stream_t* server, int status) {
+ dnshandle* handle;
+ int r;
+
+ ASSERT(status == 0);
+
+ handle = (dnshandle*) malloc(sizeof *handle);
+ ASSERT(handle != NULL);
+
+ /* initialize read buffer state */
+ handle->state.prevbuf_ptr = 0;
+ handle->state.prevbuf_pos = 0;
+ handle->state.prevbuf_rem = 0;
+
+ r = uv_tcp_init(loop, (uv_tcp_t*)handle);
+ ASSERT(r == 0);
+
+ r = uv_accept(server, (uv_stream_t*)handle);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)handle, buf_alloc, after_read);
+ ASSERT(r == 0);
+}
+
+
+static int dns_start(int port) {
+ struct sockaddr_in addr;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", port, &addr));
+
+ r = uv_tcp_init(loop, &server);
+ if (r) {
+ /* TODO: Error codes */
+ fprintf(stderr, "Socket creation error\n");
+ return 1;
+ }
+
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+ if (r) {
+ /* TODO: Error codes */
+ fprintf(stderr, "Bind error\n");
+ return 1;
+ }
+
+ r = uv_listen((uv_stream_t*)&server, 128, on_connection);
+ if (r) {
+ /* TODO: Error codes */
+ fprintf(stderr, "Listen error\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+HELPER_IMPL(dns_server) {
+ loop = uv_default_loop();
+
+ if (dns_start(TEST_PORT_2))
+ return 1;
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ return 0;
+}
diff --git a/3rdparty/libuv/test/echo-server.c b/3rdparty/libuv/test/echo-server.c
new file mode 100644
index 00000000000..bfed67675dd
--- /dev/null
+++ b/3rdparty/libuv/test/echo-server.c
@@ -0,0 +1,378 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+typedef struct {
+ uv_write_t req;
+ uv_buf_t buf;
+} write_req_t;
+
+static uv_loop_t* loop;
+
+static int server_closed;
+static stream_type serverType;
+static uv_tcp_t tcpServer;
+static uv_udp_t udpServer;
+static uv_pipe_t pipeServer;
+static uv_handle_t* server;
+
+static void after_write(uv_write_t* req, int status);
+static void after_read(uv_stream_t*, ssize_t nread, const uv_buf_t* buf);
+static void on_close(uv_handle_t* peer);
+static void on_server_close(uv_handle_t* handle);
+static void on_connection(uv_stream_t*, int status);
+
+
+static void after_write(uv_write_t* req, int status) {
+ write_req_t* wr;
+
+ /* Free the read/write buffer and the request */
+ wr = (write_req_t*) req;
+ free(wr->buf.base);
+ free(wr);
+
+ if (status == 0)
+ return;
+
+ fprintf(stderr,
+ "uv_write error: %s - %s\n",
+ uv_err_name(status),
+ uv_strerror(status));
+}
+
+
+static void after_shutdown(uv_shutdown_t* req, int status) {
+ uv_close((uv_handle_t*) req->handle, on_close);
+ free(req);
+}
+
+
+static void after_read(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ int i;
+ write_req_t *wr;
+ uv_shutdown_t* sreq;
+
+ if (nread < 0) {
+ /* Error or EOF */
+ ASSERT(nread == UV_EOF);
+
+ free(buf->base);
+ sreq = malloc(sizeof* sreq);
+ ASSERT(0 == uv_shutdown(sreq, handle, after_shutdown));
+ return;
+ }
+
+ if (nread == 0) {
+ /* Everything OK, but nothing read. */
+ free(buf->base);
+ return;
+ }
+
+ /*
+ * Scan for the letter Q which signals that we should quit the server.
+ * If we get QS it means close the stream.
+ */
+ if (!server_closed) {
+ for (i = 0; i < nread; i++) {
+ if (buf->base[i] == 'Q') {
+ if (i + 1 < nread && buf->base[i + 1] == 'S') {
+ free(buf->base);
+ uv_close((uv_handle_t*)handle, on_close);
+ return;
+ } else {
+ uv_close(server, on_server_close);
+ server_closed = 1;
+ }
+ }
+ }
+ }
+
+ wr = (write_req_t*) malloc(sizeof *wr);
+ ASSERT(wr != NULL);
+ wr->buf = uv_buf_init(buf->base, nread);
+
+ if (uv_write(&wr->req, handle, &wr->buf, 1, after_write)) {
+ FATAL("uv_write failed");
+ }
+}
+
+
+static void on_close(uv_handle_t* peer) {
+ free(peer);
+}
+
+
+static void echo_alloc(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ buf->base = malloc(suggested_size);
+ buf->len = suggested_size;
+}
+
+
+static void on_connection(uv_stream_t* server, int status) {
+ uv_stream_t* stream;
+ int r;
+
+ if (status != 0) {
+ fprintf(stderr, "Connect error %s\n", uv_err_name(status));
+ }
+ ASSERT(status == 0);
+
+ switch (serverType) {
+ case TCP:
+ stream = malloc(sizeof(uv_tcp_t));
+ ASSERT(stream != NULL);
+ r = uv_tcp_init(loop, (uv_tcp_t*)stream);
+ ASSERT(r == 0);
+ break;
+
+ case PIPE:
+ stream = malloc(sizeof(uv_pipe_t));
+ ASSERT(stream != NULL);
+ r = uv_pipe_init(loop, (uv_pipe_t*)stream, 0);
+ ASSERT(r == 0);
+ break;
+
+ default:
+ ASSERT(0 && "Bad serverType");
+ abort();
+ }
+
+ /* associate server with stream */
+ stream->data = server;
+
+ r = uv_accept(server, stream);
+ ASSERT(r == 0);
+
+ r = uv_read_start(stream, echo_alloc, after_read);
+ ASSERT(r == 0);
+}
+
+
+static void on_server_close(uv_handle_t* handle) {
+ ASSERT(handle == server);
+}
+
+
+static void on_send(uv_udp_send_t* req, int status);
+
+
+static void on_recv(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* rcvbuf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ uv_udp_send_t* req;
+ uv_buf_t sndbuf;
+
+ ASSERT(nread > 0);
+ ASSERT(addr->sa_family == AF_INET);
+
+ req = malloc(sizeof(*req));
+ ASSERT(req != NULL);
+
+ sndbuf = *rcvbuf;
+ ASSERT(0 == uv_udp_send(req, handle, &sndbuf, 1, addr, on_send));
+}
+
+
+static void on_send(uv_udp_send_t* req, int status) {
+ ASSERT(status == 0);
+ free(req);
+}
+
+
+static int tcp4_echo_start(int port) {
+ struct sockaddr_in addr;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", port, &addr));
+
+ server = (uv_handle_t*)&tcpServer;
+ serverType = TCP;
+
+ r = uv_tcp_init(loop, &tcpServer);
+ if (r) {
+ /* TODO: Error codes */
+ fprintf(stderr, "Socket creation error\n");
+ return 1;
+ }
+
+ r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr, 0);
+ if (r) {
+ /* TODO: Error codes */
+ fprintf(stderr, "Bind error\n");
+ return 1;
+ }
+
+ r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection);
+ if (r) {
+ /* TODO: Error codes */
+ fprintf(stderr, "Listen error %s\n", uv_err_name(r));
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int tcp6_echo_start(int port) {
+ struct sockaddr_in6 addr6;
+ int r;
+
+ ASSERT(0 == uv_ip6_addr("::1", port, &addr6));
+
+ server = (uv_handle_t*)&tcpServer;
+ serverType = TCP;
+
+ r = uv_tcp_init(loop, &tcpServer);
+ if (r) {
+ /* TODO: Error codes */
+ fprintf(stderr, "Socket creation error\n");
+ return 1;
+ }
+
+ /* IPv6 is optional as not all platforms support it */
+ r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr6, 0);
+ if (r) {
+ /* show message but return OK */
+ fprintf(stderr, "IPv6 not supported\n");
+ return 0;
+ }
+
+ r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection);
+ if (r) {
+ /* TODO: Error codes */
+ fprintf(stderr, "Listen error\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int udp4_echo_start(int port) {
+ int r;
+
+ server = (uv_handle_t*)&udpServer;
+ serverType = UDP;
+
+ r = uv_udp_init(loop, &udpServer);
+ if (r) {
+ fprintf(stderr, "uv_udp_init: %s\n", uv_strerror(r));
+ return 1;
+ }
+
+ r = uv_udp_recv_start(&udpServer, echo_alloc, on_recv);
+ if (r) {
+ fprintf(stderr, "uv_udp_recv_start: %s\n", uv_strerror(r));
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int pipe_echo_start(char* pipeName) {
+ int r;
+
+#ifndef _WIN32
+ {
+ uv_fs_t req;
+ uv_fs_unlink(NULL, &req, pipeName, NULL);
+ uv_fs_req_cleanup(&req);
+ }
+#endif
+
+ server = (uv_handle_t*)&pipeServer;
+ serverType = PIPE;
+
+ r = uv_pipe_init(loop, &pipeServer, 0);
+ if (r) {
+ fprintf(stderr, "uv_pipe_init: %s\n", uv_strerror(r));
+ return 1;
+ }
+
+ r = uv_pipe_bind(&pipeServer, pipeName);
+ if (r) {
+ fprintf(stderr, "uv_pipe_bind: %s\n", uv_strerror(r));
+ return 1;
+ }
+
+ r = uv_listen((uv_stream_t*)&pipeServer, SOMAXCONN, on_connection);
+ if (r) {
+ fprintf(stderr, "uv_pipe_listen: %s\n", uv_strerror(r));
+ return 1;
+ }
+
+ return 0;
+}
+
+
+HELPER_IMPL(tcp4_echo_server) {
+ loop = uv_default_loop();
+
+ if (tcp4_echo_start(TEST_PORT))
+ return 1;
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ return 0;
+}
+
+
+HELPER_IMPL(tcp6_echo_server) {
+ loop = uv_default_loop();
+
+ if (tcp6_echo_start(TEST_PORT))
+ return 1;
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ return 0;
+}
+
+
+HELPER_IMPL(pipe_echo_server) {
+ loop = uv_default_loop();
+
+ if (pipe_echo_start(TEST_PIPENAME))
+ return 1;
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ return 0;
+}
+
+
+HELPER_IMPL(udp4_echo_server) {
+ loop = uv_default_loop();
+
+ if (udp4_echo_start(TEST_PORT))
+ return 1;
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ return 0;
+}
diff --git a/3rdparty/libuv/test/fixtures/empty_file b/3rdparty/libuv/test/fixtures/empty_file
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/3rdparty/libuv/test/fixtures/empty_file
diff --git a/3rdparty/libuv/test/fixtures/load_error.node b/3rdparty/libuv/test/fixtures/load_error.node
new file mode 100644
index 00000000000..323fae03f46
--- /dev/null
+++ b/3rdparty/libuv/test/fixtures/load_error.node
@@ -0,0 +1 @@
+foobar
diff --git a/3rdparty/libuv/test/run-benchmarks.c b/3rdparty/libuv/test/run-benchmarks.c
new file mode 100644
index 00000000000..6e42623d54c
--- /dev/null
+++ b/3rdparty/libuv/test/run-benchmarks.c
@@ -0,0 +1,65 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "runner.h"
+#include "task.h"
+
+/* Actual benchmarks and helpers are defined in benchmark-list.h */
+#include "benchmark-list.h"
+
+
+static int maybe_run_test(int argc, char **argv);
+
+
+int main(int argc, char **argv) {
+ if (platform_init(argc, argv))
+ return EXIT_FAILURE;
+
+ switch (argc) {
+ case 1: return run_tests(1);
+ case 2: return maybe_run_test(argc, argv);
+ case 3: return run_test_part(argv[1], argv[2]);
+ default:
+ fprintf(stderr, "Too many arguments.\n");
+ fflush(stderr);
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+
+static int maybe_run_test(int argc, char **argv) {
+ if (strcmp(argv[1], "--list") == 0) {
+ print_tests(stdout);
+ return 0;
+ }
+
+ if (strcmp(argv[1], "spawn_helper") == 0) {
+ printf("hello world\n");
+ return 42;
+ }
+
+ return run_test(argv[1], 1, 1);
+}
diff --git a/3rdparty/libuv/test/run-tests.c b/3rdparty/libuv/test/run-tests.c
new file mode 100644
index 00000000000..b4be01f6f95
--- /dev/null
+++ b/3rdparty/libuv/test/run-tests.c
@@ -0,0 +1,181 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef _WIN32
+# include <io.h>
+#else
+# include <unistd.h>
+#endif
+
+#include "uv.h"
+#include "runner.h"
+#include "task.h"
+
+/* Actual tests and helpers are defined in test-list.h */
+#include "test-list.h"
+
+int ipc_helper(int listen_after_write);
+int ipc_helper_tcp_connection(void);
+int ipc_send_recv_helper(void);
+int ipc_helper_bind_twice(void);
+int stdio_over_pipes_helper(void);
+int spawn_stdin_stdout(void);
+
+static int maybe_run_test(int argc, char **argv);
+
+
+int main(int argc, char **argv) {
+ if (platform_init(argc, argv))
+ return EXIT_FAILURE;
+
+ argv = uv_setup_args(argc, argv);
+
+ switch (argc) {
+ case 1: return run_tests(0);
+ case 2: return maybe_run_test(argc, argv);
+ case 3: return run_test_part(argv[1], argv[2]);
+ default:
+ fprintf(stderr, "Too many arguments.\n");
+ fflush(stderr);
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+
+static int maybe_run_test(int argc, char **argv) {
+ if (strcmp(argv[1], "--list") == 0) {
+ print_tests(stdout);
+ return 0;
+ }
+
+ if (strcmp(argv[1], "ipc_helper_listen_before_write") == 0) {
+ return ipc_helper(0);
+ }
+
+ if (strcmp(argv[1], "ipc_helper_listen_after_write") == 0) {
+ return ipc_helper(1);
+ }
+
+ if (strcmp(argv[1], "ipc_send_recv_helper") == 0) {
+ return ipc_send_recv_helper();
+ }
+
+ if (strcmp(argv[1], "ipc_helper_tcp_connection") == 0) {
+ return ipc_helper_tcp_connection();
+ }
+
+ if (strcmp(argv[1], "ipc_helper_bind_twice") == 0) {
+ return ipc_helper_bind_twice();
+ }
+
+ if (strcmp(argv[1], "stdio_over_pipes_helper") == 0) {
+ return stdio_over_pipes_helper();
+ }
+
+ if (strcmp(argv[1], "spawn_helper1") == 0) {
+ return 1;
+ }
+
+ if (strcmp(argv[1], "spawn_helper2") == 0) {
+ printf("hello world\n");
+ return 1;
+ }
+
+ if (strcmp(argv[1], "spawn_helper3") == 0) {
+ char buffer[256];
+ ASSERT(buffer == fgets(buffer, sizeof(buffer) - 1, stdin));
+ buffer[sizeof(buffer) - 1] = '\0';
+ fputs(buffer, stdout);
+ return 1;
+ }
+
+ if (strcmp(argv[1], "spawn_helper4") == 0) {
+ /* Never surrender, never return! */
+ while (1) uv_sleep(10000);
+ }
+
+ if (strcmp(argv[1], "spawn_helper5") == 0) {
+ const char out[] = "fourth stdio!\n";
+#ifdef _WIN32
+ DWORD bytes;
+ WriteFile((HANDLE) _get_osfhandle(3), out, sizeof(out) - 1, &bytes, NULL);
+#else
+ {
+ ssize_t r;
+
+ do
+ r = write(3, out, sizeof(out) - 1);
+ while (r == -1 && errno == EINTR);
+
+ fsync(3);
+ }
+#endif
+ return 1;
+ }
+
+ if (strcmp(argv[1], "spawn_helper6") == 0) {
+ int r;
+
+ r = fprintf(stdout, "hello world\n");
+ ASSERT(r > 0);
+
+ r = fprintf(stderr, "hello errworld\n");
+ ASSERT(r > 0);
+
+ return 1;
+ }
+
+ if (strcmp(argv[1], "spawn_helper7") == 0) {
+ int r;
+ char *test;
+ /* Test if the test value from the parent is still set */
+ test = getenv("ENV_TEST");
+ ASSERT(test != NULL);
+
+ r = fprintf(stdout, "%s", test);
+ ASSERT(r > 0);
+
+ return 1;
+ }
+
+#ifndef _WIN32
+ if (strcmp(argv[1], "spawn_helper8") == 0) {
+ int fd;
+ ASSERT(sizeof(fd) == read(0, &fd, sizeof(fd)));
+ ASSERT(fd > 2);
+ ASSERT(-1 == write(fd, "x", 1));
+
+ return 1;
+ }
+#endif /* !_WIN32 */
+
+ if (strcmp(argv[1], "spawn_helper9") == 0) {
+ return spawn_stdin_stdout();
+ }
+
+ return run_test(argv[1], 0, 1);
+}
diff --git a/3rdparty/libuv/test/runner-unix.c b/3rdparty/libuv/test/runner-unix.c
new file mode 100644
index 00000000000..2264d1e89d5
--- /dev/null
+++ b/3rdparty/libuv/test/runner-unix.c
@@ -0,0 +1,400 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "runner-unix.h"
+#include "runner.h"
+
+#include <limits.h>
+#include <stdint.h> /* uintptr_t */
+
+#include <errno.h>
+#include <unistd.h> /* readlink, usleep */
+#include <string.h> /* strdup */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <assert.h>
+
+#include <sys/select.h>
+#include <sys/time.h>
+#include <pthread.h>
+
+
+/* Do platform-specific initialization. */
+int platform_init(int argc, char **argv) {
+ const char* tap;
+
+ tap = getenv("UV_TAP_OUTPUT");
+ tap_output = (tap != NULL && atoi(tap) > 0);
+
+ /* Disable stdio output buffering. */
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+ signal(SIGPIPE, SIG_IGN);
+
+ if (realpath(argv[0], executable_path) == NULL) {
+ perror("realpath");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* Invoke "argv[0] test-name [test-part]". Store process info in *p. */
+/* Make sure that all stdio output of the processes is buffered up. */
+int process_start(char* name, char* part, process_info_t* p, int is_helper) {
+ FILE* stdout_file;
+ const char* arg;
+ char* args[16];
+ int n;
+ pid_t pid;
+
+ stdout_file = tmpfile();
+ if (!stdout_file) {
+ perror("tmpfile");
+ return -1;
+ }
+
+ p->terminated = 0;
+ p->status = 0;
+
+ pid = fork();
+
+ if (pid < 0) {
+ perror("fork");
+ return -1;
+ }
+
+ if (pid == 0) {
+ /* child */
+ arg = getenv("UV_USE_VALGRIND");
+ n = 0;
+
+ /* Disable valgrind for helpers, it complains about helpers leaking memory.
+ * They're killed after the test and as such never get a chance to clean up.
+ */
+ if (is_helper == 0 && arg != NULL && atoi(arg) != 0) {
+ args[n++] = "valgrind";
+ args[n++] = "--quiet";
+ args[n++] = "--leak-check=full";
+ args[n++] = "--show-reachable=yes";
+ args[n++] = "--error-exitcode=125";
+ }
+
+ args[n++] = executable_path;
+ args[n++] = name;
+ args[n++] = part;
+ args[n++] = NULL;
+
+ dup2(fileno(stdout_file), STDOUT_FILENO);
+ dup2(fileno(stdout_file), STDERR_FILENO);
+ execvp(args[0], args);
+ perror("execvp()");
+ _exit(127);
+ }
+
+ /* parent */
+ p->pid = pid;
+ p->name = strdup(name);
+ p->stdout_file = stdout_file;
+
+ return 0;
+}
+
+
+typedef struct {
+ int pipe[2];
+ process_info_t* vec;
+ int n;
+} dowait_args;
+
+
+/* This function is run inside a pthread. We do this so that we can possibly
+ * timeout.
+ */
+static void* dowait(void* data) {
+ dowait_args* args = data;
+
+ int i, r;
+ process_info_t* p;
+
+ for (i = 0; i < args->n; i++) {
+ p = (process_info_t*)(args->vec + i * sizeof(process_info_t));
+ if (p->terminated) continue;
+ r = waitpid(p->pid, &p->status, 0);
+ if (r < 0) {
+ perror("waitpid");
+ return NULL;
+ }
+ p->terminated = 1;
+ }
+
+ if (args->pipe[1] >= 0) {
+ /* Write a character to the main thread to notify it about this. */
+ ssize_t r;
+
+ do
+ r = write(args->pipe[1], "", 1);
+ while (r == -1 && errno == EINTR);
+ }
+
+ return NULL;
+}
+
+
+/* Wait for all `n` processes in `vec` to terminate. */
+/* Time out after `timeout` msec, or never if timeout == -1 */
+/* Return 0 if all processes are terminated, -1 on error, -2 on timeout. */
+int process_wait(process_info_t* vec, int n, int timeout) {
+ int i;
+ int r;
+ int retval;
+ process_info_t* p;
+ dowait_args args;
+ pthread_t tid;
+ pthread_attr_t attr;
+ unsigned int elapsed_ms;
+ struct timeval timebase;
+ struct timeval tv;
+ fd_set fds;
+
+ args.vec = vec;
+ args.n = n;
+ args.pipe[0] = -1;
+ args.pipe[1] = -1;
+
+ /* The simple case is where there is no timeout */
+ if (timeout == -1) {
+ dowait(&args);
+ return 0;
+ }
+
+ /* Hard case. Do the wait with a timeout.
+ *
+ * Assumption: we are the only ones making this call right now. Otherwise
+ * we'd need to lock vec.
+ */
+
+ r = pipe((int*)&(args.pipe));
+ if (r) {
+ perror("pipe()");
+ return -1;
+ }
+
+ if (pthread_attr_init(&attr))
+ abort();
+
+ if (pthread_attr_setstacksize(&attr, 256 * 1024))
+ abort();
+
+ r = pthread_create(&tid, &attr, dowait, &args);
+
+ if (pthread_attr_destroy(&attr))
+ abort();
+
+ if (r) {
+ perror("pthread_create()");
+ retval = -1;
+ goto terminate;
+ }
+
+ if (gettimeofday(&timebase, NULL))
+ abort();
+
+ tv = timebase;
+ for (;;) {
+ /* Check that gettimeofday() doesn't jump back in time. */
+ assert(tv.tv_sec == timebase.tv_sec ||
+ (tv.tv_sec == timebase.tv_sec && tv.tv_usec >= timebase.tv_usec));
+
+ elapsed_ms =
+ (tv.tv_sec - timebase.tv_sec) * 1000 +
+ (tv.tv_usec / 1000) -
+ (timebase.tv_usec / 1000);
+
+ r = 0; /* Timeout. */
+ if (elapsed_ms >= (unsigned) timeout)
+ break;
+
+ tv.tv_sec = (timeout - elapsed_ms) / 1000;
+ tv.tv_usec = (timeout - elapsed_ms) % 1000 * 1000;
+
+ FD_ZERO(&fds);
+ FD_SET(args.pipe[0], &fds);
+
+ r = select(args.pipe[0] + 1, &fds, NULL, NULL, &tv);
+ if (!(r == -1 && errno == EINTR))
+ break;
+
+ if (gettimeofday(&tv, NULL))
+ abort();
+ }
+
+ if (r == -1) {
+ perror("select()");
+ retval = -1;
+
+ } else if (r) {
+ /* The thread completed successfully. */
+ retval = 0;
+
+ } else {
+ /* Timeout. Kill all the children. */
+ for (i = 0; i < n; i++) {
+ p = (process_info_t*)(vec + i * sizeof(process_info_t));
+ kill(p->pid, SIGTERM);
+ }
+ retval = -2;
+ }
+
+ if (pthread_join(tid, NULL))
+ abort();
+
+terminate:
+ close(args.pipe[0]);
+ close(args.pipe[1]);
+ return retval;
+}
+
+
+/* Returns the number of bytes in the stdio output buffer for process `p`. */
+long int process_output_size(process_info_t *p) {
+ /* Size of the p->stdout_file */
+ struct stat buf;
+
+ int r = fstat(fileno(p->stdout_file), &buf);
+ if (r < 0) {
+ return -1;
+ }
+
+ return (long)buf.st_size;
+}
+
+
+/* Copy the contents of the stdio output buffer to `fd`. */
+int process_copy_output(process_info_t *p, int fd) {
+ ssize_t nwritten;
+ char buf[1024];
+ int r;
+
+ r = fseek(p->stdout_file, 0, SEEK_SET);
+ if (r < 0) {
+ perror("fseek");
+ return -1;
+ }
+
+ /* TODO: what if the line is longer than buf */
+ while (fgets(buf, sizeof(buf), p->stdout_file) != NULL) {
+ /* TODO: what if write doesn't write the whole buffer... */
+ nwritten = 0;
+
+ if (tap_output)
+ nwritten += write(fd, "#", 1);
+
+ nwritten += write(fd, buf, strlen(buf));
+
+ if (nwritten < 0) {
+ perror("write");
+ return -1;
+ }
+ }
+
+ if (ferror(p->stdout_file)) {
+ perror("read");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* Copy the last line of the stdio output buffer to `buffer` */
+int process_read_last_line(process_info_t *p,
+ char* buffer,
+ size_t buffer_len) {
+ char* ptr;
+
+ int r = fseek(p->stdout_file, 0, SEEK_SET);
+ if (r < 0) {
+ perror("fseek");
+ return -1;
+ }
+
+ buffer[0] = '\0';
+
+ while (fgets(buffer, buffer_len, p->stdout_file) != NULL) {
+ for (ptr = buffer; *ptr && *ptr != '\r' && *ptr != '\n'; ptr++);
+ *ptr = '\0';
+ }
+
+ if (ferror(p->stdout_file)) {
+ perror("read");
+ buffer[0] = '\0';
+ return -1;
+ }
+ return 0;
+}
+
+
+/* Return the name that was specified when `p` was started by process_start */
+char* process_get_name(process_info_t *p) {
+ return p->name;
+}
+
+
+/* Terminate process `p`. */
+int process_terminate(process_info_t *p) {
+ return kill(p->pid, SIGTERM);
+}
+
+
+/* Return the exit code of process p. */
+/* On error, return -1. */
+int process_reap(process_info_t *p) {
+ if (WIFEXITED(p->status)) {
+ return WEXITSTATUS(p->status);
+ } else {
+ return p->status; /* ? */
+ }
+}
+
+
+/* Clean up after terminating process `p` (e.g. free the output buffer etc.). */
+void process_cleanup(process_info_t *p) {
+ fclose(p->stdout_file);
+ free(p->name);
+}
+
+
+/* Move the console cursor one line up and back to the first column. */
+void rewind_cursor(void) {
+ fprintf(stderr, "\033[2K\r");
+}
+
+
+/* Pause the calling thread for a number of milliseconds. */
+void uv_sleep(int msec) {
+ usleep(msec * 1000);
+}
diff --git a/3rdparty/libuv/test/runner-unix.h b/3rdparty/libuv/test/runner-unix.h
new file mode 100644
index 00000000000..e21847f92c0
--- /dev/null
+++ b/3rdparty/libuv/test/runner-unix.h
@@ -0,0 +1,36 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef TEST_RUNNER_UNIX_H
+#define TEST_RUNNER_UNIX_H
+
+#include <sys/types.h>
+#include <stdio.h> /* FILE */
+
+typedef struct {
+ FILE* stdout_file;
+ pid_t pid;
+ char* name;
+ int status;
+ int terminated;
+} process_info_t;
+
+#endif /* TEST_RUNNER_UNIX_H */
diff --git a/3rdparty/libuv/test/runner-win.c b/3rdparty/libuv/test/runner-win.c
new file mode 100644
index 00000000000..97ef7599eb8
--- /dev/null
+++ b/3rdparty/libuv/test/runner-win.c
@@ -0,0 +1,371 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <fcntl.h>
+#include <io.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <process.h>
+#if !defined(__MINGW32__)
+# include <crtdbg.h>
+#endif
+
+
+#include "task.h"
+#include "runner.h"
+
+
+/*
+ * Define the stuff that MinGW doesn't have
+ */
+#ifndef GetFileSizeEx
+ WINBASEAPI BOOL WINAPI GetFileSizeEx(HANDLE hFile,
+ PLARGE_INTEGER lpFileSize);
+#endif
+
+
+/* Do platform-specific initialization. */
+int platform_init(int argc, char **argv) {
+ const char* tap;
+
+ tap = getenv("UV_TAP_OUTPUT");
+ tap_output = (tap != NULL && atoi(tap) > 0);
+
+ /* Disable the "application crashed" popup. */
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
+ SEM_NOOPENFILEERRORBOX);
+#if !defined(__MINGW32__)
+ _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
+ _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
+#endif
+
+ _setmode(0, _O_BINARY);
+ _setmode(1, _O_BINARY);
+ _setmode(2, _O_BINARY);
+
+ /* Disable stdio output buffering. */
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ strcpy(executable_path, argv[0]);
+
+ return 0;
+}
+
+
+int process_start(char *name, char *part, process_info_t *p, int is_helper) {
+ HANDLE file = INVALID_HANDLE_VALUE;
+ HANDLE nul = INVALID_HANDLE_VALUE;
+ WCHAR path[MAX_PATH], filename[MAX_PATH];
+ WCHAR image[MAX_PATH + 1];
+ WCHAR args[MAX_PATH * 2];
+ STARTUPINFOW si;
+ PROCESS_INFORMATION pi;
+ DWORD result;
+
+ if (GetTempPathW(sizeof(path) / sizeof(WCHAR), (WCHAR*)&path) == 0)
+ goto error;
+ if (GetTempFileNameW((WCHAR*)&path, L"uv", 0, (WCHAR*)&filename) == 0)
+ goto error;
+
+ file = CreateFileW((WCHAR*)filename,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
+ NULL);
+ if (file == INVALID_HANDLE_VALUE)
+ goto error;
+
+ if (!SetHandleInformation(file, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
+ goto error;
+
+ nul = CreateFileA("nul",
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (nul == INVALID_HANDLE_VALUE)
+ goto error;
+
+ if (!SetHandleInformation(nul, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
+ goto error;
+
+ result = GetModuleFileNameW(NULL,
+ (WCHAR*) &image,
+ sizeof(image) / sizeof(WCHAR));
+ if (result == 0 || result == sizeof(image))
+ goto error;
+
+ if (part) {
+ if (_snwprintf((WCHAR*)args,
+ sizeof(args) / sizeof(WCHAR),
+ L"\"%s\" %S %S",
+ image,
+ name,
+ part) < 0) {
+ goto error;
+ }
+ } else {
+ if (_snwprintf((WCHAR*)args,
+ sizeof(args) / sizeof(WCHAR),
+ L"\"%s\" %S",
+ image,
+ name) < 0) {
+ goto error;
+ }
+ }
+
+ memset((void*)&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESTDHANDLES;
+ si.hStdInput = nul;
+ si.hStdOutput = file;
+ si.hStdError = file;
+
+ if (!CreateProcessW(image, args, NULL, NULL, TRUE,
+ 0, NULL, NULL, &si, &pi))
+ goto error;
+
+ CloseHandle(pi.hThread);
+
+ SetHandleInformation(nul, HANDLE_FLAG_INHERIT, 0);
+ SetHandleInformation(file, HANDLE_FLAG_INHERIT, 0);
+
+ p->stdio_in = nul;
+ p->stdio_out = file;
+ p->process = pi.hProcess;
+ p->name = part;
+
+ return 0;
+
+error:
+ if (file != INVALID_HANDLE_VALUE)
+ CloseHandle(file);
+ if (nul != INVALID_HANDLE_VALUE)
+ CloseHandle(nul);
+
+ return -1;
+}
+
+
+/* Timeout is is msecs. Set timeout < 0 to never time out. */
+/* Returns 0 when all processes are terminated, -2 on timeout. */
+int process_wait(process_info_t *vec, int n, int timeout) {
+ int i;
+ HANDLE handles[MAXIMUM_WAIT_OBJECTS];
+ DWORD timeout_api, result;
+
+ /* If there's nothing to wait for, return immediately. */
+ if (n == 0)
+ return 0;
+
+ ASSERT(n <= MAXIMUM_WAIT_OBJECTS);
+
+ for (i = 0; i < n; i++)
+ handles[i] = vec[i].process;
+
+ if (timeout >= 0) {
+ timeout_api = (DWORD)timeout;
+ } else {
+ timeout_api = INFINITE;
+ }
+
+ result = WaitForMultipleObjects(n, handles, TRUE, timeout_api);
+
+ if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + n) {
+ /* All processes are terminated. */
+ return 0;
+ }
+ if (result == WAIT_TIMEOUT) {
+ return -2;
+ }
+ return -1;
+}
+
+
+long int process_output_size(process_info_t *p) {
+ LARGE_INTEGER size;
+ if (!GetFileSizeEx(p->stdio_out, &size))
+ return -1;
+ return (long int)size.QuadPart;
+}
+
+
+int process_copy_output(process_info_t *p, int fd) {
+ DWORD read;
+ char buf[1024];
+ char *line, *start;
+
+ if (SetFilePointer(p->stdio_out,
+ 0,
+ 0,
+ FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
+ return -1;
+ }
+
+ if (tap_output)
+ write(fd, "#", 1);
+
+ while (ReadFile(p->stdio_out, (void*)&buf, sizeof(buf), &read, NULL) &&
+ read > 0) {
+ if (tap_output) {
+ start = buf;
+
+ while ((line = strchr(start, '\n')) != NULL) {
+ write(fd, start, line - start + 1);
+ write(fd, "#", 1);
+ start = line + 1;
+ }
+
+ if (start < buf + read)
+ write(fd, start, buf + read - start);
+ } else {
+ write(fd, buf, read);
+ }
+ }
+
+ if (tap_output)
+ write(fd, "\n", 1);
+
+ if (GetLastError() != ERROR_HANDLE_EOF)
+ return -1;
+
+ return 0;
+}
+
+
+int process_read_last_line(process_info_t *p,
+ char * buffer,
+ size_t buffer_len) {
+ DWORD size;
+ DWORD read;
+ DWORD start;
+ OVERLAPPED overlapped;
+
+ ASSERT(buffer_len > 0);
+
+ size = GetFileSize(p->stdio_out, NULL);
+ if (size == INVALID_FILE_SIZE)
+ return -1;
+
+ if (size == 0) {
+ buffer[0] = '\0';
+ return 1;
+ }
+
+ memset(&overlapped, 0, sizeof overlapped);
+ if (size >= buffer_len)
+ overlapped.Offset = size - buffer_len - 1;
+
+ if (!ReadFile(p->stdio_out, buffer, buffer_len - 1, &read, &overlapped))
+ return -1;
+
+ for (start = read - 1; start >= 0; start--) {
+ if (buffer[start] == '\n' || buffer[start] == '\r')
+ break;
+ }
+
+ if (start > 0)
+ memmove(buffer, buffer + start, read - start);
+
+ buffer[read - start] = '\0';
+
+ return 0;
+}
+
+
+char* process_get_name(process_info_t *p) {
+ return p->name;
+}
+
+
+int process_terminate(process_info_t *p) {
+ if (!TerminateProcess(p->process, 1))
+ return -1;
+ return 0;
+}
+
+
+int process_reap(process_info_t *p) {
+ DWORD exitCode;
+ if (!GetExitCodeProcess(p->process, &exitCode))
+ return -1;
+ return (int)exitCode;
+}
+
+
+void process_cleanup(process_info_t *p) {
+ CloseHandle(p->process);
+ CloseHandle(p->stdio_in);
+ CloseHandle(p->stdio_out);
+}
+
+
+static int clear_line() {
+ HANDLE handle;
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ COORD coord;
+ DWORD written;
+
+ handle = (HANDLE)_get_osfhandle(fileno(stderr));
+ if (handle == INVALID_HANDLE_VALUE)
+ return -1;
+
+ if (!GetConsoleScreenBufferInfo(handle, &info))
+ return -1;
+
+ coord = info.dwCursorPosition;
+ if (coord.Y <= 0)
+ return -1;
+
+ coord.X = 0;
+
+ if (!SetConsoleCursorPosition(handle, coord))
+ return -1;
+
+ if (!FillConsoleOutputCharacterW(handle,
+ 0x20,
+ info.dwSize.X,
+ coord,
+ &written)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void rewind_cursor() {
+ if (clear_line() == -1) {
+ /* If clear_line fails (stdout is not a console), print a newline. */
+ fprintf(stderr, "\n");
+ }
+}
+
+
+/* Pause the calling thread for a number of milliseconds. */
+void uv_sleep(int msec) {
+ Sleep(msec);
+}
diff --git a/3rdparty/libuv/test/runner-win.h b/3rdparty/libuv/test/runner-win.h
new file mode 100644
index 00000000000..8cc4c16eb22
--- /dev/null
+++ b/3rdparty/libuv/test/runner-win.h
@@ -0,0 +1,39 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* Don't complain about write(), fileno() etc. being deprecated. */
+#pragma warning(disable : 4996)
+
+
+#include <winsock2.h>
+#include <windows.h>
+#include <stdio.h>
+
+#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900
+extern int snprintf(char*, size_t, const char*, ...);
+#endif
+
+typedef struct {
+ HANDLE process;
+ HANDLE stdio_in;
+ HANDLE stdio_out;
+ char *name;
+} process_info_t;
diff --git a/3rdparty/libuv/test/runner.c b/3rdparty/libuv/test/runner.c
new file mode 100644
index 00000000000..c616d176445
--- /dev/null
+++ b/3rdparty/libuv/test/runner.c
@@ -0,0 +1,466 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "runner.h"
+#include "task.h"
+#include "uv.h"
+
+char executable_path[sizeof(executable_path)];
+
+int tap_output = 0;
+
+
+static void log_progress(int total,
+ int passed,
+ int failed,
+ int todos,
+ int skipped,
+ const char* name) {
+ int progress;
+
+ if (total == 0)
+ total = 1;
+
+ progress = 100 * (passed + failed + skipped + todos) / total;
+ fprintf(stderr, "[%% %3d|+ %3d|- %3d|T %3d|S %3d]: %s",
+ progress,
+ passed,
+ failed,
+ todos,
+ skipped,
+ name);
+ fflush(stderr);
+}
+
+
+const char* fmt(double d) {
+ static char buf[1024];
+ static char* p;
+ uint64_t v;
+
+ if (p == NULL)
+ p = buf;
+
+ p += 31;
+
+ if (p >= buf + sizeof(buf))
+ return "<buffer too small>";
+
+ v = (uint64_t) d;
+
+#if 0 /* works but we don't care about fractional precision */
+ if (d - v >= 0.01) {
+ *--p = '0' + (uint64_t) (d * 100) % 10;
+ *--p = '0' + (uint64_t) (d * 10) % 10;
+ *--p = '.';
+ }
+#endif
+
+ if (v == 0)
+ *--p = '0';
+
+ while (v) {
+ if (v) *--p = '0' + (v % 10), v /= 10;
+ if (v) *--p = '0' + (v % 10), v /= 10;
+ if (v) *--p = '0' + (v % 10), v /= 10;
+ if (v) *--p = ',';
+ }
+
+ return p;
+}
+
+
+int run_tests(int benchmark_output) {
+ int total;
+ int passed;
+ int failed;
+ int todos;
+ int skipped;
+ int current;
+ int test_result;
+ task_entry_t* task;
+
+ /* Count the number of tests. */
+ total = 0;
+ for (task = TASKS; task->main; task++) {
+ if (!task->is_helper) {
+ total++;
+ }
+ }
+
+ if (tap_output) {
+ fprintf(stderr, "1..%d\n", total);
+ fflush(stderr);
+ }
+
+ /* Run all tests. */
+ passed = 0;
+ failed = 0;
+ todos = 0;
+ skipped = 0;
+ current = 1;
+ for (task = TASKS; task->main; task++) {
+ if (task->is_helper) {
+ continue;
+ }
+
+ if (!tap_output)
+ rewind_cursor();
+
+ if (!benchmark_output && !tap_output) {
+ log_progress(total, passed, failed, todos, skipped, task->task_name);
+ }
+
+ test_result = run_test(task->task_name, benchmark_output, current);
+ switch (test_result) {
+ case TEST_OK: passed++; break;
+ case TEST_TODO: todos++; break;
+ case TEST_SKIP: skipped++; break;
+ default: failed++;
+ }
+ current++;
+ }
+
+ if (!tap_output)
+ rewind_cursor();
+
+ if (!benchmark_output && !tap_output) {
+ log_progress(total, passed, failed, todos, skipped, "Done.\n");
+ }
+
+ return failed;
+}
+
+
+void log_tap_result(int test_count,
+ const char* test,
+ int status,
+ process_info_t* process) {
+ const char* result;
+ const char* directive;
+ char reason[1024];
+
+ switch (status) {
+ case TEST_OK:
+ result = "ok";
+ directive = "";
+ break;
+ case TEST_TODO:
+ result = "not ok";
+ directive = " # TODO ";
+ break;
+ case TEST_SKIP:
+ result = "ok";
+ directive = " # SKIP ";
+ break;
+ default:
+ result = "not ok";
+ directive = "";
+ }
+
+ if ((status == TEST_SKIP || status == TEST_TODO) &&
+ process_output_size(process) > 0) {
+ process_read_last_line(process, reason, sizeof reason);
+ } else {
+ reason[0] = '\0';
+ }
+
+ fprintf(stderr, "%s %d - %s%s%s\n", result, test_count, test, directive, reason);
+ fflush(stderr);
+}
+
+
+int run_test(const char* test,
+ int benchmark_output,
+ int test_count) {
+ char errmsg[1024] = "no error";
+ process_info_t processes[1024];
+ process_info_t *main_proc;
+ task_entry_t* task;
+ int process_count;
+ int result;
+ int status;
+ int i;
+
+ status = 255;
+ main_proc = NULL;
+ process_count = 0;
+
+#ifndef _WIN32
+ /* Clean up stale socket from previous run. */
+ remove(TEST_PIPENAME);
+ remove(TEST_PIPENAME_2);
+ remove(TEST_PIPENAME_3);
+#endif
+
+ /* If it's a helper the user asks for, start it directly. */
+ for (task = TASKS; task->main; task++) {
+ if (task->is_helper && strcmp(test, task->process_name) == 0) {
+ return task->main();
+ }
+ }
+
+ /* Start the helpers first. */
+ for (task = TASKS; task->main; task++) {
+ if (strcmp(test, task->task_name) != 0) {
+ continue;
+ }
+
+ /* Skip the test itself. */
+ if (!task->is_helper) {
+ continue;
+ }
+
+ if (process_start(task->task_name,
+ task->process_name,
+ &processes[process_count],
+ 1 /* is_helper */) == -1) {
+ snprintf(errmsg,
+ sizeof errmsg,
+ "Process `%s` failed to start.",
+ task->process_name);
+ goto out;
+ }
+
+ process_count++;
+ }
+
+ /* Give the helpers time to settle. Race-y, fix this. */
+ uv_sleep(250);
+
+ /* Now start the test itself. */
+ for (task = TASKS; task->main; task++) {
+ if (strcmp(test, task->task_name) != 0) {
+ continue;
+ }
+
+ if (task->is_helper) {
+ continue;
+ }
+
+ if (process_start(task->task_name,
+ task->process_name,
+ &processes[process_count],
+ 0 /* !is_helper */) == -1) {
+ snprintf(errmsg,
+ sizeof errmsg,
+ "Process `%s` failed to start.",
+ task->process_name);
+ goto out;
+ }
+
+ main_proc = &processes[process_count];
+ process_count++;
+ break;
+ }
+
+ if (main_proc == NULL) {
+ snprintf(errmsg,
+ sizeof errmsg,
+ "No test with that name: %s",
+ test);
+ goto out;
+ }
+
+ result = process_wait(main_proc, 1, task->timeout);
+ if (result == -1) {
+ FATAL("process_wait failed");
+ } else if (result == -2) {
+ /* Don't have to clean up the process, process_wait() has killed it. */
+ snprintf(errmsg,
+ sizeof errmsg,
+ "timeout");
+ goto out;
+ }
+
+ status = process_reap(main_proc);
+ if (status != TEST_OK) {
+ snprintf(errmsg,
+ sizeof errmsg,
+ "exit code %d",
+ status);
+ goto out;
+ }
+
+ if (benchmark_output) {
+ /* Give the helpers time to clean up their act. */
+ uv_sleep(1000);
+ }
+
+out:
+ /* Reap running processes except the main process, it's already dead. */
+ for (i = 0; i < process_count - 1; i++) {
+ process_terminate(&processes[i]);
+ }
+
+ if (process_count > 0 &&
+ process_wait(processes, process_count - 1, -1) < 0) {
+ FATAL("process_wait failed");
+ }
+
+ if (tap_output)
+ log_tap_result(test_count, test, status, &processes[i]);
+
+ /* Show error and output from processes if the test failed. */
+ if (status != 0 || task->show_output) {
+ if (tap_output) {
+ fprintf(stderr, "#");
+ } else if (status == TEST_TODO) {
+ fprintf(stderr, "\n`%s` todo\n", test);
+ } else if (status == TEST_SKIP) {
+ fprintf(stderr, "\n`%s` skipped\n", test);
+ } else if (status != 0) {
+ fprintf(stderr, "\n`%s` failed: %s\n", test, errmsg);
+ } else {
+ fprintf(stderr, "\n");
+ }
+ fflush(stderr);
+
+ for (i = 0; i < process_count; i++) {
+ switch (process_output_size(&processes[i])) {
+ case -1:
+ fprintf(stderr, "Output from process `%s`: (unavailable)\n",
+ process_get_name(&processes[i]));
+ fflush(stderr);
+ break;
+
+ case 0:
+ fprintf(stderr, "Output from process `%s`: (no output)\n",
+ process_get_name(&processes[i]));
+ fflush(stderr);
+ break;
+
+ default:
+ fprintf(stderr, "Output from process `%s`:\n", process_get_name(&processes[i]));
+ fflush(stderr);
+ process_copy_output(&processes[i], fileno(stderr));
+ break;
+ }
+ }
+
+ if (!tap_output) {
+ fprintf(stderr, "=============================================================\n");
+ }
+
+ /* In benchmark mode show concise output from the main process. */
+ } else if (benchmark_output) {
+ switch (process_output_size(main_proc)) {
+ case -1:
+ fprintf(stderr, "%s: (unavailable)\n", test);
+ fflush(stderr);
+ break;
+
+ case 0:
+ fprintf(stderr, "%s: (no output)\n", test);
+ fflush(stderr);
+ break;
+
+ default:
+ for (i = 0; i < process_count; i++) {
+ process_copy_output(&processes[i], fileno(stderr));
+ }
+ break;
+ }
+ }
+
+ /* Clean up all process handles. */
+ for (i = 0; i < process_count; i++) {
+ process_cleanup(&processes[i]);
+ }
+
+ return status;
+}
+
+
+/* Returns the status code of the task part
+ * or 255 if no matching task was not found.
+ */
+int run_test_part(const char* test, const char* part) {
+ task_entry_t* task;
+ int r;
+
+ for (task = TASKS; task->main; task++) {
+ if (strcmp(test, task->task_name) == 0 &&
+ strcmp(part, task->process_name) == 0) {
+ r = task->main();
+ return r;
+ }
+ }
+
+ fprintf(stderr, "No test part with that name: %s:%s\n", test, part);
+ fflush(stderr);
+ return 255;
+}
+
+
+static int compare_task(const void* va, const void* vb) {
+ const task_entry_t* a = va;
+ const task_entry_t* b = vb;
+ return strcmp(a->task_name, b->task_name);
+}
+
+
+static int find_helpers(const task_entry_t* task,
+ const task_entry_t** helpers) {
+ const task_entry_t* helper;
+ int n_helpers;
+
+ for (n_helpers = 0, helper = TASKS; helper->main; helper++) {
+ if (helper->is_helper && strcmp(helper->task_name, task->task_name) == 0) {
+ *helpers++ = helper;
+ n_helpers++;
+ }
+ }
+
+ return n_helpers;
+}
+
+
+void print_tests(FILE* stream) {
+ const task_entry_t* helpers[1024];
+ const task_entry_t* task;
+ int n_helpers;
+ int n_tasks;
+ int i;
+
+ for (n_tasks = 0, task = TASKS; task->main; n_tasks++, task++);
+ qsort(TASKS, n_tasks, sizeof(TASKS[0]), compare_task);
+
+ for (task = TASKS; task->main; task++) {
+ if (task->is_helper) {
+ continue;
+ }
+
+ n_helpers = find_helpers(task, helpers);
+ if (n_helpers) {
+ printf("%-25s (helpers:", task->task_name);
+ for (i = 0; i < n_helpers; i++) {
+ printf(" %s", helpers[i]->process_name);
+ }
+ printf(")\n");
+ } else {
+ printf("%s\n", task->task_name);
+ }
+ }
+}
diff --git a/3rdparty/libuv/test/runner.h b/3rdparty/libuv/test/runner.h
new file mode 100644
index 00000000000..78f3c880a98
--- /dev/null
+++ b/3rdparty/libuv/test/runner.h
@@ -0,0 +1,178 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef RUNNER_H_
+#define RUNNER_H_
+
+#include <limits.h> /* PATH_MAX */
+#include <stdio.h> /* FILE */
+
+
+/*
+ * The maximum number of processes (main + helpers) that a test / benchmark
+ * can have.
+ */
+#define MAX_PROCESSES 8
+
+
+/*
+ * Struct to store both tests and to define helper processes for tasks.
+ */
+typedef struct {
+ char *task_name;
+ char *process_name;
+ int (*main)(void);
+ int is_helper;
+ int show_output;
+
+ /*
+ * The time in milliseconds after which a single test or benchmark times out.
+ */
+ int timeout;
+} task_entry_t, bench_entry_t;
+
+
+/*
+ * Macros used by test-list.h and benchmark-list.h.
+ */
+#define TASK_LIST_START \
+ task_entry_t TASKS[] = {
+
+#define TASK_LIST_END \
+ { 0, 0, 0, 0, 0, 0 } \
+ };
+
+#define TEST_DECLARE(name) \
+ int run_test_##name(void);
+
+#define TEST_ENTRY(name) \
+ { #name, #name, &run_test_##name, 0, 0, 5000 },
+
+#define TEST_ENTRY_CUSTOM(name, is_helper, show_output, timeout) \
+ { #name, #name, &run_test_##name, is_helper, show_output, timeout },
+
+#define BENCHMARK_DECLARE(name) \
+ int run_benchmark_##name(void);
+
+#define BENCHMARK_ENTRY(name) \
+ { #name, #name, &run_benchmark_##name, 0, 0, 60000 },
+
+#define HELPER_DECLARE(name) \
+ int run_helper_##name(void);
+
+#define HELPER_ENTRY(task_name, name) \
+ { #task_name, #name, &run_helper_##name, 1, 0, 0 },
+
+#define TEST_HELPER HELPER_ENTRY
+#define BENCHMARK_HELPER HELPER_ENTRY
+
+#ifdef PATH_MAX
+extern char executable_path[PATH_MAX];
+#else
+extern char executable_path[4096];
+#endif
+
+/*
+ * Include platform-dependent definitions
+ */
+#ifdef _WIN32
+# include "runner-win.h"
+#else
+# include "runner-unix.h"
+#endif
+
+
+/* The array that is filled by test-list.h or benchmark-list.h */
+extern task_entry_t TASKS[];
+
+/*
+ * Run all tests.
+ */
+int run_tests(int benchmark_output);
+
+/*
+ * Run a single test. Starts up any helpers.
+ */
+int run_test(const char* test,
+ int benchmark_output,
+ int test_count);
+
+/*
+ * Run a test part, i.e. the test or one of its helpers.
+ */
+int run_test_part(const char* test, const char* part);
+
+
+/*
+ * Print tests in sorted order to `stream`. Used by `./run-tests --list`.
+ */
+void print_tests(FILE* stream);
+
+
+/*
+ * Stuff that should be implemented by test-runner-<platform>.h
+ * All functions return 0 on success, -1 on failure, unless specified
+ * otherwise.
+ */
+
+/* Do platform-specific initialization. */
+int platform_init(int argc, char** argv);
+
+/* Invoke "argv[0] test-name [test-part]". Store process info in *p. */
+/* Make sure that all stdio output of the processes is buffered up. */
+int process_start(char *name, char* part, process_info_t *p, int is_helper);
+
+/* Wait for all `n` processes in `vec` to terminate. */
+/* Time out after `timeout` msec, or never if timeout == -1 */
+/* Return 0 if all processes are terminated, -1 on error, -2 on timeout. */
+int process_wait(process_info_t *vec, int n, int timeout);
+
+/* Returns the number of bytes in the stdio output buffer for process `p`. */
+long int process_output_size(process_info_t *p);
+
+/* Copy the contents of the stdio output buffer to `fd`. */
+int process_copy_output(process_info_t *p, int fd);
+
+/* Copy the last line of the stdio output buffer to `buffer` */
+int process_read_last_line(process_info_t *p,
+ char * buffer,
+ size_t buffer_len);
+
+/* Return the name that was specified when `p` was started by process_start */
+char* process_get_name(process_info_t *p);
+
+/* Terminate process `p`. */
+int process_terminate(process_info_t *p);
+
+/* Return the exit code of process p. */
+/* On error, return -1. */
+int process_reap(process_info_t *p);
+
+/* Clean up after terminating process `p` (e.g. free the output buffer etc.). */
+void process_cleanup(process_info_t *p);
+
+/* Move the console cursor one line up and back to the first column. */
+void rewind_cursor(void);
+
+/* trigger output as tap */
+extern int tap_output;
+
+#endif /* RUNNER_H_ */
diff --git a/3rdparty/libuv/test/task.h b/3rdparty/libuv/test/task.h
new file mode 100644
index 00000000000..d18c1daa364
--- /dev/null
+++ b/3rdparty/libuv/test/task.h
@@ -0,0 +1,220 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef TASK_H_
+#define TASK_H_
+
+#include "uv.h"
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+# include "stdint-msvc2008.h"
+#else
+# include <stdint.h>
+#endif
+
+#if !defined(_WIN32)
+# include <sys/time.h>
+# include <sys/resource.h> /* setrlimit() */
+#endif
+
+#ifdef __clang__
+# pragma clang diagnostic ignored "-Wvariadic-macros"
+# pragma clang diagnostic ignored "-Wc99-extensions"
+#endif
+
+#define TEST_PORT 9123
+#define TEST_PORT_2 9124
+
+#ifdef _WIN32
+# define TEST_PIPENAME "\\\\?\\pipe\\uv-test"
+# define TEST_PIPENAME_2 "\\\\?\\pipe\\uv-test2"
+# define TEST_PIPENAME_3 "\\\\?\\pipe\\uv-test3"
+#else
+# define TEST_PIPENAME "/tmp/uv-test-sock"
+# define TEST_PIPENAME_2 "/tmp/uv-test-sock2"
+# define TEST_PIPENAME_3 "/tmp/uv-test-sock3"
+#endif
+
+#ifdef _WIN32
+# include <io.h>
+# ifndef S_IRUSR
+# define S_IRUSR _S_IREAD
+# endif
+# ifndef S_IWUSR
+# define S_IWUSR _S_IWRITE
+# endif
+#endif
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+#define container_of(ptr, type, member) \
+ ((type *) ((char *) (ptr) - offsetof(type, member)))
+
+typedef enum {
+ TCP = 0,
+ UDP,
+ PIPE
+} stream_type;
+
+/* Die with fatal error. */
+#define FATAL(msg) \
+ do { \
+ fprintf(stderr, \
+ "Fatal error in %s on line %d: %s\n", \
+ __FILE__, \
+ __LINE__, \
+ msg); \
+ fflush(stderr); \
+ abort(); \
+ } while (0)
+
+/* Have our own assert, so we are sure it does not get optimized away in
+ * a release build.
+ */
+#define ASSERT(expr) \
+ do { \
+ if (!(expr)) { \
+ fprintf(stderr, \
+ "Assertion failed in %s on line %d: %s\n", \
+ __FILE__, \
+ __LINE__, \
+ #expr); \
+ abort(); \
+ } \
+ } while (0)
+
+/* This macro cleans up the main loop. This is used to avoid valgrind
+ * warnings about memory being "leaked" by the main event loop.
+ */
+#define MAKE_VALGRIND_HAPPY() \
+ do { \
+ close_loop(uv_default_loop()); \
+ uv_loop_delete(uv_default_loop()); \
+ } while (0)
+
+/* Just sugar for wrapping the main() for a task or helper. */
+#define TEST_IMPL(name) \
+ int run_test_##name(void); \
+ int run_test_##name(void)
+
+#define BENCHMARK_IMPL(name) \
+ int run_benchmark_##name(void); \
+ int run_benchmark_##name(void)
+
+#define HELPER_IMPL(name) \
+ int run_helper_##name(void); \
+ int run_helper_##name(void)
+
+/* Pause the calling thread for a number of milliseconds. */
+void uv_sleep(int msec);
+
+/* Format big numbers nicely. WARNING: leaks memory. */
+const char* fmt(double d);
+
+/* Reserved test exit codes. */
+enum test_status {
+ TEST_OK = 0,
+ TEST_TODO,
+ TEST_SKIP
+};
+
+#define RETURN_OK() \
+ do { \
+ return TEST_OK; \
+ } while (0)
+
+#define RETURN_TODO(explanation) \
+ do { \
+ fprintf(stderr, "%s\n", explanation); \
+ fflush(stderr); \
+ return TEST_TODO; \
+ } while (0)
+
+#define RETURN_SKIP(explanation) \
+ do { \
+ fprintf(stderr, "%s\n", explanation); \
+ fflush(stderr); \
+ return TEST_SKIP; \
+ } while (0)
+
+#if !defined(_WIN32)
+
+# define TEST_FILE_LIMIT(num) \
+ do { \
+ struct rlimit lim; \
+ lim.rlim_cur = (num); \
+ lim.rlim_max = lim.rlim_cur; \
+ if (setrlimit(RLIMIT_NOFILE, &lim)) \
+ RETURN_SKIP("File descriptor limit too low."); \
+ } while (0)
+
+#else /* defined(_WIN32) */
+
+# define TEST_FILE_LIMIT(num) do {} while (0)
+
+#endif
+
+#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900
+extern int snprintf(char*, size_t, const char*, ...);
+#endif
+
+#if defined(__clang__) || \
+ defined(__GNUC__) || \
+ defined(__INTEL_COMPILER) || \
+ defined(__SUNPRO_C)
+# define UNUSED __attribute__((unused))
+#else
+# define UNUSED
+#endif
+
+/* Fully close a loop */
+static void close_walk_cb(uv_handle_t* handle, void* arg) {
+ if (!uv_is_closing(handle))
+ uv_close(handle, NULL);
+}
+
+UNUSED static void close_loop(uv_loop_t* loop) {
+ uv_walk(loop, close_walk_cb, NULL);
+ uv_run(loop, UV_RUN_DEFAULT);
+}
+
+UNUSED static int can_ipv6(void) {
+ uv_interface_address_t* addr;
+ int supported;
+ int count;
+ int i;
+
+ if (uv_interface_addresses(&addr, &count))
+ return 1; /* Assume IPv6 support on failure. */
+
+ supported = 0;
+ for (i = 0; supported == 0 && i < count; i += 1)
+ supported = (AF_INET6 == addr[i].address.address6.sin6_family);
+
+ uv_free_interface_addresses(addr, count);
+ return supported;
+}
+
+#endif /* TASK_H_ */
diff --git a/3rdparty/libuv/test/test-active.c b/3rdparty/libuv/test/test-active.c
new file mode 100644
index 00000000000..b17bd176018
--- /dev/null
+++ b/3rdparty/libuv/test/test-active.c
@@ -0,0 +1,84 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(0 && "timer_cb should not have been called");
+}
+
+
+TEST_IMPL(active) {
+ int r;
+ uv_timer_t timer;
+
+ r = uv_timer_init(uv_default_loop(), &timer);
+ ASSERT(r == 0);
+
+ /* uv_is_active() and uv_is_closing() should always return either 0 or 1. */
+ ASSERT(0 == uv_is_active((uv_handle_t*) &timer));
+ ASSERT(0 == uv_is_closing((uv_handle_t*) &timer));
+
+ r = uv_timer_start(&timer, timer_cb, 1000, 0);
+ ASSERT(r == 0);
+
+ ASSERT(1 == uv_is_active((uv_handle_t*) &timer));
+ ASSERT(0 == uv_is_closing((uv_handle_t*) &timer));
+
+ r = uv_timer_stop(&timer);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_is_active((uv_handle_t*) &timer));
+ ASSERT(0 == uv_is_closing((uv_handle_t*) &timer));
+
+ r = uv_timer_start(&timer, timer_cb, 1000, 0);
+ ASSERT(r == 0);
+
+ ASSERT(1 == uv_is_active((uv_handle_t*) &timer));
+ ASSERT(0 == uv_is_closing((uv_handle_t*) &timer));
+
+ uv_close((uv_handle_t*) &timer, close_cb);
+
+ ASSERT(0 == uv_is_active((uv_handle_t*) &timer));
+ ASSERT(1 == uv_is_closing((uv_handle_t*) &timer));
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-async-null-cb.c b/3rdparty/libuv/test/test-async-null-cb.c
new file mode 100644
index 00000000000..757944a2762
--- /dev/null
+++ b/3rdparty/libuv/test/test-async-null-cb.c
@@ -0,0 +1,55 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_async_t async_handle;
+static uv_check_t check_handle;
+static int check_cb_called;
+static uv_thread_t thread;
+
+
+static void thread_cb(void* dummy) {
+ (void) &dummy;
+ uv_async_send(&async_handle);
+}
+
+
+static void check_cb(uv_check_t* handle) {
+ ASSERT(check_cb_called == 0);
+ uv_close((uv_handle_t*) &async_handle, NULL);
+ uv_close((uv_handle_t*) &check_handle, NULL);
+ check_cb_called++;
+}
+
+
+TEST_IMPL(async_null_cb) {
+ ASSERT(0 == uv_async_init(uv_default_loop(), &async_handle, NULL));
+ ASSERT(0 == uv_check_init(uv_default_loop(), &check_handle));
+ ASSERT(0 == uv_check_start(&check_handle, check_cb));
+ ASSERT(0 == uv_thread_create(&thread, thread_cb, NULL));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ ASSERT(0 == uv_thread_join(&thread));
+ ASSERT(1 == check_cb_called);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-async.c b/3rdparty/libuv/test/test-async.c
new file mode 100644
index 00000000000..6f5351bf158
--- /dev/null
+++ b/3rdparty/libuv/test/test-async.c
@@ -0,0 +1,134 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+static uv_thread_t thread;
+static uv_mutex_t mutex;
+
+static uv_prepare_t prepare;
+static uv_async_t async;
+
+static volatile int async_cb_called;
+static int prepare_cb_called;
+static int close_cb_called;
+
+
+static void thread_cb(void *arg) {
+ int n;
+ int r;
+
+ for (;;) {
+ uv_mutex_lock(&mutex);
+ n = async_cb_called;
+ uv_mutex_unlock(&mutex);
+
+ if (n == 3) {
+ break;
+ }
+
+ r = uv_async_send(&async);
+ ASSERT(r == 0);
+
+ /* Work around a bug in Valgrind.
+ *
+ * Valgrind runs threads not in parallel but sequentially, i.e. one after
+ * the other. It also doesn't preempt them, instead it depends on threads
+ * yielding voluntarily by making a syscall.
+ *
+ * That never happens here: the pipe that is associated with the async
+ * handle is written to once but that's too early for Valgrind's scheduler
+ * to kick in. Afterwards, the thread busy-loops, starving the main thread.
+ * Therefore, we yield.
+ *
+ * This behavior has been observed with Valgrind 3.7.0 and 3.9.0.
+ */
+ uv_sleep(0);
+ }
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void async_cb(uv_async_t* handle) {
+ int n;
+
+ ASSERT(handle == &async);
+
+ uv_mutex_lock(&mutex);
+ n = ++async_cb_called;
+ uv_mutex_unlock(&mutex);
+
+ if (n == 3) {
+ uv_close((uv_handle_t*)&async, close_cb);
+ uv_close((uv_handle_t*)&prepare, close_cb);
+ }
+}
+
+
+static void prepare_cb(uv_prepare_t* handle) {
+ int r;
+
+ ASSERT(handle == &prepare);
+
+ if (prepare_cb_called++)
+ return;
+
+ r = uv_thread_create(&thread, thread_cb, NULL);
+ ASSERT(r == 0);
+ uv_mutex_unlock(&mutex);
+}
+
+
+TEST_IMPL(async) {
+ int r;
+
+ r = uv_mutex_init(&mutex);
+ ASSERT(r == 0);
+ uv_mutex_lock(&mutex);
+
+ r = uv_prepare_init(uv_default_loop(), &prepare);
+ ASSERT(r == 0);
+ r = uv_prepare_start(&prepare, prepare_cb);
+ ASSERT(r == 0);
+
+ r = uv_async_init(uv_default_loop(), &async, async_cb);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(prepare_cb_called > 0);
+ ASSERT(async_cb_called == 3);
+ ASSERT(close_cb_called == 2);
+
+ ASSERT(0 == uv_thread_join(&thread));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-barrier.c b/3rdparty/libuv/test/test-barrier.c
new file mode 100644
index 00000000000..dfd2dbdef1b
--- /dev/null
+++ b/3rdparty/libuv/test/test-barrier.c
@@ -0,0 +1,106 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <string.h>
+#include <errno.h>
+
+typedef struct {
+ uv_barrier_t barrier;
+ int delay;
+ volatile int posted;
+ int main_barrier_wait_rval;
+ int worker_barrier_wait_rval;
+} worker_config;
+
+
+static void worker(void* arg) {
+ worker_config* c = arg;
+
+ if (c->delay)
+ uv_sleep(c->delay);
+
+ c->worker_barrier_wait_rval = uv_barrier_wait(&c->barrier);
+}
+
+
+TEST_IMPL(barrier_1) {
+ uv_thread_t thread;
+ worker_config wc;
+
+ memset(&wc, 0, sizeof(wc));
+
+ ASSERT(0 == uv_barrier_init(&wc.barrier, 2));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ uv_sleep(100);
+ wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier);
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_barrier_destroy(&wc.barrier);
+
+ ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval));
+
+ return 0;
+}
+
+
+TEST_IMPL(barrier_2) {
+ uv_thread_t thread;
+ worker_config wc;
+
+ memset(&wc, 0, sizeof(wc));
+ wc.delay = 100;
+
+ ASSERT(0 == uv_barrier_init(&wc.barrier, 2));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier);
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_barrier_destroy(&wc.barrier);
+
+ ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval));
+
+ return 0;
+}
+
+
+TEST_IMPL(barrier_3) {
+ uv_thread_t thread;
+ worker_config wc;
+
+ memset(&wc, 0, sizeof(wc));
+
+ ASSERT(0 == uv_barrier_init(&wc.barrier, 2));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier);
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_barrier_destroy(&wc.barrier);
+
+ ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval));
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-callback-order.c b/3rdparty/libuv/test/test-callback-order.c
new file mode 100644
index 00000000000..8bc2c4f75de
--- /dev/null
+++ b/3rdparty/libuv/test/test-callback-order.c
@@ -0,0 +1,77 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static int idle_cb_called;
+static int timer_cb_called;
+
+static uv_idle_t idle_handle;
+static uv_timer_t timer_handle;
+
+
+/* idle_cb should run before timer_cb */
+static void idle_cb(uv_idle_t* handle) {
+ ASSERT(idle_cb_called == 0);
+ ASSERT(timer_cb_called == 0);
+ uv_idle_stop(handle);
+ idle_cb_called++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(idle_cb_called == 1);
+ ASSERT(timer_cb_called == 0);
+ uv_timer_stop(handle);
+ timer_cb_called++;
+}
+
+
+static void next_tick(uv_idle_t* handle) {
+ uv_loop_t* loop = handle->loop;
+ uv_idle_stop(handle);
+ uv_idle_init(loop, &idle_handle);
+ uv_idle_start(&idle_handle, idle_cb);
+ uv_timer_init(loop, &timer_handle);
+ uv_timer_start(&timer_handle, timer_cb, 0, 0);
+}
+
+
+TEST_IMPL(callback_order) {
+ uv_loop_t* loop;
+ uv_idle_t idle;
+
+ loop = uv_default_loop();
+ uv_idle_init(loop, &idle);
+ uv_idle_start(&idle, next_tick);
+
+ ASSERT(idle_cb_called == 0);
+ ASSERT(timer_cb_called == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(idle_cb_called == 1);
+ ASSERT(timer_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-callback-stack.c b/3rdparty/libuv/test/test-callback-stack.c
new file mode 100644
index 00000000000..8855c0841b3
--- /dev/null
+++ b/3rdparty/libuv/test/test-callback-stack.c
@@ -0,0 +1,205 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/*
+ * TODO: Add explanation of why we want on_close to be called from fresh
+ * stack.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+static const char MESSAGE[] = "Failure is for the weak. Everyone dies alone.";
+
+static uv_tcp_t client;
+static uv_timer_t timer;
+static uv_connect_t connect_req;
+static uv_write_t write_req;
+static uv_shutdown_t shutdown_req;
+
+static int nested = 0;
+static int close_cb_called = 0;
+static int connect_cb_called = 0;
+static int write_cb_called = 0;
+static int timer_cb_called = 0;
+static int bytes_received = 0;
+static int shutdown_cb_called = 0;
+
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ buf->len = size;
+ buf->base = malloc(size);
+ ASSERT(buf->base != NULL);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(nested == 0 && "close_cb must be called from a fresh stack");
+
+ close_cb_called++;
+}
+
+
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+ ASSERT(status == 0);
+ ASSERT(nested == 0 && "shutdown_cb must be called from a fresh stack");
+
+ shutdown_cb_called++;
+}
+
+
+static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ ASSERT(nested == 0 && "read_cb must be called from a fresh stack");
+
+ printf("Read. nread == %d\n", (int)nread);
+ free(buf->base);
+
+ if (nread == 0) {
+ return;
+
+ } else if (nread < 0) {
+ ASSERT(nread == UV_EOF);
+
+ nested++;
+ uv_close((uv_handle_t*)tcp, close_cb);
+ nested--;
+
+ return;
+ }
+
+ bytes_received += nread;
+
+ /* We call shutdown here because when bytes_received == sizeof MESSAGE */
+ /* there will be no more data sent nor received, so here it would be */
+ /* possible for a backend to to call shutdown_cb immediately and *not* */
+ /* from a fresh stack. */
+ if (bytes_received == sizeof MESSAGE) {
+ nested++;
+
+ puts("Shutdown");
+
+ if (uv_shutdown(&shutdown_req, (uv_stream_t*)tcp, shutdown_cb)) {
+ FATAL("uv_shutdown failed");
+ }
+ nested--;
+ }
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(handle == &timer);
+ ASSERT(nested == 0 && "timer_cb must be called from a fresh stack");
+
+ puts("Timeout complete. Now read data...");
+
+ nested++;
+ if (uv_read_start((uv_stream_t*)&client, alloc_cb, read_cb)) {
+ FATAL("uv_read_start failed");
+ }
+ nested--;
+
+ timer_cb_called++;
+
+ uv_close((uv_handle_t*)handle, close_cb);
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ int r;
+
+ ASSERT(status == 0);
+ ASSERT(nested == 0 && "write_cb must be called from a fresh stack");
+
+ puts("Data written. 500ms timeout...");
+
+ /* After the data has been sent, we're going to wait for a while, then */
+ /* start reading. This makes us certain that the message has been echoed */
+ /* back to our receive buffer when we start reading. This maximizes the */
+ /* temptation for the backend to use dirty stack for calling read_cb. */
+ nested++;
+ r = uv_timer_init(uv_default_loop(), &timer);
+ ASSERT(r == 0);
+ r = uv_timer_start(&timer, timer_cb, 500, 0);
+ ASSERT(r == 0);
+ nested--;
+
+ write_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ uv_buf_t buf;
+
+ puts("Connected. Write some data to echo server...");
+
+ ASSERT(status == 0);
+ ASSERT(nested == 0 && "connect_cb must be called from a fresh stack");
+
+ nested++;
+
+ buf.base = (char*) &MESSAGE;
+ buf.len = sizeof MESSAGE;
+
+ if (uv_write(&write_req, (uv_stream_t*)req->handle, &buf, 1, write_cb)) {
+ FATAL("uv_write failed");
+ }
+
+ nested--;
+
+ connect_cb_called++;
+}
+
+
+TEST_IMPL(callback_stack) {
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ if (uv_tcp_init(uv_default_loop(), &client)) {
+ FATAL("uv_tcp_init failed");
+ }
+
+ puts("Connecting...");
+
+ nested++;
+
+ if (uv_tcp_connect(&connect_req,
+ &client,
+ (const struct sockaddr*) &addr,
+ connect_cb)) {
+ FATAL("uv_tcp_connect failed");
+ }
+ nested--;
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(nested == 0);
+ ASSERT(connect_cb_called == 1 && "connect_cb must be called exactly once");
+ ASSERT(write_cb_called == 1 && "write_cb must be called exactly once");
+ ASSERT(timer_cb_called == 1 && "timer_cb must be called exactly once");
+ ASSERT(bytes_received == sizeof MESSAGE);
+ ASSERT(shutdown_cb_called == 1 && "shutdown_cb must be called exactly once");
+ ASSERT(close_cb_called == 2 && "close_cb must be called exactly twice");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-close-fd.c b/3rdparty/libuv/test/test-close-fd.c
new file mode 100644
index 00000000000..93a7bd7c021
--- /dev/null
+++ b/3rdparty/libuv/test/test-close-fd.c
@@ -0,0 +1,76 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#if !defined(_WIN32)
+
+#include "uv.h"
+#include "task.h"
+#include <fcntl.h>
+#include <unistd.h>
+
+static unsigned int read_cb_called;
+
+static void alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
+ static char slab[1];
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+static void read_cb(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) {
+ switch (++read_cb_called) {
+ case 1:
+ ASSERT(nread == 1);
+ uv_read_stop(handle);
+ break;
+ case 2:
+ ASSERT(nread == UV_EOF);
+ uv_close((uv_handle_t *) handle, NULL);
+ break;
+ default:
+ ASSERT(!"read_cb_called > 2");
+ }
+}
+
+TEST_IMPL(close_fd) {
+ uv_pipe_t pipe_handle;
+ int fd[2];
+
+ ASSERT(0 == pipe(fd));
+ ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
+ ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
+ fd[0] = -1; /* uv_pipe_open() takes ownership of the file descriptor. */
+ ASSERT(1 == write(fd[1], "", 1));
+ ASSERT(0 == close(fd[1]));
+ fd[1] = -1;
+ ASSERT(0 == uv_read_start((uv_stream_t *) &pipe_handle, alloc_cb, read_cb));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ ASSERT(1 == read_cb_called);
+ ASSERT(0 == uv_is_active((const uv_handle_t *) &pipe_handle));
+ ASSERT(0 == uv_read_start((uv_stream_t *) &pipe_handle, alloc_cb, read_cb));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ ASSERT(2 == read_cb_called);
+ ASSERT(0 != uv_is_closing((const uv_handle_t *) &pipe_handle));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* !defined(_WIN32) */
diff --git a/3rdparty/libuv/test/test-close-order.c b/3rdparty/libuv/test/test-close-order.c
new file mode 100644
index 00000000000..2b24f6d6579
--- /dev/null
+++ b/3rdparty/libuv/test/test-close-order.c
@@ -0,0 +1,80 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static int check_cb_called;
+static int timer_cb_called;
+static int close_cb_called;
+
+static uv_check_t check_handle;
+static uv_timer_t timer_handle1;
+static uv_timer_t timer_handle2;
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+/* check_cb should run before any close_cb */
+static void check_cb(uv_check_t* handle) {
+ ASSERT(check_cb_called == 0);
+ ASSERT(timer_cb_called == 1);
+ ASSERT(close_cb_called == 0);
+ uv_close((uv_handle_t*) handle, close_cb);
+ uv_close((uv_handle_t*) &timer_handle2, close_cb);
+ check_cb_called++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ uv_close((uv_handle_t*) handle, close_cb);
+ timer_cb_called++;
+}
+
+
+TEST_IMPL(close_order) {
+ uv_loop_t* loop;
+ loop = uv_default_loop();
+
+ uv_check_init(loop, &check_handle);
+ uv_check_start(&check_handle, check_cb);
+ uv_timer_init(loop, &timer_handle1);
+ uv_timer_start(&timer_handle1, timer_cb, 0, 0);
+ uv_timer_init(loop, &timer_handle2);
+ uv_timer_start(&timer_handle2, timer_cb, 100000, 0);
+
+ ASSERT(check_cb_called == 0);
+ ASSERT(close_cb_called == 0);
+ ASSERT(timer_cb_called == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(check_cb_called == 1);
+ ASSERT(close_cb_called == 3);
+ ASSERT(timer_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-condvar.c b/3rdparty/libuv/test/test-condvar.c
new file mode 100644
index 00000000000..dbacdba384d
--- /dev/null
+++ b/3rdparty/libuv/test/test-condvar.c
@@ -0,0 +1,173 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <string.h>
+#include <errno.h>
+
+typedef struct {
+ uv_mutex_t mutex;
+ uv_cond_t cond;
+ int delay;
+ int use_broadcast;
+ volatile int posted;
+} worker_config;
+
+
+static void worker(void* arg) {
+ worker_config* c = arg;
+
+ if (c->delay)
+ uv_sleep(c->delay);
+
+ uv_mutex_lock(&c->mutex);
+ ASSERT(c->posted == 0);
+ c->posted = 1;
+ if (c->use_broadcast)
+ uv_cond_broadcast(&c->cond);
+ else
+ uv_cond_signal(&c->cond);
+ uv_mutex_unlock(&c->mutex);
+}
+
+
+TEST_IMPL(condvar_1) {
+ uv_thread_t thread;
+ worker_config wc;
+
+ memset(&wc, 0, sizeof(wc));
+
+ ASSERT(0 == uv_cond_init(&wc.cond));
+ ASSERT(0 == uv_mutex_init(&wc.mutex));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ uv_mutex_lock(&wc.mutex);
+ uv_sleep(100);
+ uv_cond_wait(&wc.cond, &wc.mutex);
+ ASSERT(wc.posted == 1);
+ uv_mutex_unlock(&wc.mutex);
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_mutex_destroy(&wc.mutex);
+ uv_cond_destroy(&wc.cond);
+
+ return 0;
+}
+
+
+TEST_IMPL(condvar_2) {
+ uv_thread_t thread;
+ worker_config wc;
+
+ memset(&wc, 0, sizeof(wc));
+ wc.delay = 100;
+
+ ASSERT(0 == uv_cond_init(&wc.cond));
+ ASSERT(0 == uv_mutex_init(&wc.mutex));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ uv_mutex_lock(&wc.mutex);
+ uv_cond_wait(&wc.cond, &wc.mutex);
+ uv_mutex_unlock(&wc.mutex);
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_mutex_destroy(&wc.mutex);
+ uv_cond_destroy(&wc.cond);
+
+ return 0;
+}
+
+
+TEST_IMPL(condvar_3) {
+ uv_thread_t thread;
+ worker_config wc;
+ int r;
+
+ memset(&wc, 0, sizeof(wc));
+ wc.delay = 100;
+
+ ASSERT(0 == uv_cond_init(&wc.cond));
+ ASSERT(0 == uv_mutex_init(&wc.mutex));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ uv_mutex_lock(&wc.mutex);
+ r = uv_cond_timedwait(&wc.cond, &wc.mutex, (uint64_t)(50 * 1e6));
+ ASSERT(r == UV_ETIMEDOUT);
+ uv_mutex_unlock(&wc.mutex);
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_mutex_destroy(&wc.mutex);
+ uv_cond_destroy(&wc.cond);
+
+ return 0;
+}
+
+
+TEST_IMPL(condvar_4) {
+ uv_thread_t thread;
+ worker_config wc;
+ int r;
+
+ memset(&wc, 0, sizeof(wc));
+ wc.delay = 100;
+
+ ASSERT(0 == uv_cond_init(&wc.cond));
+ ASSERT(0 == uv_mutex_init(&wc.mutex));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ uv_mutex_lock(&wc.mutex);
+ r = uv_cond_timedwait(&wc.cond, &wc.mutex, (uint64_t)(150 * 1e6));
+ ASSERT(r == 0);
+ uv_mutex_unlock(&wc.mutex);
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_mutex_destroy(&wc.mutex);
+ uv_cond_destroy(&wc.cond);
+
+ return 0;
+}
+
+
+TEST_IMPL(condvar_5) {
+ uv_thread_t thread;
+ worker_config wc;
+
+ memset(&wc, 0, sizeof(wc));
+ wc.use_broadcast = 1;
+
+ ASSERT(0 == uv_cond_init(&wc.cond));
+ ASSERT(0 == uv_mutex_init(&wc.mutex));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ uv_mutex_lock(&wc.mutex);
+ uv_sleep(100);
+ uv_cond_wait(&wc.cond, &wc.mutex);
+ ASSERT(wc.posted == 1);
+ uv_mutex_unlock(&wc.mutex);
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_mutex_destroy(&wc.mutex);
+ uv_cond_destroy(&wc.cond);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-connection-fail.c b/3rdparty/libuv/test/test-connection-fail.c
new file mode 100644
index 00000000000..328bff46e7d
--- /dev/null
+++ b/3rdparty/libuv/test/test-connection-fail.c
@@ -0,0 +1,151 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+
+static uv_tcp_t tcp;
+static uv_connect_t req;
+static int connect_cb_calls;
+static int close_cb_calls;
+
+static uv_timer_t timer;
+static int timer_close_cb_calls;
+static int timer_cb_calls;
+
+
+static void on_close(uv_handle_t* handle) {
+ close_cb_calls++;
+}
+
+
+static void timer_close_cb(uv_handle_t* handle) {
+ timer_close_cb_calls++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ timer_cb_calls++;
+
+ /*
+ * These are the important asserts. The connection callback has been made,
+ * but libuv hasn't automatically closed the socket. The user must
+ * uv_close the handle manually.
+ */
+ ASSERT(close_cb_calls == 0);
+ ASSERT(connect_cb_calls == 1);
+
+ /* Close the tcp handle. */
+ uv_close((uv_handle_t*)&tcp, on_close);
+
+ /* Close the timer. */
+ uv_close((uv_handle_t*)handle, timer_close_cb);
+}
+
+
+static void on_connect_with_close(uv_connect_t *req, int status) {
+ ASSERT((uv_stream_t*) &tcp == req->handle);
+ ASSERT(status == UV_ECONNREFUSED);
+ connect_cb_calls++;
+
+ ASSERT(close_cb_calls == 0);
+ uv_close((uv_handle_t*)req->handle, on_close);
+}
+
+
+static void on_connect_without_close(uv_connect_t *req, int status) {
+ ASSERT(status == UV_ECONNREFUSED);
+ connect_cb_calls++;
+
+ uv_timer_start(&timer, timer_cb, 100, 0);
+
+ ASSERT(close_cb_calls == 0);
+}
+
+
+static void connection_fail(uv_connect_cb connect_cb) {
+ struct sockaddr_in client_addr, server_addr;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &client_addr));
+
+ /* There should be no servers listening on this port. */
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
+
+ /* Try to connect to the server and do NUM_PINGS ping-pongs. */
+ r = uv_tcp_init(uv_default_loop(), &tcp);
+ ASSERT(!r);
+
+ /* We are never doing multiple reads/connects at a time anyway. */
+ /* so these handles can be pre-initialized. */
+ ASSERT(0 == uv_tcp_bind(&tcp, (const struct sockaddr*) &client_addr, 0));
+
+ r = uv_tcp_connect(&req,
+ &tcp,
+ (const struct sockaddr*) &server_addr,
+ connect_cb);
+ ASSERT(!r);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(connect_cb_calls == 1);
+ ASSERT(close_cb_calls == 1);
+}
+
+
+/*
+ * This test attempts to connect to a port where no server is running. We
+ * expect an error.
+ */
+TEST_IMPL(connection_fail) {
+ connection_fail(on_connect_with_close);
+
+ ASSERT(timer_close_cb_calls == 0);
+ ASSERT(timer_cb_calls == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+/*
+ * This test is the same as the first except it check that the close
+ * callback of the tcp handle hasn't been made after the failed connection
+ * attempt.
+ */
+TEST_IMPL(connection_fail_doesnt_auto_close) {
+ int r;
+
+ r = uv_timer_init(uv_default_loop(), &timer);
+ ASSERT(r == 0);
+
+ connection_fail(on_connect_without_close);
+
+ ASSERT(timer_close_cb_calls == 1);
+ ASSERT(timer_cb_calls == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-cwd-and-chdir.c b/3rdparty/libuv/test/test-cwd-and-chdir.c
new file mode 100644
index 00000000000..1e95043c177
--- /dev/null
+++ b/3rdparty/libuv/test/test-cwd-and-chdir.c
@@ -0,0 +1,51 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <string.h>
+
+#define PATHMAX 1024
+extern char executable_path[];
+
+TEST_IMPL(cwd_and_chdir) {
+ char buffer_orig[PATHMAX];
+ char buffer_new[PATHMAX];
+ size_t size1;
+ size_t size2;
+ int err;
+
+ size1 = sizeof buffer_orig;
+ err = uv_cwd(buffer_orig, &size1);
+ ASSERT(err == 0);
+
+ err = uv_chdir(buffer_orig);
+ ASSERT(err == 0);
+
+ size2 = sizeof buffer_new;
+ err = uv_cwd(buffer_new, &size2);
+ ASSERT(err == 0);
+
+ ASSERT(size1 == size2);
+ ASSERT(strcmp(buffer_orig, buffer_new) == 0);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-default-loop-close.c b/3rdparty/libuv/test/test-default-loop-close.c
new file mode 100644
index 00000000000..fd11cfa8c12
--- /dev/null
+++ b/3rdparty/libuv/test/test-default-loop-close.c
@@ -0,0 +1,59 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+static int timer_cb_called;
+
+
+static void timer_cb(uv_timer_t* timer) {
+ timer_cb_called++;
+ uv_close((uv_handle_t*) timer, NULL);
+}
+
+
+TEST_IMPL(default_loop_close) {
+ uv_loop_t* loop;
+ uv_timer_t timer_handle;
+
+ loop = uv_default_loop();
+ ASSERT(loop != NULL);
+
+ ASSERT(0 == uv_timer_init(loop, &timer_handle));
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1, 0));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(1 == timer_cb_called);
+ ASSERT(0 == uv_loop_close(loop));
+
+ loop = uv_default_loop();
+ ASSERT(loop != NULL);
+
+ ASSERT(0 == uv_timer_init(loop, &timer_handle));
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1, 0));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(2 == timer_cb_called);
+ ASSERT(0 == uv_loop_close(loop));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-delayed-accept.c b/3rdparty/libuv/test/test-delayed-accept.c
new file mode 100644
index 00000000000..4a7998909c3
--- /dev/null
+++ b/3rdparty/libuv/test/test-delayed-accept.c
@@ -0,0 +1,189 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+static int connection_cb_called = 0;
+static int do_accept_called = 0;
+static int close_cb_called = 0;
+static int connect_cb_called = 0;
+
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ buf->base = malloc(size);
+ buf->len = size;
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+
+ free(handle);
+
+ close_cb_called++;
+}
+
+
+static void do_accept(uv_timer_t* timer_handle) {
+ uv_tcp_t* server;
+ uv_tcp_t* accepted_handle = (uv_tcp_t*)malloc(sizeof *accepted_handle);
+ int r;
+
+ ASSERT(timer_handle != NULL);
+ ASSERT(accepted_handle != NULL);
+
+ r = uv_tcp_init(uv_default_loop(), accepted_handle);
+ ASSERT(r == 0);
+
+ server = (uv_tcp_t*)timer_handle->data;
+ r = uv_accept((uv_stream_t*)server, (uv_stream_t*)accepted_handle);
+ ASSERT(r == 0);
+
+ do_accept_called++;
+
+ /* Immediately close the accepted handle. */
+ uv_close((uv_handle_t*)accepted_handle, close_cb);
+
+ /* After accepting the two clients close the server handle */
+ if (do_accept_called == 2) {
+ uv_close((uv_handle_t*)server, close_cb);
+ }
+
+ /* Dispose the timer. */
+ uv_close((uv_handle_t*)timer_handle, close_cb);
+}
+
+
+static void connection_cb(uv_stream_t* tcp, int status) {
+ int r;
+ uv_timer_t* timer_handle;
+
+ ASSERT(status == 0);
+
+ timer_handle = (uv_timer_t*)malloc(sizeof *timer_handle);
+ ASSERT(timer_handle != NULL);
+
+ /* Accept the client after 1 second */
+ r = uv_timer_init(uv_default_loop(), timer_handle);
+ ASSERT(r == 0);
+
+ timer_handle->data = tcp;
+
+ r = uv_timer_start(timer_handle, do_accept, 1000, 0);
+ ASSERT(r == 0);
+
+ connection_cb_called++;
+}
+
+
+static void start_server(void) {
+ struct sockaddr_in addr;
+ uv_tcp_t* server = (uv_tcp_t*)malloc(sizeof *server);
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+ ASSERT(server != NULL);
+
+ r = uv_tcp_init(uv_default_loop(), server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)server, 128, connection_cb);
+ ASSERT(r == 0);
+}
+
+
+static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ /* The server will not send anything, it should close gracefully. */
+
+ if (buf->base) {
+ free(buf->base);
+ }
+
+ if (nread >= 0) {
+ ASSERT(nread == 0);
+ } else {
+ ASSERT(tcp != NULL);
+ ASSERT(nread == UV_EOF);
+ uv_close((uv_handle_t*)tcp, close_cb);
+ }
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ int r;
+
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+
+ /* Not that the server will send anything, but otherwise we'll never know */
+ /* when the server closes the connection. */
+ r = uv_read_start((uv_stream_t*)(req->handle), alloc_cb, read_cb);
+ ASSERT(r == 0);
+
+ connect_cb_called++;
+
+ free(req);
+}
+
+
+static void client_connect(void) {
+ struct sockaddr_in addr;
+ uv_tcp_t* client = (uv_tcp_t*)malloc(sizeof *client);
+ uv_connect_t* connect_req = malloc(sizeof *connect_req);
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ ASSERT(client != NULL);
+ ASSERT(connect_req != NULL);
+
+ r = uv_tcp_init(uv_default_loop(), client);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(connect_req,
+ client,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+}
+
+
+
+TEST_IMPL(delayed_accept) {
+ start_server();
+
+ client_connect();
+ client_connect();
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(connection_cb_called == 2);
+ ASSERT(do_accept_called == 2);
+ ASSERT(connect_cb_called == 2);
+ ASSERT(close_cb_called == 7);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-dlerror.c b/3rdparty/libuv/test/test-dlerror.c
new file mode 100644
index 00000000000..091200edbed
--- /dev/null
+++ b/3rdparty/libuv/test/test-dlerror.c
@@ -0,0 +1,55 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <string.h>
+
+
+TEST_IMPL(dlerror) {
+ const char* path = "test/fixtures/load_error.node";
+ const char* dlerror_no_error = "no error";
+ const char* msg;
+ uv_lib_t lib;
+ int r;
+
+ lib.errmsg = NULL;
+ lib.handle = NULL;
+ msg = uv_dlerror(&lib);
+ ASSERT(msg != NULL);
+ ASSERT(strstr(msg, dlerror_no_error) != NULL);
+
+ r = uv_dlopen(path, &lib);
+ ASSERT(r == -1);
+
+ msg = uv_dlerror(&lib);
+ ASSERT(msg != NULL);
+ ASSERT(strstr(msg, dlerror_no_error) == NULL);
+
+ /* Should return the same error twice in a row. */
+ msg = uv_dlerror(&lib);
+ ASSERT(msg != NULL);
+ ASSERT(strstr(msg, dlerror_no_error) == NULL);
+
+ uv_dlclose(&lib);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-embed.c b/3rdparty/libuv/test/test-embed.c
new file mode 100644
index 00000000000..06137456f8b
--- /dev/null
+++ b/3rdparty/libuv/test/test-embed.c
@@ -0,0 +1,138 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#ifndef HAVE_KQUEUE
+# if defined(__APPLE__) || \
+ defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__)
+# define HAVE_KQUEUE 1
+# endif
+#endif
+
+#ifndef HAVE_EPOLL
+# if defined(__linux__)
+# define HAVE_EPOLL 1
+# endif
+#endif
+
+#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
+
+#if defined(HAVE_KQUEUE)
+# include <sys/types.h>
+# include <sys/event.h>
+# include <sys/time.h>
+#endif
+
+#if defined(HAVE_EPOLL)
+# include <sys/epoll.h>
+#endif
+
+static uv_thread_t embed_thread;
+static uv_sem_t embed_sem;
+static uv_timer_t embed_timer;
+static uv_async_t embed_async;
+static volatile int embed_closed;
+
+static int embed_timer_called;
+
+
+static void embed_thread_runner(void* arg) {
+ int r;
+ int fd;
+ int timeout;
+
+ while (!embed_closed) {
+ fd = uv_backend_fd(uv_default_loop());
+ timeout = uv_backend_timeout(uv_default_loop());
+
+ do {
+#if defined(HAVE_KQUEUE)
+ struct timespec ts;
+ ts.tv_sec = timeout / 1000;
+ ts.tv_nsec = (timeout % 1000) * 1000000;
+ r = kevent(fd, NULL, 0, NULL, 0, &ts);
+#elif defined(HAVE_EPOLL)
+ {
+ struct epoll_event ev;
+ r = epoll_wait(fd, &ev, 1, timeout);
+ }
+#endif
+ } while (r == -1 && errno == EINTR);
+ uv_async_send(&embed_async);
+ uv_sem_wait(&embed_sem);
+ }
+}
+
+
+static void embed_cb(uv_async_t* async) {
+ uv_run(uv_default_loop(), UV_RUN_ONCE);
+
+ uv_sem_post(&embed_sem);
+}
+
+
+static void embed_timer_cb(uv_timer_t* timer) {
+ embed_timer_called++;
+ embed_closed = 1;
+
+ uv_close((uv_handle_t*) &embed_async, NULL);
+}
+#endif
+
+
+TEST_IMPL(embed) {
+#if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL)
+ uv_loop_t external;
+
+ ASSERT(0 == uv_loop_init(&external));
+
+ embed_timer_called = 0;
+ embed_closed = 0;
+
+ uv_async_init(&external, &embed_async, embed_cb);
+
+ /* Start timer in default loop */
+ uv_timer_init(uv_default_loop(), &embed_timer);
+ uv_timer_start(&embed_timer, embed_timer_cb, 250, 0);
+
+ /* Start worker that will interrupt external loop */
+ uv_sem_init(&embed_sem, 0);
+ uv_thread_create(&embed_thread, embed_thread_runner, NULL);
+
+ /* But run external loop */
+ uv_run(&external, UV_RUN_DEFAULT);
+
+ uv_thread_join(&embed_thread);
+ uv_loop_close(&external);
+
+ ASSERT(embed_timer_called == 1);
+#endif
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-emfile.c b/3rdparty/libuv/test/test-emfile.c
new file mode 100644
index 00000000000..dd35f785b46
--- /dev/null
+++ b/3rdparty/libuv/test/test-emfile.c
@@ -0,0 +1,110 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#if !defined(_WIN32)
+
+#include "uv.h"
+#include "task.h"
+
+#include <errno.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+static void connection_cb(uv_stream_t* server_handle, int status);
+static void connect_cb(uv_connect_t* req, int status);
+
+static const int maxfd = 31;
+static unsigned connect_cb_called;
+static uv_tcp_t server_handle;
+static uv_tcp_t client_handle;
+
+
+TEST_IMPL(emfile) {
+ struct sockaddr_in addr;
+ struct rlimit limits;
+ uv_connect_t connect_req;
+ uv_loop_t* loop;
+ int first_fd;
+
+ /* Lower the file descriptor limit and use up all fds save one. */
+ limits.rlim_cur = limits.rlim_max = maxfd + 1;
+ if (setrlimit(RLIMIT_NOFILE, &limits)) {
+ ASSERT(errno == EPERM); /* Valgrind blocks the setrlimit() call. */
+ RETURN_SKIP("setrlimit(RLIMIT_NOFILE) failed, running under valgrind?");
+ }
+
+ loop = uv_default_loop();
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ ASSERT(0 == uv_tcp_init(loop, &server_handle));
+ ASSERT(0 == uv_tcp_init(loop, &client_handle));
+ ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0));
+ ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 8, connection_cb));
+
+ /* Remember the first one so we can clean up afterwards. */
+ do
+ first_fd = dup(0);
+ while (first_fd == -1 && errno == EINTR);
+ ASSERT(first_fd > 0);
+
+ while (dup(0) != -1 || errno == EINTR);
+ ASSERT(errno == EMFILE);
+ close(maxfd);
+
+ /* Now connect and use up the last available file descriptor. The EMFILE
+ * handling logic in src/unix/stream.c should ensure that connect_cb() runs
+ * whereas connection_cb() should *not* run.
+ */
+ ASSERT(0 == uv_tcp_connect(&connect_req,
+ &client_handle,
+ (const struct sockaddr*) &addr,
+ connect_cb));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(1 == connect_cb_called);
+
+ /* Close the dups again. Ignore errors in the unlikely event that the
+ * file descriptors were not contiguous.
+ */
+ while (first_fd < maxfd) {
+ close(first_fd);
+ first_fd += 1;
+ }
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+static void connection_cb(uv_stream_t* server_handle, int status) {
+ ASSERT(0 && "connection_cb should not be called.");
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ /* |status| should equal 0 because the connection should have been accepted,
+ * it's just that the server immediately closes it again.
+ */
+ ASSERT(0 == status);
+ connect_cb_called += 1;
+ uv_close((uv_handle_t*) &server_handle, NULL);
+ uv_close((uv_handle_t*) &client_handle, NULL);
+}
+
+#endif /* !defined(_WIN32) */
diff --git a/3rdparty/libuv/test/test-error.c b/3rdparty/libuv/test/test-error.c
new file mode 100644
index 00000000000..eb337e66f33
--- /dev/null
+++ b/3rdparty/libuv/test/test-error.c
@@ -0,0 +1,50 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/*
+ * Synthetic errors (errors that originate from within libuv, not the system)
+ * should produce sensible error messages when run through uv_strerror().
+ *
+ * See https://github.com/joyent/libuv/issues/210
+ */
+TEST_IMPL(error_message) {
+ /* Cop out. Can't do proper checks on systems with
+ * i18n-ized error messages...
+ */
+ if (strcmp(uv_strerror(0), "Success") != 0) {
+ printf("i18n error messages detected, skipping test.\n");
+ return 0;
+ }
+
+ ASSERT(strstr(uv_strerror(UV_EINVAL), "Success") == NULL);
+ ASSERT(strcmp(uv_strerror(1337), "Unknown error") == 0);
+ ASSERT(strcmp(uv_strerror(-1337), "Unknown error") == 0);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-fail-always.c b/3rdparty/libuv/test/test-fail-always.c
new file mode 100644
index 00000000000..0008459eac7
--- /dev/null
+++ b/3rdparty/libuv/test/test-fail-always.c
@@ -0,0 +1,29 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+
+
+TEST_IMPL(fail_always) {
+ /* This test always fails. It is used to test the test runner. */
+ FATAL("Yes, it always fails");
+ return 2;
+}
diff --git a/3rdparty/libuv/test/test-fs-event.c b/3rdparty/libuv/test/test-fs-event.c
new file mode 100644
index 00000000000..e02ff2fda5e
--- /dev/null
+++ b/3rdparty/libuv/test/test-fs-event.c
@@ -0,0 +1,907 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <string.h>
+#include <fcntl.h>
+
+#ifndef HAVE_KQUEUE
+# if defined(__APPLE__) || \
+ defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__)
+# define HAVE_KQUEUE 1
+# endif
+#endif
+
+static uv_fs_event_t fs_event;
+static const char file_prefix[] = "fsevent-";
+static const int fs_event_file_count = 16;
+#if defined(__APPLE__) || defined(_WIN32)
+static const char file_prefix_in_subdir[] = "subdir";
+#endif
+static uv_timer_t timer;
+static int timer_cb_called;
+static int close_cb_called;
+static int fs_event_created;
+static int fs_event_removed;
+static int fs_event_cb_called;
+#if defined(PATH_MAX)
+static char fs_event_filename[PATH_MAX];
+#else
+static char fs_event_filename[1024];
+#endif /* defined(PATH_MAX) */
+static int timer_cb_touch_called;
+
+static void create_dir(const char* name) {
+ int r;
+ uv_fs_t req;
+ r = uv_fs_mkdir(NULL, &req, name, 0755, NULL);
+ ASSERT(r == 0 || r == UV_EEXIST);
+ uv_fs_req_cleanup(&req);
+}
+
+static void create_file(const char* name) {
+ int r;
+ uv_file file;
+ uv_fs_t req;
+
+ r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ file = r;
+ uv_fs_req_cleanup(&req);
+ r = uv_fs_close(NULL, &req, file, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&req);
+}
+
+static void touch_file(const char* name) {
+ int r;
+ uv_file file;
+ uv_fs_t req;
+ uv_buf_t buf;
+
+ r = uv_fs_open(NULL, &req, name, O_RDWR, 0, NULL);
+ ASSERT(r >= 0);
+ file = r;
+ uv_fs_req_cleanup(&req);
+
+ buf = uv_buf_init("foo", 4);
+ r = uv_fs_write(NULL, &req, file, &buf, 1, -1, NULL);
+ ASSERT(r >= 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_close(NULL, &req, file, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&req);
+}
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+static void fail_cb(uv_fs_event_t* handle,
+ const char* path,
+ int events,
+ int status) {
+ ASSERT(0 && "fail_cb called");
+}
+
+static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename,
+ int events, int status) {
+ ++fs_event_cb_called;
+ ASSERT(handle == &fs_event);
+ ASSERT(status == 0);
+ ASSERT(events == UV_RENAME);
+ #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
+ ASSERT(strcmp(filename, "file1") == 0);
+ #else
+ ASSERT(filename == NULL || strcmp(filename, "file1") == 0);
+ #endif
+ ASSERT(0 == uv_fs_event_stop(handle));
+ uv_close((uv_handle_t*)handle, close_cb);
+}
+
+static const char* fs_event_get_filename(int i) {
+ snprintf(fs_event_filename,
+ sizeof(fs_event_filename),
+ "watch_dir/%s%d",
+ file_prefix,
+ i);
+ return fs_event_filename;
+}
+
+static void fs_event_create_files(uv_timer_t* handle) {
+ /* Make sure we're not attempting to create files we do not intend */
+ ASSERT(fs_event_created < fs_event_file_count);
+
+ /* Create the file */
+ create_file(fs_event_get_filename(fs_event_created));
+
+ if (++fs_event_created < fs_event_file_count) {
+ /* Create another file on a different event loop tick. We do it this way
+ * to avoid fs events coalescing into one fs event. */
+ ASSERT(0 == uv_timer_start(&timer, fs_event_create_files, 1, 0));
+ }
+}
+
+static void fs_event_unlink_files(uv_timer_t* handle) {
+ int r;
+ int i;
+
+ /* NOTE: handle might be NULL if invoked not as timer callback */
+ if (handle == NULL) {
+ /* Unlink all files */
+ for (i = 0; i < 16; i++) {
+ r = remove(fs_event_get_filename(i));
+ if (handle != NULL)
+ ASSERT(r == 0);
+ }
+ } else {
+ /* Make sure we're not attempting to remove files we do not intend */
+ ASSERT(fs_event_removed < fs_event_file_count);
+
+ /* Remove the file */
+ ASSERT(0 == remove(fs_event_get_filename(fs_event_removed)));
+
+ if (++fs_event_removed < fs_event_file_count) {
+ /* Remove another file on a different event loop tick. We do it this way
+ * to avoid fs events coalescing into one fs event. */
+ ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files, 1, 0));
+ }
+ }
+}
+
+static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle,
+ const char* filename,
+ int events,
+ int status) {
+ fs_event_cb_called++;
+ ASSERT(handle == &fs_event);
+ ASSERT(status == 0);
+ ASSERT(events == UV_CHANGE || UV_RENAME);
+ #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
+ ASSERT(strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0);
+ #else
+ ASSERT(filename == NULL ||
+ strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0);
+ #endif
+
+ if (fs_event_created + fs_event_removed == fs_event_file_count) {
+ /* Once we've processed all create events, delete all files */
+ ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files, 1, 0));
+ } else if (fs_event_cb_called == 2 * fs_event_file_count) {
+ /* Once we've processed all create and delete events, stop watching */
+ uv_close((uv_handle_t*) &timer, close_cb);
+ uv_close((uv_handle_t*) handle, close_cb);
+ }
+}
+
+#if defined(__APPLE__) || defined(_WIN32)
+static const char* fs_event_get_filename_in_subdir(int i) {
+ snprintf(fs_event_filename,
+ sizeof(fs_event_filename),
+ "watch_dir/subdir/%s%d",
+ file_prefix,
+ i);
+ return fs_event_filename;
+}
+
+static void fs_event_create_files_in_subdir(uv_timer_t* handle) {
+ /* Make sure we're not attempting to create files we do not intend */
+ ASSERT(fs_event_created < fs_event_file_count);
+
+ /* Create the file */
+ create_file(fs_event_get_filename_in_subdir(fs_event_created));
+
+ if (++fs_event_created < fs_event_file_count) {
+ /* Create another file on a different event loop tick. We do it this way
+ * to avoid fs events coalescing into one fs event. */
+ ASSERT(0 == uv_timer_start(&timer, fs_event_create_files_in_subdir, 1, 0));
+ }
+}
+
+static void fs_event_unlink_files_in_subdir(uv_timer_t* handle) {
+ int r;
+ int i;
+
+ /* NOTE: handle might be NULL if invoked not as timer callback */
+ if (handle == NULL) {
+ /* Unlink all files */
+ for (i = 0; i < 16; i++) {
+ r = remove(fs_event_get_filename_in_subdir(i));
+ if (handle != NULL)
+ ASSERT(r == 0);
+ }
+ } else {
+ /* Make sure we're not attempting to remove files we do not intend */
+ ASSERT(fs_event_removed < fs_event_file_count);
+
+ /* Remove the file */
+ ASSERT(0 == remove(fs_event_get_filename_in_subdir(fs_event_removed)));
+
+ if (++fs_event_removed < fs_event_file_count) {
+ /* Remove another file on a different event loop tick. We do it this way
+ * to avoid fs events coalescing into one fs event. */
+ ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files_in_subdir, 1, 0));
+ }
+ }
+}
+
+static void fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t* handle,
+ const char* filename,
+ int events,
+ int status) {
+ fs_event_cb_called++;
+ ASSERT(handle == &fs_event);
+ ASSERT(status == 0);
+ ASSERT(events == UV_CHANGE || UV_RENAME);
+ #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
+ ASSERT(strncmp(filename,
+ file_prefix_in_subdir,
+ sizeof(file_prefix_in_subdir) - 1) == 0);
+ #else
+ ASSERT(filename == NULL ||
+ strncmp(filename,
+ file_prefix_in_subdir,
+ sizeof(file_prefix_in_subdir) - 1) == 0);
+ #endif
+
+ if (fs_event_created + fs_event_removed == fs_event_file_count) {
+ /* Once we've processed all create events, delete all files */
+ ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files_in_subdir, 1, 0));
+ } else if (fs_event_cb_called == 2 * fs_event_file_count) {
+ /* Once we've processed all create and delete events, stop watching */
+ uv_close((uv_handle_t*) &timer, close_cb);
+ uv_close((uv_handle_t*) handle, close_cb);
+ }
+}
+#endif
+
+static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename,
+ int events, int status) {
+ ++fs_event_cb_called;
+ ASSERT(handle == &fs_event);
+ ASSERT(status == 0);
+ ASSERT(events == UV_CHANGE);
+ #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
+ ASSERT(strcmp(filename, "file2") == 0);
+ #else
+ ASSERT(filename == NULL || strcmp(filename, "file2") == 0);
+ #endif
+ ASSERT(0 == uv_fs_event_stop(handle));
+ uv_close((uv_handle_t*)handle, close_cb);
+}
+
+static void timer_cb_close_handle(uv_timer_t* timer) {
+ uv_handle_t* handle;
+
+ ASSERT(timer != NULL);
+ handle = timer->data;
+
+ uv_close((uv_handle_t*)timer, NULL);
+ uv_close((uv_handle_t*)handle, close_cb);
+}
+
+static void fs_event_cb_file_current_dir(uv_fs_event_t* handle,
+ const char* filename, int events, int status) {
+ ASSERT(fs_event_cb_called == 0);
+ ++fs_event_cb_called;
+
+ ASSERT(handle == &fs_event);
+ ASSERT(status == 0);
+ ASSERT(events == UV_CHANGE);
+ #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
+ ASSERT(strcmp(filename, "watch_file") == 0);
+ #else
+ ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0);
+ #endif
+
+ /* Regression test for SunOS: touch should generate just one event. */
+ {
+ static uv_timer_t timer;
+ uv_timer_init(handle->loop, &timer);
+ timer.data = handle;
+ uv_timer_start(&timer, timer_cb_close_handle, 250, 0);
+ }
+}
+
+static void timer_cb_file(uv_timer_t* handle) {
+ ++timer_cb_called;
+
+ if (timer_cb_called == 1) {
+ touch_file("watch_dir/file1");
+ } else {
+ touch_file("watch_dir/file2");
+ uv_close((uv_handle_t*)handle, close_cb);
+ }
+}
+
+static void timer_cb_touch(uv_timer_t* timer) {
+ uv_close((uv_handle_t*)timer, NULL);
+ touch_file("watch_file");
+ timer_cb_touch_called++;
+}
+
+static void timer_cb_watch_twice(uv_timer_t* handle) {
+ uv_fs_event_t* handles = handle->data;
+ uv_close((uv_handle_t*) (handles + 0), NULL);
+ uv_close((uv_handle_t*) (handles + 1), NULL);
+ uv_close((uv_handle_t*) handle, NULL);
+}
+
+TEST_IMPL(fs_event_watch_dir) {
+ uv_loop_t* loop = uv_default_loop();
+ int r;
+
+ /* Setup */
+ fs_event_unlink_files(NULL);
+ remove("watch_dir/file2");
+ remove("watch_dir/file1");
+ remove("watch_dir/");
+ create_dir("watch_dir");
+
+ r = uv_fs_event_init(loop, &fs_event);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event, fs_event_cb_dir_multi_file, "watch_dir", 0);
+ ASSERT(r == 0);
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r == 0);
+ r = uv_timer_start(&timer, fs_event_create_files, 100, 0);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(fs_event_cb_called == fs_event_created + fs_event_removed);
+ ASSERT(close_cb_called == 2);
+
+ /* Cleanup */
+ fs_event_unlink_files(NULL);
+ remove("watch_dir/file2");
+ remove("watch_dir/file1");
+ remove("watch_dir/");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(fs_event_watch_dir_recursive) {
+#if defined(__APPLE__) || defined(_WIN32)
+ uv_loop_t* loop;
+ int r;
+
+ /* Setup */
+ loop = uv_default_loop();
+ fs_event_unlink_files(NULL);
+ remove("watch_dir/file2");
+ remove("watch_dir/file1");
+ remove("watch_dir/subdir");
+ remove("watch_dir/");
+ create_dir("watch_dir");
+ create_dir("watch_dir/subdir");
+
+ r = uv_fs_event_init(loop, &fs_event);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event, fs_event_cb_dir_multi_file_in_subdir, "watch_dir", UV_FS_EVENT_RECURSIVE);
+ ASSERT(r == 0);
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r == 0);
+ r = uv_timer_start(&timer, fs_event_create_files_in_subdir, 100, 0);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(fs_event_cb_called == fs_event_created + fs_event_removed);
+ ASSERT(close_cb_called == 2);
+
+ /* Cleanup */
+ fs_event_unlink_files_in_subdir(NULL);
+ remove("watch_dir/file2");
+ remove("watch_dir/file1");
+ remove("watch_dir/subdir");
+ remove("watch_dir/");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+#else
+ RETURN_SKIP("Recursive directory watching not supported on this platform.");
+#endif
+}
+
+
+TEST_IMPL(fs_event_watch_file) {
+ uv_loop_t* loop = uv_default_loop();
+ int r;
+
+ /* Setup */
+ remove("watch_dir/file2");
+ remove("watch_dir/file1");
+ remove("watch_dir/");
+ create_dir("watch_dir");
+ create_file("watch_dir/file1");
+ create_file("watch_dir/file2");
+
+ r = uv_fs_event_init(loop, &fs_event);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event, fs_event_cb_file, "watch_dir/file2", 0);
+ ASSERT(r == 0);
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r == 0);
+ r = uv_timer_start(&timer, timer_cb_file, 100, 100);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(fs_event_cb_called == 1);
+ ASSERT(timer_cb_called == 2);
+ ASSERT(close_cb_called == 2);
+
+ /* Cleanup */
+ remove("watch_dir/file2");
+ remove("watch_dir/file1");
+ remove("watch_dir/");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(fs_event_watch_file_twice) {
+ const char path[] = "test/fixtures/empty_file";
+ uv_fs_event_t watchers[2];
+ uv_timer_t timer;
+ uv_loop_t* loop;
+
+ loop = uv_default_loop();
+ timer.data = watchers;
+
+ ASSERT(0 == uv_fs_event_init(loop, watchers + 0));
+ ASSERT(0 == uv_fs_event_start(watchers + 0, fail_cb, path, 0));
+ ASSERT(0 == uv_fs_event_init(loop, watchers + 1));
+ ASSERT(0 == uv_fs_event_start(watchers + 1, fail_cb, path, 0));
+ ASSERT(0 == uv_timer_init(loop, &timer));
+ ASSERT(0 == uv_timer_start(&timer, timer_cb_watch_twice, 10, 0));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(fs_event_watch_file_current_dir) {
+ uv_timer_t timer;
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+
+ /* Setup */
+ remove("watch_file");
+ create_file("watch_file");
+
+ r = uv_fs_event_init(loop, &fs_event);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event,
+ fs_event_cb_file_current_dir,
+ "watch_file",
+ 0);
+ ASSERT(r == 0);
+
+
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r == 0);
+
+ r = uv_timer_start(&timer, timer_cb_touch, 10, 0);
+ ASSERT(r == 0);
+
+ ASSERT(timer_cb_touch_called == 0);
+ ASSERT(fs_event_cb_called == 0);
+ ASSERT(close_cb_called == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(timer_cb_touch_called == 1);
+ ASSERT(fs_event_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ /* Cleanup */
+ remove("watch_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(fs_event_no_callback_after_close) {
+ uv_loop_t* loop = uv_default_loop();
+ int r;
+
+ /* Setup */
+ remove("watch_dir/file1");
+ remove("watch_dir/");
+ create_dir("watch_dir");
+ create_file("watch_dir/file1");
+
+ r = uv_fs_event_init(loop, &fs_event);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event,
+ fs_event_cb_file,
+ "watch_dir/file1",
+ 0);
+ ASSERT(r == 0);
+
+
+ uv_close((uv_handle_t*)&fs_event, close_cb);
+ touch_file("watch_dir/file1");
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(fs_event_cb_called == 0);
+ ASSERT(close_cb_called == 1);
+
+ /* Cleanup */
+ remove("watch_dir/file1");
+ remove("watch_dir/");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(fs_event_no_callback_on_close) {
+ uv_loop_t* loop = uv_default_loop();
+ int r;
+
+ /* Setup */
+ remove("watch_dir/file1");
+ remove("watch_dir/");
+ create_dir("watch_dir");
+ create_file("watch_dir/file1");
+
+ r = uv_fs_event_init(loop, &fs_event);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event,
+ fs_event_cb_file,
+ "watch_dir/file1",
+ 0);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*)&fs_event, close_cb);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(fs_event_cb_called == 0);
+ ASSERT(close_cb_called == 1);
+
+ /* Cleanup */
+ remove("watch_dir/file1");
+ remove("watch_dir/");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+static void fs_event_fail(uv_fs_event_t* handle, const char* filename,
+ int events, int status) {
+ ASSERT(0 && "should never be called");
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ int r;
+
+ r = uv_fs_event_init(handle->loop, &fs_event);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event, fs_event_fail, ".", 0);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*)&fs_event, close_cb);
+ uv_close((uv_handle_t*)handle, close_cb);
+}
+
+
+TEST_IMPL(fs_event_immediate_close) {
+ uv_timer_t timer;
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r == 0);
+
+ r = uv_timer_start(&timer, timer_cb, 1, 0);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_event_close_with_pending_event) {
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+
+ create_dir("watch_dir");
+ create_file("watch_dir/file");
+
+ r = uv_fs_event_init(loop, &fs_event);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir", 0);
+ ASSERT(r == 0);
+
+ /* Generate an fs event. */
+ touch_file("watch_dir/file");
+
+ uv_close((uv_handle_t*)&fs_event, close_cb);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ /* Clean up */
+ remove("watch_dir/file");
+ remove("watch_dir/");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#if defined(HAVE_KQUEUE)
+
+/* kqueue doesn't register fs events if you don't have an active watcher.
+ * The file descriptor needs to be part of the kqueue set of interest and
+ * that's not the case until we actually enter the event loop.
+ */
+TEST_IMPL(fs_event_close_in_callback) {
+ fprintf(stderr, "Skipping test, doesn't work with kqueue.\n");
+ return 0;
+}
+
+#else /* !HAVE_KQUEUE */
+
+static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename,
+ int events, int status) {
+ ASSERT(status == 0);
+
+ ASSERT(fs_event_cb_called < 3);
+ ++fs_event_cb_called;
+
+ if (fs_event_cb_called == 3) {
+ uv_close((uv_handle_t*) handle, close_cb);
+ }
+}
+
+
+TEST_IMPL(fs_event_close_in_callback) {
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+
+ create_dir("watch_dir");
+ create_file("watch_dir/file1");
+ create_file("watch_dir/file2");
+ create_file("watch_dir/file3");
+ create_file("watch_dir/file4");
+ create_file("watch_dir/file5");
+
+ r = uv_fs_event_init(loop, &fs_event);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event, fs_event_cb_close, "watch_dir", 0);
+ ASSERT(r == 0);
+
+ /* Generate a couple of fs events. */
+ touch_file("watch_dir/file1");
+ touch_file("watch_dir/file2");
+ touch_file("watch_dir/file3");
+ touch_file("watch_dir/file4");
+ touch_file("watch_dir/file5");
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+ ASSERT(fs_event_cb_called == 3);
+
+ /* Clean up */
+ remove("watch_dir/file1");
+ remove("watch_dir/file2");
+ remove("watch_dir/file3");
+ remove("watch_dir/file4");
+ remove("watch_dir/file5");
+ remove("watch_dir/");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* HAVE_KQUEUE */
+
+TEST_IMPL(fs_event_start_and_close) {
+ uv_loop_t* loop;
+ uv_fs_event_t fs_event1;
+ uv_fs_event_t fs_event2;
+ int r;
+
+ loop = uv_default_loop();
+
+ create_dir("watch_dir");
+
+ r = uv_fs_event_init(loop, &fs_event1);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event1, fs_event_cb_dir, "watch_dir", 0);
+ ASSERT(r == 0);
+
+ r = uv_fs_event_init(loop, &fs_event2);
+ ASSERT(r == 0);
+ r = uv_fs_event_start(&fs_event2, fs_event_cb_dir, "watch_dir", 0);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*) &fs_event2, close_cb);
+ uv_close((uv_handle_t*) &fs_event1, close_cb);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 2);
+
+ remove("watch_dir/");
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(fs_event_getpath) {
+ uv_loop_t* loop = uv_default_loop();
+ int r;
+ char buf[1024];
+ size_t len;
+
+ create_dir("watch_dir");
+
+ r = uv_fs_event_init(loop, &fs_event);
+ ASSERT(r == 0);
+ len = sizeof buf;
+ r = uv_fs_event_getpath(&fs_event, buf, &len);
+ ASSERT(r == UV_EINVAL);
+ r = uv_fs_event_start(&fs_event, fail_cb, "watch_dir", 0);
+ ASSERT(r == 0);
+ len = sizeof buf;
+ r = uv_fs_event_getpath(&fs_event, buf, &len);
+ ASSERT(r == 0);
+ ASSERT(buf[len - 1] != 0);
+ ASSERT(memcmp(buf, "watch_dir", len) == 0);
+ r = uv_fs_event_stop(&fs_event);
+ ASSERT(r == 0);
+ uv_close((uv_handle_t*) &fs_event, close_cb);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ remove("watch_dir/");
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#if defined(__APPLE__)
+
+static int fs_event_error_reported;
+
+static void fs_event_error_report_cb(uv_fs_event_t* handle,
+ const char* filename,
+ int events,
+ int status) {
+ if (status != 0)
+ fs_event_error_reported = status;
+}
+
+static void timer_cb_nop(uv_timer_t* handle) {
+ ++timer_cb_called;
+ uv_close((uv_handle_t*) handle, close_cb);
+}
+
+static void fs_event_error_report_close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+
+ /* handle is allocated on-stack, no need to free it */
+}
+
+
+TEST_IMPL(fs_event_error_reporting) {
+ unsigned int i;
+ uv_loop_t loops[1024];
+ uv_fs_event_t events[ARRAY_SIZE(loops)];
+ uv_loop_t* loop;
+ uv_fs_event_t* event;
+
+ TEST_FILE_LIMIT(ARRAY_SIZE(loops) * 3);
+
+ remove("watch_dir/");
+ create_dir("watch_dir");
+
+ /* Create a lot of loops, and start FSEventStream in each of them.
+ * Eventually, this should create enough streams to make FSEventStreamStart()
+ * fail.
+ */
+ for (i = 0; i < ARRAY_SIZE(loops); i++) {
+ loop = &loops[i];
+ ASSERT(0 == uv_loop_init(loop));
+ event = &events[i];
+
+ timer_cb_called = 0;
+ close_cb_called = 0;
+ ASSERT(0 == uv_fs_event_init(loop, event));
+ ASSERT(0 == uv_fs_event_start(event,
+ fs_event_error_report_cb,
+ "watch_dir",
+ 0));
+ uv_unref((uv_handle_t*) event);
+
+ /* Let loop run for some time */
+ ASSERT(0 == uv_timer_init(loop, &timer));
+ ASSERT(0 == uv_timer_start(&timer, timer_cb_nop, 2, 0));
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(1 == timer_cb_called);
+ ASSERT(1 == close_cb_called);
+ if (fs_event_error_reported != 0)
+ break;
+ }
+
+ /* At least one loop should fail */
+ ASSERT(fs_event_error_reported == UV_EMFILE);
+
+ /* Stop and close all events, and destroy loops */
+ do {
+ loop = &loops[i];
+ event = &events[i];
+
+ ASSERT(0 == uv_fs_event_stop(event));
+ uv_ref((uv_handle_t*) event);
+ uv_close((uv_handle_t*) event, fs_event_error_report_close_cb);
+
+ close_cb_called = 0;
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(close_cb_called == 1);
+
+ uv_loop_close(loop);
+ } while (i-- != 0);
+
+ remove("watch_dir/");
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#else /* !defined(__APPLE__) */
+
+TEST_IMPL(fs_event_error_reporting) {
+ /* No-op, needed only for FSEvents backend */
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* defined(__APPLE__) */
diff --git a/3rdparty/libuv/test/test-fs-poll.c b/3rdparty/libuv/test/test-fs-poll.c
new file mode 100644
index 00000000000..dbc1515b0b1
--- /dev/null
+++ b/3rdparty/libuv/test/test-fs-poll.c
@@ -0,0 +1,186 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <string.h>
+
+#define FIXTURE "testfile"
+
+static void timer_cb(uv_timer_t* handle);
+static void close_cb(uv_handle_t* handle);
+static void poll_cb(uv_fs_poll_t* handle,
+ int status,
+ const uv_stat_t* prev,
+ const uv_stat_t* curr);
+
+static void poll_cb_fail(uv_fs_poll_t* handle,
+ int status,
+ const uv_stat_t* prev,
+ const uv_stat_t* curr);
+
+static uv_fs_poll_t poll_handle;
+static uv_timer_t timer_handle;
+static uv_loop_t* loop;
+
+static int poll_cb_called;
+static int timer_cb_called;
+static int close_cb_called;
+
+
+static void touch_file(const char* path) {
+ static int count;
+ FILE* fp;
+ int i;
+
+ ASSERT((fp = fopen(FIXTURE, "w+")));
+
+ /* Need to change the file size because the poller may not pick up
+ * sub-second mtime changes.
+ */
+ i = ++count;
+
+ while (i--)
+ fputc('*', fp);
+
+ fclose(fp);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ touch_file(FIXTURE);
+ timer_cb_called++;
+}
+
+
+static void poll_cb_fail(uv_fs_poll_t* handle,
+ int status,
+ const uv_stat_t* prev,
+ const uv_stat_t* curr) {
+ ASSERT(0 && "fail_cb called");
+}
+
+
+static void poll_cb(uv_fs_poll_t* handle,
+ int status,
+ const uv_stat_t* prev,
+ const uv_stat_t* curr) {
+ uv_stat_t zero_statbuf;
+
+ memset(&zero_statbuf, 0, sizeof(zero_statbuf));
+
+ ASSERT(handle == &poll_handle);
+ ASSERT(1 == uv_is_active((uv_handle_t*) handle));
+ ASSERT(prev != NULL);
+ ASSERT(curr != NULL);
+
+ switch (poll_cb_called++) {
+ case 0:
+ ASSERT(status == UV_ENOENT);
+ ASSERT(0 == memcmp(prev, &zero_statbuf, sizeof(zero_statbuf)));
+ ASSERT(0 == memcmp(curr, &zero_statbuf, sizeof(zero_statbuf)));
+ touch_file(FIXTURE);
+ break;
+
+ case 1:
+ ASSERT(status == 0);
+ ASSERT(0 == memcmp(prev, &zero_statbuf, sizeof(zero_statbuf)));
+ ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf)));
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 20, 0));
+ break;
+
+ case 2:
+ ASSERT(status == 0);
+ ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf)));
+ ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf)));
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 200, 0));
+ break;
+
+ case 3:
+ ASSERT(status == 0);
+ ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf)));
+ ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf)));
+ remove(FIXTURE);
+ break;
+
+ case 4:
+ ASSERT(status == UV_ENOENT);
+ ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf)));
+ ASSERT(0 == memcmp(curr, &zero_statbuf, sizeof(zero_statbuf)));
+ uv_close((uv_handle_t*)handle, close_cb);
+ break;
+
+ default:
+ ASSERT(0);
+ }
+}
+
+
+TEST_IMPL(fs_poll) {
+ loop = uv_default_loop();
+
+ remove(FIXTURE);
+
+ ASSERT(0 == uv_timer_init(loop, &timer_handle));
+ ASSERT(0 == uv_fs_poll_init(loop, &poll_handle));
+ ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb, FIXTURE, 100));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ ASSERT(poll_cb_called == 5);
+ ASSERT(timer_cb_called == 2);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_poll_getpath) {
+ char buf[1024];
+ size_t len;
+ loop = uv_default_loop();
+
+ remove(FIXTURE);
+
+ ASSERT(0 == uv_fs_poll_init(loop, &poll_handle));
+ len = sizeof buf;
+ ASSERT(UV_EINVAL == uv_fs_poll_getpath(&poll_handle, buf, &len));
+ ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100));
+ len = sizeof buf;
+ ASSERT(0 == uv_fs_poll_getpath(&poll_handle, buf, &len));
+ ASSERT(buf[len - 1] != 0);
+ ASSERT(0 == memcmp(buf, FIXTURE, len));
+
+ uv_close((uv_handle_t*) &poll_handle, close_cb);
+
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-fs.c b/3rdparty/libuv/test/test-fs.c
new file mode 100644
index 00000000000..cf37ac4909c
--- /dev/null
+++ b/3rdparty/libuv/test/test-fs.c
@@ -0,0 +1,2664 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <errno.h>
+#include <string.h> /* memset */
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/* FIXME we shouldn't need to branch in this file */
+#if defined(__unix__) || defined(__POSIX__) || \
+ defined(__APPLE__) || defined(_AIX)
+#include <unistd.h> /* unlink, rmdir, etc. */
+#else
+# include <direct.h>
+# include <io.h>
+# define unlink _unlink
+# define rmdir _rmdir
+# define open _open
+# define write _write
+# define close _close
+# ifndef stat
+# define stat _stati64
+# endif
+# ifndef lseek
+# define lseek _lseek
+# endif
+#endif
+
+#define TOO_LONG_NAME_LENGTH 65536
+#define PATHMAX 1024
+
+typedef struct {
+ const char* path;
+ double atime;
+ double mtime;
+} utime_check_t;
+
+
+static int dummy_cb_count;
+static int close_cb_count;
+static int create_cb_count;
+static int open_cb_count;
+static int read_cb_count;
+static int write_cb_count;
+static int unlink_cb_count;
+static int mkdir_cb_count;
+static int mkdtemp_cb_count;
+static int rmdir_cb_count;
+static int scandir_cb_count;
+static int stat_cb_count;
+static int rename_cb_count;
+static int fsync_cb_count;
+static int fdatasync_cb_count;
+static int ftruncate_cb_count;
+static int sendfile_cb_count;
+static int fstat_cb_count;
+static int access_cb_count;
+static int chmod_cb_count;
+static int fchmod_cb_count;
+static int chown_cb_count;
+static int fchown_cb_count;
+static int link_cb_count;
+static int symlink_cb_count;
+static int readlink_cb_count;
+static int realpath_cb_count;
+static int utime_cb_count;
+static int futime_cb_count;
+
+static uv_loop_t* loop;
+
+static uv_fs_t open_req1;
+static uv_fs_t open_req2;
+static uv_fs_t read_req;
+static uv_fs_t write_req;
+static uv_fs_t unlink_req;
+static uv_fs_t close_req;
+static uv_fs_t mkdir_req;
+static uv_fs_t mkdtemp_req1;
+static uv_fs_t mkdtemp_req2;
+static uv_fs_t rmdir_req;
+static uv_fs_t scandir_req;
+static uv_fs_t stat_req;
+static uv_fs_t rename_req;
+static uv_fs_t fsync_req;
+static uv_fs_t fdatasync_req;
+static uv_fs_t ftruncate_req;
+static uv_fs_t sendfile_req;
+static uv_fs_t utime_req;
+static uv_fs_t futime_req;
+
+static char buf[32];
+static char buf2[32];
+static char test_buf[] = "test-buffer\n";
+static char test_buf2[] = "second-buffer\n";
+static uv_buf_t iov;
+
+static void check_permission(const char* filename, unsigned int mode) {
+ int r;
+ uv_fs_t req;
+ uv_stat_t* s;
+
+ r = uv_fs_stat(NULL, &req, filename, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+
+ s = &req.statbuf;
+#ifdef _WIN32
+ /*
+ * On Windows, chmod can only modify S_IWUSR (_S_IWRITE) bit,
+ * so only testing for the specified flags.
+ */
+ ASSERT((s->st_mode & 0777) & mode);
+#else
+ ASSERT((s->st_mode & 0777) == mode);
+#endif
+
+ uv_fs_req_cleanup(&req);
+}
+
+
+static void dummy_cb(uv_fs_t* req) {
+ (void) req;
+ dummy_cb_count++;
+}
+
+
+static void link_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_LINK);
+ ASSERT(req->result == 0);
+ link_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+
+static void symlink_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_SYMLINK);
+ ASSERT(req->result == 0);
+ symlink_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+static void readlink_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_READLINK);
+ ASSERT(req->result == 0);
+ ASSERT(strcmp(req->ptr, "test_file_symlink2") == 0);
+ readlink_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+
+static void realpath_cb(uv_fs_t* req) {
+ char test_file_abs_buf[PATHMAX];
+ size_t test_file_abs_size = sizeof(test_file_abs_buf);
+ ASSERT(req->fs_type == UV_FS_REALPATH);
+#ifdef _WIN32
+ /*
+ * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW()
+ */
+ if (req->result == UV_ENOSYS) {
+ realpath_cb_count++;
+ uv_fs_req_cleanup(req);
+ return;
+ }
+#endif
+ ASSERT(req->result == 0);
+
+ uv_cwd(test_file_abs_buf, &test_file_abs_size);
+#ifdef _WIN32
+ strcat(test_file_abs_buf, "\\test_file");
+ ASSERT(stricmp(req->ptr, test_file_abs_buf) == 0);
+#else
+ strcat(test_file_abs_buf, "/test_file");
+ ASSERT(strcmp(req->ptr, test_file_abs_buf) == 0);
+#endif
+ realpath_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+
+static void access_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_ACCESS);
+ access_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+
+static void fchmod_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_FCHMOD);
+ ASSERT(req->result == 0);
+ fchmod_cb_count++;
+ uv_fs_req_cleanup(req);
+ check_permission("test_file", *(int*)req->data);
+}
+
+
+static void chmod_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_CHMOD);
+ ASSERT(req->result == 0);
+ chmod_cb_count++;
+ uv_fs_req_cleanup(req);
+ check_permission("test_file", *(int*)req->data);
+}
+
+
+static void fchown_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_FCHOWN);
+ ASSERT(req->result == 0);
+ fchown_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+
+static void chown_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_CHOWN);
+ ASSERT(req->result == 0);
+ chown_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+static void chown_root_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_CHOWN);
+#ifdef _WIN32
+ /* On windows, chown is a no-op and always succeeds. */
+ ASSERT(req->result == 0);
+#else
+ /* On unix, chown'ing the root directory is not allowed -
+ * unless you're root, of course.
+ */
+ if (geteuid() == 0)
+ ASSERT(req->result == 0);
+ else
+ ASSERT(req->result == UV_EPERM);
+#endif
+ chown_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+static void unlink_cb(uv_fs_t* req) {
+ ASSERT(req == &unlink_req);
+ ASSERT(req->fs_type == UV_FS_UNLINK);
+ ASSERT(req->result == 0);
+ unlink_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+static void fstat_cb(uv_fs_t* req) {
+ uv_stat_t* s = req->ptr;
+ ASSERT(req->fs_type == UV_FS_FSTAT);
+ ASSERT(req->result == 0);
+ ASSERT(s->st_size == sizeof(test_buf));
+ uv_fs_req_cleanup(req);
+ fstat_cb_count++;
+}
+
+
+static void close_cb(uv_fs_t* req) {
+ int r;
+ ASSERT(req == &close_req);
+ ASSERT(req->fs_type == UV_FS_CLOSE);
+ ASSERT(req->result == 0);
+ close_cb_count++;
+ uv_fs_req_cleanup(req);
+ if (close_cb_count == 3) {
+ r = uv_fs_unlink(loop, &unlink_req, "test_file2", unlink_cb);
+ ASSERT(r == 0);
+ }
+}
+
+
+static void ftruncate_cb(uv_fs_t* req) {
+ int r;
+ ASSERT(req == &ftruncate_req);
+ ASSERT(req->fs_type == UV_FS_FTRUNCATE);
+ ASSERT(req->result == 0);
+ ftruncate_cb_count++;
+ uv_fs_req_cleanup(req);
+ r = uv_fs_close(loop, &close_req, open_req1.result, close_cb);
+ ASSERT(r == 0);
+}
+
+
+static void read_cb(uv_fs_t* req) {
+ int r;
+ ASSERT(req == &read_req);
+ ASSERT(req->fs_type == UV_FS_READ);
+ ASSERT(req->result >= 0); /* FIXME(bnoordhuis) Check if requested size? */
+ read_cb_count++;
+ uv_fs_req_cleanup(req);
+ if (read_cb_count == 1) {
+ ASSERT(strcmp(buf, test_buf) == 0);
+ r = uv_fs_ftruncate(loop, &ftruncate_req, open_req1.result, 7,
+ ftruncate_cb);
+ } else {
+ ASSERT(strcmp(buf, "test-bu") == 0);
+ r = uv_fs_close(loop, &close_req, open_req1.result, close_cb);
+ }
+ ASSERT(r == 0);
+}
+
+
+static void open_cb(uv_fs_t* req) {
+ int r;
+ ASSERT(req == &open_req1);
+ ASSERT(req->fs_type == UV_FS_OPEN);
+ if (req->result < 0) {
+ fprintf(stderr, "async open error: %d\n", (int) req->result);
+ ASSERT(0);
+ }
+ open_cb_count++;
+ ASSERT(req->path);
+ ASSERT(memcmp(req->path, "test_file2\0", 11) == 0);
+ uv_fs_req_cleanup(req);
+ memset(buf, 0, sizeof(buf));
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1, -1,
+ read_cb);
+ ASSERT(r == 0);
+}
+
+
+static void open_cb_simple(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_OPEN);
+ if (req->result < 0) {
+ fprintf(stderr, "async open error: %d\n", (int) req->result);
+ ASSERT(0);
+ }
+ open_cb_count++;
+ ASSERT(req->path);
+ uv_fs_req_cleanup(req);
+}
+
+
+static void fsync_cb(uv_fs_t* req) {
+ int r;
+ ASSERT(req == &fsync_req);
+ ASSERT(req->fs_type == UV_FS_FSYNC);
+ ASSERT(req->result == 0);
+ fsync_cb_count++;
+ uv_fs_req_cleanup(req);
+ r = uv_fs_close(loop, &close_req, open_req1.result, close_cb);
+ ASSERT(r == 0);
+}
+
+
+static void fdatasync_cb(uv_fs_t* req) {
+ int r;
+ ASSERT(req == &fdatasync_req);
+ ASSERT(req->fs_type == UV_FS_FDATASYNC);
+ ASSERT(req->result == 0);
+ fdatasync_cb_count++;
+ uv_fs_req_cleanup(req);
+ r = uv_fs_fsync(loop, &fsync_req, open_req1.result, fsync_cb);
+ ASSERT(r == 0);
+}
+
+
+static void write_cb(uv_fs_t* req) {
+ int r;
+ ASSERT(req == &write_req);
+ ASSERT(req->fs_type == UV_FS_WRITE);
+ ASSERT(req->result >= 0); /* FIXME(bnoordhuis) Check if requested size? */
+ write_cb_count++;
+ uv_fs_req_cleanup(req);
+ r = uv_fs_fdatasync(loop, &fdatasync_req, open_req1.result, fdatasync_cb);
+ ASSERT(r == 0);
+}
+
+
+static void create_cb(uv_fs_t* req) {
+ int r;
+ ASSERT(req == &open_req1);
+ ASSERT(req->fs_type == UV_FS_OPEN);
+ ASSERT(req->result >= 0);
+ create_cb_count++;
+ uv_fs_req_cleanup(req);
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(loop, &write_req, req->result, &iov, 1, -1, write_cb);
+ ASSERT(r == 0);
+}
+
+
+static void rename_cb(uv_fs_t* req) {
+ ASSERT(req == &rename_req);
+ ASSERT(req->fs_type == UV_FS_RENAME);
+ ASSERT(req->result == 0);
+ rename_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+
+static void mkdir_cb(uv_fs_t* req) {
+ ASSERT(req == &mkdir_req);
+ ASSERT(req->fs_type == UV_FS_MKDIR);
+ ASSERT(req->result == 0);
+ mkdir_cb_count++;
+ ASSERT(req->path);
+ ASSERT(memcmp(req->path, "test_dir\0", 9) == 0);
+ uv_fs_req_cleanup(req);
+}
+
+
+static void check_mkdtemp_result(uv_fs_t* req) {
+ int r;
+
+ ASSERT(req->fs_type == UV_FS_MKDTEMP);
+ ASSERT(req->result == 0);
+ ASSERT(req->path);
+ ASSERT(strlen(req->path) == 15);
+ ASSERT(memcmp(req->path, "test_dir_", 9) == 0);
+ ASSERT(memcmp(req->path + 9, "XXXXXX", 6) != 0);
+ check_permission(req->path, 0700);
+
+ /* Check if req->path is actually a directory */
+ r = uv_fs_stat(NULL, &stat_req, req->path, NULL);
+ ASSERT(r == 0);
+ ASSERT(((uv_stat_t*)stat_req.ptr)->st_mode & S_IFDIR);
+ uv_fs_req_cleanup(&stat_req);
+}
+
+
+static void mkdtemp_cb(uv_fs_t* req) {
+ ASSERT(req == &mkdtemp_req1);
+ check_mkdtemp_result(req);
+ mkdtemp_cb_count++;
+}
+
+
+static void rmdir_cb(uv_fs_t* req) {
+ ASSERT(req == &rmdir_req);
+ ASSERT(req->fs_type == UV_FS_RMDIR);
+ ASSERT(req->result == 0);
+ rmdir_cb_count++;
+ ASSERT(req->path);
+ ASSERT(memcmp(req->path, "test_dir\0", 9) == 0);
+ uv_fs_req_cleanup(req);
+}
+
+
+static void assert_is_file_type(uv_dirent_t dent) {
+#ifdef HAVE_DIRENT_TYPES
+ /*
+ * For Apple and Windows, we know getdents is expected to work but for other
+ * environments, the filesystem dictates whether or not getdents supports
+ * returning the file type.
+ *
+ * See:
+ * http://man7.org/linux/man-pages/man2/getdents.2.html
+ * https://github.com/libuv/libuv/issues/501
+ */
+ #if defined(__APPLE__) || defined(_WIN32)
+ ASSERT(dent.type == UV_DIRENT_FILE);
+ #else
+ ASSERT(dent.type == UV_DIRENT_FILE || dent.type == UV_DIRENT_UNKNOWN);
+ #endif
+#else
+ ASSERT(dent.type == UV_DIRENT_UNKNOWN);
+#endif
+}
+
+
+static void scandir_cb(uv_fs_t* req) {
+ uv_dirent_t dent;
+ ASSERT(req == &scandir_req);
+ ASSERT(req->fs_type == UV_FS_SCANDIR);
+ ASSERT(req->result == 2);
+ ASSERT(req->ptr);
+
+ while (UV_EOF != uv_fs_scandir_next(req, &dent)) {
+ ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
+ assert_is_file_type(dent);
+ }
+ scandir_cb_count++;
+ ASSERT(req->path);
+ ASSERT(memcmp(req->path, "test_dir\0", 9) == 0);
+ uv_fs_req_cleanup(req);
+ ASSERT(!req->ptr);
+}
+
+
+static void empty_scandir_cb(uv_fs_t* req) {
+ uv_dirent_t dent;
+
+ ASSERT(req == &scandir_req);
+ ASSERT(req->fs_type == UV_FS_SCANDIR);
+ ASSERT(req->result == 0);
+ ASSERT(req->ptr == NULL);
+ ASSERT(UV_EOF == uv_fs_scandir_next(req, &dent));
+ uv_fs_req_cleanup(req);
+ scandir_cb_count++;
+}
+
+
+static void file_scandir_cb(uv_fs_t* req) {
+ ASSERT(req == &scandir_req);
+ ASSERT(req->fs_type == UV_FS_SCANDIR);
+ ASSERT(req->result == UV_ENOTDIR);
+ ASSERT(req->ptr == NULL);
+ uv_fs_req_cleanup(req);
+ scandir_cb_count++;
+}
+
+
+static void stat_cb(uv_fs_t* req) {
+ ASSERT(req == &stat_req);
+ ASSERT(req->fs_type == UV_FS_STAT || req->fs_type == UV_FS_LSTAT);
+ ASSERT(req->result == 0);
+ ASSERT(req->ptr);
+ stat_cb_count++;
+ uv_fs_req_cleanup(req);
+ ASSERT(!req->ptr);
+}
+
+
+static void sendfile_cb(uv_fs_t* req) {
+ ASSERT(req == &sendfile_req);
+ ASSERT(req->fs_type == UV_FS_SENDFILE);
+ ASSERT(req->result == 65546);
+ sendfile_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+
+static void open_noent_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_OPEN);
+ ASSERT(req->result == UV_ENOENT);
+ open_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+static void open_nametoolong_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_OPEN);
+ ASSERT(req->result == UV_ENAMETOOLONG);
+ open_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+static void open_loop_cb(uv_fs_t* req) {
+ ASSERT(req->fs_type == UV_FS_OPEN);
+ ASSERT(req->result == UV_ELOOP);
+ open_cb_count++;
+ uv_fs_req_cleanup(req);
+}
+
+
+TEST_IMPL(fs_file_noent) {
+ uv_fs_t req;
+ int r;
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &req, "does_not_exist", O_RDONLY, 0, NULL);
+ ASSERT(r == UV_ENOENT);
+ ASSERT(req.result == UV_ENOENT);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_open(loop, &req, "does_not_exist", O_RDONLY, 0, open_noent_cb);
+ ASSERT(r == 0);
+
+ ASSERT(open_cb_count == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(open_cb_count == 1);
+
+ /* TODO add EACCES test */
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(fs_file_nametoolong) {
+ uv_fs_t req;
+ int r;
+ char name[TOO_LONG_NAME_LENGTH + 1];
+
+ loop = uv_default_loop();
+
+ memset(name, 'a', TOO_LONG_NAME_LENGTH);
+ name[TOO_LONG_NAME_LENGTH] = 0;
+
+ r = uv_fs_open(NULL, &req, name, O_RDONLY, 0, NULL);
+ ASSERT(r == UV_ENAMETOOLONG);
+ ASSERT(req.result == UV_ENAMETOOLONG);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_open(loop, &req, name, O_RDONLY, 0, open_nametoolong_cb);
+ ASSERT(r == 0);
+
+ ASSERT(open_cb_count == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(open_cb_count == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(fs_file_loop) {
+ uv_fs_t req;
+ int r;
+
+ loop = uv_default_loop();
+
+ unlink("test_symlink");
+ r = uv_fs_symlink(NULL, &req, "test_symlink", "test_symlink", 0, NULL);
+#ifdef _WIN32
+ /*
+ * Windows XP and Server 2003 don't support symlinks; we'll get UV_ENOTSUP.
+ * Starting with vista they are supported, but only when elevated, otherwise
+ * we'll see UV_EPERM.
+ */
+ if (r == UV_ENOTSUP || r == UV_EPERM)
+ return 0;
+#endif
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_open(NULL, &req, "test_symlink", O_RDONLY, 0, NULL);
+ ASSERT(r == UV_ELOOP);
+ ASSERT(req.result == UV_ELOOP);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_open(loop, &req, "test_symlink", O_RDONLY, 0, open_loop_cb);
+ ASSERT(r == 0);
+
+ ASSERT(open_cb_count == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(open_cb_count == 1);
+
+ unlink("test_symlink");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+static void check_utime(const char* path, double atime, double mtime) {
+ uv_stat_t* s;
+ uv_fs_t req;
+ int r;
+
+ r = uv_fs_stat(loop, &req, path, NULL);
+ ASSERT(r == 0);
+
+ ASSERT(req.result == 0);
+ s = &req.statbuf;
+
+ ASSERT(s->st_atim.tv_sec == atime);
+ ASSERT(s->st_mtim.tv_sec == mtime);
+
+ uv_fs_req_cleanup(&req);
+}
+
+
+static void utime_cb(uv_fs_t* req) {
+ utime_check_t* c;
+
+ ASSERT(req == &utime_req);
+ ASSERT(req->result == 0);
+ ASSERT(req->fs_type == UV_FS_UTIME);
+
+ c = req->data;
+ check_utime(c->path, c->atime, c->mtime);
+
+ uv_fs_req_cleanup(req);
+ utime_cb_count++;
+}
+
+
+static void futime_cb(uv_fs_t* req) {
+ utime_check_t* c;
+
+ ASSERT(req == &futime_req);
+ ASSERT(req->result == 0);
+ ASSERT(req->fs_type == UV_FS_FUTIME);
+
+ c = req->data;
+ check_utime(c->path, c->atime, c->mtime);
+
+ uv_fs_req_cleanup(req);
+ futime_cb_count++;
+}
+
+
+TEST_IMPL(fs_file_async) {
+ int r;
+
+ /* Setup. */
+ unlink("test_file");
+ unlink("test_file2");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT,
+ S_IRUSR | S_IWUSR, create_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(create_cb_count == 1);
+ ASSERT(write_cb_count == 1);
+ ASSERT(fsync_cb_count == 1);
+ ASSERT(fdatasync_cb_count == 1);
+ ASSERT(close_cb_count == 1);
+
+ r = uv_fs_rename(loop, &rename_req, "test_file", "test_file2", rename_cb);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(create_cb_count == 1);
+ ASSERT(write_cb_count == 1);
+ ASSERT(close_cb_count == 1);
+ ASSERT(rename_cb_count == 1);
+
+ r = uv_fs_open(loop, &open_req1, "test_file2", O_RDWR, 0, open_cb);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(open_cb_count == 1);
+ ASSERT(read_cb_count == 1);
+ ASSERT(close_cb_count == 2);
+ ASSERT(rename_cb_count == 1);
+ ASSERT(create_cb_count == 1);
+ ASSERT(write_cb_count == 1);
+ ASSERT(ftruncate_cb_count == 1);
+
+ r = uv_fs_open(loop, &open_req1, "test_file2", O_RDONLY, 0, open_cb);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(open_cb_count == 2);
+ ASSERT(read_cb_count == 2);
+ ASSERT(close_cb_count == 3);
+ ASSERT(rename_cb_count == 1);
+ ASSERT(unlink_cb_count == 1);
+ ASSERT(create_cb_count == 1);
+ ASSERT(write_cb_count == 1);
+ ASSERT(ftruncate_cb_count == 1);
+
+ /* Cleanup. */
+ unlink("test_file");
+ unlink("test_file2");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_file_sync) {
+ int r;
+
+ /* Setup. */
+ unlink("test_file");
+ unlink("test_file2");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r >= 0);
+ ASSERT(write_req.result >= 0);
+ uv_fs_req_cleanup(&write_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r >= 0);
+ ASSERT(read_req.result >= 0);
+ ASSERT(strcmp(buf, test_buf) == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ r = uv_fs_ftruncate(NULL, &ftruncate_req, open_req1.result, 7, NULL);
+ ASSERT(r == 0);
+ ASSERT(ftruncate_req.result == 0);
+ uv_fs_req_cleanup(&ftruncate_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_rename(NULL, &rename_req, "test_file", "test_file2", NULL);
+ ASSERT(r == 0);
+ ASSERT(rename_req.result == 0);
+ uv_fs_req_cleanup(&rename_req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_file2", O_RDONLY, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ memset(buf, 0, sizeof(buf));
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r >= 0);
+ ASSERT(read_req.result >= 0);
+ ASSERT(strcmp(buf, "test-bu") == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_unlink(NULL, &unlink_req, "test_file2", NULL);
+ ASSERT(r == 0);
+ ASSERT(unlink_req.result == 0);
+ uv_fs_req_cleanup(&unlink_req);
+
+ /* Cleanup */
+ unlink("test_file");
+ unlink("test_file2");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_file_write_null_buffer) {
+ int r;
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ iov = uv_buf_init(NULL, 0);
+ r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r == 0);
+ ASSERT(write_req.result == 0);
+ uv_fs_req_cleanup(&write_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ unlink("test_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_async_dir) {
+ int r;
+ uv_dirent_t dent;
+
+ /* Setup */
+ unlink("test_dir/file1");
+ unlink("test_dir/file2");
+ rmdir("test_dir");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_mkdir(loop, &mkdir_req, "test_dir", 0755, mkdir_cb);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(mkdir_cb_count == 1);
+
+ /* Create 2 files synchronously. */
+ r = uv_fs_open(NULL, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ uv_fs_req_cleanup(&open_req1);
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_dir/file2", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ uv_fs_req_cleanup(&open_req1);
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_scandir(loop, &scandir_req, "test_dir", 0, scandir_cb);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(scandir_cb_count == 1);
+
+ /* sync uv_fs_scandir */
+ r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL);
+ ASSERT(r == 2);
+ ASSERT(scandir_req.result == 2);
+ ASSERT(scandir_req.ptr);
+ while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
+ ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
+ assert_is_file_type(dent);
+ }
+ uv_fs_req_cleanup(&scandir_req);
+ ASSERT(!scandir_req.ptr);
+
+ r = uv_fs_stat(loop, &stat_req, "test_dir", stat_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ r = uv_fs_stat(loop, &stat_req, "test_dir/", stat_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ r = uv_fs_lstat(loop, &stat_req, "test_dir", stat_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ r = uv_fs_lstat(loop, &stat_req, "test_dir/", stat_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(stat_cb_count == 4);
+
+ r = uv_fs_unlink(loop, &unlink_req, "test_dir/file1", unlink_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(unlink_cb_count == 1);
+
+ r = uv_fs_unlink(loop, &unlink_req, "test_dir/file2", unlink_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(unlink_cb_count == 2);
+
+ r = uv_fs_rmdir(loop, &rmdir_req, "test_dir", rmdir_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(rmdir_cb_count == 1);
+
+ /* Cleanup */
+ unlink("test_dir/file1");
+ unlink("test_dir/file2");
+ rmdir("test_dir");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_async_sendfile) {
+ int f, r;
+ struct stat s1, s2;
+
+ loop = uv_default_loop();
+
+ /* Setup. */
+ unlink("test_file");
+ unlink("test_file2");
+
+ f = open("test_file", O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR);
+ ASSERT(f != -1);
+
+ r = write(f, "begin\n", 6);
+ ASSERT(r == 6);
+
+ r = lseek(f, 65536, SEEK_CUR);
+ ASSERT(r == 65542);
+
+ r = write(f, "end\n", 4);
+ ASSERT(r != -1);
+
+ r = close(f);
+ ASSERT(r == 0);
+
+ /* Test starts here. */
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ r = uv_fs_open(NULL, &open_req2, "test_file2", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req2.result >= 0);
+ uv_fs_req_cleanup(&open_req2);
+
+ r = uv_fs_sendfile(loop, &sendfile_req, open_req2.result, open_req1.result,
+ 0, 131072, sendfile_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(sendfile_cb_count == 1);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&close_req);
+ r = uv_fs_close(NULL, &close_req, open_req2.result, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ stat("test_file", &s1);
+ stat("test_file2", &s2);
+ ASSERT(65546 == s2.st_size && s1.st_size == s2.st_size);
+
+ /* Cleanup. */
+ unlink("test_file");
+ unlink("test_file2");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_mkdtemp) {
+ int r;
+ const char* path_template = "test_dir_XXXXXX";
+
+ loop = uv_default_loop();
+
+ r = uv_fs_mkdtemp(loop, &mkdtemp_req1, path_template, mkdtemp_cb);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(mkdtemp_cb_count == 1);
+
+ /* sync mkdtemp */
+ r = uv_fs_mkdtemp(NULL, &mkdtemp_req2, path_template, NULL);
+ ASSERT(r == 0);
+ check_mkdtemp_result(&mkdtemp_req2);
+
+ /* mkdtemp return different values on subsequent calls */
+ ASSERT(strcmp(mkdtemp_req1.path, mkdtemp_req2.path) != 0);
+
+ /* Cleanup */
+ rmdir(mkdtemp_req1.path);
+ rmdir(mkdtemp_req2.path);
+ uv_fs_req_cleanup(&mkdtemp_req1);
+ uv_fs_req_cleanup(&mkdtemp_req2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_fstat) {
+ int r;
+ uv_fs_t req;
+ uv_file file;
+ uv_stat_t* s;
+#ifndef _WIN32
+ struct stat t;
+#endif
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ file = req.result;
+ uv_fs_req_cleanup(&req);
+
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
+ ASSERT(r == sizeof(test_buf));
+ ASSERT(req.result == sizeof(test_buf));
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_fstat(NULL, &req, file, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ s = req.ptr;
+ ASSERT(s->st_size == sizeof(test_buf));
+
+#ifndef _WIN32
+ r = fstat(file, &t);
+ ASSERT(r == 0);
+
+ ASSERT(s->st_dev == (uint64_t) t.st_dev);
+ ASSERT(s->st_mode == (uint64_t) t.st_mode);
+ ASSERT(s->st_nlink == (uint64_t) t.st_nlink);
+ ASSERT(s->st_uid == (uint64_t) t.st_uid);
+ ASSERT(s->st_gid == (uint64_t) t.st_gid);
+ ASSERT(s->st_rdev == (uint64_t) t.st_rdev);
+ ASSERT(s->st_ino == (uint64_t) t.st_ino);
+ ASSERT(s->st_size == (uint64_t) t.st_size);
+ ASSERT(s->st_blksize == (uint64_t) t.st_blksize);
+ ASSERT(s->st_blocks == (uint64_t) t.st_blocks);
+#if defined(__APPLE__)
+ ASSERT(s->st_atim.tv_sec == t.st_atimespec.tv_sec);
+ ASSERT(s->st_atim.tv_nsec == t.st_atimespec.tv_nsec);
+ ASSERT(s->st_mtim.tv_sec == t.st_mtimespec.tv_sec);
+ ASSERT(s->st_mtim.tv_nsec == t.st_mtimespec.tv_nsec);
+ ASSERT(s->st_ctim.tv_sec == t.st_ctimespec.tv_sec);
+ ASSERT(s->st_ctim.tv_nsec == t.st_ctimespec.tv_nsec);
+ ASSERT(s->st_birthtim.tv_sec == t.st_birthtimespec.tv_sec);
+ ASSERT(s->st_birthtim.tv_nsec == t.st_birthtimespec.tv_nsec);
+ ASSERT(s->st_flags == t.st_flags);
+ ASSERT(s->st_gen == t.st_gen);
+#elif defined(_AIX)
+ ASSERT(s->st_atim.tv_sec == t.st_atime);
+ ASSERT(s->st_atim.tv_nsec == 0);
+ ASSERT(s->st_mtim.tv_sec == t.st_mtime);
+ ASSERT(s->st_mtim.tv_nsec == 0);
+ ASSERT(s->st_ctim.tv_sec == t.st_ctime);
+ ASSERT(s->st_ctim.tv_nsec == 0);
+#elif defined(__sun) || \
+ defined(_BSD_SOURCE) || \
+ defined(_SVID_SOURCE) || \
+ defined(_XOPEN_SOURCE) || \
+ defined(_DEFAULT_SOURCE)
+ ASSERT(s->st_atim.tv_sec == t.st_atim.tv_sec);
+ ASSERT(s->st_atim.tv_nsec == t.st_atim.tv_nsec);
+ ASSERT(s->st_mtim.tv_sec == t.st_mtim.tv_sec);
+ ASSERT(s->st_mtim.tv_nsec == t.st_mtim.tv_nsec);
+ ASSERT(s->st_ctim.tv_sec == t.st_ctim.tv_sec);
+ ASSERT(s->st_ctim.tv_nsec == t.st_ctim.tv_nsec);
+# if defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__)
+ ASSERT(s->st_birthtim.tv_sec == t.st_birthtim.tv_sec);
+ ASSERT(s->st_birthtim.tv_nsec == t.st_birthtim.tv_nsec);
+ ASSERT(s->st_flags == t.st_flags);
+ ASSERT(s->st_gen == t.st_gen);
+# endif
+#else
+ ASSERT(s->st_atim.tv_sec == t.st_atime);
+ ASSERT(s->st_atim.tv_nsec == 0);
+ ASSERT(s->st_mtim.tv_sec == t.st_mtime);
+ ASSERT(s->st_mtim.tv_nsec == 0);
+ ASSERT(s->st_ctim.tv_sec == t.st_ctime);
+ ASSERT(s->st_ctim.tv_nsec == 0);
+#endif
+#endif
+
+ uv_fs_req_cleanup(&req);
+
+ /* Now do the uv_fs_fstat call asynchronously */
+ r = uv_fs_fstat(loop, &req, file, fstat_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(fstat_cb_count == 1);
+
+
+ r = uv_fs_close(NULL, &req, file, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ /*
+ * Run the loop just to check we don't have make any extraneous uv_ref()
+ * calls. This should drop out immediately.
+ */
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ /* Cleanup. */
+ unlink("test_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_access) {
+ int r;
+ uv_fs_t req;
+ uv_file file;
+
+ /* Setup. */
+ unlink("test_file");
+ rmdir("test_dir");
+
+ loop = uv_default_loop();
+
+ /* File should not exist */
+ r = uv_fs_access(NULL, &req, "test_file", F_OK, NULL);
+ ASSERT(r < 0);
+ ASSERT(req.result < 0);
+ uv_fs_req_cleanup(&req);
+
+ /* File should not exist */
+ r = uv_fs_access(loop, &req, "test_file", F_OK, access_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(access_cb_count == 1);
+ access_cb_count = 0; /* reset for the next test */
+
+ /* Create file */
+ r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ file = req.result;
+ uv_fs_req_cleanup(&req);
+
+ /* File should exist */
+ r = uv_fs_access(NULL, &req, "test_file", F_OK, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ /* File should exist */
+ r = uv_fs_access(loop, &req, "test_file", F_OK, access_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(access_cb_count == 1);
+ access_cb_count = 0; /* reset for the next test */
+
+ /* Close file */
+ r = uv_fs_close(NULL, &req, file, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ /* Directory access */
+ r = uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_access(NULL, &req, "test_dir", W_OK, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ /*
+ * Run the loop just to check we don't have make any extraneous uv_ref()
+ * calls. This should drop out immediately.
+ */
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ /* Cleanup. */
+ unlink("test_file");
+ rmdir("test_dir");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_chmod) {
+ int r;
+ uv_fs_t req;
+ uv_file file;
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ file = req.result;
+ uv_fs_req_cleanup(&req);
+
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
+ ASSERT(r == sizeof(test_buf));
+ ASSERT(req.result == sizeof(test_buf));
+ uv_fs_req_cleanup(&req);
+
+#ifndef _WIN32
+ /* Make the file write-only */
+ r = uv_fs_chmod(NULL, &req, "test_file", 0200, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ check_permission("test_file", 0200);
+#endif
+
+ /* Make the file read-only */
+ r = uv_fs_chmod(NULL, &req, "test_file", 0400, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ check_permission("test_file", 0400);
+
+ /* Make the file read+write with sync uv_fs_fchmod */
+ r = uv_fs_fchmod(NULL, &req, file, 0600, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ check_permission("test_file", 0600);
+
+#ifndef _WIN32
+ /* async chmod */
+ {
+ static int mode = 0200;
+ req.data = &mode;
+ }
+ r = uv_fs_chmod(loop, &req, "test_file", 0200, chmod_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(chmod_cb_count == 1);
+ chmod_cb_count = 0; /* reset for the next test */
+#endif
+
+ /* async chmod */
+ {
+ static int mode = 0400;
+ req.data = &mode;
+ }
+ r = uv_fs_chmod(loop, &req, "test_file", 0400, chmod_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(chmod_cb_count == 1);
+
+ /* async fchmod */
+ {
+ static int mode = 0600;
+ req.data = &mode;
+ }
+ r = uv_fs_fchmod(loop, &req, file, 0600, fchmod_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(fchmod_cb_count == 1);
+
+ close(file);
+
+ /*
+ * Run the loop just to check we don't have make any extraneous uv_ref()
+ * calls. This should drop out immediately.
+ */
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ /* Cleanup. */
+ unlink("test_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_unlink_readonly) {
+ int r;
+ uv_fs_t req;
+ uv_file file;
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL,
+ &req,
+ "test_file",
+ O_RDWR | O_CREAT,
+ S_IWUSR | S_IRUSR,
+ NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ file = req.result;
+ uv_fs_req_cleanup(&req);
+
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
+ ASSERT(r == sizeof(test_buf));
+ ASSERT(req.result == sizeof(test_buf));
+ uv_fs_req_cleanup(&req);
+
+ close(file);
+
+ /* Make the file read-only */
+ r = uv_fs_chmod(NULL, &req, "test_file", 0400, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ check_permission("test_file", 0400);
+
+ /* Try to unlink the file */
+ r = uv_fs_unlink(NULL, &req, "test_file", NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ /*
+ * Run the loop just to check we don't have make any extraneous uv_ref()
+ * calls. This should drop out immediately.
+ */
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ /* Cleanup. */
+ uv_fs_chmod(NULL, &req, "test_file", 0600, NULL);
+ uv_fs_req_cleanup(&req);
+ unlink("test_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_chown) {
+ int r;
+ uv_fs_t req;
+ uv_file file;
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ file = req.result;
+ uv_fs_req_cleanup(&req);
+
+ /* sync chown */
+ r = uv_fs_chown(NULL, &req, "test_file", -1, -1, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ /* sync fchown */
+ r = uv_fs_fchown(NULL, &req, file, -1, -1, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ /* async chown */
+ r = uv_fs_chown(loop, &req, "test_file", -1, -1, chown_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(chown_cb_count == 1);
+
+ /* chown to root (fail) */
+ chown_cb_count = 0;
+ r = uv_fs_chown(loop, &req, "test_file", 0, 0, chown_root_cb);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(chown_cb_count == 1);
+
+ /* async fchown */
+ r = uv_fs_fchown(loop, &req, file, -1, -1, fchown_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(fchown_cb_count == 1);
+
+ close(file);
+
+ /*
+ * Run the loop just to check we don't have make any extraneous uv_ref()
+ * calls. This should drop out immediately.
+ */
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ /* Cleanup. */
+ unlink("test_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_link) {
+ int r;
+ uv_fs_t req;
+ uv_file file;
+ uv_file link;
+
+ /* Setup. */
+ unlink("test_file");
+ unlink("test_file_link");
+ unlink("test_file_link2");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ file = req.result;
+ uv_fs_req_cleanup(&req);
+
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
+ ASSERT(r == sizeof(test_buf));
+ ASSERT(req.result == sizeof(test_buf));
+ uv_fs_req_cleanup(&req);
+
+ close(file);
+
+ /* sync link */
+ r = uv_fs_link(NULL, &req, "test_file", "test_file_link", NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_open(NULL, &req, "test_file_link", O_RDWR, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ link = req.result;
+ uv_fs_req_cleanup(&req);
+
+ memset(buf, 0, sizeof(buf));
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ ASSERT(strcmp(buf, test_buf) == 0);
+
+ close(link);
+
+ /* async link */
+ r = uv_fs_link(loop, &req, "test_file", "test_file_link2", link_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(link_cb_count == 1);
+
+ r = uv_fs_open(NULL, &req, "test_file_link2", O_RDWR, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ link = req.result;
+ uv_fs_req_cleanup(&req);
+
+ memset(buf, 0, sizeof(buf));
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ ASSERT(strcmp(buf, test_buf) == 0);
+
+ close(link);
+
+ /*
+ * Run the loop just to check we don't have make any extraneous uv_ref()
+ * calls. This should drop out immediately.
+ */
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ /* Cleanup. */
+ unlink("test_file");
+ unlink("test_file_link");
+ unlink("test_file_link2");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_readlink) {
+ uv_fs_t req;
+
+ loop = uv_default_loop();
+ ASSERT(0 == uv_fs_readlink(loop, &req, "no_such_file", dummy_cb));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(dummy_cb_count == 1);
+ ASSERT(req.ptr == NULL);
+ ASSERT(req.result == UV_ENOENT);
+ uv_fs_req_cleanup(&req);
+
+ ASSERT(UV_ENOENT == uv_fs_readlink(NULL, &req, "no_such_file", NULL));
+ ASSERT(req.ptr == NULL);
+ ASSERT(req.result == UV_ENOENT);
+ uv_fs_req_cleanup(&req);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_realpath) {
+ uv_fs_t req;
+
+ loop = uv_default_loop();
+ ASSERT(0 == uv_fs_realpath(loop, &req, "no_such_file", dummy_cb));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(dummy_cb_count == 1);
+ ASSERT(req.ptr == NULL);
+#ifdef _WIN32
+ /*
+ * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW()
+ */
+ if (req.result == UV_ENOSYS) {
+ uv_fs_req_cleanup(&req);
+ RETURN_SKIP("realpath is not supported on Windows XP");
+ }
+#endif
+ ASSERT(req.result == UV_ENOENT);
+ uv_fs_req_cleanup(&req);
+
+ ASSERT(UV_ENOENT == uv_fs_realpath(NULL, &req, "no_such_file", NULL));
+ ASSERT(req.ptr == NULL);
+ ASSERT(req.result == UV_ENOENT);
+ uv_fs_req_cleanup(&req);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_symlink) {
+ int r;
+ uv_fs_t req;
+ uv_file file;
+ uv_file link;
+ char test_file_abs_buf[PATHMAX];
+ size_t test_file_abs_size;
+
+ /* Setup. */
+ unlink("test_file");
+ unlink("test_file_symlink");
+ unlink("test_file_symlink2");
+ unlink("test_file_symlink_symlink");
+ unlink("test_file_symlink2_symlink");
+ test_file_abs_size = sizeof(test_file_abs_buf);
+#ifdef _WIN32
+ uv_cwd(test_file_abs_buf, &test_file_abs_size);
+ strcat(test_file_abs_buf, "\\test_file");
+#else
+ uv_cwd(test_file_abs_buf, &test_file_abs_size);
+ strcat(test_file_abs_buf, "/test_file");
+#endif
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ file = req.result;
+ uv_fs_req_cleanup(&req);
+
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
+ ASSERT(r == sizeof(test_buf));
+ ASSERT(req.result == sizeof(test_buf));
+ uv_fs_req_cleanup(&req);
+
+ close(file);
+
+ /* sync symlink */
+ r = uv_fs_symlink(NULL, &req, "test_file", "test_file_symlink", 0, NULL);
+#ifdef _WIN32
+ if (r < 0) {
+ if (r == UV_ENOTSUP) {
+ /*
+ * Windows doesn't support symlinks on older versions.
+ * We just pass the test and bail out early if we get ENOTSUP.
+ */
+ return 0;
+ } else if (r == UV_EPERM) {
+ /*
+ * Creating a symlink is only allowed when running elevated.
+ * We pass the test and bail out early if we get UV_EPERM.
+ */
+ return 0;
+ }
+ }
+#endif
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_open(NULL, &req, "test_file_symlink", O_RDWR, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ link = req.result;
+ uv_fs_req_cleanup(&req);
+
+ memset(buf, 0, sizeof(buf));
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ ASSERT(strcmp(buf, test_buf) == 0);
+
+ close(link);
+
+ r = uv_fs_symlink(NULL,
+ &req,
+ "test_file_symlink",
+ "test_file_symlink_symlink",
+ 0,
+ NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_readlink(NULL, &req, "test_file_symlink_symlink", NULL);
+ ASSERT(r == 0);
+ ASSERT(strcmp(req.ptr, "test_file_symlink") == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_realpath(NULL, &req, "test_file_symlink_symlink", NULL);
+#ifdef _WIN32
+ /*
+ * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW()
+ */
+ if (r == UV_ENOSYS) {
+ uv_fs_req_cleanup(&req);
+ RETURN_SKIP("realpath is not supported on Windows XP");
+ }
+#endif
+ ASSERT(r == 0);
+#ifdef _WIN32
+ ASSERT(stricmp(req.ptr, test_file_abs_buf) == 0);
+#else
+ ASSERT(strcmp(req.ptr, test_file_abs_buf) == 0);
+#endif
+ uv_fs_req_cleanup(&req);
+
+ /* async link */
+ r = uv_fs_symlink(loop,
+ &req,
+ "test_file",
+ "test_file_symlink2",
+ 0,
+ symlink_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(symlink_cb_count == 1);
+
+ r = uv_fs_open(NULL, &req, "test_file_symlink2", O_RDWR, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ link = req.result;
+ uv_fs_req_cleanup(&req);
+
+ memset(buf, 0, sizeof(buf));
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ ASSERT(strcmp(buf, test_buf) == 0);
+
+ close(link);
+
+ r = uv_fs_symlink(NULL,
+ &req,
+ "test_file_symlink2",
+ "test_file_symlink2_symlink",
+ 0,
+ NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_readlink(loop, &req, "test_file_symlink2_symlink", readlink_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(readlink_cb_count == 1);
+
+ r = uv_fs_realpath(loop, &req, "test_file", realpath_cb);
+#ifdef _WIN32
+ /*
+ * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW()
+ */
+ if (r == UV_ENOSYS) {
+ uv_fs_req_cleanup(&req);
+ RETURN_SKIP("realpath is not supported on Windows XP");
+ }
+#endif
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(realpath_cb_count == 1);
+
+ /*
+ * Run the loop just to check we don't have make any extraneous uv_ref()
+ * calls. This should drop out immediately.
+ */
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ /* Cleanup. */
+ unlink("test_file");
+ unlink("test_file_symlink");
+ unlink("test_file_symlink_symlink");
+ unlink("test_file_symlink2");
+ unlink("test_file_symlink2_symlink");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_symlink_dir) {
+ uv_fs_t req;
+ int r;
+ char* test_dir;
+ uv_dirent_t dent;
+ static char test_dir_abs_buf[PATHMAX];
+ size_t test_dir_abs_size;
+
+ /* set-up */
+ unlink("test_dir/file1");
+ unlink("test_dir/file2");
+ rmdir("test_dir");
+ rmdir("test_dir_symlink");
+ test_dir_abs_size = sizeof(test_dir_abs_buf);
+
+ loop = uv_default_loop();
+
+ uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL);
+ uv_fs_req_cleanup(&req);
+
+#ifdef _WIN32
+ strcpy(test_dir_abs_buf, "\\\\?\\");
+ uv_cwd(test_dir_abs_buf + 4, &test_dir_abs_size);
+ test_dir_abs_size += 4;
+ strcat(test_dir_abs_buf, "\\test_dir\\");
+ test_dir_abs_size += strlen("\\test_dir\\");
+ test_dir = test_dir_abs_buf;
+#else
+ uv_cwd(test_dir_abs_buf, &test_dir_abs_size);
+ strcat(test_dir_abs_buf, "/test_dir");
+ test_dir_abs_size += strlen("/test_dir");
+ test_dir = "test_dir";
+#endif
+
+ r = uv_fs_symlink(NULL, &req, test_dir, "test_dir_symlink",
+ UV_FS_SYMLINK_JUNCTION, NULL);
+ fprintf(stderr, "r == %i\n", r);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_stat(NULL, &req, "test_dir_symlink", NULL);
+ ASSERT(r == 0);
+ ASSERT(((uv_stat_t*)req.ptr)->st_mode & S_IFDIR);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_lstat(NULL, &req, "test_dir_symlink", NULL);
+ ASSERT(r == 0);
+ ASSERT(((uv_stat_t*)req.ptr)->st_mode & S_IFLNK);
+#ifdef _WIN32
+ ASSERT(((uv_stat_t*)req.ptr)->st_size == strlen(test_dir + 4));
+#else
+ ASSERT(((uv_stat_t*)req.ptr)->st_size == strlen(test_dir));
+#endif
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_readlink(NULL, &req, "test_dir_symlink", NULL);
+ ASSERT(r == 0);
+#ifdef _WIN32
+ ASSERT(strcmp(req.ptr, test_dir + 4) == 0);
+#else
+ ASSERT(strcmp(req.ptr, test_dir) == 0);
+#endif
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_realpath(NULL, &req, "test_dir_symlink", NULL);
+#ifdef _WIN32
+ /*
+ * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW()
+ */
+ if (r == UV_ENOSYS) {
+ uv_fs_req_cleanup(&req);
+ RETURN_SKIP("realpath is not supported on Windows XP");
+ }
+#endif
+ ASSERT(r == 0);
+#ifdef _WIN32
+ ASSERT(strlen(req.ptr) == test_dir_abs_size - 5);
+ ASSERT(strnicmp(req.ptr, test_dir + 4, test_dir_abs_size - 5) == 0);
+#else
+ ASSERT(strcmp(req.ptr, test_dir_abs_buf) == 0);
+#endif
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ uv_fs_req_cleanup(&open_req1);
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_dir/file2", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ uv_fs_req_cleanup(&open_req1);
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_scandir(NULL, &scandir_req, "test_dir_symlink", 0, NULL);
+ ASSERT(r == 2);
+ ASSERT(scandir_req.result == 2);
+ ASSERT(scandir_req.ptr);
+ while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
+ ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
+ assert_is_file_type(dent);
+ }
+ uv_fs_req_cleanup(&scandir_req);
+ ASSERT(!scandir_req.ptr);
+
+ /* unlink will remove the directory symlink */
+ r = uv_fs_unlink(NULL, &req, "test_dir_symlink", NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_scandir(NULL, &scandir_req, "test_dir_symlink", 0, NULL);
+ ASSERT(r == UV_ENOENT);
+ uv_fs_req_cleanup(&scandir_req);
+
+ r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL);
+ ASSERT(r == 2);
+ ASSERT(scandir_req.result == 2);
+ ASSERT(scandir_req.ptr);
+ while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
+ ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
+ assert_is_file_type(dent);
+ }
+ uv_fs_req_cleanup(&scandir_req);
+ ASSERT(!scandir_req.ptr);
+
+ /* clean-up */
+ unlink("test_dir/file1");
+ unlink("test_dir/file2");
+ rmdir("test_dir");
+ rmdir("test_dir_symlink");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_utime) {
+ utime_check_t checkme;
+ const char* path = "test_file";
+ double atime;
+ double mtime;
+ uv_fs_t req;
+ int r;
+
+ /* Setup. */
+ loop = uv_default_loop();
+ unlink(path);
+ r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ uv_fs_req_cleanup(&req);
+ close(r);
+
+ atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
+
+ r = uv_fs_utime(NULL, &req, path, atime, mtime, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_stat(NULL, &req, path, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ check_utime(path, atime, mtime);
+ uv_fs_req_cleanup(&req);
+
+ atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */
+ checkme.path = path;
+ checkme.atime = atime;
+ checkme.mtime = mtime;
+
+ /* async utime */
+ utime_req.data = &checkme;
+ r = uv_fs_utime(loop, &utime_req, path, atime, mtime, utime_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(utime_cb_count == 1);
+
+ /* Cleanup. */
+ unlink(path);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+#ifdef _WIN32
+TEST_IMPL(fs_stat_root) {
+ int r;
+ uv_loop_t* loop = uv_default_loop();
+
+ r = uv_fs_stat(NULL, &stat_req, "\\", NULL);
+ ASSERT(r == 0);
+
+ r = uv_fs_stat(NULL, &stat_req, "..\\..\\..\\..\\..\\..\\..", NULL);
+ ASSERT(r == 0);
+
+ r = uv_fs_stat(NULL, &stat_req, "..", NULL);
+ ASSERT(r == 0);
+
+ r = uv_fs_stat(NULL, &stat_req, "..\\", NULL);
+ ASSERT(r == 0);
+
+ /* stats the current directory on c: */
+ r = uv_fs_stat(NULL, &stat_req, "c:", NULL);
+ ASSERT(r == 0);
+
+ r = uv_fs_stat(NULL, &stat_req, "c:\\", NULL);
+ ASSERT(r == 0);
+
+ r = uv_fs_stat(NULL, &stat_req, "\\\\?\\C:\\", NULL);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif
+
+
+TEST_IMPL(fs_futime) {
+ utime_check_t checkme;
+ const char* path = "test_file";
+ double atime;
+ double mtime;
+ uv_file file;
+ uv_fs_t req;
+ int r;
+
+ /* Setup. */
+ loop = uv_default_loop();
+ unlink(path);
+ r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ uv_fs_req_cleanup(&req);
+ close(r);
+
+ atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
+
+ r = uv_fs_open(NULL, &req, path, O_RDWR, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ file = req.result; /* FIXME probably not how it's supposed to be used */
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_futime(NULL, &req, file, atime, mtime, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_stat(NULL, &req, path, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ check_utime(path, atime, mtime);
+ uv_fs_req_cleanup(&req);
+
+ atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */
+
+ checkme.atime = atime;
+ checkme.mtime = mtime;
+ checkme.path = path;
+
+ /* async futime */
+ futime_req.data = &checkme;
+ r = uv_fs_futime(loop, &futime_req, file, atime, mtime, futime_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(futime_cb_count == 1);
+
+ /* Cleanup. */
+ unlink(path);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_stat_missing_path) {
+ uv_fs_t req;
+ int r;
+
+ loop = uv_default_loop();
+
+ r = uv_fs_stat(NULL, &req, "non_existent_file", NULL);
+ ASSERT(r == UV_ENOENT);
+ ASSERT(req.result == UV_ENOENT);
+ uv_fs_req_cleanup(&req);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_scandir_empty_dir) {
+ const char* path;
+ uv_fs_t req;
+ uv_dirent_t dent;
+ int r;
+
+ path = "./empty_dir/";
+ loop = uv_default_loop();
+
+ uv_fs_mkdir(NULL, &req, path, 0777, NULL);
+ uv_fs_req_cleanup(&req);
+
+ /* Fill the req to ensure that required fields are cleaned up */
+ memset(&req, 0xdb, sizeof(req));
+
+ r = uv_fs_scandir(NULL, &req, path, 0, NULL);
+ ASSERT(r == 0);
+ ASSERT(req.result == 0);
+ ASSERT(req.ptr == NULL);
+ ASSERT(UV_EOF == uv_fs_scandir_next(&req, &dent));
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_scandir(loop, &scandir_req, path, 0, empty_scandir_cb);
+ ASSERT(r == 0);
+
+ ASSERT(scandir_cb_count == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(scandir_cb_count == 1);
+
+ uv_fs_rmdir(NULL, &req, path, NULL);
+ uv_fs_req_cleanup(&req);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_scandir_file) {
+ const char* path;
+ int r;
+
+ path = "test/fixtures/empty_file";
+ loop = uv_default_loop();
+
+ r = uv_fs_scandir(NULL, &scandir_req, path, 0, NULL);
+ ASSERT(r == UV_ENOTDIR);
+ uv_fs_req_cleanup(&scandir_req);
+
+ r = uv_fs_scandir(loop, &scandir_req, path, 0, file_scandir_cb);
+ ASSERT(r == 0);
+
+ ASSERT(scandir_cb_count == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(scandir_cb_count == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_open_dir) {
+ const char* path;
+ uv_fs_t req;
+ int r, file;
+
+ path = ".";
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &req, path, O_RDONLY, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ ASSERT(req.ptr == NULL);
+ file = r;
+ uv_fs_req_cleanup(&req);
+
+ r = uv_fs_close(NULL, &req, file, NULL);
+ ASSERT(r == 0);
+
+ r = uv_fs_open(loop, &req, path, O_RDONLY, 0, open_cb_simple);
+ ASSERT(r == 0);
+
+ ASSERT(open_cb_count == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(open_cb_count == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_file_open_append) {
+ int r;
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r >= 0);
+ ASSERT(write_req.result >= 0);
+ uv_fs_req_cleanup(&write_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR | O_APPEND, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r >= 0);
+ ASSERT(write_req.result >= 0);
+ uv_fs_req_cleanup(&write_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY, S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
+ printf("read = %d\n", r);
+ ASSERT(r == 26);
+ ASSERT(read_req.result == 26);
+ ASSERT(memcmp(buf,
+ "test-buffer\n\0test-buffer\n\0",
+ sizeof("test-buffer\n\0test-buffer\n\0") - 1) == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ /* Cleanup */
+ unlink("test_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_rename_to_existing_file) {
+ int r;
+
+ /* Setup. */
+ unlink("test_file");
+ unlink("test_file2");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r >= 0);
+ ASSERT(write_req.result >= 0);
+ uv_fs_req_cleanup(&write_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_file2", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_rename(NULL, &rename_req, "test_file", "test_file2", NULL);
+ ASSERT(r == 0);
+ ASSERT(rename_req.result == 0);
+ uv_fs_req_cleanup(&rename_req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_file2", O_RDONLY, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ memset(buf, 0, sizeof(buf));
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r >= 0);
+ ASSERT(read_req.result >= 0);
+ ASSERT(strcmp(buf, test_buf) == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ /* Cleanup */
+ unlink("test_file");
+ unlink("test_file2");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_read_file_eof) {
+ int r;
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ iov = uv_buf_init(test_buf, sizeof(test_buf));
+ r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r >= 0);
+ ASSERT(write_req.result >= 0);
+ uv_fs_req_cleanup(&write_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ memset(buf, 0, sizeof(buf));
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r >= 0);
+ ASSERT(read_req.result >= 0);
+ ASSERT(strcmp(buf, test_buf) == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1,
+ read_req.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(read_req.result == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ /* Cleanup */
+ unlink("test_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_write_multiple_bufs) {
+ uv_buf_t iovs[2];
+ int r;
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT,
+ S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ iovs[0] = uv_buf_init(test_buf, sizeof(test_buf));
+ iovs[1] = uv_buf_init(test_buf2, sizeof(test_buf2));
+ r = uv_fs_write(NULL, &write_req, open_req1.result, iovs, 2, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(write_req.result >= 0);
+ uv_fs_req_cleanup(&write_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ memset(buf, 0, sizeof(buf));
+ memset(buf2, 0, sizeof(buf2));
+ /* Read the strings back to separate buffers. */
+ iovs[0] = uv_buf_init(buf, sizeof(test_buf));
+ iovs[1] = uv_buf_init(buf2, sizeof(test_buf2));
+ r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, 2, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT(read_req.result >= 0);
+ ASSERT(strcmp(buf, test_buf) == 0);
+ ASSERT(strcmp(buf2, test_buf2) == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1,
+ read_req.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(read_req.result == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ /* Cleanup */
+ unlink("test_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_write_alotof_bufs) {
+ const size_t iovcount = 54321;
+ uv_buf_t* iovs;
+ char* buffer;
+ size_t index;
+ int r;
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ iovs = malloc(sizeof(*iovs) * iovcount);
+ ASSERT(iovs != NULL);
+
+ r = uv_fs_open(NULL,
+ &open_req1,
+ "test_file",
+ O_RDWR | O_CREAT,
+ S_IWUSR | S_IRUSR,
+ NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ for (index = 0; index < iovcount; ++index)
+ iovs[index] = uv_buf_init(test_buf, sizeof(test_buf));
+
+ r = uv_fs_write(NULL,
+ &write_req,
+ open_req1.result,
+ iovs,
+ iovcount,
+ -1,
+ NULL);
+ ASSERT(r >= 0);
+ ASSERT((size_t)write_req.result == sizeof(test_buf) * iovcount);
+ uv_fs_req_cleanup(&write_req);
+
+ /* Read the strings back to separate buffers. */
+ buffer = malloc(sizeof(test_buf) * iovcount);
+ ASSERT(buffer != NULL);
+
+ for (index = 0; index < iovcount; ++index)
+ iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf),
+ sizeof(test_buf));
+
+ r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, iovcount, 0, NULL);
+ ASSERT(r >= 0);
+ ASSERT((size_t)read_req.result == sizeof(test_buf) * iovcount);
+
+ for (index = 0; index < iovcount; ++index)
+ ASSERT(strncmp(buffer + index * sizeof(test_buf),
+ test_buf,
+ sizeof(test_buf)) == 0);
+
+ uv_fs_req_cleanup(&read_req);
+ free(buffer);
+
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL,
+ &read_req,
+ open_req1.result,
+ &iov,
+ 1,
+ read_req.result,
+ NULL);
+ ASSERT(r == 0);
+ ASSERT(read_req.result == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ /* Cleanup */
+ unlink("test_file");
+ free(iovs);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_write_alotof_bufs_with_offset) {
+ const size_t iovcount = 54321;
+ uv_buf_t* iovs;
+ char* buffer;
+ size_t index;
+ int r;
+ int64_t offset;
+ char* filler = "0123456789";
+ int filler_len = strlen(filler);
+
+ /* Setup. */
+ unlink("test_file");
+
+ loop = uv_default_loop();
+
+ iovs = malloc(sizeof(*iovs) * iovcount);
+ ASSERT(iovs != NULL);
+
+ r = uv_fs_open(NULL,
+ &open_req1,
+ "test_file",
+ O_RDWR | O_CREAT,
+ S_IWUSR | S_IRUSR,
+ NULL);
+ ASSERT(r >= 0);
+ ASSERT(open_req1.result >= 0);
+ uv_fs_req_cleanup(&open_req1);
+
+ iov = uv_buf_init(filler, filler_len);
+ r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
+ ASSERT(r == filler_len);
+ ASSERT(write_req.result == filler_len);
+ uv_fs_req_cleanup(&write_req);
+ offset = (int64_t)r;
+
+ for (index = 0; index < iovcount; ++index)
+ iovs[index] = uv_buf_init(test_buf, sizeof(test_buf));
+
+ r = uv_fs_write(NULL,
+ &write_req,
+ open_req1.result,
+ iovs,
+ iovcount,
+ offset,
+ NULL);
+ ASSERT(r >= 0);
+ ASSERT((size_t)write_req.result == sizeof(test_buf) * iovcount);
+ uv_fs_req_cleanup(&write_req);
+
+ /* Read the strings back to separate buffers. */
+ buffer = malloc(sizeof(test_buf) * iovcount);
+ ASSERT(buffer != NULL);
+
+ for (index = 0; index < iovcount; ++index)
+ iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf),
+ sizeof(test_buf));
+
+ r = uv_fs_read(NULL, &read_req, open_req1.result,
+ iovs, iovcount, offset, NULL);
+ ASSERT(r >= 0);
+ ASSERT(read_req.result == sizeof(test_buf) * iovcount);
+
+ for (index = 0; index < iovcount; ++index)
+ ASSERT(strncmp(buffer + index * sizeof(test_buf),
+ test_buf,
+ sizeof(test_buf)) == 0);
+
+ uv_fs_req_cleanup(&read_req);
+ free(buffer);
+
+ r = uv_fs_stat(NULL, &stat_req, "test_file", NULL);
+ ASSERT(r == 0);
+ ASSERT((int64_t)((uv_stat_t*)stat_req.ptr)->st_size ==
+ offset + (int64_t)(iovcount * sizeof(test_buf)));
+ uv_fs_req_cleanup(&stat_req);
+
+ iov = uv_buf_init(buf, sizeof(buf));
+ r = uv_fs_read(NULL,
+ &read_req,
+ open_req1.result,
+ &iov,
+ 1,
+ read_req.result + offset,
+ NULL);
+ ASSERT(r == 0);
+ ASSERT(read_req.result == 0);
+ uv_fs_req_cleanup(&read_req);
+
+ r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
+ ASSERT(r == 0);
+ ASSERT(close_req.result == 0);
+ uv_fs_req_cleanup(&close_req);
+
+ /* Cleanup */
+ unlink("test_file");
+ free(iovs);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_read_write_null_arguments) {
+ int r;
+
+ r = uv_fs_read(NULL, NULL, 0, NULL, 0, -1, NULL);
+ ASSERT(r == UV_EINVAL);
+
+ r = uv_fs_write(NULL, NULL, 0, NULL, 0, -1, NULL);
+ ASSERT(r == UV_EINVAL);
+
+ iov = uv_buf_init(NULL, 0);
+ r = uv_fs_read(NULL, NULL, 0, &iov, 0, -1, NULL);
+ ASSERT(r == UV_EINVAL);
+
+ iov = uv_buf_init(NULL, 0);
+ r = uv_fs_write(NULL, NULL, 0, &iov, 0, -1, NULL);
+ ASSERT(r == UV_EINVAL);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-get-currentexe.c b/3rdparty/libuv/test/test-get-currentexe.c
new file mode 100644
index 00000000000..0e9d6965402
--- /dev/null
+++ b/3rdparty/libuv/test/test-get-currentexe.c
@@ -0,0 +1,86 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <string.h>
+
+#define PATHMAX 1024
+extern char executable_path[];
+
+TEST_IMPL(get_currentexe) {
+ char buffer[PATHMAX];
+ size_t size;
+ char* match;
+ char* path;
+ int r;
+
+ size = sizeof(buffer) / sizeof(buffer[0]);
+ r = uv_exepath(buffer, &size);
+ ASSERT(!r);
+
+ /* uv_exepath can return an absolute path on darwin, so if the test runner
+ * was run with a relative prefix of "./", we need to strip that prefix off
+ * executable_path or we'll fail. */
+ if (executable_path[0] == '.' && executable_path[1] == '/') {
+ path = executable_path + 2;
+ } else {
+ path = executable_path;
+ }
+
+ match = strstr(buffer, path);
+ /* Verify that the path returned from uv_exepath is a subdirectory of
+ * executable_path.
+ */
+ ASSERT(match && !strcmp(match, path));
+ ASSERT(size == strlen(buffer));
+
+ /* Negative tests */
+ size = sizeof(buffer) / sizeof(buffer[0]);
+ r = uv_exepath(NULL, &size);
+ ASSERT(r == UV_EINVAL);
+
+ r = uv_exepath(buffer, NULL);
+ ASSERT(r == UV_EINVAL);
+
+ size = 0;
+ r = uv_exepath(buffer, &size);
+ ASSERT(r == UV_EINVAL);
+
+ memset(buffer, -1, sizeof(buffer));
+
+ size = 1;
+ r = uv_exepath(buffer, &size);
+ ASSERT(r == 0);
+ ASSERT(size == 0);
+ ASSERT(buffer[0] == '\0');
+
+ memset(buffer, -1, sizeof(buffer));
+
+ size = 2;
+ r = uv_exepath(buffer, &size);
+ ASSERT(r == 0);
+ ASSERT(size == 1);
+ ASSERT(buffer[0] != '\0');
+ ASSERT(buffer[1] == '\0');
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-get-loadavg.c b/3rdparty/libuv/test/test-get-loadavg.c
new file mode 100644
index 00000000000..4762e47576d
--- /dev/null
+++ b/3rdparty/libuv/test/test-get-loadavg.c
@@ -0,0 +1,35 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+TEST_IMPL(get_loadavg) {
+
+ double avg[3] = {-1, -1, -1};
+ uv_loadavg(avg);
+
+ ASSERT(avg[0] >= 0);
+ ASSERT(avg[1] >= 0);
+ ASSERT(avg[2] >= 0);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-get-memory.c b/3rdparty/libuv/test/test-get-memory.c
new file mode 100644
index 00000000000..2396939bcb1
--- /dev/null
+++ b/3rdparty/libuv/test/test-get-memory.c
@@ -0,0 +1,38 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+TEST_IMPL(get_memory) {
+ uint64_t free_mem = uv_get_free_memory();
+ uint64_t total_mem = uv_get_total_memory();
+
+ printf("free_mem=%llu, total_mem=%llu\n",
+ (unsigned long long) free_mem,
+ (unsigned long long) total_mem);
+
+ ASSERT(free_mem > 0);
+ ASSERT(total_mem > 0);
+ ASSERT(total_mem > free_mem);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-getaddrinfo.c b/3rdparty/libuv/test/test-getaddrinfo.c
new file mode 100644
index 00000000000..6b644a8d442
--- /dev/null
+++ b/3rdparty/libuv/test/test-getaddrinfo.c
@@ -0,0 +1,184 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdlib.h>
+
+#define CONCURRENT_COUNT 10
+
+static const char* name = "localhost";
+
+static int getaddrinfo_cbs = 0;
+
+/* data used for running multiple calls concurrently */
+static uv_getaddrinfo_t* getaddrinfo_handle;
+static uv_getaddrinfo_t getaddrinfo_handles[CONCURRENT_COUNT];
+static int callback_counts[CONCURRENT_COUNT];
+static int fail_cb_called;
+
+
+static void getaddrinfo_fail_cb(uv_getaddrinfo_t* req,
+ int status,
+ struct addrinfo* res) {
+ ASSERT(fail_cb_called == 0);
+ ASSERT(status < 0);
+ ASSERT(res == NULL);
+ uv_freeaddrinfo(res); /* Should not crash. */
+ fail_cb_called++;
+}
+
+
+static void getaddrinfo_basic_cb(uv_getaddrinfo_t* handle,
+ int status,
+ struct addrinfo* res) {
+ ASSERT(handle == getaddrinfo_handle);
+ getaddrinfo_cbs++;
+ free(handle);
+ uv_freeaddrinfo(res);
+}
+
+
+static void getaddrinfo_cuncurrent_cb(uv_getaddrinfo_t* handle,
+ int status,
+ struct addrinfo* res) {
+ int i;
+ int* data = (int*)handle->data;
+
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ if (&getaddrinfo_handles[i] == handle) {
+ ASSERT(i == *data);
+
+ callback_counts[i]++;
+ break;
+ }
+ }
+ ASSERT (i < CONCURRENT_COUNT);
+
+ free(data);
+ uv_freeaddrinfo(res);
+
+ getaddrinfo_cbs++;
+}
+
+
+TEST_IMPL(getaddrinfo_fail) {
+ uv_getaddrinfo_t req;
+
+ /* Use a FQDN by ending in a period */
+ ASSERT(0 == uv_getaddrinfo(uv_default_loop(),
+ &req,
+ getaddrinfo_fail_cb,
+ "xyzzy.xyzzy.xyzzy.",
+ NULL,
+ NULL));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ ASSERT(fail_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(getaddrinfo_fail_sync) {
+ uv_getaddrinfo_t req;
+
+ /* Use a FQDN by ending in a period */
+ ASSERT(0 > uv_getaddrinfo(uv_default_loop(),
+ &req,
+ NULL,
+ "xyzzy.xyzzy.xyzzy.",
+ NULL,
+ NULL));
+ uv_freeaddrinfo(req.addrinfo);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(getaddrinfo_basic) {
+ int r;
+ getaddrinfo_handle = (uv_getaddrinfo_t*)malloc(sizeof(uv_getaddrinfo_t));
+
+ r = uv_getaddrinfo(uv_default_loop(),
+ getaddrinfo_handle,
+ &getaddrinfo_basic_cb,
+ name,
+ NULL,
+ NULL);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(getaddrinfo_cbs == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(getaddrinfo_basic_sync) {
+ uv_getaddrinfo_t req;
+
+ ASSERT(0 == uv_getaddrinfo(uv_default_loop(),
+ &req,
+ NULL,
+ name,
+ NULL,
+ NULL));
+ uv_freeaddrinfo(req.addrinfo);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(getaddrinfo_concurrent) {
+ int i, r;
+ int* data;
+
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ callback_counts[i] = 0;
+
+ data = (int*)malloc(sizeof(int));
+ ASSERT(data != NULL);
+ *data = i;
+ getaddrinfo_handles[i].data = data;
+
+ r = uv_getaddrinfo(uv_default_loop(),
+ &getaddrinfo_handles[i],
+ &getaddrinfo_cuncurrent_cb,
+ name,
+ NULL,
+ NULL);
+ ASSERT(r == 0);
+ }
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ for (i = 0; i < CONCURRENT_COUNT; i++) {
+ ASSERT(callback_counts[i] == 1);
+ }
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-getnameinfo.c b/3rdparty/libuv/test/test-getnameinfo.c
new file mode 100644
index 00000000000..b1391616d13
--- /dev/null
+++ b/3rdparty/libuv/test/test-getnameinfo.c
@@ -0,0 +1,101 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to
+* deal in the Software without restriction, including without limitation the
+* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+* sell copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+* IN THE SOFTWARE.
+*/
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+static const char* address_ip4 = "127.0.0.1";
+static const char* address_ip6 = "::1";
+static const int port = 80;
+
+static struct sockaddr_in addr4;
+static struct sockaddr_in6 addr6;
+static uv_getnameinfo_t req;
+
+static void getnameinfo_req(uv_getnameinfo_t* handle,
+ int status,
+ const char* hostname,
+ const char* service) {
+ ASSERT(handle != NULL);
+ ASSERT(status == 0);
+ ASSERT(hostname != NULL);
+ ASSERT(service != NULL);
+}
+
+
+TEST_IMPL(getnameinfo_basic_ip4) {
+ int r;
+
+ r = uv_ip4_addr(address_ip4, port, &addr4);
+ ASSERT(r == 0);
+
+ r = uv_getnameinfo(uv_default_loop(),
+ &req,
+ &getnameinfo_req,
+ (const struct sockaddr*)&addr4,
+ 0);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(getnameinfo_basic_ip4_sync) {
+ ASSERT(0 == uv_ip4_addr(address_ip4, port, &addr4));
+
+ ASSERT(0 == uv_getnameinfo(uv_default_loop(),
+ &req,
+ NULL,
+ (const struct sockaddr*)&addr4,
+ 0));
+ ASSERT(req.host[0] != '\0');
+ ASSERT(req.service[0] != '\0');
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(getnameinfo_basic_ip6) {
+ int r;
+
+ r = uv_ip6_addr(address_ip6, port, &addr6);
+ ASSERT(r == 0);
+
+ r = uv_getnameinfo(uv_default_loop(),
+ &req,
+ &getnameinfo_req,
+ (const struct sockaddr*)&addr6,
+ 0);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-getsockname.c b/3rdparty/libuv/test/test-getsockname.c
new file mode 100644
index 00000000000..565c17fe50b
--- /dev/null
+++ b/3rdparty/libuv/test/test-getsockname.c
@@ -0,0 +1,361 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const int server_port = TEST_PORT;
+/* Will be updated right after making the uv_connect_call */
+static int connect_port = -1;
+
+static int getsocknamecount = 0;
+static int getpeernamecount = 0;
+
+static uv_loop_t* loop;
+static uv_tcp_t tcp;
+static uv_udp_t udp;
+static uv_connect_t connect_req;
+static uv_tcp_t tcpServer;
+static uv_udp_t udpServer;
+static uv_udp_send_t send_req;
+
+
+static void alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
+ buf->base = malloc(suggested_size);
+ buf->len = suggested_size;
+}
+
+
+static void on_close(uv_handle_t* peer) {
+ free(peer);
+ uv_close((uv_handle_t*)&tcpServer, NULL);
+}
+
+
+static void after_shutdown(uv_shutdown_t* req, int status) {
+ uv_close((uv_handle_t*) req->handle, on_close);
+ free(req);
+}
+
+
+static void after_read(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ uv_shutdown_t* req;
+ int r;
+
+ if (buf->base) {
+ free(buf->base);
+ }
+
+ req = (uv_shutdown_t*) malloc(sizeof *req);
+ r = uv_shutdown(req, handle, after_shutdown);
+ ASSERT(r == 0);
+}
+
+
+static void check_sockname(struct sockaddr* addr, const char* compare_ip,
+ int compare_port, const char* context) {
+ struct sockaddr_in check_addr = *(struct sockaddr_in*) addr;
+ struct sockaddr_in compare_addr;
+ char check_ip[17];
+ int r;
+
+ ASSERT(0 == uv_ip4_addr(compare_ip, compare_port, &compare_addr));
+
+ /* Both addresses should be ipv4 */
+ ASSERT(check_addr.sin_family == AF_INET);
+ ASSERT(compare_addr.sin_family == AF_INET);
+
+ /* Check if the ip matches */
+ ASSERT(memcmp(&check_addr.sin_addr,
+ &compare_addr.sin_addr,
+ sizeof compare_addr.sin_addr) == 0);
+
+ /* Check if the port matches. If port == 0 anything goes. */
+ ASSERT(compare_port == 0 || check_addr.sin_port == compare_addr.sin_port);
+
+ r = uv_ip4_name(&check_addr, (char*) check_ip, sizeof check_ip);
+ ASSERT(r == 0);
+
+ printf("%s: %s:%d\n", context, check_ip, ntohs(check_addr.sin_port));
+}
+
+
+static void on_connection(uv_stream_t* server, int status) {
+ struct sockaddr sockname, peername;
+ int namelen;
+ uv_tcp_t* handle;
+ int r;
+
+ if (status != 0) {
+ fprintf(stderr, "Connect error %s\n", uv_err_name(status));
+ }
+ ASSERT(status == 0);
+
+ handle = malloc(sizeof(*handle));
+ ASSERT(handle != NULL);
+
+ r = uv_tcp_init(loop, handle);
+ ASSERT(r == 0);
+
+ /* associate server with stream */
+ handle->data = server;
+
+ r = uv_accept(server, (uv_stream_t*)handle);
+ ASSERT(r == 0);
+
+ namelen = sizeof sockname;
+ r = uv_tcp_getsockname(handle, &sockname, &namelen);
+ ASSERT(r == 0);
+ check_sockname(&sockname, "127.0.0.1", server_port, "accepted socket");
+ getsocknamecount++;
+
+ namelen = sizeof peername;
+ r = uv_tcp_getpeername(handle, &peername, &namelen);
+ ASSERT(r == 0);
+ check_sockname(&peername, "127.0.0.1", connect_port, "accepted socket peer");
+ getpeernamecount++;
+
+ r = uv_read_start((uv_stream_t*)handle, alloc, after_read);
+ ASSERT(r == 0);
+}
+
+
+static void on_connect(uv_connect_t* req, int status) {
+ struct sockaddr sockname, peername;
+ int r, namelen;
+
+ ASSERT(status == 0);
+
+ namelen = sizeof sockname;
+ r = uv_tcp_getsockname((uv_tcp_t*) req->handle, &sockname, &namelen);
+ ASSERT(r == 0);
+ check_sockname(&sockname, "127.0.0.1", 0, "connected socket");
+ getsocknamecount++;
+
+ namelen = sizeof peername;
+ r = uv_tcp_getpeername((uv_tcp_t*) req->handle, &peername, &namelen);
+ ASSERT(r == 0);
+ check_sockname(&peername, "127.0.0.1", server_port, "connected socket peer");
+ getpeernamecount++;
+
+ uv_close((uv_handle_t*)&tcp, NULL);
+}
+
+
+static int tcp_listener(void) {
+ struct sockaddr_in addr;
+ struct sockaddr sockname, peername;
+ int namelen;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", server_port, &addr));
+
+ r = uv_tcp_init(loop, &tcpServer);
+ if (r) {
+ fprintf(stderr, "Socket creation error\n");
+ return 1;
+ }
+
+ r = uv_tcp_bind(&tcpServer, (const struct sockaddr*) &addr, 0);
+ if (r) {
+ fprintf(stderr, "Bind error\n");
+ return 1;
+ }
+
+ r = uv_listen((uv_stream_t*)&tcpServer, 128, on_connection);
+ if (r) {
+ fprintf(stderr, "Listen error\n");
+ return 1;
+ }
+
+ memset(&sockname, -1, sizeof sockname);
+ namelen = sizeof sockname;
+ r = uv_tcp_getsockname(&tcpServer, &sockname, &namelen);
+ ASSERT(r == 0);
+ check_sockname(&sockname, "0.0.0.0", server_port, "server socket");
+ getsocknamecount++;
+
+ namelen = sizeof sockname;
+ r = uv_tcp_getpeername(&tcpServer, &peername, &namelen);
+ ASSERT(r == UV_ENOTCONN);
+ getpeernamecount++;
+
+ return 0;
+}
+
+
+static void tcp_connector(void) {
+ struct sockaddr_in server_addr;
+ struct sockaddr sockname;
+ int r, namelen;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", server_port, &server_addr));
+
+ r = uv_tcp_init(loop, &tcp);
+ tcp.data = &connect_req;
+ ASSERT(!r);
+
+ r = uv_tcp_connect(&connect_req,
+ &tcp,
+ (const struct sockaddr*) &server_addr,
+ on_connect);
+ ASSERT(!r);
+
+ /* Fetch the actual port used by the connecting socket. */
+ namelen = sizeof sockname;
+ r = uv_tcp_getsockname(&tcp, &sockname, &namelen);
+ ASSERT(!r);
+ ASSERT(sockname.sa_family == AF_INET);
+ connect_port = ntohs(((struct sockaddr_in*) &sockname)->sin_port);
+ ASSERT(connect_port > 0);
+}
+
+
+static void udp_recv(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ struct sockaddr sockname;
+ int namelen;
+ int r;
+
+ ASSERT(nread >= 0);
+ free(buf->base);
+
+ if (nread == 0) {
+ return;
+ }
+
+ memset(&sockname, -1, sizeof sockname);
+ namelen = sizeof(sockname);
+ r = uv_udp_getsockname(&udp, &sockname, &namelen);
+ ASSERT(r == 0);
+ check_sockname(&sockname, "0.0.0.0", 0, "udp receiving socket");
+ getsocknamecount++;
+
+ uv_close((uv_handle_t*) &udp, NULL);
+ uv_close((uv_handle_t*) handle, NULL);
+}
+
+
+static void udp_send(uv_udp_send_t* req, int status) {
+
+}
+
+
+static int udp_listener(void) {
+ struct sockaddr_in addr;
+ struct sockaddr sockname;
+ int namelen;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", server_port, &addr));
+
+ r = uv_udp_init(loop, &udpServer);
+ if (r) {
+ fprintf(stderr, "Socket creation error\n");
+ return 1;
+ }
+
+ r = uv_udp_bind(&udpServer, (const struct sockaddr*) &addr, 0);
+ if (r) {
+ fprintf(stderr, "Bind error\n");
+ return 1;
+ }
+
+ memset(&sockname, -1, sizeof sockname);
+ namelen = sizeof sockname;
+ r = uv_udp_getsockname(&udpServer, &sockname, &namelen);
+ ASSERT(r == 0);
+ check_sockname(&sockname, "0.0.0.0", server_port, "udp listener socket");
+ getsocknamecount++;
+
+ r = uv_udp_recv_start(&udpServer, alloc, udp_recv);
+ ASSERT(r == 0);
+
+ return 0;
+}
+
+
+static void udp_sender(void) {
+ struct sockaddr_in server_addr;
+ uv_buf_t buf;
+ int r;
+
+ r = uv_udp_init(loop, &udp);
+ ASSERT(!r);
+
+ buf = uv_buf_init("PING", 4);
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", server_port, &server_addr));
+
+ r = uv_udp_send(&send_req,
+ &udp,
+ &buf,
+ 1,
+ (const struct sockaddr*) &server_addr,
+ udp_send);
+ ASSERT(!r);
+}
+
+
+TEST_IMPL(getsockname_tcp) {
+ loop = uv_default_loop();
+
+ if (tcp_listener())
+ return 1;
+
+ tcp_connector();
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(getsocknamecount == 3);
+ ASSERT(getpeernamecount == 3);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(getsockname_udp) {
+ loop = uv_default_loop();
+
+ if (udp_listener())
+ return 1;
+
+ udp_sender();
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(getsocknamecount == 2);
+
+ ASSERT(udp.send_queue_size == 0);
+ ASSERT(udpServer.send_queue_size == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-handle-fileno.c b/3rdparty/libuv/test/test-handle-fileno.c
new file mode 100644
index 00000000000..3fe933adebd
--- /dev/null
+++ b/3rdparty/libuv/test/test-handle-fileno.c
@@ -0,0 +1,121 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+static int get_tty_fd(void) {
+ /* Make sure we have an FD that refers to a tty */
+#ifdef _WIN32
+ HANDLE handle;
+ handle = CreateFileA("conout$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE)
+ return -1;
+ return _open_osfhandle((intptr_t) handle, 0);
+#else /* unix */
+ return open("/dev/tty", O_RDONLY, 0);
+#endif
+}
+
+
+TEST_IMPL(handle_fileno) {
+ int r;
+ int tty_fd;
+ struct sockaddr_in addr;
+ uv_os_fd_t fd;
+ uv_tcp_t tcp;
+ uv_udp_t udp;
+ uv_pipe_t pipe;
+ uv_tty_t tty;
+ uv_idle_t idle;
+ uv_loop_t* loop;
+
+ loop = uv_default_loop();
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_idle_init(loop, &idle);
+ ASSERT(r == 0);
+ r = uv_fileno((uv_handle_t*) &idle, &fd);
+ ASSERT(r == UV_EINVAL);
+ uv_close((uv_handle_t*) &idle, NULL);
+
+ r = uv_tcp_init(loop, &tcp);
+ ASSERT(r == 0);
+ r = uv_fileno((uv_handle_t*) &tcp, &fd);
+ ASSERT(r == UV_EBADF);
+ r = uv_tcp_bind(&tcp, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+ r = uv_fileno((uv_handle_t*) &tcp, &fd);
+ ASSERT(r == 0);
+ uv_close((uv_handle_t*) &tcp, NULL);
+ r = uv_fileno((uv_handle_t*) &tcp, &fd);
+ ASSERT(r == UV_EBADF);
+
+ r = uv_udp_init(loop, &udp);
+ ASSERT(r == 0);
+ r = uv_fileno((uv_handle_t*) &udp, &fd);
+ ASSERT(r == UV_EBADF);
+ r = uv_udp_bind(&udp, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+ r = uv_fileno((uv_handle_t*) &udp, &fd);
+ ASSERT(r == 0);
+ uv_close((uv_handle_t*) &udp, NULL);
+ r = uv_fileno((uv_handle_t*) &udp, &fd);
+ ASSERT(r == UV_EBADF);
+
+ r = uv_pipe_init(loop, &pipe, 0);
+ ASSERT(r == 0);
+ r = uv_fileno((uv_handle_t*) &pipe, &fd);
+ ASSERT(r == UV_EBADF);
+ r = uv_pipe_bind(&pipe, TEST_PIPENAME);
+ ASSERT(r == 0);
+ r = uv_fileno((uv_handle_t*) &pipe, &fd);
+ ASSERT(r == 0);
+ uv_close((uv_handle_t*) &pipe, NULL);
+ r = uv_fileno((uv_handle_t*) &pipe, &fd);
+ ASSERT(r == UV_EBADF);
+
+ tty_fd = get_tty_fd();
+ if (tty_fd < 0) {
+ fprintf(stderr, "Cannot open a TTY fd");
+ fflush(stderr);
+ } else {
+ r = uv_tty_init(loop, &tty, tty_fd, 0);
+ ASSERT(r == 0);
+ r = uv_fileno((uv_handle_t*) &tty, &fd);
+ ASSERT(r == 0);
+ uv_close((uv_handle_t*) &tty, NULL);
+ r = uv_fileno((uv_handle_t*) &tty, &fd);
+ ASSERT(r == UV_EBADF);
+ }
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-homedir.c b/3rdparty/libuv/test/test-homedir.c
new file mode 100644
index 00000000000..cbc47566c55
--- /dev/null
+++ b/3rdparty/libuv/test/test-homedir.c
@@ -0,0 +1,49 @@
+#include "uv.h"
+#include "task.h"
+#include <string.h>
+
+#define PATHMAX 1024
+#define SMALLPATH 1
+
+TEST_IMPL(homedir) {
+ char homedir[PATHMAX];
+ size_t len;
+ char last;
+ int r;
+
+ /* Test the normal case */
+ len = sizeof homedir;
+ homedir[0] = '\0';
+ ASSERT(strlen(homedir) == 0);
+ r = uv_os_homedir(homedir, &len);
+ ASSERT(r == 0);
+ ASSERT(strlen(homedir) == len);
+ ASSERT(len > 0);
+ ASSERT(homedir[len] == '\0');
+
+ if (len > 1) {
+ last = homedir[len - 1];
+#ifdef _WIN32
+ ASSERT(last != '\\');
+#else
+ ASSERT(last != '/');
+#endif
+ }
+
+ /* Test the case where the buffer is too small */
+ len = SMALLPATH;
+ r = uv_os_homedir(homedir, &len);
+ ASSERT(r == UV_ENOBUFS);
+ ASSERT(len > SMALLPATH);
+
+ /* Test invalid inputs */
+ r = uv_os_homedir(NULL, &len);
+ ASSERT(r == UV_EINVAL);
+ r = uv_os_homedir(homedir, NULL);
+ ASSERT(r == UV_EINVAL);
+ len = 0;
+ r = uv_os_homedir(homedir, &len);
+ ASSERT(r == UV_EINVAL);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-hrtime.c b/3rdparty/libuv/test/test-hrtime.c
new file mode 100644
index 00000000000..72a4d4b181d
--- /dev/null
+++ b/3rdparty/libuv/test/test-hrtime.c
@@ -0,0 +1,54 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#ifndef MILLISEC
+# define MILLISEC 1000
+#endif
+
+#ifndef NANOSEC
+# define NANOSEC ((uint64_t) 1e9)
+#endif
+
+
+TEST_IMPL(hrtime) {
+ uint64_t a, b, diff;
+ int i = 75;
+ while (i > 0) {
+ a = uv_hrtime();
+ uv_sleep(45);
+ b = uv_hrtime();
+
+ diff = b - a;
+
+ /* printf("i= %d diff = %llu\n", i, (unsigned long long int) diff); */
+
+ /* The windows Sleep() function has only a resolution of 10-20 ms. */
+ /* Check that the difference between the two hrtime values is somewhat in */
+ /* the range we expect it to be. */
+ ASSERT(diff > (uint64_t) 25 * NANOSEC / MILLISEC);
+ ASSERT(diff < (uint64_t) 80 * NANOSEC / MILLISEC);
+ --i;
+ }
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-idle.c b/3rdparty/libuv/test/test-idle.c
new file mode 100644
index 00000000000..f49d1964827
--- /dev/null
+++ b/3rdparty/libuv/test/test-idle.c
@@ -0,0 +1,99 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+static uv_idle_t idle_handle;
+static uv_check_t check_handle;
+static uv_timer_t timer_handle;
+
+static int idle_cb_called = 0;
+static int check_cb_called = 0;
+static int timer_cb_called = 0;
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(handle == &timer_handle);
+
+ uv_close((uv_handle_t*) &idle_handle, close_cb);
+ uv_close((uv_handle_t*) &check_handle, close_cb);
+ uv_close((uv_handle_t*) &timer_handle, close_cb);
+
+ timer_cb_called++;
+ fprintf(stderr, "timer_cb %d\n", timer_cb_called);
+ fflush(stderr);
+}
+
+
+static void idle_cb(uv_idle_t* handle) {
+ ASSERT(handle == &idle_handle);
+
+ idle_cb_called++;
+ fprintf(stderr, "idle_cb %d\n", idle_cb_called);
+ fflush(stderr);
+}
+
+
+static void check_cb(uv_check_t* handle) {
+ ASSERT(handle == &check_handle);
+
+ check_cb_called++;
+ fprintf(stderr, "check_cb %d\n", check_cb_called);
+ fflush(stderr);
+}
+
+
+TEST_IMPL(idle_starvation) {
+ int r;
+
+ r = uv_idle_init(uv_default_loop(), &idle_handle);
+ ASSERT(r == 0);
+ r = uv_idle_start(&idle_handle, idle_cb);
+ ASSERT(r == 0);
+
+ r = uv_check_init(uv_default_loop(), &check_handle);
+ ASSERT(r == 0);
+ r = uv_check_start(&check_handle, check_cb);
+ ASSERT(r == 0);
+
+ r = uv_timer_init(uv_default_loop(), &timer_handle);
+ ASSERT(r == 0);
+ r = uv_timer_start(&timer_handle, timer_cb, 50, 0);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(idle_cb_called > 0);
+ ASSERT(timer_cb_called == 1);
+ ASSERT(close_cb_called == 3);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-ip4-addr.c b/3rdparty/libuv/test/test-ip4-addr.c
new file mode 100644
index 00000000000..3d6e0cf286a
--- /dev/null
+++ b/3rdparty/libuv/test/test-ip4-addr.c
@@ -0,0 +1,46 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <string.h>
+
+
+TEST_IMPL(ip4_addr) {
+
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ ASSERT(0 == uv_ip4_addr("255.255.255.255", TEST_PORT, &addr));
+ ASSERT(UV_EINVAL == uv_ip4_addr("255.255.255*000", TEST_PORT, &addr));
+ ASSERT(UV_EINVAL == uv_ip4_addr("255.255.255.256", TEST_PORT, &addr));
+ ASSERT(UV_EINVAL == uv_ip4_addr("2555.0.0.0", TEST_PORT, &addr));
+ ASSERT(UV_EINVAL == uv_ip4_addr("255", TEST_PORT, &addr));
+
+ /* for broken address family */
+ ASSERT(UV_EAFNOSUPPORT == uv_inet_pton(42, "127.0.0.1",
+ &addr.sin_addr.s_addr));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-ip6-addr.c b/3rdparty/libuv/test/test-ip6-addr.c
new file mode 100644
index 00000000000..869b099e0fc
--- /dev/null
+++ b/3rdparty/libuv/test/test-ip6-addr.c
@@ -0,0 +1,141 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef __linux__
+# include <sys/socket.h>
+# include <net/if.h>
+#endif
+
+
+TEST_IMPL(ip6_addr_link_local) {
+ char string_address[INET6_ADDRSTRLEN];
+ uv_interface_address_t* addresses;
+ uv_interface_address_t* address;
+ struct sockaddr_in6 addr;
+ unsigned int iface_index;
+ const char* device_name;
+ /* 40 bytes address, 16 bytes device name, plus reserve. */
+ char scoped_addr[128];
+ int count;
+ int ix;
+
+ ASSERT(0 == uv_interface_addresses(&addresses, &count));
+
+ for (ix = 0; ix < count; ix++) {
+ address = addresses + ix;
+
+ if (address->address.address6.sin6_family != AF_INET6)
+ continue;
+
+ ASSERT(0 == uv_inet_ntop(AF_INET6,
+ &address->address.address6.sin6_addr,
+ string_address,
+ sizeof(string_address)));
+
+ /* Skip addresses that are not link-local. */
+ if (strncmp(string_address, "fe80::", 6) != 0)
+ continue;
+
+ iface_index = address->address.address6.sin6_scope_id;
+ device_name = address->name;
+
+#ifdef _WIN32
+ snprintf(scoped_addr,
+ sizeof(scoped_addr),
+ "%s%%%d",
+ string_address,
+ iface_index);
+#else
+ snprintf(scoped_addr,
+ sizeof(scoped_addr),
+ "%s%%%s",
+ string_address,
+ device_name);
+#endif
+
+ fprintf(stderr, "Testing link-local address %s "
+ "(iface_index: 0x%02x, device_name: %s)\n",
+ scoped_addr,
+ iface_index,
+ device_name);
+ fflush(stderr);
+
+ ASSERT(0 == uv_ip6_addr(scoped_addr, TEST_PORT, &addr));
+ fprintf(stderr, "Got scope_id 0x%02x\n", addr.sin6_scope_id);
+ fflush(stderr);
+ ASSERT(iface_index == addr.sin6_scope_id);
+ }
+
+ uv_free_interface_addresses(addresses, count);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+#define GOOD_ADDR_LIST(X) \
+ X("::") \
+ X("::1") \
+ X("fe80::1") \
+ X("fe80::") \
+ X("fe80::2acf:daff:fedd:342a") \
+ X("fe80:0:0:0:2acf:daff:fedd:342a") \
+ X("fe80:0:0:0:2acf:daff:1.2.3.4") \
+ X("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") \
+
+#define BAD_ADDR_LIST(X) \
+ X(":::1") \
+ X("abcde::1") \
+ X("fe80:0:0:0:2acf:daff:fedd:342a:5678") \
+ X("fe80:0:0:0:2acf:daff:abcd:1.2.3.4") \
+ X("fe80:0:0:2acf:daff:1.2.3.4.5") \
+ X("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255.255") \
+
+#define TEST_GOOD(ADDR) \
+ ASSERT(0 == uv_inet_pton(AF_INET6, ADDR, &addr)); \
+ ASSERT(0 == uv_inet_pton(AF_INET6, ADDR "%en1", &addr)); \
+ ASSERT(0 == uv_inet_pton(AF_INET6, ADDR "%%%%", &addr)); \
+ ASSERT(0 == uv_inet_pton(AF_INET6, ADDR "%en1:1.2.3.4", &addr)); \
+
+#define TEST_BAD(ADDR) \
+ ASSERT(0 != uv_inet_pton(AF_INET6, ADDR, &addr)); \
+ ASSERT(0 != uv_inet_pton(AF_INET6, ADDR "%en1", &addr)); \
+ ASSERT(0 != uv_inet_pton(AF_INET6, ADDR "%%%%", &addr)); \
+ ASSERT(0 != uv_inet_pton(AF_INET6, ADDR "%en1:1.2.3.4", &addr)); \
+
+TEST_IMPL(ip6_pton) {
+ struct in6_addr addr;
+
+ GOOD_ADDR_LIST(TEST_GOOD)
+ BAD_ADDR_LIST(TEST_BAD)
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#undef GOOD_ADDR_LIST
+#undef BAD_ADDR_LIST
diff --git a/3rdparty/libuv/test/test-ipc-send-recv.c b/3rdparty/libuv/test/test-ipc-send-recv.c
new file mode 100644
index 00000000000..c445483fa08
--- /dev/null
+++ b/3rdparty/libuv/test/test-ipc-send-recv.c
@@ -0,0 +1,411 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <string.h>
+
+/* See test-ipc.ctx */
+void spawn_helper(uv_pipe_t* channel,
+ uv_process_t* process,
+ const char* helper);
+
+void ipc_send_recv_helper_threadproc(void* arg);
+
+union handles {
+ uv_handle_t handle;
+ uv_stream_t stream;
+ uv_pipe_t pipe;
+ uv_tcp_t tcp;
+ uv_tty_t tty;
+};
+
+struct test_ctx {
+ uv_pipe_t channel;
+ uv_connect_t connect_req;
+ uv_write_t write_req;
+ uv_write_t write_req2;
+ uv_handle_type expected_type;
+ union handles send;
+ union handles send2;
+ union handles recv;
+ union handles recv2;
+};
+
+struct echo_ctx {
+ uv_pipe_t listen;
+ uv_pipe_t channel;
+ uv_write_t write_req;
+ uv_write_t write_req2;
+ uv_handle_type expected_type;
+ union handles recv;
+ union handles recv2;
+};
+
+static struct test_ctx ctx;
+static struct echo_ctx ctx2;
+
+/* Used in write2_cb to decide if we need to cleanup or not */
+static int is_child_process;
+static int is_in_process;
+static int read_cb_called;
+static int recv_cb_called;
+static int write2_cb_called;
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ /* we're not actually reading anything so a small buffer is okay */
+ static char slab[8];
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void recv_cb(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ uv_handle_type pending;
+ uv_pipe_t* pipe;
+ int r;
+ union handles* recv;
+
+ if (++recv_cb_called == 1) {
+ recv = &ctx.recv;
+ } else {
+ recv = &ctx.recv2;
+ }
+
+ pipe = (uv_pipe_t*) handle;
+ ASSERT(pipe == &ctx.channel);
+
+ /* Depending on the OS, the final recv_cb can be called after the child
+ * process has terminated which can result in nread being UV_EOF instead of
+ * the number of bytes read. Since the other end of the pipe has closed this
+ * UV_EOF is an acceptable value. */
+ if (nread == UV_EOF) {
+ /* UV_EOF is only acceptable for the final recv_cb call */
+ ASSERT(recv_cb_called == 2);
+ } else {
+ ASSERT(nread >= 0);
+ ASSERT(1 == uv_pipe_pending_count(pipe));
+
+ pending = uv_pipe_pending_type(pipe);
+ ASSERT(pending == ctx.expected_type);
+
+ if (pending == UV_NAMED_PIPE)
+ r = uv_pipe_init(ctx.channel.loop, &recv->pipe, 0);
+ else if (pending == UV_TCP)
+ r = uv_tcp_init(ctx.channel.loop, &recv->tcp);
+ else
+ abort();
+ ASSERT(r == 0);
+
+ r = uv_accept(handle, &recv->stream);
+ ASSERT(r == 0);
+ }
+
+ /* Close after two writes received */
+ if (recv_cb_called == 2) {
+ uv_close((uv_handle_t*)&ctx.channel, NULL);
+ }
+}
+
+static void connect_cb(uv_connect_t* req, int status) {
+ int r;
+ uv_buf_t buf;
+
+ ASSERT(req == &ctx.connect_req);
+ ASSERT(status == 0);
+
+ buf = uv_buf_init(".", 1);
+ r = uv_write2(&ctx.write_req,
+ (uv_stream_t*)&ctx.channel,
+ &buf, 1,
+ &ctx.send.stream,
+ NULL);
+ ASSERT(r == 0);
+
+ /* Perform two writes to the same pipe to make sure that on Windows we are
+ * not running into issue 505:
+ * https://github.com/libuv/libuv/issues/505 */
+ buf = uv_buf_init(".", 1);
+ r = uv_write2(&ctx.write_req2,
+ (uv_stream_t*)&ctx.channel,
+ &buf, 1,
+ &ctx.send2.stream,
+ NULL);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)&ctx.channel, alloc_cb, recv_cb);
+ ASSERT(r == 0);
+}
+
+static int run_test(int inprocess) {
+ uv_process_t process;
+ uv_thread_t tid;
+ int r;
+
+ if (inprocess) {
+ r = uv_thread_create(&tid, ipc_send_recv_helper_threadproc, (void *) 42);
+ ASSERT(r == 0);
+
+ uv_sleep(1000);
+
+ r = uv_pipe_init(uv_default_loop(), &ctx.channel, 1);
+ ASSERT(r == 0);
+
+ uv_pipe_connect(&ctx.connect_req, &ctx.channel, TEST_PIPENAME_3, connect_cb);
+ } else {
+ spawn_helper(&ctx.channel, &process, "ipc_send_recv_helper");
+
+ connect_cb(&ctx.connect_req, 0);
+ }
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(recv_cb_called == 2);
+
+ if (inprocess) {
+ r = uv_thread_join(&tid);
+ ASSERT(r == 0);
+ }
+
+ return 0;
+}
+
+static int run_ipc_send_recv_pipe(int inprocess) {
+ int r;
+
+ ctx.expected_type = UV_NAMED_PIPE;
+
+ r = uv_pipe_init(uv_default_loop(), &ctx.send.pipe, 1);
+ ASSERT(r == 0);
+
+ r = uv_pipe_bind(&ctx.send.pipe, TEST_PIPENAME);
+ ASSERT(r == 0);
+
+ r = uv_pipe_init(uv_default_loop(), &ctx.send2.pipe, 1);
+ ASSERT(r == 0);
+
+ r = uv_pipe_bind(&ctx.send2.pipe, TEST_PIPENAME_2);
+ ASSERT(r == 0);
+
+ r = run_test(inprocess);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(ipc_send_recv_pipe) {
+ return run_ipc_send_recv_pipe(0);
+}
+
+TEST_IMPL(ipc_send_recv_pipe_inprocess) {
+ return run_ipc_send_recv_pipe(1);
+}
+
+static int run_ipc_send_recv_tcp(int inprocess) {
+ struct sockaddr_in addr;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ ctx.expected_type = UV_TCP;
+
+ r = uv_tcp_init(uv_default_loop(), &ctx.send.tcp);
+ ASSERT(r == 0);
+
+ r = uv_tcp_init(uv_default_loop(), &ctx.send2.tcp);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(&ctx.send.tcp, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(&ctx.send2.tcp, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = run_test(inprocess);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(ipc_send_recv_tcp) {
+ return run_ipc_send_recv_tcp(0);
+}
+
+TEST_IMPL(ipc_send_recv_tcp_inprocess) {
+ return run_ipc_send_recv_tcp(1);
+}
+
+
+/* Everything here runs in a child process or second thread. */
+
+static void write2_cb(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+
+ /* After two successful writes in the child process, allow the child
+ * process to be closed. */
+ if (++write2_cb_called == 2 && (is_child_process || is_in_process)) {
+ uv_close(&ctx2.recv.handle, NULL);
+ uv_close(&ctx2.recv2.handle, NULL);
+ uv_close((uv_handle_t*)&ctx2.channel, NULL);
+ uv_close((uv_handle_t*)&ctx2.listen, NULL);
+ }
+}
+
+static void read_cb(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* rdbuf) {
+ uv_buf_t wrbuf;
+ uv_pipe_t* pipe;
+ uv_handle_type pending;
+ int r;
+ union handles* recv;
+ uv_write_t* write_req;
+
+ if (nread == UV__EOF || nread == UV__ECONNABORTED) {
+ return;
+ }
+
+ if (++read_cb_called == 2) {
+ recv = &ctx2.recv;
+ write_req = &ctx2.write_req;
+ } else {
+ recv = &ctx2.recv2;
+ write_req = &ctx2.write_req2;
+ }
+
+ pipe = (uv_pipe_t*) handle;
+ ASSERT(pipe == &ctx2.channel);
+ ASSERT(nread >= 0);
+ ASSERT(1 == uv_pipe_pending_count(pipe));
+
+ pending = uv_pipe_pending_type(pipe);
+ ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP);
+
+ if (pending == UV_NAMED_PIPE)
+ r = uv_pipe_init(ctx2.channel.loop, &recv->pipe, 0);
+ else if (pending == UV_TCP)
+ r = uv_tcp_init(ctx2.channel.loop, &recv->tcp);
+ else
+ abort();
+ ASSERT(r == 0);
+
+ r = uv_accept(handle, &recv->stream);
+ ASSERT(r == 0);
+
+ wrbuf = uv_buf_init(".", 1);
+ r = uv_write2(write_req,
+ (uv_stream_t*)&ctx2.channel,
+ &wrbuf,
+ 1,
+ &recv->stream,
+ write2_cb);
+ ASSERT(r == 0);
+}
+
+static void send_recv_start() {
+ int r;
+ ASSERT(1 == uv_is_readable((uv_stream_t*)&ctx2.channel));
+ ASSERT(1 == uv_is_writable((uv_stream_t*)&ctx2.channel));
+ ASSERT(0 == uv_is_closing((uv_handle_t*)&ctx2.channel));
+
+ r = uv_read_start((uv_stream_t*)&ctx2.channel, alloc_cb, read_cb);
+ ASSERT(r == 0);
+}
+
+static void listen_cb(uv_stream_t* handle, int status) {
+ int r;
+ ASSERT(handle == (uv_stream_t*)&ctx2.listen);
+ ASSERT(status == 0);
+
+ r = uv_accept((uv_stream_t*)&ctx2.listen, (uv_stream_t*)&ctx2.channel);
+ ASSERT(r == 0);
+
+ send_recv_start();
+}
+
+int run_ipc_send_recv_helper(uv_loop_t* loop, int inprocess) {
+ int r;
+
+ is_in_process = inprocess;
+
+ memset(&ctx2, 0, sizeof(ctx2));
+
+ r = uv_pipe_init(loop, &ctx2.listen, 0);
+ ASSERT(r == 0);
+
+ r = uv_pipe_init(loop, &ctx2.channel, 1);
+ ASSERT(r == 0);
+
+ if (inprocess) {
+ r = uv_pipe_bind(&ctx2.listen, TEST_PIPENAME_3);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&ctx2.listen, SOMAXCONN, listen_cb);
+ ASSERT(r == 0);
+ } else {
+ r = uv_pipe_open(&ctx2.channel, 0);
+ ASSERT(r == 0);
+
+ send_recv_start();
+ }
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ return 0;
+}
+
+/* stdin is a duplex channel over which a handle is sent.
+ * We receive it and send it back where it came from.
+ */
+int ipc_send_recv_helper(void) {
+ int r;
+
+ r = run_ipc_send_recv_helper(uv_default_loop(), 0);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+void ipc_send_recv_helper_threadproc(void* arg) {
+ int r;
+ uv_loop_t loop;
+
+ r = uv_loop_init(&loop);
+ ASSERT(r == 0);
+
+ r = run_ipc_send_recv_helper(&loop, 1);
+ ASSERT(r == 0);
+
+ r = uv_loop_close(&loop);
+ ASSERT(r == 0);
+}
diff --git a/3rdparty/libuv/test/test-ipc.c b/3rdparty/libuv/test/test-ipc.c
new file mode 100644
index 00000000000..f018c2d4d49
--- /dev/null
+++ b/3rdparty/libuv/test/test-ipc.c
@@ -0,0 +1,779 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static uv_pipe_t channel;
+static uv_tcp_t tcp_server;
+static uv_tcp_t tcp_server2;
+static uv_tcp_t tcp_connection;
+
+static int exit_cb_called;
+static int read_cb_called;
+static int tcp_write_cb_called;
+static int tcp_read_cb_called;
+static int on_pipe_read_called;
+static int local_conn_accepted;
+static int remote_conn_accepted;
+static int tcp_server_listening;
+static uv_write_t write_req;
+static uv_write_t conn_notify_req;
+static int close_cb_called;
+static int connection_accepted;
+static int tcp_conn_read_cb_called;
+static int tcp_conn_write_cb_called;
+
+typedef struct {
+ uv_connect_t conn_req;
+ uv_write_t tcp_write_req;
+ uv_tcp_t conn;
+} tcp_conn;
+
+#define CONN_COUNT 100
+#define BACKLOG 128
+
+
+static void close_server_conn_cb(uv_handle_t* handle) {
+ free(handle);
+}
+
+
+static void on_connection(uv_stream_t* server, int status) {
+ uv_tcp_t* conn;
+ int r;
+
+ if (!local_conn_accepted) {
+ /* Accept the connection and close it. Also and close the server. */
+ ASSERT(status == 0);
+ ASSERT((uv_stream_t*)&tcp_server == server);
+
+ conn = malloc(sizeof(*conn));
+ ASSERT(conn);
+ r = uv_tcp_init(server->loop, conn);
+ ASSERT(r == 0);
+
+ r = uv_accept(server, (uv_stream_t*)conn);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*)conn, close_server_conn_cb);
+ uv_close((uv_handle_t*)server, NULL);
+ local_conn_accepted = 1;
+ }
+}
+
+
+static void exit_cb(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ printf("exit_cb\n");
+ exit_cb_called++;
+ ASSERT(exit_status == 0);
+ uv_close((uv_handle_t*)process, NULL);
+}
+
+
+static void on_alloc(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ buf->base = malloc(suggested_size);
+ buf->len = suggested_size;
+}
+
+
+static void close_client_conn_cb(uv_handle_t* handle) {
+ tcp_conn* p = (tcp_conn*)handle->data;
+ free(p);
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ uv_close((uv_handle_t*)req->handle, close_client_conn_cb);
+}
+
+
+static void make_many_connections(void) {
+ tcp_conn* conn;
+ struct sockaddr_in addr;
+ int r, i;
+
+ for (i = 0; i < CONN_COUNT; i++) {
+ conn = malloc(sizeof(*conn));
+ ASSERT(conn);
+
+ r = uv_tcp_init(uv_default_loop(), &conn->conn);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_connect(&conn->conn_req,
+ (uv_tcp_t*) &conn->conn,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+
+ conn->conn.data = conn;
+ }
+}
+
+
+static void on_read(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ int r;
+ uv_pipe_t* pipe;
+ uv_handle_type pending;
+ uv_buf_t outbuf;
+
+ pipe = (uv_pipe_t*) handle;
+
+ if (nread == 0) {
+ /* Everything OK, but nothing read. */
+ free(buf->base);
+ return;
+ }
+
+ if (nread < 0) {
+ if (nread == UV_EOF) {
+ free(buf->base);
+ return;
+ }
+
+ printf("error recving on channel: %s\n", uv_strerror(nread));
+ abort();
+ }
+
+ fprintf(stderr, "got %d bytes\n", (int)nread);
+
+ pending = uv_pipe_pending_type(pipe);
+ if (!tcp_server_listening) {
+ ASSERT(1 == uv_pipe_pending_count(pipe));
+ ASSERT(nread > 0 && buf->base && pending != UV_UNKNOWN_HANDLE);
+ read_cb_called++;
+
+ /* Accept the pending TCP server, and start listening on it. */
+ ASSERT(pending == UV_TCP);
+ r = uv_tcp_init(uv_default_loop(), &tcp_server);
+ ASSERT(r == 0);
+
+ r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, on_connection);
+ ASSERT(r == 0);
+
+ tcp_server_listening = 1;
+
+ /* Make sure that the expected data is correctly multiplexed. */
+ ASSERT(memcmp("hello\n", buf->base, nread) == 0);
+
+ outbuf = uv_buf_init("world\n", 6);
+ r = uv_write(&write_req, (uv_stream_t*)pipe, &outbuf, 1, NULL);
+ ASSERT(r == 0);
+
+ /* Create a bunch of connections to get both servers to accept. */
+ make_many_connections();
+ } else if (memcmp("accepted_connection\n", buf->base, nread) == 0) {
+ /* Remote server has accepted a connection. Close the channel. */
+ ASSERT(0 == uv_pipe_pending_count(pipe));
+ ASSERT(pending == UV_UNKNOWN_HANDLE);
+ remote_conn_accepted = 1;
+ uv_close((uv_handle_t*)&channel, NULL);
+ }
+
+ free(buf->base);
+}
+
+#ifdef _WIN32
+static void on_read_listen_after_bound_twice(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ int r;
+ uv_pipe_t* pipe;
+ uv_handle_type pending;
+
+ pipe = (uv_pipe_t*) handle;
+
+ if (nread == 0) {
+ /* Everything OK, but nothing read. */
+ free(buf->base);
+ return;
+ }
+
+ if (nread < 0) {
+ if (nread == UV_EOF) {
+ free(buf->base);
+ return;
+ }
+
+ printf("error recving on channel: %s\n", uv_strerror(nread));
+ abort();
+ }
+
+ fprintf(stderr, "got %d bytes\n", (int)nread);
+
+ ASSERT(uv_pipe_pending_count(pipe) > 0);
+ pending = uv_pipe_pending_type(pipe);
+ ASSERT(nread > 0 && buf->base && pending != UV_UNKNOWN_HANDLE);
+ read_cb_called++;
+
+ if (read_cb_called == 1) {
+ /* Accept the first TCP server, and start listening on it. */
+ ASSERT(pending == UV_TCP);
+ r = uv_tcp_init(uv_default_loop(), &tcp_server);
+ ASSERT(r == 0);
+
+ r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, on_connection);
+ ASSERT(r == 0);
+ } else if (read_cb_called == 2) {
+ /* Accept the second TCP server, and start listening on it. */
+ ASSERT(pending == UV_TCP);
+ r = uv_tcp_init(uv_default_loop(), &tcp_server2);
+ ASSERT(r == 0);
+
+ r = uv_accept((uv_stream_t*)pipe, (uv_stream_t*)&tcp_server2);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&tcp_server2, BACKLOG, on_connection);
+ ASSERT(r == UV_EADDRINUSE);
+
+ uv_close((uv_handle_t*)&tcp_server, NULL);
+ uv_close((uv_handle_t*)&tcp_server2, NULL);
+ ASSERT(0 == uv_pipe_pending_count(pipe));
+ uv_close((uv_handle_t*)&channel, NULL);
+ }
+
+ free(buf->base);
+}
+#endif
+
+void spawn_helper(uv_pipe_t* channel,
+ uv_process_t* process,
+ const char* helper) {
+ uv_process_options_t options;
+ size_t exepath_size;
+ char exepath[1024];
+ char* args[3];
+ int r;
+ uv_stdio_container_t stdio[1];
+
+ r = uv_pipe_init(uv_default_loop(), channel, 1);
+ ASSERT(r == 0);
+ ASSERT(channel->ipc);
+
+ exepath_size = sizeof(exepath);
+ r = uv_exepath(exepath, &exepath_size);
+ ASSERT(r == 0);
+
+ exepath[exepath_size] = '\0';
+ args[0] = exepath;
+ args[1] = (char*)helper;
+ args[2] = NULL;
+
+ memset(&options, 0, sizeof(options));
+ options.file = exepath;
+ options.args = args;
+ options.exit_cb = exit_cb;
+
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE |
+ UV_READABLE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*)channel;
+ options.stdio_count = 1;
+
+ r = uv_spawn(uv_default_loop(), process, &options);
+ ASSERT(r == 0);
+}
+
+
+static void on_tcp_write(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+ ASSERT(req->handle == (uv_stream_t*)&tcp_connection);
+ tcp_write_cb_called++;
+}
+
+
+static void on_read_alloc(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ buf->base = malloc(suggested_size);
+ buf->len = suggested_size;
+}
+
+
+static void on_tcp_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ ASSERT(nread > 0);
+ ASSERT(memcmp("hello again\n", buf->base, nread) == 0);
+ ASSERT(tcp == (uv_stream_t*)&tcp_connection);
+ free(buf->base);
+
+ tcp_read_cb_called++;
+
+ uv_close((uv_handle_t*)tcp, NULL);
+ uv_close((uv_handle_t*)&channel, NULL);
+}
+
+
+static void on_read_connection(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ int r;
+ uv_buf_t outbuf;
+ uv_pipe_t* pipe;
+ uv_handle_type pending;
+
+ pipe = (uv_pipe_t*) handle;
+ if (nread == 0) {
+ /* Everything OK, but nothing read. */
+ free(buf->base);
+ return;
+ }
+
+ if (nread < 0) {
+ if (nread == UV_EOF) {
+ free(buf->base);
+ return;
+ }
+
+ printf("error recving on channel: %s\n", uv_strerror(nread));
+ abort();
+ }
+
+ fprintf(stderr, "got %d bytes\n", (int)nread);
+
+ ASSERT(1 == uv_pipe_pending_count(pipe));
+ pending = uv_pipe_pending_type(pipe);
+
+ ASSERT(nread > 0 && buf->base && pending != UV_UNKNOWN_HANDLE);
+ read_cb_called++;
+
+ /* Accept the pending TCP connection */
+ ASSERT(pending == UV_TCP);
+ r = uv_tcp_init(uv_default_loop(), &tcp_connection);
+ ASSERT(r == 0);
+
+ r = uv_accept(handle, (uv_stream_t*)&tcp_connection);
+ ASSERT(r == 0);
+
+ /* Make sure that the expected data is correctly multiplexed. */
+ ASSERT(memcmp("hello\n", buf->base, nread) == 0);
+
+ /* Write/read to/from the connection */
+ outbuf = uv_buf_init("world\n", 6);
+ r = uv_write(&write_req, (uv_stream_t*)&tcp_connection, &outbuf, 1,
+ on_tcp_write);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)&tcp_connection, on_read_alloc, on_tcp_read);
+ ASSERT(r == 0);
+
+ free(buf->base);
+}
+
+
+static int run_ipc_test(const char* helper, uv_read_cb read_cb) {
+ uv_process_t process;
+ int r;
+
+ spawn_helper(&channel, &process, helper);
+ uv_read_start((uv_stream_t*)&channel, on_alloc, read_cb);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(ipc_listen_before_write) {
+ int r = run_ipc_test("ipc_helper_listen_before_write", on_read);
+ ASSERT(local_conn_accepted == 1);
+ ASSERT(remote_conn_accepted == 1);
+ ASSERT(read_cb_called == 1);
+ ASSERT(exit_cb_called == 1);
+ return r;
+}
+
+
+TEST_IMPL(ipc_listen_after_write) {
+ int r = run_ipc_test("ipc_helper_listen_after_write", on_read);
+ ASSERT(local_conn_accepted == 1);
+ ASSERT(remote_conn_accepted == 1);
+ ASSERT(read_cb_called == 1);
+ ASSERT(exit_cb_called == 1);
+ return r;
+}
+
+
+TEST_IMPL(ipc_tcp_connection) {
+ int r = run_ipc_test("ipc_helper_tcp_connection", on_read_connection);
+ ASSERT(read_cb_called == 1);
+ ASSERT(tcp_write_cb_called == 1);
+ ASSERT(tcp_read_cb_called == 1);
+ ASSERT(exit_cb_called == 1);
+ return r;
+}
+
+
+#ifdef _WIN32
+TEST_IMPL(listen_with_simultaneous_accepts) {
+ uv_tcp_t server;
+ int r;
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_tcp_simultaneous_accepts(&server, 1);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL);
+ ASSERT(r == 0);
+ ASSERT(server.reqs_pending == 32);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(listen_no_simultaneous_accepts) {
+ uv_tcp_t server;
+ int r;
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_tcp_simultaneous_accepts(&server, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL);
+ ASSERT(r == 0);
+ ASSERT(server.reqs_pending == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(ipc_listen_after_bind_twice) {
+ int r = run_ipc_test("ipc_helper_bind_twice", on_read_listen_after_bound_twice);
+ ASSERT(read_cb_called == 2);
+ ASSERT(exit_cb_called == 1);
+ return r;
+}
+#endif
+
+
+/* Everything here runs in a child process. */
+
+static tcp_conn conn;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void conn_notify_write_cb(uv_write_t* req, int status) {
+ uv_close((uv_handle_t*)&tcp_server, close_cb);
+ uv_close((uv_handle_t*)&channel, close_cb);
+}
+
+
+static void tcp_connection_write_cb(uv_write_t* req, int status) {
+ ASSERT((uv_handle_t*)&conn.conn == (uv_handle_t*)req->handle);
+ uv_close((uv_handle_t*)req->handle, close_cb);
+ uv_close((uv_handle_t*)&channel, close_cb);
+ uv_close((uv_handle_t*)&tcp_server, close_cb);
+ tcp_conn_write_cb_called++;
+}
+
+
+static void on_tcp_child_process_read(uv_stream_t* tcp,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ uv_buf_t outbuf;
+ int r;
+
+ if (nread < 0) {
+ if (nread == UV_EOF) {
+ free(buf->base);
+ return;
+ }
+
+ printf("error recving on tcp connection: %s\n", uv_strerror(nread));
+ abort();
+ }
+
+ ASSERT(nread > 0);
+ ASSERT(memcmp("world\n", buf->base, nread) == 0);
+ on_pipe_read_called++;
+ free(buf->base);
+
+ /* Write to the socket */
+ outbuf = uv_buf_init("hello again\n", 12);
+ r = uv_write(&conn.tcp_write_req, tcp, &outbuf, 1, tcp_connection_write_cb);
+ ASSERT(r == 0);
+
+ tcp_conn_read_cb_called++;
+}
+
+
+static void connect_child_process_cb(uv_connect_t* req, int status) {
+ int r;
+
+ ASSERT(status == 0);
+ r = uv_read_start(req->handle, on_read_alloc, on_tcp_child_process_read);
+ ASSERT(r == 0);
+}
+
+
+static void ipc_on_connection(uv_stream_t* server, int status) {
+ int r;
+ uv_buf_t buf;
+
+ if (!connection_accepted) {
+ /*
+ * Accept the connection and close it. Also let the other
+ * side know.
+ */
+ ASSERT(status == 0);
+ ASSERT((uv_stream_t*)&tcp_server == server);
+
+ r = uv_tcp_init(server->loop, &conn.conn);
+ ASSERT(r == 0);
+
+ r = uv_accept(server, (uv_stream_t*)&conn.conn);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*)&conn.conn, close_cb);
+
+ buf = uv_buf_init("accepted_connection\n", 20);
+ r = uv_write2(&conn_notify_req, (uv_stream_t*)&channel, &buf, 1,
+ NULL, conn_notify_write_cb);
+ ASSERT(r == 0);
+
+ connection_accepted = 1;
+ }
+}
+
+
+static void ipc_on_connection_tcp_conn(uv_stream_t* server, int status) {
+ int r;
+ uv_buf_t buf;
+ uv_tcp_t* conn;
+
+ ASSERT(status == 0);
+ ASSERT((uv_stream_t*)&tcp_server == server);
+
+ conn = malloc(sizeof(*conn));
+ ASSERT(conn);
+
+ r = uv_tcp_init(server->loop, conn);
+ ASSERT(r == 0);
+
+ r = uv_accept(server, (uv_stream_t*)conn);
+ ASSERT(r == 0);
+
+ /* Send the accepted connection to the other process */
+ buf = uv_buf_init("hello\n", 6);
+ r = uv_write2(&conn_notify_req, (uv_stream_t*)&channel, &buf, 1,
+ (uv_stream_t*)conn, NULL);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) conn,
+ on_read_alloc,
+ on_tcp_child_process_read);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*)conn, close_cb);
+}
+
+
+int ipc_helper(int listen_after_write) {
+ /*
+ * This is launched from test-ipc.c. stdin is a duplex channel that we
+ * over which a handle will be transmitted.
+ */
+ struct sockaddr_in addr;
+ uv_write_t write_req;
+ int r;
+ uv_buf_t buf;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_pipe_init(uv_default_loop(), &channel, 1);
+ ASSERT(r == 0);
+
+ uv_pipe_open(&channel, 0);
+
+ ASSERT(1 == uv_is_readable((uv_stream_t*) &channel));
+ ASSERT(1 == uv_is_writable((uv_stream_t*) &channel));
+ ASSERT(0 == uv_is_closing((uv_handle_t*) &channel));
+
+ r = uv_tcp_init(uv_default_loop(), &tcp_server);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ if (!listen_after_write) {
+ r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, ipc_on_connection);
+ ASSERT(r == 0);
+ }
+
+ buf = uv_buf_init("hello\n", 6);
+ r = uv_write2(&write_req, (uv_stream_t*)&channel, &buf, 1,
+ (uv_stream_t*)&tcp_server, NULL);
+ ASSERT(r == 0);
+
+ if (listen_after_write) {
+ r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, ipc_on_connection);
+ ASSERT(r == 0);
+ }
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(connection_accepted == 1);
+ ASSERT(close_cb_called == 3);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+int ipc_helper_tcp_connection(void) {
+ /*
+ * This is launched from test-ipc.c. stdin is a duplex channel
+ * over which a handle will be transmitted.
+ */
+
+ int r;
+ struct sockaddr_in addr;
+
+ r = uv_pipe_init(uv_default_loop(), &channel, 1);
+ ASSERT(r == 0);
+
+ uv_pipe_open(&channel, 0);
+
+ ASSERT(1 == uv_is_readable((uv_stream_t*) &channel));
+ ASSERT(1 == uv_is_writable((uv_stream_t*) &channel));
+ ASSERT(0 == uv_is_closing((uv_handle_t*) &channel));
+
+ r = uv_tcp_init(uv_default_loop(), &tcp_server);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&tcp_server, BACKLOG, ipc_on_connection_tcp_conn);
+ ASSERT(r == 0);
+
+ /* Make a connection to the server */
+ r = uv_tcp_init(uv_default_loop(), &conn.conn);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_connect(&conn.conn_req,
+ (uv_tcp_t*) &conn.conn,
+ (const struct sockaddr*) &addr,
+ connect_child_process_cb);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(tcp_conn_read_cb_called == 1);
+ ASSERT(tcp_conn_write_cb_called == 1);
+ ASSERT(close_cb_called == 4);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+int ipc_helper_bind_twice(void) {
+ /*
+ * This is launched from test-ipc.c. stdin is a duplex channel
+ * over which two handles will be transmitted.
+ */
+ struct sockaddr_in addr;
+ uv_write_t write_req;
+ uv_write_t write_req2;
+ int r;
+ uv_buf_t buf;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_pipe_init(uv_default_loop(), &channel, 1);
+ ASSERT(r == 0);
+
+ uv_pipe_open(&channel, 0);
+
+ ASSERT(1 == uv_is_readable((uv_stream_t*) &channel));
+ ASSERT(1 == uv_is_writable((uv_stream_t*) &channel));
+ ASSERT(0 == uv_is_closing((uv_handle_t*) &channel));
+
+ buf = uv_buf_init("hello\n", 6);
+
+ r = uv_tcp_init(uv_default_loop(), &tcp_server);
+ ASSERT(r == 0);
+ r = uv_tcp_init(uv_default_loop(), &tcp_server2);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&tcp_server2, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_write2(&write_req, (uv_stream_t*)&channel, &buf, 1,
+ (uv_stream_t*)&tcp_server, NULL);
+ ASSERT(r == 0);
+ r = uv_write2(&write_req2, (uv_stream_t*)&channel, &buf, 1,
+ (uv_stream_t*)&tcp_server2, NULL);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-list.h b/3rdparty/libuv/test/test-list.h
new file mode 100644
index 00000000000..858a20af49c
--- /dev/null
+++ b/3rdparty/libuv/test/test-list.h
@@ -0,0 +1,732 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+TEST_DECLARE (platform_output)
+TEST_DECLARE (callback_order)
+TEST_DECLARE (close_order)
+TEST_DECLARE (run_once)
+TEST_DECLARE (run_nowait)
+TEST_DECLARE (loop_alive)
+TEST_DECLARE (loop_close)
+TEST_DECLARE (loop_stop)
+TEST_DECLARE (loop_update_time)
+TEST_DECLARE (loop_backend_timeout)
+TEST_DECLARE (loop_configure)
+TEST_DECLARE (default_loop_close)
+TEST_DECLARE (barrier_1)
+TEST_DECLARE (barrier_2)
+TEST_DECLARE (barrier_3)
+TEST_DECLARE (condvar_1)
+TEST_DECLARE (condvar_2)
+TEST_DECLARE (condvar_3)
+TEST_DECLARE (condvar_4)
+TEST_DECLARE (condvar_5)
+TEST_DECLARE (semaphore_1)
+TEST_DECLARE (semaphore_2)
+TEST_DECLARE (semaphore_3)
+TEST_DECLARE (tty)
+TEST_DECLARE (tty_file)
+TEST_DECLARE (stdio_over_pipes)
+TEST_DECLARE (ip6_pton)
+TEST_DECLARE (ipc_listen_before_write)
+TEST_DECLARE (ipc_listen_after_write)
+#ifndef _WIN32
+TEST_DECLARE (ipc_send_recv_pipe)
+TEST_DECLARE (ipc_send_recv_pipe_inprocess)
+#endif
+TEST_DECLARE (ipc_send_recv_tcp)
+TEST_DECLARE (ipc_send_recv_tcp_inprocess)
+TEST_DECLARE (ipc_tcp_connection)
+TEST_DECLARE (tcp_ping_pong)
+TEST_DECLARE (tcp_ping_pong_v6)
+TEST_DECLARE (pipe_ping_pong)
+TEST_DECLARE (delayed_accept)
+TEST_DECLARE (multiple_listen)
+#ifndef _WIN32
+TEST_DECLARE (tcp_write_after_connect)
+#endif
+TEST_DECLARE (tcp_writealot)
+TEST_DECLARE (tcp_write_fail)
+TEST_DECLARE (tcp_try_write)
+TEST_DECLARE (tcp_write_queue_order)
+TEST_DECLARE (tcp_open)
+TEST_DECLARE (tcp_open_twice)
+TEST_DECLARE (tcp_connect_error_after_write)
+TEST_DECLARE (tcp_shutdown_after_write)
+TEST_DECLARE (tcp_bind_error_addrinuse)
+TEST_DECLARE (tcp_bind_error_addrnotavail_1)
+TEST_DECLARE (tcp_bind_error_addrnotavail_2)
+TEST_DECLARE (tcp_bind_error_fault)
+TEST_DECLARE (tcp_bind_error_inval)
+TEST_DECLARE (tcp_bind_localhost_ok)
+TEST_DECLARE (tcp_bind_invalid_flags)
+TEST_DECLARE (tcp_listen_without_bind)
+TEST_DECLARE (tcp_connect_error_fault)
+TEST_DECLARE (tcp_connect_timeout)
+TEST_DECLARE (tcp_close_while_connecting)
+TEST_DECLARE (tcp_close)
+TEST_DECLARE (tcp_create_early)
+TEST_DECLARE (tcp_create_early_bad_bind)
+TEST_DECLARE (tcp_create_early_bad_domain)
+TEST_DECLARE (tcp_create_early_accept)
+#ifndef _WIN32
+TEST_DECLARE (tcp_close_accept)
+TEST_DECLARE (tcp_oob)
+#endif
+TEST_DECLARE (tcp_flags)
+TEST_DECLARE (tcp_write_to_half_open_connection)
+TEST_DECLARE (tcp_unexpected_read)
+TEST_DECLARE (tcp_read_stop)
+TEST_DECLARE (tcp_bind6_error_addrinuse)
+TEST_DECLARE (tcp_bind6_error_addrnotavail)
+TEST_DECLARE (tcp_bind6_error_fault)
+TEST_DECLARE (tcp_bind6_error_inval)
+TEST_DECLARE (tcp_bind6_localhost_ok)
+TEST_DECLARE (udp_bind)
+TEST_DECLARE (udp_bind_reuseaddr)
+TEST_DECLARE (udp_create_early)
+TEST_DECLARE (udp_create_early_bad_bind)
+TEST_DECLARE (udp_create_early_bad_domain)
+TEST_DECLARE (udp_send_and_recv)
+TEST_DECLARE (udp_send_immediate)
+TEST_DECLARE (udp_send_unreachable)
+TEST_DECLARE (udp_multicast_join)
+TEST_DECLARE (udp_multicast_join6)
+TEST_DECLARE (udp_multicast_ttl)
+TEST_DECLARE (udp_multicast_interface)
+TEST_DECLARE (udp_multicast_interface6)
+TEST_DECLARE (udp_dgram_too_big)
+TEST_DECLARE (udp_dual_stack)
+TEST_DECLARE (udp_ipv6_only)
+TEST_DECLARE (udp_options)
+TEST_DECLARE (udp_options6)
+TEST_DECLARE (udp_no_autobind)
+TEST_DECLARE (udp_open)
+TEST_DECLARE (udp_open_twice)
+TEST_DECLARE (udp_try_send)
+TEST_DECLARE (pipe_bind_error_addrinuse)
+TEST_DECLARE (pipe_bind_error_addrnotavail)
+TEST_DECLARE (pipe_bind_error_inval)
+TEST_DECLARE (pipe_connect_multiple)
+TEST_DECLARE (pipe_listen_without_bind)
+TEST_DECLARE (pipe_connect_bad_name)
+TEST_DECLARE (pipe_connect_to_file)
+TEST_DECLARE (pipe_connect_on_prepare)
+TEST_DECLARE (pipe_getsockname)
+TEST_DECLARE (pipe_getsockname_abstract)
+TEST_DECLARE (pipe_getsockname_blocking)
+TEST_DECLARE (pipe_pending_instances)
+TEST_DECLARE (pipe_sendmsg)
+TEST_DECLARE (pipe_server_close)
+TEST_DECLARE (connection_fail)
+TEST_DECLARE (connection_fail_doesnt_auto_close)
+TEST_DECLARE (shutdown_close_tcp)
+TEST_DECLARE (shutdown_close_pipe)
+TEST_DECLARE (shutdown_eof)
+TEST_DECLARE (shutdown_twice)
+TEST_DECLARE (callback_stack)
+TEST_DECLARE (error_message)
+TEST_DECLARE (timer)
+TEST_DECLARE (timer_init)
+TEST_DECLARE (timer_again)
+TEST_DECLARE (timer_start_twice)
+TEST_DECLARE (timer_order)
+TEST_DECLARE (timer_huge_timeout)
+TEST_DECLARE (timer_huge_repeat)
+TEST_DECLARE (timer_run_once)
+TEST_DECLARE (timer_from_check)
+TEST_DECLARE (timer_null_callback)
+TEST_DECLARE (idle_starvation)
+TEST_DECLARE (loop_handles)
+TEST_DECLARE (get_loadavg)
+TEST_DECLARE (walk_handles)
+TEST_DECLARE (watcher_cross_stop)
+TEST_DECLARE (ref)
+TEST_DECLARE (idle_ref)
+TEST_DECLARE (async_ref)
+TEST_DECLARE (prepare_ref)
+TEST_DECLARE (check_ref)
+TEST_DECLARE (unref_in_prepare_cb)
+TEST_DECLARE (timer_ref)
+TEST_DECLARE (timer_ref2)
+TEST_DECLARE (fs_event_ref)
+TEST_DECLARE (fs_poll_ref)
+TEST_DECLARE (tcp_ref)
+TEST_DECLARE (tcp_ref2)
+TEST_DECLARE (tcp_ref2b)
+TEST_DECLARE (tcp_ref3)
+TEST_DECLARE (tcp_ref4)
+TEST_DECLARE (udp_ref)
+TEST_DECLARE (udp_ref2)
+TEST_DECLARE (udp_ref3)
+TEST_DECLARE (pipe_ref)
+TEST_DECLARE (pipe_ref2)
+TEST_DECLARE (pipe_ref3)
+TEST_DECLARE (pipe_ref4)
+#ifndef _WIN32
+TEST_DECLARE (pipe_close_stdout_read_stdin)
+#endif
+TEST_DECLARE (pipe_set_non_blocking)
+TEST_DECLARE (process_ref)
+TEST_DECLARE (has_ref)
+TEST_DECLARE (active)
+TEST_DECLARE (embed)
+TEST_DECLARE (async)
+TEST_DECLARE (async_null_cb)
+TEST_DECLARE (get_currentexe)
+TEST_DECLARE (process_title)
+TEST_DECLARE (cwd_and_chdir)
+TEST_DECLARE (get_memory)
+TEST_DECLARE (handle_fileno)
+TEST_DECLARE (homedir)
+TEST_DECLARE (hrtime)
+TEST_DECLARE (getaddrinfo_fail)
+TEST_DECLARE (getaddrinfo_fail_sync)
+TEST_DECLARE (getaddrinfo_basic)
+TEST_DECLARE (getaddrinfo_basic_sync)
+TEST_DECLARE (getaddrinfo_concurrent)
+TEST_DECLARE (getnameinfo_basic_ip4)
+TEST_DECLARE (getnameinfo_basic_ip4_sync)
+TEST_DECLARE (getnameinfo_basic_ip6)
+TEST_DECLARE (getsockname_tcp)
+TEST_DECLARE (getsockname_udp)
+TEST_DECLARE (fail_always)
+TEST_DECLARE (pass_always)
+TEST_DECLARE (socket_buffer_size)
+TEST_DECLARE (spawn_fails)
+#ifndef _WIN32
+TEST_DECLARE (spawn_fails_check_for_waitpid_cleanup)
+#endif
+TEST_DECLARE (spawn_exit_code)
+TEST_DECLARE (spawn_stdout)
+TEST_DECLARE (spawn_stdin)
+TEST_DECLARE (spawn_stdio_greater_than_3)
+TEST_DECLARE (spawn_ignored_stdio)
+TEST_DECLARE (spawn_and_kill)
+TEST_DECLARE (spawn_detached)
+TEST_DECLARE (spawn_and_kill_with_std)
+TEST_DECLARE (spawn_and_ping)
+TEST_DECLARE (spawn_preserve_env)
+TEST_DECLARE (spawn_setuid_fails)
+TEST_DECLARE (spawn_setgid_fails)
+TEST_DECLARE (spawn_stdout_to_file)
+TEST_DECLARE (spawn_stdout_and_stderr_to_file)
+TEST_DECLARE (spawn_stdout_and_stderr_to_file2)
+TEST_DECLARE (spawn_stdout_and_stderr_to_file_swap)
+TEST_DECLARE (spawn_auto_unref)
+TEST_DECLARE (spawn_closed_process_io)
+TEST_DECLARE (spawn_reads_child_path)
+TEST_DECLARE (spawn_inherit_streams)
+TEST_DECLARE (fs_poll)
+TEST_DECLARE (fs_poll_getpath)
+TEST_DECLARE (kill)
+TEST_DECLARE (fs_file_noent)
+TEST_DECLARE (fs_file_nametoolong)
+TEST_DECLARE (fs_file_loop)
+TEST_DECLARE (fs_file_async)
+TEST_DECLARE (fs_file_sync)
+TEST_DECLARE (fs_file_write_null_buffer)
+TEST_DECLARE (fs_async_dir)
+TEST_DECLARE (fs_async_sendfile)
+TEST_DECLARE (fs_mkdtemp)
+TEST_DECLARE (fs_fstat)
+TEST_DECLARE (fs_access)
+TEST_DECLARE (fs_chmod)
+TEST_DECLARE (fs_unlink_readonly)
+TEST_DECLARE (fs_chown)
+TEST_DECLARE (fs_link)
+TEST_DECLARE (fs_readlink)
+TEST_DECLARE (fs_realpath)
+TEST_DECLARE (fs_symlink)
+TEST_DECLARE (fs_symlink_dir)
+TEST_DECLARE (fs_utime)
+TEST_DECLARE (fs_futime)
+TEST_DECLARE (fs_file_open_append)
+TEST_DECLARE (fs_stat_missing_path)
+TEST_DECLARE (fs_read_file_eof)
+TEST_DECLARE (fs_event_watch_dir)
+TEST_DECLARE (fs_event_watch_dir_recursive)
+TEST_DECLARE (fs_event_watch_file)
+TEST_DECLARE (fs_event_watch_file_twice)
+TEST_DECLARE (fs_event_watch_file_current_dir)
+TEST_DECLARE (fs_event_no_callback_after_close)
+TEST_DECLARE (fs_event_no_callback_on_close)
+TEST_DECLARE (fs_event_immediate_close)
+TEST_DECLARE (fs_event_close_with_pending_event)
+TEST_DECLARE (fs_event_close_in_callback)
+TEST_DECLARE (fs_event_start_and_close)
+TEST_DECLARE (fs_event_error_reporting)
+TEST_DECLARE (fs_event_getpath)
+TEST_DECLARE (fs_scandir_empty_dir)
+TEST_DECLARE (fs_scandir_file)
+TEST_DECLARE (fs_open_dir)
+TEST_DECLARE (fs_rename_to_existing_file)
+TEST_DECLARE (fs_write_multiple_bufs)
+TEST_DECLARE (fs_read_write_null_arguments)
+TEST_DECLARE (fs_write_alotof_bufs)
+TEST_DECLARE (fs_write_alotof_bufs_with_offset)
+TEST_DECLARE (threadpool_queue_work_simple)
+TEST_DECLARE (threadpool_queue_work_einval)
+TEST_DECLARE (threadpool_multiple_event_loops)
+TEST_DECLARE (threadpool_cancel_getaddrinfo)
+TEST_DECLARE (threadpool_cancel_getnameinfo)
+TEST_DECLARE (threadpool_cancel_work)
+TEST_DECLARE (threadpool_cancel_fs)
+TEST_DECLARE (threadpool_cancel_single)
+TEST_DECLARE (thread_local_storage)
+TEST_DECLARE (thread_mutex)
+TEST_DECLARE (thread_rwlock)
+TEST_DECLARE (thread_rwlock_trylock)
+TEST_DECLARE (thread_create)
+TEST_DECLARE (thread_equal)
+TEST_DECLARE (dlerror)
+TEST_DECLARE (poll_duplex)
+TEST_DECLARE (poll_unidirectional)
+TEST_DECLARE (poll_close)
+
+TEST_DECLARE (ip4_addr)
+TEST_DECLARE (ip6_addr_link_local)
+
+#ifdef _WIN32
+TEST_DECLARE (poll_close_doesnt_corrupt_stack)
+TEST_DECLARE (poll_closesocket)
+TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows)
+#if !defined(USING_UV_SHARED)
+TEST_DECLARE (argument_escaping)
+TEST_DECLARE (environment_creation)
+#endif
+TEST_DECLARE (listen_with_simultaneous_accepts)
+TEST_DECLARE (listen_no_simultaneous_accepts)
+TEST_DECLARE (fs_stat_root)
+TEST_DECLARE (spawn_with_an_odd_path)
+TEST_DECLARE (ipc_listen_after_bind_twice)
+#else
+TEST_DECLARE (emfile)
+TEST_DECLARE (close_fd)
+TEST_DECLARE (spawn_fs_open)
+TEST_DECLARE (spawn_setuid_setgid)
+TEST_DECLARE (we_get_signal)
+TEST_DECLARE (we_get_signals)
+TEST_DECLARE (signal_multiple_loops)
+TEST_DECLARE (closed_fd_events)
+#endif
+#ifdef __APPLE__
+TEST_DECLARE (osx_select)
+TEST_DECLARE (osx_select_many_fds)
+#endif
+HELPER_DECLARE (tcp4_echo_server)
+HELPER_DECLARE (tcp6_echo_server)
+HELPER_DECLARE (udp4_echo_server)
+HELPER_DECLARE (pipe_echo_server)
+
+TEST_DECLARE (queue_foreach_delete)
+
+TASK_LIST_START
+ TEST_ENTRY_CUSTOM (platform_output, 0, 1, 5000)
+
+#if 0
+ TEST_ENTRY (callback_order)
+#endif
+ TEST_ENTRY (close_order)
+ TEST_ENTRY (run_once)
+ TEST_ENTRY (run_nowait)
+ TEST_ENTRY (loop_alive)
+ TEST_ENTRY (loop_close)
+ TEST_ENTRY (loop_stop)
+ TEST_ENTRY (loop_update_time)
+ TEST_ENTRY (loop_backend_timeout)
+ TEST_ENTRY (loop_configure)
+ TEST_ENTRY (default_loop_close)
+ TEST_ENTRY (barrier_1)
+ TEST_ENTRY (barrier_2)
+ TEST_ENTRY (barrier_3)
+ TEST_ENTRY (condvar_1)
+ TEST_ENTRY (condvar_2)
+ TEST_ENTRY (condvar_3)
+ TEST_ENTRY (condvar_4)
+ TEST_ENTRY (condvar_5)
+ TEST_ENTRY (semaphore_1)
+ TEST_ENTRY (semaphore_2)
+ TEST_ENTRY (semaphore_3)
+
+ TEST_ENTRY (pipe_connect_bad_name)
+ TEST_ENTRY (pipe_connect_to_file)
+ TEST_ENTRY (pipe_connect_on_prepare)
+
+ TEST_ENTRY (pipe_server_close)
+#ifndef _WIN32
+ TEST_ENTRY (pipe_close_stdout_read_stdin)
+#endif
+ TEST_ENTRY (pipe_set_non_blocking)
+ TEST_ENTRY (tty)
+ TEST_ENTRY (tty_file)
+ TEST_ENTRY (stdio_over_pipes)
+ TEST_ENTRY (ip6_pton)
+ TEST_ENTRY (ipc_listen_before_write)
+ TEST_ENTRY (ipc_listen_after_write)
+#ifndef _WIN32
+ TEST_ENTRY (ipc_send_recv_pipe)
+ TEST_ENTRY (ipc_send_recv_pipe_inprocess)
+#endif
+ TEST_ENTRY (ipc_send_recv_tcp)
+ TEST_ENTRY (ipc_send_recv_tcp_inprocess)
+ TEST_ENTRY (ipc_tcp_connection)
+
+ TEST_ENTRY (tcp_ping_pong)
+ TEST_HELPER (tcp_ping_pong, tcp4_echo_server)
+
+ TEST_ENTRY (tcp_ping_pong_v6)
+ TEST_HELPER (tcp_ping_pong_v6, tcp6_echo_server)
+
+ TEST_ENTRY (pipe_ping_pong)
+ TEST_HELPER (pipe_ping_pong, pipe_echo_server)
+
+ TEST_ENTRY (delayed_accept)
+ TEST_ENTRY (multiple_listen)
+
+#ifndef _WIN32
+ TEST_ENTRY (tcp_write_after_connect)
+#endif
+
+ TEST_ENTRY (tcp_writealot)
+ TEST_HELPER (tcp_writealot, tcp4_echo_server)
+
+ TEST_ENTRY (tcp_write_fail)
+ TEST_HELPER (tcp_write_fail, tcp4_echo_server)
+
+ TEST_ENTRY (tcp_try_write)
+
+ TEST_ENTRY (tcp_write_queue_order)
+
+ TEST_ENTRY (tcp_open)
+ TEST_HELPER (tcp_open, tcp4_echo_server)
+ TEST_ENTRY (tcp_open_twice)
+
+ TEST_ENTRY (tcp_shutdown_after_write)
+ TEST_HELPER (tcp_shutdown_after_write, tcp4_echo_server)
+
+ TEST_ENTRY (tcp_connect_error_after_write)
+ TEST_ENTRY (tcp_bind_error_addrinuse)
+ TEST_ENTRY (tcp_bind_error_addrnotavail_1)
+ TEST_ENTRY (tcp_bind_error_addrnotavail_2)
+ TEST_ENTRY (tcp_bind_error_fault)
+ TEST_ENTRY (tcp_bind_error_inval)
+ TEST_ENTRY (tcp_bind_localhost_ok)
+ TEST_ENTRY (tcp_bind_invalid_flags)
+ TEST_ENTRY (tcp_listen_without_bind)
+ TEST_ENTRY (tcp_connect_error_fault)
+ TEST_ENTRY (tcp_connect_timeout)
+ TEST_ENTRY (tcp_close_while_connecting)
+ TEST_ENTRY (tcp_close)
+ TEST_ENTRY (tcp_create_early)
+ TEST_ENTRY (tcp_create_early_bad_bind)
+ TEST_ENTRY (tcp_create_early_bad_domain)
+ TEST_ENTRY (tcp_create_early_accept)
+#ifndef _WIN32
+ TEST_ENTRY (tcp_close_accept)
+ TEST_ENTRY (tcp_oob)
+#endif
+ TEST_ENTRY (tcp_flags)
+ TEST_ENTRY (tcp_write_to_half_open_connection)
+ TEST_ENTRY (tcp_unexpected_read)
+
+ TEST_ENTRY (tcp_read_stop)
+ TEST_HELPER (tcp_read_stop, tcp4_echo_server)
+
+ TEST_ENTRY (tcp_bind6_error_addrinuse)
+ TEST_ENTRY (tcp_bind6_error_addrnotavail)
+ TEST_ENTRY (tcp_bind6_error_fault)
+ TEST_ENTRY (tcp_bind6_error_inval)
+ TEST_ENTRY (tcp_bind6_localhost_ok)
+
+ TEST_ENTRY (udp_bind)
+ TEST_ENTRY (udp_bind_reuseaddr)
+ TEST_ENTRY (udp_create_early)
+ TEST_ENTRY (udp_create_early_bad_bind)
+ TEST_ENTRY (udp_create_early_bad_domain)
+ TEST_ENTRY (udp_send_and_recv)
+ TEST_ENTRY (udp_send_immediate)
+ TEST_ENTRY (udp_send_unreachable)
+ TEST_ENTRY (udp_dgram_too_big)
+ TEST_ENTRY (udp_dual_stack)
+ TEST_ENTRY (udp_ipv6_only)
+ TEST_ENTRY (udp_options)
+ TEST_ENTRY (udp_options6)
+ TEST_ENTRY (udp_no_autobind)
+ TEST_ENTRY (udp_multicast_interface)
+ TEST_ENTRY (udp_multicast_interface6)
+ TEST_ENTRY (udp_multicast_join)
+ TEST_ENTRY (udp_multicast_join6)
+ TEST_ENTRY (udp_multicast_ttl)
+ TEST_ENTRY (udp_try_send)
+
+ TEST_ENTRY (udp_open)
+ TEST_HELPER (udp_open, udp4_echo_server)
+ TEST_ENTRY (udp_open_twice)
+
+ TEST_ENTRY (pipe_bind_error_addrinuse)
+ TEST_ENTRY (pipe_bind_error_addrnotavail)
+ TEST_ENTRY (pipe_bind_error_inval)
+ TEST_ENTRY (pipe_connect_multiple)
+ TEST_ENTRY (pipe_listen_without_bind)
+ TEST_ENTRY (pipe_getsockname)
+ TEST_ENTRY (pipe_getsockname_abstract)
+ TEST_ENTRY (pipe_getsockname_blocking)
+ TEST_ENTRY (pipe_pending_instances)
+ TEST_ENTRY (pipe_sendmsg)
+
+ TEST_ENTRY (connection_fail)
+ TEST_ENTRY (connection_fail_doesnt_auto_close)
+
+ TEST_ENTRY (shutdown_close_tcp)
+ TEST_HELPER (shutdown_close_tcp, tcp4_echo_server)
+ TEST_ENTRY (shutdown_close_pipe)
+ TEST_HELPER (shutdown_close_pipe, pipe_echo_server)
+
+ TEST_ENTRY (shutdown_eof)
+ TEST_HELPER (shutdown_eof, tcp4_echo_server)
+
+ TEST_ENTRY (shutdown_twice)
+ TEST_HELPER (shutdown_twice, tcp4_echo_server)
+
+ TEST_ENTRY (callback_stack)
+ TEST_HELPER (callback_stack, tcp4_echo_server)
+
+ TEST_ENTRY (error_message)
+
+ TEST_ENTRY (timer)
+ TEST_ENTRY (timer_init)
+ TEST_ENTRY (timer_again)
+ TEST_ENTRY (timer_start_twice)
+ TEST_ENTRY (timer_order)
+ TEST_ENTRY (timer_huge_timeout)
+ TEST_ENTRY (timer_huge_repeat)
+ TEST_ENTRY (timer_run_once)
+ TEST_ENTRY (timer_from_check)
+ TEST_ENTRY (timer_null_callback)
+
+ TEST_ENTRY (idle_starvation)
+
+ TEST_ENTRY (ref)
+ TEST_ENTRY (idle_ref)
+ TEST_ENTRY (fs_poll_ref)
+ TEST_ENTRY (async_ref)
+ TEST_ENTRY (prepare_ref)
+ TEST_ENTRY (check_ref)
+ TEST_ENTRY (unref_in_prepare_cb)
+ TEST_ENTRY (timer_ref)
+ TEST_ENTRY (timer_ref2)
+ TEST_ENTRY (fs_event_ref)
+ TEST_ENTRY (tcp_ref)
+ TEST_ENTRY (tcp_ref2)
+ TEST_ENTRY (tcp_ref2b)
+ TEST_ENTRY (tcp_ref3)
+ TEST_HELPER (tcp_ref3, tcp4_echo_server)
+ TEST_ENTRY (tcp_ref4)
+ TEST_HELPER (tcp_ref4, tcp4_echo_server)
+ TEST_ENTRY (udp_ref)
+ TEST_ENTRY (udp_ref2)
+ TEST_ENTRY (udp_ref3)
+ TEST_HELPER (udp_ref3, udp4_echo_server)
+ TEST_ENTRY (pipe_ref)
+ TEST_ENTRY (pipe_ref2)
+ TEST_ENTRY (pipe_ref3)
+ TEST_HELPER (pipe_ref3, pipe_echo_server)
+ TEST_ENTRY (pipe_ref4)
+ TEST_HELPER (pipe_ref4, pipe_echo_server)
+ TEST_ENTRY (process_ref)
+ TEST_ENTRY (has_ref)
+
+ TEST_ENTRY (loop_handles)
+ TEST_ENTRY (walk_handles)
+
+ TEST_ENTRY (watcher_cross_stop)
+
+ TEST_ENTRY (active)
+
+ TEST_ENTRY (embed)
+
+ TEST_ENTRY (async)
+ TEST_ENTRY (async_null_cb)
+
+ TEST_ENTRY (get_currentexe)
+
+ TEST_ENTRY (process_title)
+
+ TEST_ENTRY (cwd_and_chdir)
+
+ TEST_ENTRY (get_memory)
+
+ TEST_ENTRY (get_loadavg)
+
+ TEST_ENTRY (handle_fileno)
+
+ TEST_ENTRY (homedir)
+
+ TEST_ENTRY (hrtime)
+
+ TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000)
+ TEST_ENTRY (getaddrinfo_fail_sync)
+
+ TEST_ENTRY (getaddrinfo_basic)
+ TEST_ENTRY (getaddrinfo_basic_sync)
+ TEST_ENTRY (getaddrinfo_concurrent)
+
+ TEST_ENTRY (getnameinfo_basic_ip4)
+ TEST_ENTRY (getnameinfo_basic_ip4_sync)
+ TEST_ENTRY (getnameinfo_basic_ip6)
+
+ TEST_ENTRY (getsockname_tcp)
+ TEST_ENTRY (getsockname_udp)
+
+ TEST_ENTRY (poll_duplex)
+ TEST_ENTRY (poll_unidirectional)
+ TEST_ENTRY (poll_close)
+
+ TEST_ENTRY (socket_buffer_size)
+
+ TEST_ENTRY (spawn_fails)
+#ifndef _WIN32
+ TEST_ENTRY (spawn_fails_check_for_waitpid_cleanup)
+#endif
+ TEST_ENTRY (spawn_exit_code)
+ TEST_ENTRY (spawn_stdout)
+ TEST_ENTRY (spawn_stdin)
+ TEST_ENTRY (spawn_stdio_greater_than_3)
+ TEST_ENTRY (spawn_ignored_stdio)
+ TEST_ENTRY (spawn_and_kill)
+ TEST_ENTRY (spawn_detached)
+ TEST_ENTRY (spawn_and_kill_with_std)
+ TEST_ENTRY (spawn_and_ping)
+ TEST_ENTRY (spawn_preserve_env)
+ TEST_ENTRY (spawn_setuid_fails)
+ TEST_ENTRY (spawn_setgid_fails)
+ TEST_ENTRY (spawn_stdout_to_file)
+ TEST_ENTRY (spawn_stdout_and_stderr_to_file)
+ TEST_ENTRY (spawn_stdout_and_stderr_to_file2)
+ TEST_ENTRY (spawn_stdout_and_stderr_to_file_swap)
+ TEST_ENTRY (spawn_auto_unref)
+ TEST_ENTRY (spawn_closed_process_io)
+ TEST_ENTRY (spawn_reads_child_path)
+ TEST_ENTRY (spawn_inherit_streams)
+ TEST_ENTRY (fs_poll)
+ TEST_ENTRY (fs_poll_getpath)
+ TEST_ENTRY (kill)
+
+#ifdef _WIN32
+ TEST_ENTRY (poll_close_doesnt_corrupt_stack)
+ TEST_ENTRY (poll_closesocket)
+ TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows)
+#if !defined(USING_UV_SHARED)
+ TEST_ENTRY (argument_escaping)
+ TEST_ENTRY (environment_creation)
+# endif
+ TEST_ENTRY (listen_with_simultaneous_accepts)
+ TEST_ENTRY (listen_no_simultaneous_accepts)
+ TEST_ENTRY (fs_stat_root)
+ TEST_ENTRY (spawn_with_an_odd_path)
+ TEST_ENTRY (ipc_listen_after_bind_twice)
+#else
+ TEST_ENTRY (emfile)
+ TEST_ENTRY (close_fd)
+ TEST_ENTRY (spawn_fs_open)
+ TEST_ENTRY (spawn_setuid_setgid)
+ TEST_ENTRY (we_get_signal)
+ TEST_ENTRY (we_get_signals)
+ TEST_ENTRY (signal_multiple_loops)
+ TEST_ENTRY (closed_fd_events)
+#endif
+
+#ifdef __APPLE__
+ TEST_ENTRY (osx_select)
+ TEST_ENTRY (osx_select_many_fds)
+#endif
+
+ TEST_ENTRY (fs_file_noent)
+ TEST_ENTRY (fs_file_nametoolong)
+ TEST_ENTRY (fs_file_loop)
+ TEST_ENTRY (fs_file_async)
+ TEST_ENTRY (fs_file_sync)
+ TEST_ENTRY (fs_file_write_null_buffer)
+ TEST_ENTRY (fs_async_dir)
+ TEST_ENTRY (fs_async_sendfile)
+ TEST_ENTRY (fs_mkdtemp)
+ TEST_ENTRY (fs_fstat)
+ TEST_ENTRY (fs_access)
+ TEST_ENTRY (fs_chmod)
+ TEST_ENTRY (fs_unlink_readonly)
+ TEST_ENTRY (fs_chown)
+ TEST_ENTRY (fs_utime)
+ TEST_ENTRY (fs_futime)
+ TEST_ENTRY (fs_readlink)
+ TEST_ENTRY (fs_realpath)
+ TEST_ENTRY (fs_symlink)
+ TEST_ENTRY (fs_symlink_dir)
+ TEST_ENTRY (fs_stat_missing_path)
+ TEST_ENTRY (fs_read_file_eof)
+ TEST_ENTRY (fs_file_open_append)
+ TEST_ENTRY (fs_event_watch_dir)
+ TEST_ENTRY (fs_event_watch_dir_recursive)
+ TEST_ENTRY (fs_event_watch_file)
+ TEST_ENTRY (fs_event_watch_file_twice)
+ TEST_ENTRY (fs_event_watch_file_current_dir)
+ TEST_ENTRY (fs_event_no_callback_after_close)
+ TEST_ENTRY (fs_event_no_callback_on_close)
+ TEST_ENTRY (fs_event_immediate_close)
+ TEST_ENTRY (fs_event_close_with_pending_event)
+ TEST_ENTRY (fs_event_close_in_callback)
+ TEST_ENTRY (fs_event_start_and_close)
+ TEST_ENTRY (fs_event_error_reporting)
+ TEST_ENTRY (fs_event_getpath)
+ TEST_ENTRY (fs_scandir_empty_dir)
+ TEST_ENTRY (fs_scandir_file)
+ TEST_ENTRY (fs_open_dir)
+ TEST_ENTRY (fs_rename_to_existing_file)
+ TEST_ENTRY (fs_write_multiple_bufs)
+ TEST_ENTRY (fs_write_alotof_bufs)
+ TEST_ENTRY (fs_write_alotof_bufs_with_offset)
+ TEST_ENTRY (fs_read_write_null_arguments)
+ TEST_ENTRY (threadpool_queue_work_simple)
+ TEST_ENTRY (threadpool_queue_work_einval)
+ TEST_ENTRY (threadpool_multiple_event_loops)
+ TEST_ENTRY (threadpool_cancel_getaddrinfo)
+ TEST_ENTRY (threadpool_cancel_getnameinfo)
+ TEST_ENTRY (threadpool_cancel_work)
+ TEST_ENTRY (threadpool_cancel_fs)
+ TEST_ENTRY (threadpool_cancel_single)
+ TEST_ENTRY (thread_local_storage)
+ TEST_ENTRY (thread_mutex)
+ TEST_ENTRY (thread_rwlock)
+ TEST_ENTRY (thread_rwlock_trylock)
+ TEST_ENTRY (thread_create)
+ TEST_ENTRY (thread_equal)
+ TEST_ENTRY (dlerror)
+ TEST_ENTRY (ip4_addr)
+ TEST_ENTRY (ip6_addr_link_local)
+
+ TEST_ENTRY (queue_foreach_delete)
+
+#if 0
+ /* These are for testing the test runner. */
+ TEST_ENTRY (fail_always)
+ TEST_ENTRY (pass_always)
+#endif
+TASK_LIST_END
diff --git a/3rdparty/libuv/test/test-loop-alive.c b/3rdparty/libuv/test/test-loop-alive.c
new file mode 100644
index 00000000000..cf4d301930c
--- /dev/null
+++ b/3rdparty/libuv/test/test-loop-alive.c
@@ -0,0 +1,67 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_timer_t timer_handle;
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(handle);
+}
+
+
+static uv_work_t work_req;
+
+static void work_cb(uv_work_t* req) {
+ ASSERT(req);
+}
+
+static void after_work_cb(uv_work_t* req, int status) {
+ ASSERT(req);
+ ASSERT(status == 0);
+}
+
+
+TEST_IMPL(loop_alive) {
+ int r;
+ ASSERT(!uv_loop_alive(uv_default_loop()));
+
+ /* loops with handles are alive */
+ uv_timer_init(uv_default_loop(), &timer_handle);
+ uv_timer_start(&timer_handle, timer_cb, 100, 0);
+ ASSERT(uv_loop_alive(uv_default_loop()));
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+ ASSERT(!uv_loop_alive(uv_default_loop()));
+
+ /* loops with requests are alive */
+ r = uv_queue_work(uv_default_loop(), &work_req, work_cb, after_work_cb);
+ ASSERT(r == 0);
+ ASSERT(uv_loop_alive(uv_default_loop()));
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+ ASSERT(!uv_loop_alive(uv_default_loop()));
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-loop-close.c b/3rdparty/libuv/test/test-loop-close.c
new file mode 100644
index 00000000000..5aec234ed03
--- /dev/null
+++ b/3rdparty/libuv/test/test-loop-close.c
@@ -0,0 +1,53 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_timer_t timer_handle;
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(handle);
+ uv_stop(handle->loop);
+}
+
+
+TEST_IMPL(loop_close) {
+ int r;
+ uv_loop_t loop;
+
+ ASSERT(0 == uv_loop_init(&loop));
+
+ uv_timer_init(&loop, &timer_handle);
+ uv_timer_start(&timer_handle, timer_cb, 100, 100);
+
+ ASSERT(UV_EBUSY == uv_loop_close(&loop));
+
+ uv_run(&loop, UV_RUN_DEFAULT);
+
+ uv_close((uv_handle_t*) &timer_handle, NULL);
+ r = uv_run(&loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_loop_close(&loop));
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-loop-configure.c b/3rdparty/libuv/test/test-loop-configure.c
new file mode 100644
index 00000000000..d057c1ed8a7
--- /dev/null
+++ b/3rdparty/libuv/test/test-loop-configure.c
@@ -0,0 +1,38 @@
+/* Copyright (c) 2014, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static void timer_cb(uv_timer_t* handle) {
+ uv_close((uv_handle_t*) handle, NULL);
+}
+
+
+TEST_IMPL(loop_configure) {
+ uv_timer_t timer_handle;
+ uv_loop_t loop;
+ ASSERT(0 == uv_loop_init(&loop));
+#ifdef _WIN32
+ ASSERT(UV_ENOSYS == uv_loop_configure(&loop, UV_LOOP_BLOCK_SIGNAL, 0));
+#else
+ ASSERT(0 == uv_loop_configure(&loop, UV_LOOP_BLOCK_SIGNAL, SIGPROF));
+#endif
+ ASSERT(0 == uv_timer_init(&loop, &timer_handle));
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 10, 0));
+ ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT));
+ ASSERT(0 == uv_loop_close(&loop));
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-loop-handles.c b/3rdparty/libuv/test/test-loop-handles.c
new file mode 100644
index 00000000000..c3e8498ae90
--- /dev/null
+++ b/3rdparty/libuv/test/test-loop-handles.c
@@ -0,0 +1,337 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* Tests commented out with XXX are ones that are failing on Linux */
+
+/*
+ * Purpose of this test is to check semantics of starting and stopping
+ * prepare, check and idle watchers.
+ *
+ * - A watcher must be able to safely stop or close itself;
+ * - Once a watcher is stopped or closed its callback should never be called.
+ * - If a watcher is closed, it is implicitly stopped and its close_cb should
+ * be called exactly once.
+ * - A watcher can safely start and stop other watchers of the same type.
+ * - Prepare and check watchers are called once per event loop iterations.
+ * - All active idle watchers are queued when the event loop has no more work
+ * to do. This is done repeatedly until all idle watchers are inactive.
+ * - If a watcher starts another watcher of the same type its callback is not
+ * immediately queued. For check and prepare watchers, that means that if
+ * a watcher makes another of the same type active, it'll not be called until
+ * the next event loop iteration. For idle. watchers this means that the
+ * newly activated idle watcher might not be queued immediately.
+ * - Prepare, check, idle watchers keep the event loop alive even when they're
+ * not active.
+ *
+ * This is what the test globally does:
+ *
+ * - prepare_1 is always active and counts event loop iterations. It also
+ * creates and starts prepare_2 every other iteration. Finally it verifies
+ * that no idle watchers are active before polling.
+ * - prepare_2 is started by prepare_1 every other iteration. It immediately
+ * stops itself. It verifies that a watcher is not queued immediately
+ * if created by another watcher of the same type.
+ * - There's a check watcher that stops the event loop after a certain number
+ * of iterations. It starts a varying number of idle_1 watchers.
+ * - Idle_1 watchers stop themselves after being called a few times. All idle_1
+ * watchers try to start the idle_2 watcher if it is not already started or
+ * awaiting its close callback.
+ * - The idle_2 watcher always exists but immediately closes itself after
+ * being started by a check_1 watcher. It verifies that a watcher is
+ * implicitly stopped when closed, and that a watcher can close itself
+ * safely.
+ * - There is a repeating timer. It does not keep the event loop alive
+ * (ev_unref) but makes sure that the loop keeps polling the system for
+ * events.
+ */
+
+
+#include "uv.h"
+#include "task.h"
+
+#include <math.h>
+
+
+#define IDLE_COUNT 7
+#define ITERATIONS 21
+#define TIMEOUT 100
+
+
+static uv_prepare_t prepare_1_handle;
+static uv_prepare_t prepare_2_handle;
+
+static uv_check_t check_handle;
+
+static uv_idle_t idle_1_handles[IDLE_COUNT];
+static uv_idle_t idle_2_handle;
+
+static uv_timer_t timer_handle;
+
+
+static int loop_iteration = 0;
+
+static int prepare_1_cb_called = 0;
+static int prepare_1_close_cb_called = 0;
+
+static int prepare_2_cb_called = 0;
+static int prepare_2_close_cb_called = 0;
+
+static int check_cb_called = 0;
+static int check_close_cb_called = 0;
+
+static int idle_1_cb_called = 0;
+static int idle_1_close_cb_called = 0;
+static int idles_1_active = 0;
+
+static int idle_2_cb_called = 0;
+static int idle_2_close_cb_called = 0;
+static int idle_2_cb_started = 0;
+static int idle_2_is_active = 0;
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(handle == &timer_handle);
+}
+
+
+static void idle_2_close_cb(uv_handle_t* handle) {
+ fprintf(stderr, "%s", "IDLE_2_CLOSE_CB\n");
+ fflush(stderr);
+
+ ASSERT(handle == (uv_handle_t*)&idle_2_handle);
+
+ ASSERT(idle_2_is_active);
+
+ idle_2_close_cb_called++;
+ idle_2_is_active = 0;
+}
+
+
+static void idle_2_cb(uv_idle_t* handle) {
+ fprintf(stderr, "%s", "IDLE_2_CB\n");
+ fflush(stderr);
+
+ ASSERT(handle == &idle_2_handle);
+
+ idle_2_cb_called++;
+
+ uv_close((uv_handle_t*)handle, idle_2_close_cb);
+}
+
+
+static void idle_1_cb(uv_idle_t* handle) {
+ int r;
+
+ fprintf(stderr, "%s", "IDLE_1_CB\n");
+ fflush(stderr);
+
+ ASSERT(handle != NULL);
+ ASSERT(idles_1_active > 0);
+
+ /* Init idle_2 and make it active */
+ if (!idle_2_is_active && !uv_is_closing((uv_handle_t*)&idle_2_handle)) {
+ r = uv_idle_init(uv_default_loop(), &idle_2_handle);
+ ASSERT(r == 0);
+ r = uv_idle_start(&idle_2_handle, idle_2_cb);
+ ASSERT(r == 0);
+ idle_2_is_active = 1;
+ idle_2_cb_started++;
+ }
+
+ idle_1_cb_called++;
+
+ if (idle_1_cb_called % 5 == 0) {
+ r = uv_idle_stop((uv_idle_t*)handle);
+ ASSERT(r == 0);
+ idles_1_active--;
+ }
+}
+
+
+static void idle_1_close_cb(uv_handle_t* handle) {
+ fprintf(stderr, "%s", "IDLE_1_CLOSE_CB\n");
+ fflush(stderr);
+
+ ASSERT(handle != NULL);
+
+ idle_1_close_cb_called++;
+}
+
+
+static void prepare_1_close_cb(uv_handle_t* handle) {
+ fprintf(stderr, "%s", "PREPARE_1_CLOSE_CB");
+ fflush(stderr);
+ ASSERT(handle == (uv_handle_t*)&prepare_1_handle);
+
+ prepare_1_close_cb_called++;
+}
+
+
+static void check_close_cb(uv_handle_t* handle) {
+ fprintf(stderr, "%s", "CHECK_CLOSE_CB\n");
+ fflush(stderr);
+ ASSERT(handle == (uv_handle_t*)&check_handle);
+
+ check_close_cb_called++;
+}
+
+
+static void prepare_2_close_cb(uv_handle_t* handle) {
+ fprintf(stderr, "%s", "PREPARE_2_CLOSE_CB\n");
+ fflush(stderr);
+ ASSERT(handle == (uv_handle_t*)&prepare_2_handle);
+
+ prepare_2_close_cb_called++;
+}
+
+
+static void check_cb(uv_check_t* handle) {
+ int i, r;
+
+ fprintf(stderr, "%s", "CHECK_CB\n");
+ fflush(stderr);
+ ASSERT(handle == &check_handle);
+
+ if (loop_iteration < ITERATIONS) {
+ /* Make some idle watchers active */
+ for (i = 0; i < 1 + (loop_iteration % IDLE_COUNT); i++) {
+ r = uv_idle_start(&idle_1_handles[i], idle_1_cb);
+ ASSERT(r == 0);
+ idles_1_active++;
+ }
+
+ } else {
+ /* End of the test - close all handles */
+ uv_close((uv_handle_t*)&prepare_1_handle, prepare_1_close_cb);
+ uv_close((uv_handle_t*)&check_handle, check_close_cb);
+ uv_close((uv_handle_t*)&prepare_2_handle, prepare_2_close_cb);
+
+ for (i = 0; i < IDLE_COUNT; i++) {
+ uv_close((uv_handle_t*)&idle_1_handles[i], idle_1_close_cb);
+ }
+
+ /* This handle is closed/recreated every time, close it only if it is */
+ /* active.*/
+ if (idle_2_is_active) {
+ uv_close((uv_handle_t*)&idle_2_handle, idle_2_close_cb);
+ }
+ }
+
+ check_cb_called++;
+}
+
+
+static void prepare_2_cb(uv_prepare_t* handle) {
+ int r;
+
+ fprintf(stderr, "%s", "PREPARE_2_CB\n");
+ fflush(stderr);
+ ASSERT(handle == &prepare_2_handle);
+
+ /* prepare_2 gets started by prepare_1 when (loop_iteration % 2 == 0), */
+ /* and it stops itself immediately. A started watcher is not queued */
+ /* until the next round, so when this callback is made */
+ /* (loop_iteration % 2 == 0) cannot be true. */
+ ASSERT(loop_iteration % 2 != 0);
+
+ r = uv_prepare_stop((uv_prepare_t*)handle);
+ ASSERT(r == 0);
+
+ prepare_2_cb_called++;
+}
+
+
+static void prepare_1_cb(uv_prepare_t* handle) {
+ int r;
+
+ fprintf(stderr, "%s", "PREPARE_1_CB\n");
+ fflush(stderr);
+ ASSERT(handle == &prepare_1_handle);
+
+ if (loop_iteration % 2 == 0) {
+ r = uv_prepare_start(&prepare_2_handle, prepare_2_cb);
+ ASSERT(r == 0);
+ }
+
+ prepare_1_cb_called++;
+ loop_iteration++;
+
+ printf("Loop iteration %d of %d.\n", loop_iteration, ITERATIONS);
+}
+
+
+TEST_IMPL(loop_handles) {
+ int i;
+ int r;
+
+ r = uv_prepare_init(uv_default_loop(), &prepare_1_handle);
+ ASSERT(r == 0);
+ r = uv_prepare_start(&prepare_1_handle, prepare_1_cb);
+ ASSERT(r == 0);
+
+ r = uv_check_init(uv_default_loop(), &check_handle);
+ ASSERT(r == 0);
+ r = uv_check_start(&check_handle, check_cb);
+ ASSERT(r == 0);
+
+ /* initialize only, prepare_2 is started by prepare_1_cb */
+ r = uv_prepare_init(uv_default_loop(), &prepare_2_handle);
+ ASSERT(r == 0);
+
+ for (i = 0; i < IDLE_COUNT; i++) {
+ /* initialize only, idle_1 handles are started by check_cb */
+ r = uv_idle_init(uv_default_loop(), &idle_1_handles[i]);
+ ASSERT(r == 0);
+ }
+
+ /* don't init or start idle_2, both is done by idle_1_cb */
+
+ /* the timer callback is there to keep the event loop polling */
+ /* unref it as it is not supposed to keep the loop alive */
+ r = uv_timer_init(uv_default_loop(), &timer_handle);
+ ASSERT(r == 0);
+ r = uv_timer_start(&timer_handle, timer_cb, TIMEOUT, TIMEOUT);
+ ASSERT(r == 0);
+ uv_unref((uv_handle_t*)&timer_handle);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(loop_iteration == ITERATIONS);
+
+ ASSERT(prepare_1_cb_called == ITERATIONS);
+ ASSERT(prepare_1_close_cb_called == 1);
+
+ ASSERT(prepare_2_cb_called == floor(ITERATIONS / 2.0));
+ ASSERT(prepare_2_close_cb_called == 1);
+
+ ASSERT(check_cb_called == ITERATIONS);
+ ASSERT(check_close_cb_called == 1);
+
+ /* idle_1_cb should be called a lot */
+ ASSERT(idle_1_close_cb_called == IDLE_COUNT);
+
+ ASSERT(idle_2_close_cb_called == idle_2_cb_started);
+ ASSERT(idle_2_is_active == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-loop-stop.c b/3rdparty/libuv/test/test-loop-stop.c
new file mode 100644
index 00000000000..14b8c11186c
--- /dev/null
+++ b/3rdparty/libuv/test/test-loop-stop.c
@@ -0,0 +1,71 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_prepare_t prepare_handle;
+static uv_timer_t timer_handle;
+static int prepare_called = 0;
+static int timer_called = 0;
+static int num_ticks = 10;
+
+
+static void prepare_cb(uv_prepare_t* handle) {
+ ASSERT(handle == &prepare_handle);
+ prepare_called++;
+ if (prepare_called == num_ticks)
+ uv_prepare_stop(handle);
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(handle == &timer_handle);
+ timer_called++;
+ if (timer_called == 1)
+ uv_stop(uv_default_loop());
+ else if (timer_called == num_ticks)
+ uv_timer_stop(handle);
+}
+
+
+TEST_IMPL(loop_stop) {
+ int r;
+ uv_prepare_init(uv_default_loop(), &prepare_handle);
+ uv_prepare_start(&prepare_handle, prepare_cb);
+ uv_timer_init(uv_default_loop(), &timer_handle);
+ uv_timer_start(&timer_handle, timer_cb, 100, 100);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r != 0);
+ ASSERT(timer_called == 1);
+
+ r = uv_run(uv_default_loop(), UV_RUN_NOWAIT);
+ ASSERT(r != 0);
+ ASSERT(prepare_called > 1);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+ ASSERT(timer_called == 10);
+ ASSERT(prepare_called == 10);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-loop-time.c b/3rdparty/libuv/test/test-loop-time.c
new file mode 100644
index 00000000000..a2db42cceec
--- /dev/null
+++ b/3rdparty/libuv/test/test-loop-time.c
@@ -0,0 +1,63 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+TEST_IMPL(loop_update_time) {
+ uint64_t start;
+
+ start = uv_now(uv_default_loop());
+ while (uv_now(uv_default_loop()) - start < 1000)
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_NOWAIT));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+static void cb(uv_timer_t* timer) {
+ uv_close((uv_handle_t*)timer, NULL);
+}
+
+TEST_IMPL(loop_backend_timeout) {
+ uv_loop_t *loop = uv_default_loop();
+ uv_timer_t timer;
+ int r;
+
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r == 0);
+
+ ASSERT(!uv_loop_alive(loop));
+ ASSERT(uv_backend_timeout(loop) == 0);
+
+ r = uv_timer_start(&timer, cb, 1000, 0); /* 1 sec */
+ ASSERT(r == 0);
+ ASSERT(uv_backend_timeout(loop) > 100); /* 0.1 sec */
+ ASSERT(uv_backend_timeout(loop) <= 1000); /* 1 sec */
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+ ASSERT(uv_backend_timeout(loop) == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-multiple-listen.c b/3rdparty/libuv/test/test-multiple-listen.c
new file mode 100644
index 00000000000..4ae5fa67b3a
--- /dev/null
+++ b/3rdparty/libuv/test/test-multiple-listen.c
@@ -0,0 +1,109 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+static int connection_cb_called = 0;
+static int close_cb_called = 0;
+static int connect_cb_called = 0;
+static uv_tcp_t server;
+static uv_tcp_t client;
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void connection_cb(uv_stream_t* tcp, int status) {
+ ASSERT(status == 0);
+ uv_close((uv_handle_t*)&server, close_cb);
+ connection_cb_called++;
+}
+
+
+static void start_server(void) {
+ struct sockaddr_in addr;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&server, 128, connection_cb);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&server, 128, connection_cb);
+ ASSERT(r == 0);
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+ free(req);
+ uv_close((uv_handle_t*)&client, close_cb);
+ connect_cb_called++;
+}
+
+
+static void client_connect(void) {
+ struct sockaddr_in addr;
+ uv_connect_t* connect_req = malloc(sizeof *connect_req);
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ ASSERT(connect_req != NULL);
+
+ r = uv_tcp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(connect_req,
+ &client,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+}
+
+
+
+TEST_IMPL(multiple_listen) {
+ start_server();
+
+ client_connect();
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(connection_cb_called == 1);
+ ASSERT(connect_cb_called == 1);
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-mutexes.c b/3rdparty/libuv/test/test-mutexes.c
new file mode 100644
index 00000000000..af5e4e88a22
--- /dev/null
+++ b/3rdparty/libuv/test/test-mutexes.c
@@ -0,0 +1,162 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static uv_cond_t condvar;
+static uv_mutex_t mutex;
+static uv_rwlock_t rwlock;
+static int step;
+
+/* The mutex and rwlock tests are really poor.
+ * They're very basic sanity checks and nothing more.
+ * Apologies if that rhymes.
+ */
+
+TEST_IMPL(thread_mutex) {
+ uv_mutex_t mutex;
+ int r;
+
+ r = uv_mutex_init(&mutex);
+ ASSERT(r == 0);
+
+ uv_mutex_lock(&mutex);
+ uv_mutex_unlock(&mutex);
+ uv_mutex_destroy(&mutex);
+
+ return 0;
+}
+
+
+TEST_IMPL(thread_rwlock) {
+ uv_rwlock_t rwlock;
+ int r;
+
+ r = uv_rwlock_init(&rwlock);
+ ASSERT(r == 0);
+
+ uv_rwlock_rdlock(&rwlock);
+ uv_rwlock_rdunlock(&rwlock);
+ uv_rwlock_wrlock(&rwlock);
+ uv_rwlock_wrunlock(&rwlock);
+ uv_rwlock_destroy(&rwlock);
+
+ return 0;
+}
+
+
+/* Call when holding |mutex|. */
+static void synchronize_nowait(void) {
+ step += 1;
+ uv_cond_signal(&condvar);
+}
+
+
+/* Call when holding |mutex|. */
+static void synchronize(void) {
+ int current;
+
+ synchronize_nowait();
+ /* Wait for the other thread. Guard against spurious wakeups. */
+ for (current = step; current == step; uv_cond_wait(&condvar, &mutex));
+ ASSERT(step == current + 1);
+}
+
+
+static void thread_rwlock_trylock_peer(void* unused) {
+ (void) &unused;
+
+ uv_mutex_lock(&mutex);
+
+ /* Write lock held by other thread. */
+ ASSERT(UV_EBUSY == uv_rwlock_tryrdlock(&rwlock));
+ ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock));
+ synchronize();
+
+ /* Read lock held by other thread. */
+ ASSERT(0 == uv_rwlock_tryrdlock(&rwlock));
+ uv_rwlock_rdunlock(&rwlock);
+ ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock));
+ synchronize();
+
+ /* Acquire write lock. */
+ ASSERT(0 == uv_rwlock_trywrlock(&rwlock));
+ synchronize();
+
+ /* Release write lock and acquire read lock. */
+ uv_rwlock_wrunlock(&rwlock);
+ ASSERT(0 == uv_rwlock_tryrdlock(&rwlock));
+ synchronize();
+
+ uv_rwlock_rdunlock(&rwlock);
+ synchronize_nowait(); /* Signal main thread we're going away. */
+ uv_mutex_unlock(&mutex);
+}
+
+
+TEST_IMPL(thread_rwlock_trylock) {
+ uv_thread_t thread;
+
+ ASSERT(0 == uv_cond_init(&condvar));
+ ASSERT(0 == uv_mutex_init(&mutex));
+ ASSERT(0 == uv_rwlock_init(&rwlock));
+
+ uv_mutex_lock(&mutex);
+ ASSERT(0 == uv_thread_create(&thread, thread_rwlock_trylock_peer, NULL));
+
+ /* Hold write lock. */
+ ASSERT(0 == uv_rwlock_trywrlock(&rwlock));
+ synchronize(); /* Releases the mutex to the other thread. */
+
+ /* Release write lock and acquire read lock. Pthreads doesn't support
+ * the notion of upgrading or downgrading rwlocks, so neither do we.
+ */
+ uv_rwlock_wrunlock(&rwlock);
+ ASSERT(0 == uv_rwlock_tryrdlock(&rwlock));
+ synchronize();
+
+ /* Release read lock. */
+ uv_rwlock_rdunlock(&rwlock);
+ synchronize();
+
+ /* Write lock held by other thread. */
+ ASSERT(UV_EBUSY == uv_rwlock_tryrdlock(&rwlock));
+ ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock));
+ synchronize();
+
+ /* Read lock held by other thread. */
+ ASSERT(0 == uv_rwlock_tryrdlock(&rwlock));
+ uv_rwlock_rdunlock(&rwlock);
+ ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock));
+ synchronize();
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_rwlock_destroy(&rwlock);
+ uv_mutex_unlock(&mutex);
+ uv_mutex_destroy(&mutex);
+ uv_cond_destroy(&condvar);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-osx-select.c b/3rdparty/libuv/test/test-osx-select.c
new file mode 100644
index 00000000000..a0afda9181e
--- /dev/null
+++ b/3rdparty/libuv/test/test-osx-select.c
@@ -0,0 +1,140 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#ifdef __APPLE__
+
+#include <sys/ioctl.h>
+#include <string.h>
+
+static int read_count;
+
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ static char slab[1024];
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
+ fprintf(stdout, "got data %d\n", ++read_count);
+ fflush(stdout);
+
+ if (read_count == 3)
+ uv_close((uv_handle_t*) stream, NULL);
+}
+
+
+TEST_IMPL(osx_select) {
+ int r;
+ int fd;
+ size_t i;
+ size_t len;
+ const char* str;
+ uv_tty_t tty;
+
+ fd = open("/dev/tty", O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Cannot open /dev/tty as read-only: %s\n", strerror(errno));
+ fflush(stderr);
+ return TEST_SKIP;
+ }
+
+ r = uv_tty_init(uv_default_loop(), &tty, fd, 1);
+ ASSERT(r == 0);
+
+ uv_read_start((uv_stream_t*) &tty, alloc_cb, read_cb);
+
+ /* Emulate user-input */
+ str = "got some input\n"
+ "with a couple of lines\n"
+ "feel pretty happy\n";
+ for (i = 0, len = strlen(str); i < len; i++) {
+ r = ioctl(fd, TIOCSTI, str + i);
+ ASSERT(r == 0);
+ }
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(read_count == 3);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(osx_select_many_fds) {
+ int r;
+ int fd;
+ size_t i;
+ size_t len;
+ const char* str;
+ struct sockaddr_in addr;
+ uv_tty_t tty;
+ uv_tcp_t tcps[1500];
+
+ TEST_FILE_LIMIT(ARRAY_SIZE(tcps) + 100);
+
+ r = uv_ip4_addr("127.0.0.1", 0, &addr);
+ ASSERT(r == 0);
+
+ for (i = 0; i < ARRAY_SIZE(tcps); i++) {
+ r = uv_tcp_init(uv_default_loop(), &tcps[i]);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&tcps[i], (const struct sockaddr *) &addr, 0);
+ ASSERT(r == 0);
+ uv_unref((uv_handle_t*) &tcps[i]);
+ }
+
+ fd = open("/dev/tty", O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Cannot open /dev/tty as read-only: %s\n", strerror(errno));
+ fflush(stderr);
+ return TEST_SKIP;
+ }
+
+ r = uv_tty_init(uv_default_loop(), &tty, fd, 1);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &tty, alloc_cb, read_cb);
+ ASSERT(r == 0);
+
+ /* Emulate user-input */
+ str = "got some input\n"
+ "with a couple of lines\n"
+ "feel pretty happy\n";
+ for (i = 0, len = strlen(str); i < len; i++) {
+ r = ioctl(fd, TIOCSTI, str + i);
+ ASSERT(r == 0);
+ }
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(read_count == 3);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* __APPLE__ */
diff --git a/3rdparty/libuv/test/test-pass-always.c b/3rdparty/libuv/test/test-pass-always.c
new file mode 100644
index 00000000000..4fb58ff94be
--- /dev/null
+++ b/3rdparty/libuv/test/test-pass-always.c
@@ -0,0 +1,28 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "task.h"
+
+
+TEST_IMPL(pass_always) {
+ /* This test always passes. It is used to test the test runner. */
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-ping-pong.c b/3rdparty/libuv/test/test-ping-pong.c
new file mode 100644
index 00000000000..c074178541b
--- /dev/null
+++ b/3rdparty/libuv/test/test-ping-pong.c
@@ -0,0 +1,270 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+static int completed_pingers = 0;
+
+#define NUM_PINGS 1000
+
+/* 64 bytes is enough for a pinger */
+#define BUFSIZE 10240
+
+static char PING[] = "PING\n";
+static int pinger_on_connect_count;
+
+
+typedef struct {
+ int pongs;
+ int state;
+ union {
+ uv_tcp_t tcp;
+ uv_pipe_t pipe;
+ } stream;
+ uv_connect_t connect_req;
+ char read_buffer[BUFSIZE];
+} pinger_t;
+
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ buf->base = malloc(size);
+ buf->len = size;
+}
+
+
+static void pinger_on_close(uv_handle_t* handle) {
+ pinger_t* pinger = (pinger_t*)handle->data;
+
+ ASSERT(NUM_PINGS == pinger->pongs);
+
+ free(pinger);
+
+ completed_pingers++;
+}
+
+
+static void pinger_after_write(uv_write_t *req, int status) {
+ ASSERT(status == 0);
+ free(req);
+}
+
+
+static void pinger_write_ping(pinger_t* pinger) {
+ uv_write_t *req;
+ uv_buf_t buf;
+
+ buf = uv_buf_init(PING, sizeof(PING) - 1);
+
+ req = malloc(sizeof(*req));
+ if (uv_write(req,
+ (uv_stream_t*) &pinger->stream.tcp,
+ &buf,
+ 1,
+ pinger_after_write)) {
+ FATAL("uv_write failed");
+ }
+
+ puts("PING");
+}
+
+
+static void pinger_read_cb(uv_stream_t* stream,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ ssize_t i;
+ pinger_t* pinger;
+
+ pinger = (pinger_t*)stream->data;
+
+ if (nread < 0) {
+ ASSERT(nread == UV_EOF);
+
+ puts("got EOF");
+ free(buf->base);
+
+ uv_close((uv_handle_t*)(&pinger->stream.tcp), pinger_on_close);
+
+ return;
+ }
+
+ /* Now we count the pings */
+ for (i = 0; i < nread; i++) {
+ ASSERT(buf->base[i] == PING[pinger->state]);
+ pinger->state = (pinger->state + 1) % (sizeof(PING) - 1);
+
+ if (pinger->state != 0)
+ continue;
+
+ printf("PONG %d\n", pinger->pongs);
+ pinger->pongs++;
+
+ if (pinger->pongs < NUM_PINGS) {
+ pinger_write_ping(pinger);
+ } else {
+ uv_close((uv_handle_t*)(&pinger->stream.tcp), pinger_on_close);
+ break;
+ }
+ }
+
+ free(buf->base);
+}
+
+
+static void pinger_on_connect(uv_connect_t *req, int status) {
+ pinger_t *pinger = (pinger_t*)req->handle->data;
+
+ pinger_on_connect_count++;
+
+ ASSERT(status == 0);
+
+ ASSERT(1 == uv_is_readable(req->handle));
+ ASSERT(1 == uv_is_writable(req->handle));
+ ASSERT(0 == uv_is_closing((uv_handle_t *) req->handle));
+
+ pinger_write_ping(pinger);
+
+ uv_read_start((uv_stream_t*)(req->handle), alloc_cb, pinger_read_cb);
+}
+
+
+/* same ping-pong test, but using IPv6 connection */
+static void tcp_pinger_v6_new(void) {
+ int r;
+ struct sockaddr_in6 server_addr;
+ pinger_t *pinger;
+
+
+ ASSERT(0 ==uv_ip6_addr("::1", TEST_PORT, &server_addr));
+ pinger = malloc(sizeof(*pinger));
+ ASSERT(pinger != NULL);
+ pinger->state = 0;
+ pinger->pongs = 0;
+
+ /* Try to connect to the server and do NUM_PINGS ping-pongs. */
+ r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp);
+ pinger->stream.tcp.data = pinger;
+ ASSERT(!r);
+
+ /* We are never doing multiple reads/connects at a time anyway. */
+ /* so these handles can be pre-initialized. */
+ r = uv_tcp_connect(&pinger->connect_req,
+ &pinger->stream.tcp,
+ (const struct sockaddr*) &server_addr,
+ pinger_on_connect);
+ ASSERT(!r);
+
+ /* Synchronous connect callbacks are not allowed. */
+ ASSERT(pinger_on_connect_count == 0);
+}
+
+
+static void tcp_pinger_new(void) {
+ int r;
+ struct sockaddr_in server_addr;
+ pinger_t *pinger;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
+ pinger = malloc(sizeof(*pinger));
+ ASSERT(pinger != NULL);
+ pinger->state = 0;
+ pinger->pongs = 0;
+
+ /* Try to connect to the server and do NUM_PINGS ping-pongs. */
+ r = uv_tcp_init(uv_default_loop(), &pinger->stream.tcp);
+ pinger->stream.tcp.data = pinger;
+ ASSERT(!r);
+
+ /* We are never doing multiple reads/connects at a time anyway. */
+ /* so these handles can be pre-initialized. */
+ r = uv_tcp_connect(&pinger->connect_req,
+ &pinger->stream.tcp,
+ (const struct sockaddr*) &server_addr,
+ pinger_on_connect);
+ ASSERT(!r);
+
+ /* Synchronous connect callbacks are not allowed. */
+ ASSERT(pinger_on_connect_count == 0);
+}
+
+
+static void pipe_pinger_new(void) {
+ int r;
+ pinger_t *pinger;
+
+ pinger = (pinger_t*)malloc(sizeof(*pinger));
+ ASSERT(pinger != NULL);
+ pinger->state = 0;
+ pinger->pongs = 0;
+
+ /* Try to connect to the server and do NUM_PINGS ping-pongs. */
+ r = uv_pipe_init(uv_default_loop(), &pinger->stream.pipe, 0);
+ pinger->stream.pipe.data = pinger;
+ ASSERT(!r);
+
+ /* We are never doing multiple reads/connects at a time anyway. */
+ /* so these handles can be pre-initialized. */
+
+ uv_pipe_connect(&pinger->connect_req, &pinger->stream.pipe, TEST_PIPENAME,
+ pinger_on_connect);
+
+ /* Synchronous connect callbacks are not allowed. */
+ ASSERT(pinger_on_connect_count == 0);
+}
+
+
+TEST_IMPL(tcp_ping_pong) {
+ tcp_pinger_new();
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(completed_pingers == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_ping_pong_v6) {
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+ tcp_pinger_v6_new();
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(completed_pingers == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(pipe_ping_pong) {
+ pipe_pinger_new();
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(completed_pingers == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-pipe-bind-error.c b/3rdparty/libuv/test/test-pipe-bind-error.c
new file mode 100644
index 00000000000..38b57db6991
--- /dev/null
+++ b/3rdparty/libuv/test/test-pipe-bind-error.c
@@ -0,0 +1,136 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#ifdef _WIN32
+# define BAD_PIPENAME "bad-pipe"
+#else
+# define BAD_PIPENAME "/path/to/unix/socket/that/really/should/not/be/there"
+#endif
+
+
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+TEST_IMPL(pipe_bind_error_addrinuse) {
+ uv_pipe_t server1, server2;
+ int r;
+
+ r = uv_pipe_init(uv_default_loop(), &server1, 0);
+ ASSERT(r == 0);
+ r = uv_pipe_bind(&server1, TEST_PIPENAME);
+ ASSERT(r == 0);
+
+ r = uv_pipe_init(uv_default_loop(), &server2, 0);
+ ASSERT(r == 0);
+ r = uv_pipe_bind(&server2, TEST_PIPENAME);
+ ASSERT(r == UV_EADDRINUSE);
+
+ r = uv_listen((uv_stream_t*)&server1, SOMAXCONN, NULL);
+ ASSERT(r == 0);
+ r = uv_listen((uv_stream_t*)&server2, SOMAXCONN, NULL);
+ ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server1, close_cb);
+ uv_close((uv_handle_t*)&server2, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(pipe_bind_error_addrnotavail) {
+ uv_pipe_t server;
+ int r;
+
+ r = uv_pipe_init(uv_default_loop(), &server, 0);
+ ASSERT(r == 0);
+
+ r = uv_pipe_bind(&server, BAD_PIPENAME);
+ ASSERT(r == UV_EACCES);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(pipe_bind_error_inval) {
+ uv_pipe_t server;
+ int r;
+
+ r = uv_pipe_init(uv_default_loop(), &server, 0);
+ ASSERT(r == 0);
+ r = uv_pipe_bind(&server, TEST_PIPENAME);
+ ASSERT(r == 0);
+ r = uv_pipe_bind(&server, TEST_PIPENAME_2);
+ ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(pipe_listen_without_bind) {
+ uv_pipe_t server;
+ int r;
+
+ r = uv_pipe_init(uv_default_loop(), &server, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL);
+ ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-pipe-close-stdout-read-stdin.c b/3rdparty/libuv/test/test-pipe-close-stdout-read-stdin.c
new file mode 100644
index 00000000000..ee8bb2a9a8b
--- /dev/null
+++ b/3rdparty/libuv/test/test-pipe-close-stdout-read-stdin.c
@@ -0,0 +1,104 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _WIN32
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+
+#include "uv.h"
+#include "task.h"
+
+void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t* buf)
+{
+ static char buffer[1024];
+
+ buf->base = buffer;
+ buf->len = sizeof(buffer);
+}
+
+void read_stdin(uv_stream_t *stream, ssize_t nread, const uv_buf_t* buf)
+{
+ if (nread < 0) {
+ uv_close((uv_handle_t*)stream, NULL);
+ return;
+ }
+}
+
+/*
+ * This test is a reproduction of joyent/libuv#1419 .
+ */
+TEST_IMPL(pipe_close_stdout_read_stdin) {
+ int r = -1;
+ int pid;
+ int fd[2];
+ int status;
+ uv_pipe_t stdin_pipe;
+
+ r = pipe(fd);
+ ASSERT(r == 0);
+
+ if ((pid = fork()) == 0) {
+ /*
+ * Make the read side of the pipe our stdin.
+ * The write side will be closed by the parent process.
+ */
+ close(fd[1]);
+ close(0);
+ r = dup(fd[0]);
+ ASSERT(r != -1);
+
+ /* Create a stream that reads from the pipe. */
+ r = uv_pipe_init(uv_default_loop(), (uv_pipe_t *)&stdin_pipe, 0);
+ ASSERT(r == 0);
+
+ r = uv_pipe_open((uv_pipe_t *)&stdin_pipe, 0);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t *)&stdin_pipe, alloc_buffer, read_stdin);
+ ASSERT(r == 0);
+
+ /*
+ * Because the other end of the pipe was closed, there should
+ * be no event left to process after one run of the event loop.
+ * Otherwise, it means that events were not processed correctly.
+ */
+ ASSERT(uv_run(uv_default_loop(), UV_RUN_NOWAIT) == 0);
+ } else {
+ /*
+ * Close both ends of the pipe so that the child
+ * get a POLLHUP event when it tries to read from
+ * the other end.
+ */
+ close(fd[1]);
+ close(fd[0]);
+
+ waitpid(pid, &status, 0);
+ ASSERT(WIFEXITED(status) && WEXITSTATUS(status) == 0);
+ }
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* ifndef _WIN32 */
diff --git a/3rdparty/libuv/test/test-pipe-connect-error.c b/3rdparty/libuv/test/test-pipe-connect-error.c
new file mode 100644
index 00000000000..ebb2a6ca826
--- /dev/null
+++ b/3rdparty/libuv/test/test-pipe-connect-error.c
@@ -0,0 +1,95 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#ifdef _WIN32
+# define BAD_PIPENAME "bad-pipe"
+#else
+# define BAD_PIPENAME "/path/to/unix/socket/that/really/should/not/be/there"
+#endif
+
+
+static int close_cb_called = 0;
+static int connect_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* connect_req, int status) {
+ ASSERT(status == UV_ENOENT);
+ uv_close((uv_handle_t*)connect_req->handle, close_cb);
+ connect_cb_called++;
+}
+
+
+static void connect_cb_file(uv_connect_t* connect_req, int status) {
+ ASSERT(status == UV_ENOTSOCK || status == UV_ECONNREFUSED);
+ uv_close((uv_handle_t*)connect_req->handle, close_cb);
+ connect_cb_called++;
+}
+
+
+TEST_IMPL(pipe_connect_bad_name) {
+ uv_pipe_t client;
+ uv_connect_t req;
+ int r;
+
+ r = uv_pipe_init(uv_default_loop(), &client, 0);
+ ASSERT(r == 0);
+ uv_pipe_connect(&req, &client, BAD_PIPENAME, connect_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+ ASSERT(connect_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(pipe_connect_to_file) {
+ const char* path = "test/fixtures/empty_file";
+ uv_pipe_t client;
+ uv_connect_t req;
+ int r;
+
+ r = uv_pipe_init(uv_default_loop(), &client, 0);
+ ASSERT(r == 0);
+ uv_pipe_connect(&req, &client, path, connect_cb_file);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+ ASSERT(connect_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-pipe-connect-multiple.c b/3rdparty/libuv/test/test-pipe-connect-multiple.c
new file mode 100644
index 00000000000..3de5a9a0bf4
--- /dev/null
+++ b/3rdparty/libuv/test/test-pipe-connect-multiple.c
@@ -0,0 +1,104 @@
+/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int connection_cb_called = 0;
+static int connect_cb_called = 0;
+
+#define NUM_CLIENTS 4
+
+typedef struct {
+ uv_pipe_t pipe_handle;
+ uv_connect_t conn_req;
+} client_t;
+
+static uv_pipe_t server_handle;
+static client_t clients[NUM_CLIENTS];
+static uv_pipe_t connections[NUM_CLIENTS];
+
+
+static void connection_cb(uv_stream_t* server, int status) {
+ int r;
+ uv_pipe_t* conn;
+ ASSERT(status == 0);
+
+ conn = &connections[connection_cb_called];
+ r = uv_pipe_init(server->loop, conn, 0);
+ ASSERT(r == 0);
+
+ r = uv_accept(server, (uv_stream_t*)conn);
+ ASSERT(r == 0);
+
+ if (++connection_cb_called == NUM_CLIENTS &&
+ connect_cb_called == NUM_CLIENTS) {
+ uv_stop(server->loop);
+ }
+}
+
+
+static void connect_cb(uv_connect_t* connect_req, int status) {
+ ASSERT(status == 0);
+ if (++connect_cb_called == NUM_CLIENTS &&
+ connection_cb_called == NUM_CLIENTS) {
+ uv_stop(connect_req->handle->loop);
+ }
+}
+
+
+TEST_IMPL(pipe_connect_multiple) {
+ int i;
+ int r;
+ uv_loop_t* loop;
+
+ loop = uv_default_loop();
+
+ r = uv_pipe_init(loop, &server_handle, 0);
+ ASSERT(r == 0);
+
+ r = uv_pipe_bind(&server_handle, TEST_PIPENAME);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&server_handle, 128, connection_cb);
+ ASSERT(r == 0);
+
+ for (i = 0; i < NUM_CLIENTS; i++) {
+ r = uv_pipe_init(loop, &clients[i].pipe_handle, 0);
+ ASSERT(r == 0);
+ uv_pipe_connect(&clients[i].conn_req,
+ &clients[i].pipe_handle,
+ TEST_PIPENAME,
+ connect_cb);
+ }
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(connection_cb_called == NUM_CLIENTS);
+ ASSERT(connect_cb_called == NUM_CLIENTS);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-pipe-connect-prepare.c b/3rdparty/libuv/test/test-pipe-connect-prepare.c
new file mode 100644
index 00000000000..a86e7284a79
--- /dev/null
+++ b/3rdparty/libuv/test/test-pipe-connect-prepare.c
@@ -0,0 +1,83 @@
+/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#ifdef _WIN32
+# define BAD_PIPENAME "bad-pipe"
+#else
+# define BAD_PIPENAME "/path/to/unix/socket/that/really/should/not/be/there"
+#endif
+
+
+static int close_cb_called = 0;
+static int connect_cb_called = 0;
+
+static uv_pipe_t pipe_handle;
+static uv_prepare_t prepare_handle;
+static uv_connect_t conn_req;
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* connect_req, int status) {
+ ASSERT(status == UV_ENOENT);
+ connect_cb_called++;
+ uv_close((uv_handle_t*)&prepare_handle, close_cb);
+ uv_close((uv_handle_t*)&pipe_handle, close_cb);
+}
+
+
+static void prepare_cb(uv_prepare_t* handle) {
+ ASSERT(handle == &prepare_handle);
+ uv_pipe_connect(&conn_req, &pipe_handle, BAD_PIPENAME, connect_cb);
+}
+
+
+TEST_IMPL(pipe_connect_on_prepare) {
+ int r;
+
+ r = uv_pipe_init(uv_default_loop(), &pipe_handle, 0);
+ ASSERT(r == 0);
+
+ r = uv_prepare_init(uv_default_loop(), &prepare_handle);
+ ASSERT(r == 0);
+ r = uv_prepare_start(&prepare_handle, prepare_cb);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 2);
+ ASSERT(connect_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-pipe-getsockname.c b/3rdparty/libuv/test/test-pipe-getsockname.c
new file mode 100644
index 00000000000..5e036f9d528
--- /dev/null
+++ b/3rdparty/libuv/test/test-pipe-getsockname.c
@@ -0,0 +1,263 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(__linux__)
+ #include <sys/socket.h>
+ #include <sys/un.h>
+#endif
+
+#ifndef _WIN32
+# include <unistd.h> /* close */
+#else
+# include <fcntl.h>
+#endif
+
+static uv_pipe_t pipe_client;
+static uv_pipe_t pipe_server;
+static uv_connect_t connect_req;
+
+static int pipe_close_cb_called = 0;
+static int pipe_client_connect_cb_called = 0;
+
+
+static void pipe_close_cb(uv_handle_t* handle) {
+ ASSERT(handle == (uv_handle_t*) &pipe_client ||
+ handle == (uv_handle_t*) &pipe_server);
+ pipe_close_cb_called++;
+}
+
+
+static void pipe_client_connect_cb(uv_connect_t* req, int status) {
+ char buf[1024];
+ size_t len;
+ int r;
+
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getpeername(&pipe_client, buf, &len);
+ ASSERT(r == 0);
+
+ ASSERT(buf[len - 1] != 0);
+ ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getsockname(&pipe_client, buf, &len);
+ ASSERT(r == 0 && len == 0);
+
+ pipe_client_connect_cb_called++;
+
+
+ uv_close((uv_handle_t*) &pipe_client, pipe_close_cb);
+ uv_close((uv_handle_t*) &pipe_server, pipe_close_cb);
+}
+
+
+static void pipe_server_connection_cb(uv_stream_t* handle, int status) {
+ /* This function *may* be called, depending on whether accept or the
+ * connection callback is called first.
+ */
+ ASSERT(status == 0);
+}
+
+
+TEST_IMPL(pipe_getsockname) {
+ uv_loop_t* loop;
+ char buf[1024];
+ size_t len;
+ int r;
+
+ loop = uv_default_loop();
+ ASSERT(loop != NULL);
+
+ r = uv_pipe_init(loop, &pipe_server, 0);
+ ASSERT(r == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getsockname(&pipe_server, buf, &len);
+ ASSERT(r == UV_EBADF);
+
+ len = sizeof buf;
+ r = uv_pipe_getpeername(&pipe_server, buf, &len);
+ ASSERT(r == UV_EBADF);
+
+ r = uv_pipe_bind(&pipe_server, TEST_PIPENAME);
+ ASSERT(r == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getsockname(&pipe_server, buf, &len);
+ ASSERT(r == 0);
+
+ ASSERT(buf[len - 1] != 0);
+ ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getpeername(&pipe_server, buf, &len);
+ ASSERT(r == UV_ENOTCONN);
+
+ r = uv_listen((uv_stream_t*) &pipe_server, 0, pipe_server_connection_cb);
+ ASSERT(r == 0);
+
+ r = uv_pipe_init(loop, &pipe_client, 0);
+ ASSERT(r == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getsockname(&pipe_client, buf, &len);
+ ASSERT(r == UV_EBADF);
+
+ len = sizeof buf;
+ r = uv_pipe_getpeername(&pipe_client, buf, &len);
+ ASSERT(r == UV_EBADF);
+
+ uv_pipe_connect(&connect_req, &pipe_client, TEST_PIPENAME, pipe_client_connect_cb);
+
+ len = sizeof buf;
+ r = uv_pipe_getsockname(&pipe_client, buf, &len);
+ ASSERT(r == 0 && len == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getpeername(&pipe_client, buf, &len);
+ ASSERT(r == 0);
+
+ ASSERT(buf[len - 1] != 0);
+ ASSERT(memcmp(buf, TEST_PIPENAME, len) == 0);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+ ASSERT(pipe_client_connect_cb_called == 1);
+ ASSERT(pipe_close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(pipe_getsockname_abstract) {
+#if defined(__linux__)
+ char buf[1024];
+ size_t len;
+ int r;
+ int sock;
+ struct sockaddr_un sun;
+ socklen_t sun_len;
+ char abstract_pipe[] = "\0test-pipe";
+
+ sock = socket(AF_LOCAL, SOCK_STREAM, 0);
+ ASSERT(sock != -1);
+
+ sun_len = sizeof sun;
+ memset(&sun, 0, sun_len);
+ sun.sun_family = AF_UNIX;
+ memcpy(sun.sun_path, abstract_pipe, sizeof abstract_pipe);
+
+ r = bind(sock, (struct sockaddr*)&sun, sun_len);
+ ASSERT(r == 0);
+
+ r = uv_pipe_init(uv_default_loop(), &pipe_server, 0);
+ ASSERT(r == 0);
+ r = uv_pipe_open(&pipe_server, sock);
+ ASSERT(r == 0);
+
+ len = sizeof buf;
+ r = uv_pipe_getsockname(&pipe_server, buf, &len);
+ ASSERT(r == 0);
+
+ ASSERT(memcmp(buf, abstract_pipe, sizeof abstract_pipe) == 0);
+
+ uv_close((uv_handle_t*)&pipe_server, pipe_close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ close(sock);
+
+ ASSERT(pipe_close_cb_called == 1);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+#else
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+#endif
+}
+
+TEST_IMPL(pipe_getsockname_blocking) {
+#ifdef _WIN32
+ HANDLE readh, writeh;
+ int readfd;
+ char buf1[1024], buf2[1024];
+ size_t len1, len2;
+ int r;
+
+ r = CreatePipe(&readh, &writeh, NULL, 65536);
+ ASSERT(r != 0);
+
+ r = uv_pipe_init(uv_default_loop(), &pipe_client, 0);
+ ASSERT(r == 0);
+ readfd = _open_osfhandle((intptr_t)readh, _O_RDONLY);
+ ASSERT(r != -1);
+ r = uv_pipe_open(&pipe_client, readfd);
+ ASSERT(r == 0);
+ r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL);
+ ASSERT(r == 0);
+ Sleep(100);
+ r = uv_read_stop((uv_stream_t*)&pipe_client);
+ ASSERT(r == 0);
+
+ len1 = sizeof buf1;
+ r = uv_pipe_getsockname(&pipe_client, buf1, &len1);
+ ASSERT(r == 0);
+ ASSERT(buf1[len1 - 1] != 0);
+
+ r = uv_read_start((uv_stream_t*)&pipe_client, NULL, NULL);
+ ASSERT(r == 0);
+ Sleep(100);
+
+ len2 = sizeof buf2;
+ r = uv_pipe_getsockname(&pipe_client, buf2, &len2);
+ ASSERT(r == 0);
+ ASSERT(buf2[len2 - 1] != 0);
+
+ r = uv_read_stop((uv_stream_t*)&pipe_client);
+ ASSERT(r == 0);
+
+ ASSERT(len1 == len2);
+ ASSERT(memcmp(buf1, buf2, len1) == 0);
+
+ pipe_close_cb_called = 0;
+ uv_close((uv_handle_t*)&pipe_client, pipe_close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(pipe_close_cb_called == 1);
+
+ _close(readfd);
+ CloseHandle(writeh);
+#endif
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-pipe-pending-instances.c b/3rdparty/libuv/test/test-pipe-pending-instances.c
new file mode 100644
index 00000000000..b6ff911a0f2
--- /dev/null
+++ b/3rdparty/libuv/test/test-pipe-pending-instances.c
@@ -0,0 +1,59 @@
+/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+static void connection_cb(uv_stream_t* server, int status) {
+ ASSERT(0 && "this will never be called");
+}
+
+
+TEST_IMPL(pipe_pending_instances) {
+ int r;
+ uv_pipe_t pipe_handle;
+ uv_loop_t* loop;
+
+ loop = uv_default_loop();
+
+ r = uv_pipe_init(loop, &pipe_handle, 0);
+ ASSERT(r == 0);
+
+ uv_pipe_pending_instances(&pipe_handle, 8);
+
+ r = uv_pipe_bind(&pipe_handle, TEST_PIPENAME);
+ ASSERT(r == 0);
+
+ uv_pipe_pending_instances(&pipe_handle, 16);
+
+ r = uv_listen((uv_stream_t*)&pipe_handle, 128, connection_cb);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*)&pipe_handle, NULL);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-pipe-sendmsg.c b/3rdparty/libuv/test/test-pipe-sendmsg.c
new file mode 100644
index 00000000000..f6d893b4494
--- /dev/null
+++ b/3rdparty/libuv/test/test-pipe-sendmsg.c
@@ -0,0 +1,169 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+#ifndef _WIN32
+
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+
+/* NOTE: size should be divisible by 2 */
+static uv_pipe_t incoming[4];
+static unsigned int incoming_count;
+static unsigned int close_called;
+
+
+static void set_nonblocking(uv_os_sock_t sock) {
+ int r;
+#ifdef _WIN32
+ unsigned long on = 1;
+ r = ioctlsocket(sock, FIONBIO, &on);
+ ASSERT(r == 0);
+#else
+ int flags = fcntl(sock, F_GETFL, 0);
+ ASSERT(flags >= 0);
+ r = fcntl(sock, F_SETFL, flags | O_NONBLOCK);
+ ASSERT(r >= 0);
+#endif
+}
+
+
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_called++;
+}
+
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ static char base[1];
+
+ buf->base = base;
+ buf->len = sizeof(base);
+}
+
+
+static void read_cb(uv_stream_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf) {
+ uv_pipe_t* p;
+ uv_pipe_t* inc;
+ uv_handle_type pending;
+ unsigned int i;
+
+ p = (uv_pipe_t*) handle;
+ ASSERT(nread >= 0);
+
+ while (uv_pipe_pending_count(p) != 0) {
+ pending = uv_pipe_pending_type(p);
+ ASSERT(pending == UV_NAMED_PIPE);
+
+ ASSERT(incoming_count < ARRAY_SIZE(incoming));
+ inc = &incoming[incoming_count++];
+ ASSERT(0 == uv_pipe_init(p->loop, inc, 0));
+ ASSERT(0 == uv_accept(handle, (uv_stream_t*) inc));
+ }
+
+ if (incoming_count != ARRAY_SIZE(incoming))
+ return;
+
+ ASSERT(0 == uv_read_stop((uv_stream_t*) p));
+ uv_close((uv_handle_t*) p, close_cb);
+ for (i = 0; i < ARRAY_SIZE(incoming); i++)
+ uv_close((uv_handle_t*) &incoming[i], close_cb);
+}
+
+
+TEST_IMPL(pipe_sendmsg) {
+ uv_pipe_t p;
+ int r;
+ int fds[2];
+ int send_fds[ARRAY_SIZE(incoming)];
+ struct msghdr msg;
+ char scratch[64];
+ struct cmsghdr *cmsg;
+ unsigned int i;
+ uv_buf_t buf;
+
+ ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, fds));
+ for (i = 0; i < ARRAY_SIZE(send_fds); i += 2)
+ ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, send_fds + i));
+ ASSERT(i == ARRAY_SIZE(send_fds));
+ ASSERT(0 == uv_pipe_init(uv_default_loop(), &p, 1));
+ ASSERT(0 == uv_pipe_open(&p, fds[1]));
+
+ buf = uv_buf_init("X", 1);
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = (struct iovec*) &buf;
+ msg.msg_iovlen = 1;
+ msg.msg_flags = 0;
+
+ msg.msg_control = (void*) scratch;
+ msg.msg_controllen = CMSG_LEN(sizeof(send_fds));
+ ASSERT(sizeof(scratch) >= msg.msg_controllen);
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = msg.msg_controllen;
+
+ /* silence aliasing warning */
+ {
+ void* pv = CMSG_DATA(cmsg);
+ int* pi = pv;
+ for (i = 0; i < ARRAY_SIZE(send_fds); i++)
+ pi[i] = send_fds[i];
+ }
+
+ set_nonblocking(fds[1]);
+ ASSERT(0 == uv_read_start((uv_stream_t*) &p, alloc_cb, read_cb));
+
+ do
+ r = sendmsg(fds[0], &msg, 0);
+ while (r == -1 && errno == EINTR);
+ ASSERT(r == 1);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(ARRAY_SIZE(incoming) == incoming_count);
+ ASSERT(ARRAY_SIZE(incoming) + 1 == close_called);
+ close(fds[0]);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#else /* !_WIN32 */
+
+TEST_IMPL(pipe_sendmsg) {
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* _WIN32 */
diff --git a/3rdparty/libuv/test/test-pipe-server-close.c b/3rdparty/libuv/test/test-pipe-server-close.c
new file mode 100644
index 00000000000..1dcdfffaf7c
--- /dev/null
+++ b/3rdparty/libuv/test/test-pipe-server-close.c
@@ -0,0 +1,91 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <string.h>
+#include <errno.h>
+
+
+static uv_pipe_t pipe_client;
+static uv_pipe_t pipe_server;
+static uv_connect_t connect_req;
+
+static int pipe_close_cb_called = 0;
+static int pipe_client_connect_cb_called = 0;
+
+
+static void pipe_close_cb(uv_handle_t* handle) {
+ ASSERT(handle == (uv_handle_t*) &pipe_client ||
+ handle == (uv_handle_t*) &pipe_server);
+ pipe_close_cb_called++;
+}
+
+
+static void pipe_client_connect_cb(uv_connect_t* req, int status) {
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+
+ pipe_client_connect_cb_called++;
+
+ uv_close((uv_handle_t*) &pipe_client, pipe_close_cb);
+ uv_close((uv_handle_t*) &pipe_server, pipe_close_cb);
+}
+
+
+static void pipe_server_connection_cb(uv_stream_t* handle, int status) {
+ /* This function *may* be called, depending on whether accept or the
+ * connection callback is called first.
+ */
+ ASSERT(status == 0);
+}
+
+
+TEST_IMPL(pipe_server_close) {
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+ ASSERT(loop != NULL);
+
+ r = uv_pipe_init(loop, &pipe_server, 0);
+ ASSERT(r == 0);
+
+ r = uv_pipe_bind(&pipe_server, TEST_PIPENAME);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*) &pipe_server, 0, pipe_server_connection_cb);
+ ASSERT(r == 0);
+
+ r = uv_pipe_init(loop, &pipe_client, 0);
+ ASSERT(r == 0);
+
+ uv_pipe_connect(&connect_req, &pipe_client, TEST_PIPENAME, pipe_client_connect_cb);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+ ASSERT(pipe_client_connect_cb_called == 1);
+ ASSERT(pipe_close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-pipe-set-non-blocking.c b/3rdparty/libuv/test/test-pipe-set-non-blocking.c
new file mode 100644
index 00000000000..fcc9fc0da85
--- /dev/null
+++ b/3rdparty/libuv/test/test-pipe-set-non-blocking.c
@@ -0,0 +1,99 @@
+/* Copyright (c) 2015, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#ifdef _WIN32
+
+TEST_IMPL(pipe_set_non_blocking) {
+ RETURN_SKIP("Test not implemented on Windows.");
+}
+
+#else /* !_WIN32 */
+
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+struct thread_ctx {
+ uv_barrier_t barrier;
+ int fd;
+};
+
+static void thread_main(void* arg) {
+ struct thread_ctx* ctx;
+ char buf[4096];
+ ssize_t n;
+
+ ctx = arg;
+ uv_barrier_wait(&ctx->barrier);
+
+ do
+ n = read(ctx->fd, buf, sizeof(buf));
+ while (n > 0 || (n == -1 && errno == EINTR));
+
+ ASSERT(n == 0);
+}
+
+TEST_IMPL(pipe_set_non_blocking) {
+ struct thread_ctx ctx;
+ uv_pipe_t pipe_handle;
+ uv_thread_t thread;
+ size_t nwritten;
+ char data[4096];
+ uv_buf_t buf;
+ int fd[2];
+ int n;
+
+ ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
+ ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, fd));
+ ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
+ ASSERT(0 == uv_stream_set_blocking((uv_stream_t*) &pipe_handle, 1));
+
+ ctx.fd = fd[1];
+ ASSERT(0 == uv_barrier_init(&ctx.barrier, 2));
+ ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx));
+ uv_barrier_wait(&ctx.barrier);
+
+ buf.len = sizeof(data);
+ buf.base = data;
+ memset(data, '.', sizeof(data));
+
+ nwritten = 0;
+ while (nwritten < 10 << 20) {
+ /* The stream is in blocking mode so uv_try_write() should always succeed
+ * with the exact number of bytes that we wanted written.
+ */
+ n = uv_try_write((uv_stream_t*) &pipe_handle, &buf, 1);
+ ASSERT(n == sizeof(data));
+ nwritten += n;
+ }
+
+ uv_close((uv_handle_t*) &pipe_handle, NULL);
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ ASSERT(0 == uv_thread_join(&thread));
+ ASSERT(0 == close(fd[1])); /* fd[0] is closed by uv_close(). */
+ uv_barrier_destroy(&ctx.barrier);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* !_WIN32 */
diff --git a/3rdparty/libuv/test/test-platform-output.c b/3rdparty/libuv/test/test-platform-output.c
new file mode 100644
index 00000000000..76495e14fd8
--- /dev/null
+++ b/3rdparty/libuv/test/test-platform-output.c
@@ -0,0 +1,126 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <string.h>
+
+
+TEST_IMPL(platform_output) {
+ char buffer[512];
+ size_t rss;
+ size_t size;
+ double uptime;
+ uv_rusage_t rusage;
+ uv_cpu_info_t* cpus;
+ uv_interface_address_t* interfaces;
+ int count;
+ int i;
+ int err;
+
+ err = uv_get_process_title(buffer, sizeof(buffer));
+ ASSERT(err == 0);
+ printf("uv_get_process_title: %s\n", buffer);
+
+ size = sizeof(buffer);
+ err = uv_cwd(buffer, &size);
+ ASSERT(err == 0);
+ printf("uv_cwd: %s\n", buffer);
+
+ err = uv_resident_set_memory(&rss);
+ ASSERT(err == 0);
+ printf("uv_resident_set_memory: %llu\n", (unsigned long long) rss);
+
+ err = uv_uptime(&uptime);
+ ASSERT(err == 0);
+ ASSERT(uptime > 0);
+ printf("uv_uptime: %f\n", uptime);
+
+ err = uv_getrusage(&rusage);
+ ASSERT(err == 0);
+ ASSERT(rusage.ru_utime.tv_sec >= 0);
+ ASSERT(rusage.ru_utime.tv_usec >= 0);
+ ASSERT(rusage.ru_stime.tv_sec >= 0);
+ ASSERT(rusage.ru_stime.tv_usec >= 0);
+ printf("uv_getrusage:\n");
+ printf(" user: %llu sec %llu microsec\n",
+ (unsigned long long) rusage.ru_utime.tv_sec,
+ (unsigned long long) rusage.ru_utime.tv_usec);
+ printf(" system: %llu sec %llu microsec\n",
+ (unsigned long long) rusage.ru_stime.tv_sec,
+ (unsigned long long) rusage.ru_stime.tv_usec);
+
+ err = uv_cpu_info(&cpus, &count);
+ ASSERT(err == 0);
+
+ printf("uv_cpu_info:\n");
+ for (i = 0; i < count; i++) {
+ printf(" model: %s\n", cpus[i].model);
+ printf(" speed: %d\n", cpus[i].speed);
+ printf(" times.sys: %llu\n", (unsigned long long) cpus[i].cpu_times.sys);
+ printf(" times.user: %llu\n",
+ (unsigned long long) cpus[i].cpu_times.user);
+ printf(" times.idle: %llu\n",
+ (unsigned long long) cpus[i].cpu_times.idle);
+ printf(" times.irq: %llu\n", (unsigned long long) cpus[i].cpu_times.irq);
+ printf(" times.nice: %llu\n",
+ (unsigned long long) cpus[i].cpu_times.nice);
+ }
+ uv_free_cpu_info(cpus, count);
+
+ err = uv_interface_addresses(&interfaces, &count);
+ ASSERT(err == 0);
+
+ printf("uv_interface_addresses:\n");
+ for (i = 0; i < count; i++) {
+ printf(" name: %s\n", interfaces[i].name);
+ printf(" internal: %d\n", interfaces[i].is_internal);
+ printf(" physical address: ");
+ printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
+ (unsigned char)interfaces[i].phys_addr[0],
+ (unsigned char)interfaces[i].phys_addr[1],
+ (unsigned char)interfaces[i].phys_addr[2],
+ (unsigned char)interfaces[i].phys_addr[3],
+ (unsigned char)interfaces[i].phys_addr[4],
+ (unsigned char)interfaces[i].phys_addr[5]);
+
+ if (interfaces[i].address.address4.sin_family == AF_INET) {
+ uv_ip4_name(&interfaces[i].address.address4, buffer, sizeof(buffer));
+ } else if (interfaces[i].address.address4.sin_family == AF_INET6) {
+ uv_ip6_name(&interfaces[i].address.address6, buffer, sizeof(buffer));
+ }
+
+ printf(" address: %s\n", buffer);
+
+ if (interfaces[i].netmask.netmask4.sin_family == AF_INET) {
+ uv_ip4_name(&interfaces[i].netmask.netmask4, buffer, sizeof(buffer));
+ printf(" netmask: %s\n", buffer);
+ } else if (interfaces[i].netmask.netmask4.sin_family == AF_INET6) {
+ uv_ip6_name(&interfaces[i].netmask.netmask6, buffer, sizeof(buffer));
+ printf(" netmask: %s\n", buffer);
+ } else {
+ printf(" netmask: none\n");
+ }
+ }
+ uv_free_interface_addresses(interfaces, count);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-poll-close-doesnt-corrupt-stack.c b/3rdparty/libuv/test/test-poll-close-doesnt-corrupt-stack.c
new file mode 100644
index 00000000000..fc2cc004f16
--- /dev/null
+++ b/3rdparty/libuv/test/test-poll-close-doesnt-corrupt-stack.c
@@ -0,0 +1,114 @@
+/* Copyright Bert Belder, and other libuv contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifdef _WIN32
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "uv.h"
+#include "task.h"
+
+#ifdef _MSC_VER /* msvc */
+# define NO_INLINE __declspec(noinline)
+#else /* gcc */
+# define NO_INLINE __attribute__ ((noinline))
+#endif
+
+
+uv_os_sock_t sock;
+uv_poll_t handle;
+
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* h) {
+ close_cb_called++;
+}
+
+
+static void poll_cb(uv_poll_t* h, int status, int events) {
+ ASSERT(0 && "should never get here");
+}
+
+
+static void NO_INLINE close_socket_and_verify_stack() {
+ const uint32_t MARKER = 0xDEADBEEF;
+ const int VERIFY_AFTER = 10; /* ms */
+ int r;
+
+ volatile uint32_t data[65536];
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(data); i++)
+ data[i] = MARKER;
+
+ r = closesocket(sock);
+ ASSERT(r == 0);
+
+ uv_sleep(VERIFY_AFTER);
+
+ for (i = 0; i < ARRAY_SIZE(data); i++)
+ ASSERT(data[i] == MARKER);
+}
+
+
+TEST_IMPL(poll_close_doesnt_corrupt_stack) {
+ struct WSAData wsa_data;
+ int r;
+ unsigned long on;
+ struct sockaddr_in addr;
+
+ r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ ASSERT(r == 0);
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ ASSERT(sock != INVALID_SOCKET);
+ on = 1;
+ r = ioctlsocket(sock, FIONBIO, &on);
+ ASSERT(r == 0);
+
+ r = uv_ip4_addr("127.0.0.1", TEST_PORT, &addr);
+ ASSERT(r == 0);
+
+ r = connect(sock, (const struct sockaddr*) &addr, sizeof addr);
+ ASSERT(r != 0);
+ ASSERT(WSAGetLastError() == WSAEWOULDBLOCK);
+
+ r = uv_poll_init_socket(uv_default_loop(), &handle, sock);
+ ASSERT(r == 0);
+ r = uv_poll_start(&handle, UV_READABLE | UV_WRITABLE, poll_cb);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*) &handle, close_cb);
+
+ close_socket_and_verify_stack();
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* _WIN32 */
diff --git a/3rdparty/libuv/test/test-poll-close.c b/3rdparty/libuv/test/test-poll-close.c
new file mode 100644
index 00000000000..2eccddf5b0b
--- /dev/null
+++ b/3rdparty/libuv/test/test-poll-close.c
@@ -0,0 +1,73 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+
+#ifndef _WIN32
+# include <fcntl.h>
+# include <sys/socket.h>
+# include <unistd.h>
+#endif
+
+#include "uv.h"
+#include "task.h"
+
+#define NUM_SOCKETS 64
+
+
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+TEST_IMPL(poll_close) {
+ uv_os_sock_t sockets[NUM_SOCKETS];
+ uv_poll_t poll_handles[NUM_SOCKETS];
+ int i;
+
+#ifdef _WIN32
+ {
+ struct WSAData wsa_data;
+ int r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ ASSERT(r == 0);
+ }
+#endif
+
+ for (i = 0; i < NUM_SOCKETS; i++) {
+ sockets[i] = socket(AF_INET, SOCK_STREAM, 0);
+ uv_poll_init_socket(uv_default_loop(), &poll_handles[i], sockets[i]);
+ uv_poll_start(&poll_handles[i], UV_READABLE | UV_WRITABLE, NULL);
+ }
+
+ for (i = 0; i < NUM_SOCKETS; i++) {
+ uv_close((uv_handle_t*) &poll_handles[i], close_cb);
+ }
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == NUM_SOCKETS);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-poll-closesocket.c b/3rdparty/libuv/test/test-poll-closesocket.c
new file mode 100644
index 00000000000..4db74a01f63
--- /dev/null
+++ b/3rdparty/libuv/test/test-poll-closesocket.c
@@ -0,0 +1,89 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifdef _WIN32
+
+#include <errno.h>
+
+#include "uv.h"
+#include "task.h"
+
+uv_os_sock_t sock;
+uv_poll_t handle;
+
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* h) {
+ close_cb_called++;
+}
+
+
+static void poll_cb(uv_poll_t* h, int status, int events) {
+ int r;
+
+ ASSERT(status == 0);
+ ASSERT(h == &handle);
+
+ r = uv_poll_start(&handle, UV_READABLE, poll_cb);
+ ASSERT(r == 0);
+
+ closesocket(sock);
+ uv_close((uv_handle_t*) &handle, close_cb);
+
+}
+
+
+TEST_IMPL(poll_closesocket) {
+ struct WSAData wsa_data;
+ int r;
+ unsigned long on;
+ struct sockaddr_in addr;
+
+ r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ ASSERT(r == 0);
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ ASSERT(sock != INVALID_SOCKET);
+ on = 1;
+ r = ioctlsocket(sock, FIONBIO, &on);
+ ASSERT(r == 0);
+
+ r = uv_ip4_addr("127.0.0.1", TEST_PORT, &addr);
+ ASSERT(r == 0);
+
+ r = connect(sock, (const struct sockaddr*) &addr, sizeof addr);
+ ASSERT(r != 0);
+ ASSERT(WSAGetLastError() == WSAEWOULDBLOCK);
+
+ r = uv_poll_init_socket(uv_default_loop(), &handle, sock);
+ ASSERT(r == 0);
+ r = uv_poll_start(&handle, UV_WRITABLE, poll_cb);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif
diff --git a/3rdparty/libuv/test/test-poll.c b/3rdparty/libuv/test/test-poll.c
new file mode 100644
index 00000000000..be8b00c32ca
--- /dev/null
+++ b/3rdparty/libuv/test/test-poll.c
@@ -0,0 +1,560 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+
+#ifndef _WIN32
+# include <sys/socket.h>
+# include <unistd.h>
+#endif
+
+#include "uv.h"
+#include "task.h"
+
+
+#define NUM_CLIENTS 5
+#define TRANSFER_BYTES (1 << 16)
+
+#undef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b));
+
+
+typedef enum {
+ UNIDIRECTIONAL,
+ DUPLEX
+} test_mode_t;
+
+typedef struct connection_context_s {
+ uv_poll_t poll_handle;
+ uv_timer_t timer_handle;
+ uv_os_sock_t sock;
+ size_t read, sent;
+ int is_server_connection;
+ int open_handles;
+ int got_fin, sent_fin;
+ unsigned int events, delayed_events;
+} connection_context_t;
+
+typedef struct server_context_s {
+ uv_poll_t poll_handle;
+ uv_os_sock_t sock;
+ int connections;
+} server_context_t;
+
+
+static void delay_timer_cb(uv_timer_t* timer);
+
+
+static test_mode_t test_mode = DUPLEX;
+
+static int closed_connections = 0;
+
+static int valid_writable_wakeups = 0;
+static int spurious_writable_wakeups = 0;
+
+
+static int got_eagain(void) {
+#ifdef _WIN32
+ return WSAGetLastError() == WSAEWOULDBLOCK;
+#else
+ return errno == EAGAIN
+ || errno == EINPROGRESS
+#ifdef EWOULDBLOCK
+ || errno == EWOULDBLOCK;
+#endif
+ ;
+#endif
+}
+
+
+static uv_os_sock_t create_bound_socket (struct sockaddr_in bind_addr) {
+ uv_os_sock_t sock;
+ int r;
+
+ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+#ifdef _WIN32
+ ASSERT(sock != INVALID_SOCKET);
+#else
+ ASSERT(sock >= 0);
+#endif
+
+#ifndef _WIN32
+ {
+ /* Allow reuse of the port. */
+ int yes = 1;
+ r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);
+ ASSERT(r == 0);
+ }
+#endif
+
+ r = bind(sock, (const struct sockaddr*) &bind_addr, sizeof bind_addr);
+ ASSERT(r == 0);
+
+ return sock;
+}
+
+
+static void close_socket(uv_os_sock_t sock) {
+ int r;
+#ifdef _WIN32
+ r = closesocket(sock);
+#else
+ r = close(sock);
+#endif
+ ASSERT(r == 0);
+}
+
+
+static connection_context_t* create_connection_context(
+ uv_os_sock_t sock, int is_server_connection) {
+ int r;
+ connection_context_t* context;
+
+ context = (connection_context_t*) malloc(sizeof *context);
+ ASSERT(context != NULL);
+
+ context->sock = sock;
+ context->is_server_connection = is_server_connection;
+ context->read = 0;
+ context->sent = 0;
+ context->open_handles = 0;
+ context->events = 0;
+ context->delayed_events = 0;
+ context->got_fin = 0;
+ context->sent_fin = 0;
+
+ r = uv_poll_init_socket(uv_default_loop(), &context->poll_handle, sock);
+ context->open_handles++;
+ context->poll_handle.data = context;
+ ASSERT(r == 0);
+
+ r = uv_timer_init(uv_default_loop(), &context->timer_handle);
+ context->open_handles++;
+ context->timer_handle.data = context;
+ ASSERT(r == 0);
+
+ return context;
+}
+
+
+static void connection_close_cb(uv_handle_t* handle) {
+ connection_context_t* context = (connection_context_t*) handle->data;
+
+ if (--context->open_handles == 0) {
+ if (test_mode == DUPLEX || context->is_server_connection) {
+ ASSERT(context->read == TRANSFER_BYTES);
+ } else {
+ ASSERT(context->read == 0);
+ }
+
+ if (test_mode == DUPLEX || !context->is_server_connection) {
+ ASSERT(context->sent == TRANSFER_BYTES);
+ } else {
+ ASSERT(context->sent == 0);
+ }
+
+ closed_connections++;
+
+ free(context);
+ }
+}
+
+
+static void destroy_connection_context(connection_context_t* context) {
+ uv_close((uv_handle_t*) &context->poll_handle, connection_close_cb);
+ uv_close((uv_handle_t*) &context->timer_handle, connection_close_cb);
+}
+
+
+static void connection_poll_cb(uv_poll_t* handle, int status, int events) {
+ connection_context_t* context = (connection_context_t*) handle->data;
+ unsigned int new_events;
+ int r;
+
+ ASSERT(status == 0);
+ ASSERT(events & context->events);
+ ASSERT(!(events & ~context->events));
+
+ new_events = context->events;
+
+ if (events & UV_READABLE) {
+ int action = rand() % 7;
+
+ switch (action) {
+ case 0:
+ case 1: {
+ /* Read a couple of bytes. */
+ static char buffer[74];
+ r = recv(context->sock, buffer, sizeof buffer, 0);
+ ASSERT(r >= 0);
+
+ if (r > 0) {
+ context->read += r;
+ } else {
+ /* Got FIN. */
+ context->got_fin = 1;
+ new_events &= ~UV_READABLE;
+ }
+
+ break;
+ }
+
+ case 2:
+ case 3: {
+ /* Read until EAGAIN. */
+ static char buffer[931];
+ r = recv(context->sock, buffer, sizeof buffer, 0);
+ ASSERT(r >= 0);
+
+ while (r > 0) {
+ context->read += r;
+ r = recv(context->sock, buffer, sizeof buffer, 0);
+ }
+
+ if (r == 0) {
+ /* Got FIN. */
+ context->got_fin = 1;
+ new_events &= ~UV_READABLE;
+ } else {
+ ASSERT(got_eagain());
+ }
+
+ break;
+ }
+
+ case 4:
+ /* Ignore. */
+ break;
+
+ case 5:
+ /* Stop reading for a while. Restart in timer callback. */
+ new_events &= ~UV_READABLE;
+ if (!uv_is_active((uv_handle_t*) &context->timer_handle)) {
+ context->delayed_events = UV_READABLE;
+ uv_timer_start(&context->timer_handle, delay_timer_cb, 10, 0);
+ } else {
+ context->delayed_events |= UV_READABLE;
+ }
+ break;
+
+ case 6:
+ /* Fudge with the event mask. */
+ uv_poll_start(&context->poll_handle, UV_WRITABLE, connection_poll_cb);
+ uv_poll_start(&context->poll_handle, UV_READABLE, connection_poll_cb);
+ context->events = UV_READABLE;
+ break;
+
+ default:
+ ASSERT(0);
+ }
+ }
+
+ if (events & UV_WRITABLE) {
+ if (context->sent < TRANSFER_BYTES &&
+ !(test_mode == UNIDIRECTIONAL && context->is_server_connection)) {
+ /* We have to send more bytes. */
+ int action = rand() % 7;
+
+ switch (action) {
+ case 0:
+ case 1: {
+ /* Send a couple of bytes. */
+ static char buffer[103];
+
+ int send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer);
+ ASSERT(send_bytes > 0);
+
+ r = send(context->sock, buffer, send_bytes, 0);
+
+ if (r < 0) {
+ ASSERT(got_eagain());
+ spurious_writable_wakeups++;
+ break;
+ }
+
+ ASSERT(r > 0);
+ context->sent += r;
+ valid_writable_wakeups++;
+ break;
+ }
+
+ case 2:
+ case 3: {
+ /* Send until EAGAIN. */
+ static char buffer[1234];
+
+ int send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer);
+ ASSERT(send_bytes > 0);
+
+ r = send(context->sock, buffer, send_bytes, 0);
+
+ if (r < 0) {
+ ASSERT(got_eagain());
+ spurious_writable_wakeups++;
+ break;
+ }
+
+ ASSERT(r > 0);
+ valid_writable_wakeups++;
+ context->sent += r;
+
+ while (context->sent < TRANSFER_BYTES) {
+ send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer);
+ ASSERT(send_bytes > 0);
+
+ r = send(context->sock, buffer, send_bytes, 0);
+
+ if (r <= 0) break;
+ context->sent += r;
+ }
+ ASSERT(r > 0 || got_eagain());
+ break;
+ }
+
+ case 4:
+ /* Ignore. */
+ break;
+
+ case 5:
+ /* Stop sending for a while. Restart in timer callback. */
+ new_events &= ~UV_WRITABLE;
+ if (!uv_is_active((uv_handle_t*) &context->timer_handle)) {
+ context->delayed_events = UV_WRITABLE;
+ uv_timer_start(&context->timer_handle, delay_timer_cb, 100, 0);
+ } else {
+ context->delayed_events |= UV_WRITABLE;
+ }
+ break;
+
+ case 6:
+ /* Fudge with the event mask. */
+ uv_poll_start(&context->poll_handle,
+ UV_READABLE,
+ connection_poll_cb);
+ uv_poll_start(&context->poll_handle,
+ UV_WRITABLE,
+ connection_poll_cb);
+ context->events = UV_WRITABLE;
+ break;
+
+ default:
+ ASSERT(0);
+ }
+
+ } else {
+ /* Nothing more to write. Send FIN. */
+ int r;
+#ifdef _WIN32
+ r = shutdown(context->sock, SD_SEND);
+#else
+ r = shutdown(context->sock, SHUT_WR);
+#endif
+ ASSERT(r == 0);
+ context->sent_fin = 1;
+ new_events &= ~UV_WRITABLE;
+ }
+ }
+
+ if (context->got_fin && context->sent_fin) {
+ /* Sent and received FIN. Close and destroy context. */
+ close_socket(context->sock);
+ destroy_connection_context(context);
+ context->events = 0;
+
+ } else if (new_events != context->events) {
+ /* Poll mask changed. Call uv_poll_start again. */
+ context->events = new_events;
+ uv_poll_start(handle, new_events, connection_poll_cb);
+ }
+
+ /* Assert that uv_is_active works correctly for poll handles. */
+ if (context->events != 0) {
+ ASSERT(1 == uv_is_active((uv_handle_t*) handle));
+ } else {
+ ASSERT(0 == uv_is_active((uv_handle_t*) handle));
+ }
+}
+
+
+static void delay_timer_cb(uv_timer_t* timer) {
+ connection_context_t* context = (connection_context_t*) timer->data;
+ int r;
+
+ /* Timer should auto stop. */
+ ASSERT(0 == uv_is_active((uv_handle_t*) timer));
+
+ /* Add the requested events to the poll mask. */
+ ASSERT(context->delayed_events != 0);
+ context->events |= context->delayed_events;
+ context->delayed_events = 0;
+
+ r = uv_poll_start(&context->poll_handle,
+ context->events,
+ connection_poll_cb);
+ ASSERT(r == 0);
+}
+
+
+static server_context_t* create_server_context(
+ uv_os_sock_t sock) {
+ int r;
+ server_context_t* context;
+
+ context = (server_context_t*) malloc(sizeof *context);
+ ASSERT(context != NULL);
+
+ context->sock = sock;
+ context->connections = 0;
+
+ r = uv_poll_init_socket(uv_default_loop(), &context->poll_handle, sock);
+ context->poll_handle.data = context;
+ ASSERT(r == 0);
+
+ return context;
+}
+
+
+static void server_close_cb(uv_handle_t* handle) {
+ server_context_t* context = (server_context_t*) handle->data;
+ free(context);
+}
+
+
+static void destroy_server_context(server_context_t* context) {
+ uv_close((uv_handle_t*) &context->poll_handle, server_close_cb);
+}
+
+
+static void server_poll_cb(uv_poll_t* handle, int status, int events) {
+ server_context_t* server_context = (server_context_t*)
+ handle->data;
+ connection_context_t* connection_context;
+ struct sockaddr_in addr;
+ socklen_t addr_len;
+ uv_os_sock_t sock;
+ int r;
+
+ addr_len = sizeof addr;
+ sock = accept(server_context->sock, (struct sockaddr*) &addr, &addr_len);
+#ifdef _WIN32
+ ASSERT(sock != INVALID_SOCKET);
+#else
+ ASSERT(sock >= 0);
+#endif
+
+ connection_context = create_connection_context(sock, 1);
+ connection_context->events = UV_READABLE | UV_WRITABLE;
+ r = uv_poll_start(&connection_context->poll_handle,
+ UV_READABLE | UV_WRITABLE,
+ connection_poll_cb);
+ ASSERT(r == 0);
+
+ if (++server_context->connections == NUM_CLIENTS) {
+ close_socket(server_context->sock);
+ destroy_server_context(server_context);
+ }
+}
+
+
+static void start_server(void) {
+ server_context_t* context;
+ struct sockaddr_in addr;
+ uv_os_sock_t sock;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ sock = create_bound_socket(addr);
+ context = create_server_context(sock);
+
+ r = listen(sock, 100);
+ ASSERT(r == 0);
+
+ r = uv_poll_start(&context->poll_handle, UV_READABLE, server_poll_cb);
+ ASSERT(r == 0);
+}
+
+
+static void start_client(void) {
+ uv_os_sock_t sock;
+ connection_context_t* context;
+ struct sockaddr_in server_addr;
+ struct sockaddr_in addr;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &addr));
+
+ sock = create_bound_socket(addr);
+ context = create_connection_context(sock, 0);
+
+ context->events = UV_READABLE | UV_WRITABLE;
+ r = uv_poll_start(&context->poll_handle,
+ UV_READABLE | UV_WRITABLE,
+ connection_poll_cb);
+ ASSERT(r == 0);
+
+ r = connect(sock, (struct sockaddr*) &server_addr, sizeof server_addr);
+ ASSERT(r == 0 || got_eagain());
+}
+
+
+static void start_poll_test(void) {
+ int i, r;
+
+#ifdef _WIN32
+ {
+ struct WSAData wsa_data;
+ int r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ ASSERT(r == 0);
+ }
+#endif
+
+ start_server();
+
+ for (i = 0; i < NUM_CLIENTS; i++)
+ start_client();
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ /* Assert that at most five percent of the writable wakeups was spurious. */
+ ASSERT(spurious_writable_wakeups == 0 ||
+ (valid_writable_wakeups + spurious_writable_wakeups) /
+ spurious_writable_wakeups > 20);
+
+ ASSERT(closed_connections == NUM_CLIENTS * 2);
+
+ MAKE_VALGRIND_HAPPY();
+}
+
+
+TEST_IMPL(poll_duplex) {
+ test_mode = DUPLEX;
+ start_poll_test();
+ return 0;
+}
+
+
+TEST_IMPL(poll_unidirectional) {
+ test_mode = UNIDIRECTIONAL;
+ start_poll_test();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-process-title.c b/3rdparty/libuv/test/test-process-title.c
new file mode 100644
index 00000000000..42ade441604
--- /dev/null
+++ b/3rdparty/libuv/test/test-process-title.c
@@ -0,0 +1,53 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <string.h>
+
+
+static void set_title(const char* title) {
+ char buffer[512];
+ int err;
+
+ err = uv_get_process_title(buffer, sizeof(buffer));
+ ASSERT(err == 0);
+
+ err = uv_set_process_title(title);
+ ASSERT(err == 0);
+
+ err = uv_get_process_title(buffer, sizeof(buffer));
+ ASSERT(err == 0);
+
+ ASSERT(strcmp(buffer, title) == 0);
+}
+
+
+TEST_IMPL(process_title) {
+#if defined(__sun) || defined(_AIX)
+ RETURN_SKIP("uv_(get|set)_process_title is not implemented.");
+#else
+ /* Check for format string vulnerabilities. */
+ set_title("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s");
+ set_title("new title");
+ return 0;
+#endif
+}
diff --git a/3rdparty/libuv/test/test-queue-foreach-delete.c b/3rdparty/libuv/test/test-queue-foreach-delete.c
new file mode 100644
index 00000000000..45da225381f
--- /dev/null
+++ b/3rdparty/libuv/test/test-queue-foreach-delete.c
@@ -0,0 +1,200 @@
+/* Copyright The libuv project and contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <string.h>
+
+
+/*
+ * The idea behind the test is as follows.
+ * Certain handle types are stored in a queue internally.
+ * Extra care should be taken for removal of a handle from the queue while iterating over the queue.
+ * (i.e., QUEUE_REMOVE() called within QUEUE_FOREACH())
+ * This usually happens when someone closes or stops a handle from within its callback.
+ * So we need to check that we haven't screwed the queue on close/stop.
+ * To do so we do the following (for each handle type):
+ * 1. Create and start 3 handles (#0, #1, and #2).
+ *
+ * The queue after the start() calls:
+ * ..=> [queue head] <=> [handle] <=> [handle #1] <=> [handle] <=..
+ *
+ * 2. Trigger handles to fire (for uv_idle_t, uv_prepare_t, and uv_check_t there is nothing to do).
+ *
+ * 3. In the callback for the first-executed handle (#0 or #2 depending on handle type)
+ * stop the handle and the next one (#1).
+ * (for uv_idle_t, uv_prepare_t, and uv_check_t callbacks are executed in the reverse order as they are start()'ed,
+ * so callback for handle #2 will be called first)
+ *
+ * The queue after the stop() calls:
+ * correct foreach "next" |
+ * \/
+ * ..=> [queue head] <==============================> [handle] <=..
+ * [ ] <- [handle] <=> [handle #1] -> [ ]
+ * /\
+ * wrong foreach "next" |
+ *
+ * 4. The callback for handle #1 shouldn't be called because the handle #1 is stopped in the previous step.
+ * However, if QUEUE_REMOVE() is not handled properly within QUEUE_FOREACH(), the callback _will_ be called.
+ */
+
+static const unsigned first_handle_number_idle = 2;
+static const unsigned first_handle_number_prepare = 2;
+static const unsigned first_handle_number_check = 2;
+#ifdef __linux__
+static const unsigned first_handle_number_fs_event = 0;
+#endif
+
+
+#define DEFINE_GLOBALS_AND_CBS(name) \
+ static uv_##name##_t (name)[3]; \
+ static unsigned name##_cb_calls[3]; \
+ \
+ static void name##2_cb(uv_##name##_t* handle) { \
+ ASSERT(handle == &(name)[2]); \
+ if (first_handle_number_##name == 2) { \
+ uv_close((uv_handle_t*)&(name)[2], NULL); \
+ uv_close((uv_handle_t*)&(name)[1], NULL); \
+ } \
+ name##_cb_calls[2]++; \
+ } \
+ \
+ static void name##1_cb(uv_##name##_t* handle) { \
+ ASSERT(handle == &(name)[1]); \
+ ASSERT(0 && "Shouldn't be called" && (&name[0])); \
+ } \
+ \
+ static void name##0_cb(uv_##name##_t* handle) { \
+ ASSERT(handle == &(name)[0]); \
+ if (first_handle_number_##name == 0) { \
+ uv_close((uv_handle_t*)&(name)[0], NULL); \
+ uv_close((uv_handle_t*)&(name)[1], NULL); \
+ } \
+ name##_cb_calls[0]++; \
+ } \
+ \
+ static const uv_##name##_cb name##_cbs[] = { \
+ (uv_##name##_cb)name##0_cb, \
+ (uv_##name##_cb)name##1_cb, \
+ (uv_##name##_cb)name##2_cb, \
+ };
+
+#define INIT_AND_START(name, loop) \
+ do { \
+ size_t i; \
+ for (i = 0; i < ARRAY_SIZE(name); i++) { \
+ int r; \
+ r = uv_##name##_init((loop), &(name)[i]); \
+ ASSERT(r == 0); \
+ \
+ r = uv_##name##_start(&(name)[i], name##_cbs[i]); \
+ ASSERT(r == 0); \
+ } \
+ } while (0)
+
+#define END_ASSERTS(name) \
+ do { \
+ ASSERT(name##_cb_calls[0] == 1); \
+ ASSERT(name##_cb_calls[1] == 0); \
+ ASSERT(name##_cb_calls[2] == 1); \
+ } while (0)
+
+DEFINE_GLOBALS_AND_CBS(idle)
+DEFINE_GLOBALS_AND_CBS(prepare)
+DEFINE_GLOBALS_AND_CBS(check)
+
+#ifdef __linux__
+DEFINE_GLOBALS_AND_CBS(fs_event)
+
+static const char watched_dir[] = ".";
+static uv_timer_t timer;
+static unsigned helper_timer_cb_calls;
+
+
+static void init_and_start_fs_events(uv_loop_t* loop) {
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(fs_event); i++) {
+ int r;
+ r = uv_fs_event_init(loop, &fs_event[i]);
+ ASSERT(r == 0);
+
+ r = uv_fs_event_start(&fs_event[i],
+ (uv_fs_event_cb)fs_event_cbs[i],
+ watched_dir,
+ 0);
+ ASSERT(r == 0);
+ }
+}
+
+static void helper_timer_cb(uv_timer_t* thandle) {
+ int r;
+ uv_fs_t fs_req;
+
+ /* fire all fs_events */
+ r = uv_fs_utime(thandle->loop, &fs_req, watched_dir, 0, 0, NULL);
+ ASSERT(r == 0);
+ ASSERT(fs_req.result == 0);
+ ASSERT(fs_req.fs_type == UV_FS_UTIME);
+ ASSERT(strcmp(fs_req.path, watched_dir) == 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ helper_timer_cb_calls++;
+}
+#endif
+
+
+TEST_IMPL(queue_foreach_delete) {
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+
+ INIT_AND_START(idle, loop);
+ INIT_AND_START(prepare, loop);
+ INIT_AND_START(check, loop);
+
+#ifdef __linux__
+ init_and_start_fs_events(loop);
+
+ /* helper timer to trigger async and fs_event callbacks */
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r == 0);
+
+ r = uv_timer_start(&timer, helper_timer_cb, 0, 0);
+ ASSERT(r == 0);
+#endif
+
+ r = uv_run(loop, UV_RUN_NOWAIT);
+ ASSERT(r == 1);
+
+ END_ASSERTS(idle);
+ END_ASSERTS(prepare);
+ END_ASSERTS(check);
+
+#ifdef __linux__
+ ASSERT(helper_timer_cb_calls == 1);
+#endif
+
+ MAKE_VALGRIND_HAPPY();
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-ref.c b/3rdparty/libuv/test/test-ref.c
new file mode 100644
index 00000000000..ddaa1738083
--- /dev/null
+++ b/3rdparty/libuv/test/test-ref.c
@@ -0,0 +1,442 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+
+static uv_write_t write_req;
+static uv_shutdown_t shutdown_req;
+static uv_connect_t connect_req;
+
+static char buffer[32767];
+
+static int req_cb_called;
+static int connect_cb_called;
+static int write_cb_called;
+static int shutdown_cb_called;
+static int close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void do_close(void* handle) {
+ close_cb_called = 0;
+ uv_close((uv_handle_t*)handle, close_cb);
+ ASSERT(close_cb_called == 0);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(close_cb_called == 1);
+}
+
+
+static void fail_cb(void) {
+ FATAL("fail_cb should not have been called");
+}
+
+
+static void fail_cb2(void) {
+ ASSERT(0 && "fail_cb2 should not have been called");
+}
+
+
+static void req_cb(uv_handle_t* req, int status) {
+ req_cb_called++;
+}
+
+
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+ ASSERT(req == &shutdown_req);
+ shutdown_cb_called++;
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(req == &write_req);
+ uv_shutdown(&shutdown_req, req->handle, shutdown_cb);
+ write_cb_called++;
+}
+
+
+static void connect_and_write(uv_connect_t* req, int status) {
+ uv_buf_t buf = uv_buf_init(buffer, sizeof buffer);
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+ uv_write(&write_req, req->handle, &buf, 1, write_cb);
+ connect_cb_called++;
+}
+
+
+
+static void connect_and_shutdown(uv_connect_t* req, int status) {
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+ uv_shutdown(&shutdown_req, req->handle, shutdown_cb);
+ connect_cb_called++;
+}
+
+
+TEST_IMPL(ref) {
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(idle_ref) {
+ uv_idle_t h;
+ uv_idle_init(uv_default_loop(), &h);
+ uv_idle_start(&h, (uv_idle_cb) fail_cb2);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(async_ref) {
+ uv_async_t h;
+ uv_async_init(uv_default_loop(), &h, NULL);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(prepare_ref) {
+ uv_prepare_t h;
+ uv_prepare_init(uv_default_loop(), &h);
+ uv_prepare_start(&h, (uv_prepare_cb) fail_cb2);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(check_ref) {
+ uv_check_t h;
+ uv_check_init(uv_default_loop(), &h);
+ uv_check_start(&h, (uv_check_cb) fail_cb2);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+static void prepare_cb(uv_prepare_t* h) {
+ ASSERT(h != NULL);
+ uv_unref((uv_handle_t*)h);
+}
+
+
+TEST_IMPL(unref_in_prepare_cb) {
+ uv_prepare_t h;
+ uv_prepare_init(uv_default_loop(), &h);
+ uv_prepare_start(&h, prepare_cb);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(timer_ref) {
+ uv_timer_t h;
+ uv_timer_init(uv_default_loop(), &h);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(timer_ref2) {
+ uv_timer_t h;
+ uv_timer_init(uv_default_loop(), &h);
+ uv_timer_start(&h, (uv_timer_cb)fail_cb, 42, 42);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_event_ref) {
+ uv_fs_event_t h;
+ uv_fs_event_init(uv_default_loop(), &h);
+ uv_fs_event_start(&h, (uv_fs_event_cb)fail_cb, ".", 0);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(fs_poll_ref) {
+ uv_fs_poll_t h;
+ uv_fs_poll_init(uv_default_loop(), &h);
+ uv_fs_poll_start(&h, NULL, ".", 999);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_ref) {
+ uv_tcp_t h;
+ uv_tcp_init(uv_default_loop(), &h);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_ref2) {
+ uv_tcp_t h;
+ uv_tcp_init(uv_default_loop(), &h);
+ uv_listen((uv_stream_t*)&h, 128, (uv_connection_cb)fail_cb);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_ref2b) {
+ uv_tcp_t h;
+ uv_tcp_init(uv_default_loop(), &h);
+ uv_listen((uv_stream_t*)&h, 128, (uv_connection_cb)fail_cb);
+ uv_unref((uv_handle_t*)&h);
+ uv_close((uv_handle_t*)&h, close_cb);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(close_cb_called == 1);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_ref3) {
+ struct sockaddr_in addr;
+ uv_tcp_t h;
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ uv_tcp_init(uv_default_loop(), &h);
+ uv_tcp_connect(&connect_req,
+ &h,
+ (const struct sockaddr*) &addr,
+ connect_and_shutdown);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(connect_cb_called == 1);
+ ASSERT(shutdown_cb_called == 1);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_ref4) {
+ struct sockaddr_in addr;
+ uv_tcp_t h;
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ uv_tcp_init(uv_default_loop(), &h);
+ uv_tcp_connect(&connect_req,
+ &h,
+ (const struct sockaddr*) &addr,
+ connect_and_write);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(connect_cb_called == 1);
+ ASSERT(write_cb_called == 1);
+ ASSERT(shutdown_cb_called == 1);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(udp_ref) {
+ uv_udp_t h;
+ uv_udp_init(uv_default_loop(), &h);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(udp_ref2) {
+ struct sockaddr_in addr;
+ uv_udp_t h;
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ uv_udp_init(uv_default_loop(), &h);
+ uv_udp_bind(&h, (const struct sockaddr*) &addr, 0);
+ uv_udp_recv_start(&h, (uv_alloc_cb)fail_cb, (uv_udp_recv_cb)fail_cb);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(udp_ref3) {
+ struct sockaddr_in addr;
+ uv_buf_t buf = uv_buf_init("PING", 4);
+ uv_udp_send_t req;
+ uv_udp_t h;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ uv_udp_init(uv_default_loop(), &h);
+ uv_udp_send(&req,
+ &h,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ (uv_udp_send_cb) req_cb);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(req_cb_called == 1);
+ do_close(&h);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(pipe_ref) {
+ uv_pipe_t h;
+ uv_pipe_init(uv_default_loop(), &h, 0);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(pipe_ref2) {
+ uv_pipe_t h;
+ uv_pipe_init(uv_default_loop(), &h, 0);
+ uv_listen((uv_stream_t*)&h, 128, (uv_connection_cb)fail_cb);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(pipe_ref3) {
+ uv_pipe_t h;
+ uv_pipe_init(uv_default_loop(), &h, 0);
+ uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_and_shutdown);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(connect_cb_called == 1);
+ ASSERT(shutdown_cb_called == 1);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(pipe_ref4) {
+ uv_pipe_t h;
+ uv_pipe_init(uv_default_loop(), &h, 0);
+ uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_and_write);
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(connect_cb_called == 1);
+ ASSERT(write_cb_called == 1);
+ ASSERT(shutdown_cb_called == 1);
+ do_close(&h);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(process_ref) {
+ /* spawn_helper4 blocks indefinitely. */
+ char *argv[] = { NULL, "spawn_helper4", NULL };
+ uv_process_options_t options;
+ size_t exepath_size;
+ char exepath[256];
+ uv_process_t h;
+ int r;
+
+ memset(&options, 0, sizeof(options));
+ exepath_size = sizeof(exepath);
+
+ r = uv_exepath(exepath, &exepath_size);
+ ASSERT(r == 0);
+
+ argv[0] = exepath;
+ options.file = exepath;
+ options.args = argv;
+ options.exit_cb = NULL;
+
+ r = uv_spawn(uv_default_loop(), &h, &options);
+ ASSERT(r == 0);
+
+ uv_unref((uv_handle_t*)&h);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ r = uv_process_kill(&h, /* SIGTERM */ 15);
+ ASSERT(r == 0);
+
+ do_close(&h);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(has_ref) {
+ uv_idle_t h;
+ uv_idle_init(uv_default_loop(), &h);
+ uv_ref((uv_handle_t*)&h);
+ ASSERT(uv_has_ref((uv_handle_t*)&h) == 1);
+ uv_unref((uv_handle_t*)&h);
+ ASSERT(uv_has_ref((uv_handle_t*)&h) == 0);
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-run-nowait.c b/3rdparty/libuv/test/test-run-nowait.c
new file mode 100644
index 00000000000..43524f636d8
--- /dev/null
+++ b/3rdparty/libuv/test/test-run-nowait.c
@@ -0,0 +1,45 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_timer_t timer_handle;
+static int timer_called = 0;
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(handle == &timer_handle);
+ timer_called = 1;
+}
+
+
+TEST_IMPL(run_nowait) {
+ int r;
+ uv_timer_init(uv_default_loop(), &timer_handle);
+ uv_timer_start(&timer_handle, timer_cb, 100, 100);
+
+ r = uv_run(uv_default_loop(), UV_RUN_NOWAIT);
+ ASSERT(r != 0);
+ ASSERT(timer_called == 0);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-run-once.c b/3rdparty/libuv/test/test-run-once.c
new file mode 100644
index 00000000000..10cbf95e4ad
--- /dev/null
+++ b/3rdparty/libuv/test/test-run-once.c
@@ -0,0 +1,48 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#define NUM_TICKS 64
+
+static uv_idle_t idle_handle;
+static int idle_counter;
+
+
+static void idle_cb(uv_idle_t* handle) {
+ ASSERT(handle == &idle_handle);
+
+ if (++idle_counter == NUM_TICKS)
+ uv_idle_stop(handle);
+}
+
+
+TEST_IMPL(run_once) {
+ uv_idle_init(uv_default_loop(), &idle_handle);
+ uv_idle_start(&idle_handle, idle_cb);
+
+ while (uv_run(uv_default_loop(), UV_RUN_ONCE));
+ ASSERT(idle_counter == NUM_TICKS);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-semaphore.c b/3rdparty/libuv/test/test-semaphore.c
new file mode 100644
index 00000000000..ac03bb08f17
--- /dev/null
+++ b/3rdparty/libuv/test/test-semaphore.c
@@ -0,0 +1,111 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+ uv_mutex_t mutex;
+ uv_sem_t sem;
+ int delay;
+ volatile int posted;
+} worker_config;
+
+
+static void worker(void* arg) {
+ worker_config* c = arg;
+
+ if (c->delay)
+ uv_sleep(c->delay);
+
+ uv_mutex_lock(&c->mutex);
+ ASSERT(c->posted == 0);
+ uv_sem_post(&c->sem);
+ c->posted = 1;
+ uv_mutex_unlock(&c->mutex);
+}
+
+
+TEST_IMPL(semaphore_1) {
+ uv_thread_t thread;
+ worker_config wc;
+
+ memset(&wc, 0, sizeof(wc));
+
+ ASSERT(0 == uv_sem_init(&wc.sem, 0));
+ ASSERT(0 == uv_mutex_init(&wc.mutex));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ uv_sleep(100);
+ uv_mutex_lock(&wc.mutex);
+ ASSERT(wc.posted == 1);
+ uv_sem_wait(&wc.sem); /* should not block */
+ uv_mutex_unlock(&wc.mutex); /* ergo, it should be ok to unlock after wait */
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_mutex_destroy(&wc.mutex);
+ uv_sem_destroy(&wc.sem);
+
+ return 0;
+}
+
+
+TEST_IMPL(semaphore_2) {
+ uv_thread_t thread;
+ worker_config wc;
+
+ memset(&wc, 0, sizeof(wc));
+ wc.delay = 100;
+
+ ASSERT(0 == uv_sem_init(&wc.sem, 0));
+ ASSERT(0 == uv_mutex_init(&wc.mutex));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ uv_sem_wait(&wc.sem);
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_mutex_destroy(&wc.mutex);
+ uv_sem_destroy(&wc.sem);
+
+ return 0;
+}
+
+
+TEST_IMPL(semaphore_3) {
+ uv_sem_t sem;
+
+ ASSERT(0 == uv_sem_init(&sem, 3));
+ uv_sem_wait(&sem); /* should not block */
+ uv_sem_wait(&sem); /* should not block */
+ ASSERT(0 == uv_sem_trywait(&sem));
+ ASSERT(UV_EAGAIN == uv_sem_trywait(&sem));
+
+ uv_sem_post(&sem);
+ ASSERT(0 == uv_sem_trywait(&sem));
+ ASSERT(UV_EAGAIN == uv_sem_trywait(&sem));
+
+ uv_sem_destroy(&sem);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-shutdown-close.c b/3rdparty/libuv/test/test-shutdown-close.c
new file mode 100644
index 00000000000..78c369be2d9
--- /dev/null
+++ b/3rdparty/libuv/test/test-shutdown-close.c
@@ -0,0 +1,108 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/*
+ * These tests verify that the uv_shutdown callback is always made, even when
+ * it is immediately followed by an uv_close call.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+static uv_shutdown_t shutdown_req;
+static uv_connect_t connect_req;
+
+static int connect_cb_called = 0;
+static int shutdown_cb_called = 0;
+static int close_cb_called = 0;
+
+
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+ ASSERT(req == &shutdown_req);
+ ASSERT(status == 0 || status == UV_ECANCELED);
+ shutdown_cb_called++;
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ int r;
+
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+
+ r = uv_shutdown(&shutdown_req, req->handle, shutdown_cb);
+ ASSERT(r == 0);
+ ASSERT(0 == uv_is_closing((uv_handle_t*) req->handle));
+ uv_close((uv_handle_t*) req->handle, close_cb);
+ ASSERT(1 == uv_is_closing((uv_handle_t*) req->handle));
+
+ connect_cb_called++;
+}
+
+
+TEST_IMPL(shutdown_close_tcp) {
+ struct sockaddr_in addr;
+ uv_tcp_t h;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ r = uv_tcp_init(uv_default_loop(), &h);
+ ASSERT(r == 0);
+ r = uv_tcp_connect(&connect_req,
+ &h,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(shutdown_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(shutdown_close_pipe) {
+ uv_pipe_t h;
+ int r;
+
+ r = uv_pipe_init(uv_default_loop(), &h, 0);
+ ASSERT(r == 0);
+ uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_cb);
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(shutdown_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-shutdown-eof.c b/3rdparty/libuv/test/test-shutdown-eof.c
new file mode 100644
index 00000000000..9f95e7561f2
--- /dev/null
+++ b/3rdparty/libuv/test/test-shutdown-eof.c
@@ -0,0 +1,182 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+static uv_timer_t timer;
+static uv_tcp_t tcp;
+static uv_connect_t connect_req;
+static uv_write_t write_req;
+static uv_shutdown_t shutdown_req;
+static uv_buf_t qbuf;
+static int got_q;
+static int got_eof;
+static int called_connect_cb;
+static int called_shutdown_cb;
+static int called_tcp_close_cb;
+static int called_timer_close_cb;
+static int called_timer_cb;
+
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ buf->base = malloc(size);
+ buf->len = size;
+}
+
+
+static void read_cb(uv_stream_t* t, ssize_t nread, const uv_buf_t* buf) {
+ ASSERT((uv_tcp_t*)t == &tcp);
+
+ if (nread == 0) {
+ free(buf->base);
+ return;
+ }
+
+ if (!got_q) {
+ ASSERT(nread == 1);
+ ASSERT(!got_eof);
+ ASSERT(buf->base[0] == 'Q');
+ free(buf->base);
+ got_q = 1;
+ puts("got Q");
+ } else {
+ ASSERT(nread == UV_EOF);
+ if (buf->base) {
+ free(buf->base);
+ }
+ got_eof = 1;
+ puts("got EOF");
+ }
+}
+
+
+static void shutdown_cb(uv_shutdown_t *req, int status) {
+ ASSERT(req == &shutdown_req);
+
+ ASSERT(called_connect_cb == 1);
+ ASSERT(!got_eof);
+ ASSERT(called_tcp_close_cb == 0);
+ ASSERT(called_timer_close_cb == 0);
+ ASSERT(called_timer_cb == 0);
+
+ called_shutdown_cb++;
+}
+
+
+static void connect_cb(uv_connect_t *req, int status) {
+ ASSERT(status == 0);
+ ASSERT(req == &connect_req);
+
+ /* Start reading from our connection so we can receive the EOF. */
+ uv_read_start((uv_stream_t*)&tcp, alloc_cb, read_cb);
+
+ /*
+ * Write the letter 'Q' to gracefully kill the echo-server. This will not
+ * effect our connection.
+ */
+ uv_write(&write_req, (uv_stream_t*) &tcp, &qbuf, 1, NULL);
+
+ /* Shutdown our end of the connection. */
+ uv_shutdown(&shutdown_req, (uv_stream_t*) &tcp, shutdown_cb);
+
+ called_connect_cb++;
+ ASSERT(called_shutdown_cb == 0);
+}
+
+
+static void tcp_close_cb(uv_handle_t* handle) {
+ ASSERT(handle == (uv_handle_t*) &tcp);
+
+ ASSERT(called_connect_cb == 1);
+ ASSERT(got_q);
+ ASSERT(got_eof);
+ ASSERT(called_timer_cb == 1);
+
+ called_tcp_close_cb++;
+}
+
+
+static void timer_close_cb(uv_handle_t* handle) {
+ ASSERT(handle == (uv_handle_t*) &timer);
+ called_timer_close_cb++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(handle == &timer);
+ uv_close((uv_handle_t*) handle, timer_close_cb);
+
+ /*
+ * The most important assert of the test: we have not received
+ * tcp_close_cb yet.
+ */
+ ASSERT(called_tcp_close_cb == 0);
+ uv_close((uv_handle_t*) &tcp, tcp_close_cb);
+
+ called_timer_cb++;
+}
+
+
+/*
+ * This test has a client which connects to the echo_server and immediately
+ * issues a shutdown. The echo-server, in response, will also shutdown their
+ * connection. We check, with a timer, that libuv is not automatically
+ * calling uv_close when the client receives the EOF from echo-server.
+ */
+TEST_IMPL(shutdown_eof) {
+ struct sockaddr_in server_addr;
+ int r;
+
+ qbuf.base = "Q";
+ qbuf.len = 1;
+
+ r = uv_timer_init(uv_default_loop(), &timer);
+ ASSERT(r == 0);
+
+ uv_timer_start(&timer, timer_cb, 100, 0);
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
+ r = uv_tcp_init(uv_default_loop(), &tcp);
+ ASSERT(!r);
+
+ r = uv_tcp_connect(&connect_req,
+ &tcp,
+ (const struct sockaddr*) &server_addr,
+ connect_cb);
+ ASSERT(!r);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(called_connect_cb == 1);
+ ASSERT(called_shutdown_cb == 1);
+ ASSERT(got_eof);
+ ASSERT(got_q);
+ ASSERT(called_tcp_close_cb == 1);
+ ASSERT(called_timer_close_cb == 1);
+ ASSERT(called_timer_cb == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
diff --git a/3rdparty/libuv/test/test-shutdown-twice.c b/3rdparty/libuv/test/test-shutdown-twice.c
new file mode 100644
index 00000000000..75c05435499
--- /dev/null
+++ b/3rdparty/libuv/test/test-shutdown-twice.c
@@ -0,0 +1,84 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/*
+ * This is a regression test for issue #1113 (calling uv_shutdown twice will
+ * leave a ghost request in the system)
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_shutdown_t req1;
+static uv_shutdown_t req2;
+
+static int shutdown_cb_called = 0;
+
+static void close_cb(uv_handle_t* handle) {
+
+}
+
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+ ASSERT(req == &req1);
+ ASSERT(status == 0);
+ shutdown_cb_called++;
+ uv_close((uv_handle_t*) req->handle, close_cb);
+}
+
+static void connect_cb(uv_connect_t* req, int status) {
+ int r;
+
+ ASSERT(status == 0);
+
+ r = uv_shutdown(&req1, req->handle, shutdown_cb);
+ ASSERT(r == 0);
+ r = uv_shutdown(&req2, req->handle, shutdown_cb);
+ ASSERT(r != 0);
+
+}
+
+TEST_IMPL(shutdown_twice) {
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+ int r;
+ uv_tcp_t h;
+
+ uv_connect_t connect_req;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ loop = uv_default_loop();
+
+ r = uv_tcp_init(loop, &h);
+
+ r = uv_tcp_connect(&connect_req,
+ &h,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(shutdown_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-signal-multiple-loops.c b/3rdparty/libuv/test/test-signal-multiple-loops.c
new file mode 100644
index 00000000000..158129919bd
--- /dev/null
+++ b/3rdparty/libuv/test/test-signal-multiple-loops.c
@@ -0,0 +1,290 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+/* This test does not pretend to be cross-platform. */
+#ifndef _WIN32
+
+#include "uv.h"
+#include "task.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* The value of NUM_SIGNAL_HANDLING_THREADS is not arbitrary; it needs to be a
+ * multiple of three for reasons that will become clear when you scroll down.
+ * We're basically creating three different thread groups. The total needs
+ * to be divisible by three in order for the numbers in the final check to
+ * match up.
+ */
+#define NUM_SIGNAL_HANDLING_THREADS 24
+#define NUM_LOOP_CREATING_THREADS 10
+
+enum signal_action {
+ ONLY_SIGUSR1,
+ ONLY_SIGUSR2,
+ SIGUSR1_AND_SIGUSR2
+};
+
+static uv_sem_t sem;
+static uv_mutex_t counter_lock;
+static volatile int stop = 0;
+
+static volatile int signal1_cb_counter = 0;
+static volatile int signal2_cb_counter = 0;
+static volatile int loop_creation_counter = 0;
+
+
+static void increment_counter(volatile int* counter) {
+ uv_mutex_lock(&counter_lock);
+ ++(*counter);
+ uv_mutex_unlock(&counter_lock);
+}
+
+
+static void signal1_cb(uv_signal_t* handle, int signum) {
+ ASSERT(signum == SIGUSR1);
+ increment_counter(&signal1_cb_counter);
+ uv_signal_stop(handle);
+}
+
+
+static void signal2_cb(uv_signal_t* handle, int signum) {
+ ASSERT(signum == SIGUSR2);
+ increment_counter(&signal2_cb_counter);
+ uv_signal_stop(handle);
+}
+
+
+static void signal_handling_worker(void* context) {
+ enum signal_action action;
+ uv_signal_t signal1a;
+ uv_signal_t signal1b;
+ uv_signal_t signal2;
+ uv_loop_t loop;
+ int r;
+
+ action = (enum signal_action) (uintptr_t) context;
+
+ ASSERT(0 == uv_loop_init(&loop));
+
+ /* Setup the signal watchers and start them. */
+ if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) {
+ r = uv_signal_init(&loop, &signal1a);
+ ASSERT(r == 0);
+ r = uv_signal_start(&signal1a, signal1_cb, SIGUSR1);
+ ASSERT(r == 0);
+ r = uv_signal_init(&loop, &signal1b);
+ ASSERT(r == 0);
+ r = uv_signal_start(&signal1b, signal1_cb, SIGUSR1);
+ ASSERT(r == 0);
+ }
+
+ if (action == ONLY_SIGUSR2 || action == SIGUSR1_AND_SIGUSR2) {
+ r = uv_signal_init(&loop, &signal2);
+ ASSERT(r == 0);
+ r = uv_signal_start(&signal2, signal2_cb, SIGUSR2);
+ ASSERT(r == 0);
+ }
+
+ /* Signal watchers are now set up. */
+ uv_sem_post(&sem);
+
+ /* Wait for all signals. The signal callbacks stop the watcher, so uv_run
+ * will return when all signal watchers caught a signal.
+ */
+ r = uv_run(&loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ /* Restart the signal watchers. */
+ if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) {
+ r = uv_signal_start(&signal1a, signal1_cb, SIGUSR1);
+ ASSERT(r == 0);
+ r = uv_signal_start(&signal1b, signal1_cb, SIGUSR1);
+ ASSERT(r == 0);
+ }
+
+ if (action == ONLY_SIGUSR2 || action == SIGUSR1_AND_SIGUSR2) {
+ r = uv_signal_start(&signal2, signal2_cb, SIGUSR2);
+ ASSERT(r == 0);
+ }
+
+ /* Wait for signals once more. */
+ uv_sem_post(&sem);
+
+ r = uv_run(&loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ /* Close the watchers. */
+ if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) {
+ uv_close((uv_handle_t*) &signal1a, NULL);
+ uv_close((uv_handle_t*) &signal1b, NULL);
+ }
+
+ if (action == ONLY_SIGUSR2 || action == SIGUSR1_AND_SIGUSR2) {
+ uv_close((uv_handle_t*) &signal2, NULL);
+ }
+
+ /* Wait for the signal watchers to close. */
+ r = uv_run(&loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ uv_loop_close(&loop);
+}
+
+
+static void signal_unexpected_cb(uv_signal_t* handle, int signum) {
+ ASSERT(0 && "signal_unexpected_cb should never be called");
+}
+
+
+static void loop_creating_worker(void* context) {
+ (void) context;
+
+ do {
+ uv_loop_t *loop;
+ uv_signal_t signal;
+ int r;
+
+ loop = malloc(sizeof(*loop));
+ ASSERT(loop != NULL);
+ ASSERT(0 == uv_loop_init(loop));
+
+ r = uv_signal_init(loop, &signal);
+ ASSERT(r == 0);
+
+ r = uv_signal_start(&signal, signal_unexpected_cb, SIGTERM);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*) &signal, NULL);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ uv_loop_close(loop);
+ free(loop);
+
+ increment_counter(&loop_creation_counter);
+ } while (!stop);
+}
+
+
+TEST_IMPL(signal_multiple_loops) {
+ uv_thread_t loop_creating_threads[NUM_LOOP_CREATING_THREADS];
+ uv_thread_t signal_handling_threads[NUM_SIGNAL_HANDLING_THREADS];
+ enum signal_action action;
+ sigset_t sigset;
+ int i;
+ int r;
+
+ r = uv_sem_init(&sem, 0);
+ ASSERT(r == 0);
+
+ r = uv_mutex_init(&counter_lock);
+ ASSERT(r == 0);
+
+ /* Create a couple of threads that create a destroy loops continuously. */
+ for (i = 0; i < NUM_LOOP_CREATING_THREADS; i++) {
+ r = uv_thread_create(&loop_creating_threads[i],
+ loop_creating_worker,
+ NULL);
+ ASSERT(r == 0);
+ }
+
+ /* Create a couple of threads that actually handle signals. */
+ for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++) {
+ switch (i % 3) {
+ case 0: action = ONLY_SIGUSR1; break;
+ case 1: action = ONLY_SIGUSR2; break;
+ case 2: action = SIGUSR1_AND_SIGUSR2; break;
+ }
+
+ r = uv_thread_create(&signal_handling_threads[i],
+ signal_handling_worker,
+ (void*) (uintptr_t) action);
+ ASSERT(r == 0);
+ }
+
+ /* Wait until all threads have started and set up their signal watchers. */
+ for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++)
+ uv_sem_wait(&sem);
+
+ r = kill(getpid(), SIGUSR1);
+ ASSERT(r == 0);
+ r = kill(getpid(), SIGUSR2);
+ ASSERT(r == 0);
+
+ /* Wait for all threads to handle these signals. */
+ for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++)
+ uv_sem_wait(&sem);
+
+ /* Block all signals to this thread, so we are sure that from here the signal
+ * handler runs in another thread. This is is more likely to catch thread and
+ * signal safety issues if there are any.
+ */
+ sigfillset(&sigset);
+ pthread_sigmask(SIG_SETMASK, &sigset, NULL);
+
+ r = kill(getpid(), SIGUSR1);
+ ASSERT(r == 0);
+ r = kill(getpid(), SIGUSR2);
+ ASSERT(r == 0);
+
+ /* Wait for all signal handling threads to exit. */
+ for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++) {
+ r = uv_thread_join(&signal_handling_threads[i]);
+ ASSERT(r == 0);
+ }
+
+ /* Tell all loop creating threads to stop. */
+ stop = 1;
+
+ /* Wait for all loop creating threads to exit. */
+ for (i = 0; i < NUM_LOOP_CREATING_THREADS; i++) {
+ r = uv_thread_join(&loop_creating_threads[i]);
+ ASSERT(r == 0);
+ }
+
+ printf("signal1_cb calls: %d\n", signal1_cb_counter);
+ printf("signal2_cb calls: %d\n", signal2_cb_counter);
+ printf("loops created and destroyed: %d\n", loop_creation_counter);
+
+ /* The division by three reflects the fact that we spawn three different
+ * thread groups of (NUM_SIGNAL_HANDLING_THREADS / 3) threads each.
+ */
+ ASSERT(signal1_cb_counter == 8 * (NUM_SIGNAL_HANDLING_THREADS / 3));
+ ASSERT(signal2_cb_counter == 4 * (NUM_SIGNAL_HANDLING_THREADS / 3));
+
+ /* We don't know exactly how much loops will be created and destroyed, but at
+ * least there should be 1 for every loop creating thread.
+ */
+ ASSERT(loop_creation_counter >= NUM_LOOP_CREATING_THREADS);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* !_WIN32 */
diff --git a/3rdparty/libuv/test/test-signal.c b/3rdparty/libuv/test/test-signal.c
new file mode 100644
index 00000000000..fcdd8e4d2dd
--- /dev/null
+++ b/3rdparty/libuv/test/test-signal.c
@@ -0,0 +1,152 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+/* This test does not pretend to be cross-platform. */
+#ifndef _WIN32
+
+#include "uv.h"
+#include "task.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define NSIGNALS 10
+
+struct timer_ctx {
+ unsigned int ncalls;
+ uv_timer_t handle;
+ int signum;
+};
+
+struct signal_ctx {
+ enum { CLOSE, STOP } stop_or_close;
+ unsigned int ncalls;
+ uv_signal_t handle;
+ int signum;
+};
+
+
+static void signal_cb(uv_signal_t* handle, int signum) {
+ struct signal_ctx* ctx = container_of(handle, struct signal_ctx, handle);
+ ASSERT(signum == ctx->signum);
+
+ if (++ctx->ncalls == NSIGNALS) {
+ if (ctx->stop_or_close == STOP)
+ uv_signal_stop(handle);
+ else if (ctx->stop_or_close == CLOSE)
+ uv_close((uv_handle_t*)handle, NULL);
+ else
+ ASSERT(0);
+ }
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ struct timer_ctx* ctx = container_of(handle, struct timer_ctx, handle);
+
+ raise(ctx->signum);
+
+ if (++ctx->ncalls == NSIGNALS)
+ uv_close((uv_handle_t*)handle, NULL);
+}
+
+
+static void start_watcher(uv_loop_t* loop, int signum, struct signal_ctx* ctx) {
+ ctx->ncalls = 0;
+ ctx->signum = signum;
+ ctx->stop_or_close = CLOSE;
+ ASSERT(0 == uv_signal_init(loop, &ctx->handle));
+ ASSERT(0 == uv_signal_start(&ctx->handle, signal_cb, signum));
+}
+
+
+static void start_timer(uv_loop_t* loop, int signum, struct timer_ctx* ctx) {
+ ctx->ncalls = 0;
+ ctx->signum = signum;
+ ASSERT(0 == uv_timer_init(loop, &ctx->handle));
+ ASSERT(0 == uv_timer_start(&ctx->handle, timer_cb, 5, 5));
+}
+
+
+TEST_IMPL(we_get_signal) {
+ struct signal_ctx sc;
+ struct timer_ctx tc;
+ uv_loop_t* loop;
+
+ loop = uv_default_loop();
+ start_timer(loop, SIGCHLD, &tc);
+ start_watcher(loop, SIGCHLD, &sc);
+ sc.stop_or_close = STOP; /* stop, don't close the signal handle */
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(tc.ncalls == NSIGNALS);
+ ASSERT(sc.ncalls == NSIGNALS);
+
+ start_timer(loop, SIGCHLD, &tc);
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(tc.ncalls == NSIGNALS);
+ ASSERT(sc.ncalls == NSIGNALS);
+
+ sc.ncalls = 0;
+ sc.stop_or_close = CLOSE; /* now close it when it's done */
+ uv_signal_start(&sc.handle, signal_cb, SIGCHLD);
+
+ start_timer(loop, SIGCHLD, &tc);
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(tc.ncalls == NSIGNALS);
+ ASSERT(sc.ncalls == NSIGNALS);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(we_get_signals) {
+ struct signal_ctx sc[4];
+ struct timer_ctx tc[2];
+ uv_loop_t* loop;
+ unsigned int i;
+
+ loop = uv_default_loop();
+ start_watcher(loop, SIGUSR1, sc + 0);
+ start_watcher(loop, SIGUSR1, sc + 1);
+ start_watcher(loop, SIGUSR2, sc + 2);
+ start_watcher(loop, SIGUSR2, sc + 3);
+ start_timer(loop, SIGUSR1, tc + 0);
+ start_timer(loop, SIGUSR2, tc + 1);
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ for (i = 0; i < ARRAY_SIZE(sc); i++)
+ ASSERT(sc[i].ncalls == NSIGNALS);
+
+ for (i = 0; i < ARRAY_SIZE(tc); i++)
+ ASSERT(tc[i].ncalls == NSIGNALS);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* _WIN32 */
diff --git a/3rdparty/libuv/test/test-socket-buffer-size.c b/3rdparty/libuv/test/test-socket-buffer-size.c
new file mode 100644
index 00000000000..72f8c2524c0
--- /dev/null
+++ b/3rdparty/libuv/test/test-socket-buffer-size.c
@@ -0,0 +1,77 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static uv_udp_t udp;
+static uv_tcp_t tcp;
+static int close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void check_buffer_size(uv_handle_t* handle) {
+ int value;
+
+ value = 0;
+ ASSERT(0 == uv_recv_buffer_size(handle, &value));
+ ASSERT(value > 0);
+
+ value = 10000;
+ ASSERT(0 == uv_recv_buffer_size(handle, &value));
+
+ value = 0;
+ ASSERT(0 == uv_recv_buffer_size(handle, &value));
+ /* linux sets double the value */
+ ASSERT(value == 10000 || value == 20000);
+}
+
+
+TEST_IMPL(socket_buffer_size) {
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ ASSERT(0 == uv_tcp_init(uv_default_loop(), &tcp));
+ ASSERT(0 == uv_tcp_bind(&tcp, (struct sockaddr*) &addr, 0));
+ check_buffer_size((uv_handle_t*) &tcp);
+ uv_close((uv_handle_t*) &tcp, close_cb);
+
+ ASSERT(0 == uv_udp_init(uv_default_loop(), &udp));
+ ASSERT(0 == uv_udp_bind(&udp, (struct sockaddr*) &addr, 0));
+ check_buffer_size((uv_handle_t*) &udp);
+ uv_close((uv_handle_t*) &udp, close_cb);
+
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-spawn.c b/3rdparty/libuv/test/test-spawn.c
new file mode 100644
index 00000000000..eba54ae7054
--- /dev/null
+++ b/3rdparty/libuv/test/test-spawn.c
@@ -0,0 +1,1706 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _WIN32
+# if defined(__MINGW32__)
+# include <basetyps.h>
+# endif
+# include <shellapi.h>
+# include <wchar.h>
+#else
+# include <unistd.h>
+# include <sys/wait.h>
+#endif
+
+
+static int close_cb_called;
+static int exit_cb_called;
+static uv_process_t process;
+static uv_timer_t timer;
+static uv_process_options_t options;
+static char exepath[1024];
+static size_t exepath_size = 1024;
+static char* args[3];
+static int no_term_signal;
+static int timer_counter;
+
+#define OUTPUT_SIZE 1024
+static char output[OUTPUT_SIZE];
+static int output_used;
+
+
+static void close_cb(uv_handle_t* handle) {
+ printf("close_cb\n");
+ close_cb_called++;
+}
+
+static void exit_cb(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ printf("exit_cb\n");
+ exit_cb_called++;
+ ASSERT(exit_status == 1);
+ ASSERT(term_signal == 0);
+ uv_close((uv_handle_t*)process, close_cb);
+}
+
+
+static void fail_cb(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ ASSERT(0 && "fail_cb called");
+}
+
+
+static void kill_cb(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ int err;
+
+ printf("exit_cb\n");
+ exit_cb_called++;
+#ifdef _WIN32
+ ASSERT(exit_status == 1);
+#else
+ ASSERT(exit_status == 0);
+#endif
+ ASSERT(no_term_signal || term_signal == 15);
+ uv_close((uv_handle_t*)process, close_cb);
+
+ /*
+ * Sending signum == 0 should check if the
+ * child process is still alive, not kill it.
+ * This process should be dead.
+ */
+ err = uv_kill(process->pid, 0);
+ ASSERT(err == UV_ESRCH);
+}
+
+static void detach_failure_cb(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ printf("detach_cb\n");
+ exit_cb_called++;
+}
+
+static void on_alloc(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ buf->base = output + output_used;
+ buf->len = OUTPUT_SIZE - output_used;
+}
+
+
+static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ if (nread > 0) {
+ output_used += nread;
+ } else if (nread < 0) {
+ ASSERT(nread == UV_EOF);
+ uv_close((uv_handle_t*)tcp, close_cb);
+ }
+}
+
+
+static void on_read_once(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ uv_read_stop(tcp);
+ on_read(tcp, nread, buf);
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+ uv_close((uv_handle_t*)req->handle, close_cb);
+}
+
+
+static void init_process_options(char* test, uv_exit_cb exit_cb) {
+ /* Note spawn_helper1 defined in test/run-tests.c */
+ int r = uv_exepath(exepath, &exepath_size);
+ ASSERT(r == 0);
+ exepath[exepath_size] = '\0';
+ args[0] = exepath;
+ args[1] = test;
+ args[2] = NULL;
+ options.file = exepath;
+ options.args = args;
+ options.exit_cb = exit_cb;
+ options.flags = 0;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ uv_process_kill(&process, /* SIGTERM */ 15);
+ uv_close((uv_handle_t*)handle, close_cb);
+}
+
+
+static void timer_counter_cb(uv_timer_t* handle) {
+ ++timer_counter;
+}
+
+
+TEST_IMPL(spawn_fails) {
+ int r;
+
+ init_process_options("", fail_cb);
+ options.file = options.args[0] = "program-that-had-better-not-exist";
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == UV_ENOENT || r == UV_EACCES);
+ ASSERT(0 == uv_is_active((uv_handle_t*) &process));
+ uv_close((uv_handle_t*) &process, NULL);
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+#ifndef _WIN32
+TEST_IMPL(spawn_fails_check_for_waitpid_cleanup) {
+ int r;
+ int status;
+ int err;
+
+ init_process_options("", fail_cb);
+ options.file = options.args[0] = "program-that-had-better-not-exist";
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == UV_ENOENT || r == UV_EACCES);
+ ASSERT(0 == uv_is_active((uv_handle_t*) &process));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ /* verify the child is successfully cleaned up within libuv */
+ do
+ err = waitpid(process.pid, &status, 0);
+ while (err == -1 && errno == EINTR);
+
+ ASSERT(err == -1);
+ ASSERT(errno == ECHILD);
+
+ uv_close((uv_handle_t*) &process, NULL);
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif
+
+
+TEST_IMPL(spawn_exit_code) {
+ int r;
+
+ init_process_options("spawn_helper1", exit_cb);
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_stdout) {
+ int r;
+ uv_pipe_t out;
+ uv_stdio_container_t stdio[2];
+
+ init_process_options("spawn_helper2", exit_cb);
+
+ uv_pipe_init(uv_default_loop(), &out, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+ options.stdio_count = 2;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
+ printf("output is: %s", output);
+ ASSERT(strcmp("hello world\n", output) == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_stdout_to_file) {
+ int r;
+ uv_file file;
+ uv_fs_t fs_req;
+ uv_stdio_container_t stdio[2];
+ uv_buf_t buf;
+
+ /* Setup. */
+ unlink("stdout_file");
+
+ init_process_options("spawn_helper2", exit_cb);
+
+ r = uv_fs_open(NULL, &fs_req, "stdout_file", O_CREAT | O_RDWR,
+ S_IRUSR | S_IWUSR, NULL);
+ ASSERT(r != -1);
+ uv_fs_req_cleanup(&fs_req);
+
+ file = r;
+
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_INHERIT_FD;
+ options.stdio[1].data.fd = file;
+ options.stdio_count = 2;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ buf = uv_buf_init(output, sizeof(output));
+ r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL);
+ ASSERT(r == 12);
+ uv_fs_req_cleanup(&fs_req);
+
+ r = uv_fs_close(NULL, &fs_req, file, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ printf("output is: %s", output);
+ ASSERT(strcmp("hello world\n", output) == 0);
+
+ /* Cleanup. */
+ unlink("stdout_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_stdout_and_stderr_to_file) {
+ int r;
+ uv_file file;
+ uv_fs_t fs_req;
+ uv_stdio_container_t stdio[3];
+ uv_buf_t buf;
+
+ /* Setup. */
+ unlink("stdout_file");
+
+ init_process_options("spawn_helper6", exit_cb);
+
+ r = uv_fs_open(NULL, &fs_req, "stdout_file", O_CREAT | O_RDWR,
+ S_IRUSR | S_IWUSR, NULL);
+ ASSERT(r != -1);
+ uv_fs_req_cleanup(&fs_req);
+
+ file = r;
+
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_INHERIT_FD;
+ options.stdio[1].data.fd = file;
+ options.stdio[2].flags = UV_INHERIT_FD;
+ options.stdio[2].data.fd = file;
+ options.stdio_count = 3;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ buf = uv_buf_init(output, sizeof(output));
+ r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL);
+ ASSERT(r == 27);
+ uv_fs_req_cleanup(&fs_req);
+
+ r = uv_fs_close(NULL, &fs_req, file, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ printf("output is: %s", output);
+ ASSERT(strcmp("hello world\nhello errworld\n", output) == 0);
+
+ /* Cleanup. */
+ unlink("stdout_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_stdout_and_stderr_to_file2) {
+#ifndef _WIN32
+ int r;
+ uv_file file;
+ uv_fs_t fs_req;
+ uv_stdio_container_t stdio[3];
+ uv_buf_t buf;
+
+ /* Setup. */
+ unlink("stdout_file");
+
+ init_process_options("spawn_helper6", exit_cb);
+
+ /* Replace stderr with our file */
+ r = uv_fs_open(NULL,
+ &fs_req,
+ "stdout_file",
+ O_CREAT | O_RDWR,
+ S_IRUSR | S_IWUSR,
+ NULL);
+ ASSERT(r != -1);
+ uv_fs_req_cleanup(&fs_req);
+ file = dup2(r, STDERR_FILENO);
+ ASSERT(file != -1);
+
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_INHERIT_FD;
+ options.stdio[1].data.fd = file;
+ options.stdio[2].flags = UV_INHERIT_FD;
+ options.stdio[2].data.fd = file;
+ options.stdio_count = 3;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ buf = uv_buf_init(output, sizeof(output));
+ r = uv_fs_read(NULL, &fs_req, file, &buf, 1, 0, NULL);
+ ASSERT(r == 27);
+ uv_fs_req_cleanup(&fs_req);
+
+ r = uv_fs_close(NULL, &fs_req, file, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ printf("output is: %s", output);
+ ASSERT(strcmp("hello world\nhello errworld\n", output) == 0);
+
+ /* Cleanup. */
+ unlink("stdout_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+#else
+ RETURN_SKIP("Unix only test");
+#endif
+}
+
+
+TEST_IMPL(spawn_stdout_and_stderr_to_file_swap) {
+#ifndef _WIN32
+ int r;
+ uv_file stdout_file;
+ uv_file stderr_file;
+ uv_fs_t fs_req;
+ uv_stdio_container_t stdio[3];
+ uv_buf_t buf;
+
+ /* Setup. */
+ unlink("stdout_file");
+ unlink("stderr_file");
+
+ init_process_options("spawn_helper6", exit_cb);
+
+ /* open 'stdout_file' and replace STDOUT_FILENO with it */
+ r = uv_fs_open(NULL,
+ &fs_req,
+ "stdout_file",
+ O_CREAT | O_RDWR,
+ S_IRUSR | S_IWUSR,
+ NULL);
+ ASSERT(r != -1);
+ uv_fs_req_cleanup(&fs_req);
+ stdout_file = dup2(r, STDOUT_FILENO);
+ ASSERT(stdout_file != -1);
+
+ /* open 'stderr_file' and replace STDERR_FILENO with it */
+ r = uv_fs_open(NULL, &fs_req, "stderr_file", O_CREAT | O_RDWR,
+ S_IRUSR | S_IWUSR, NULL);
+ ASSERT(r != -1);
+ uv_fs_req_cleanup(&fs_req);
+ stderr_file = dup2(r, STDERR_FILENO);
+ ASSERT(stderr_file != -1);
+
+ /* now we're going to swap them: the child process' stdout will be our
+ * stderr_file and vice versa */
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_INHERIT_FD;
+ options.stdio[1].data.fd = stderr_file;
+ options.stdio[2].flags = UV_INHERIT_FD;
+ options.stdio[2].data.fd = stdout_file;
+ options.stdio_count = 3;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ buf = uv_buf_init(output, sizeof(output));
+
+ /* check the content of stdout_file */
+ r = uv_fs_read(NULL, &fs_req, stdout_file, &buf, 1, 0, NULL);
+ ASSERT(r >= 15);
+ uv_fs_req_cleanup(&fs_req);
+
+ r = uv_fs_close(NULL, &fs_req, stdout_file, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ printf("output is: %s", output);
+ ASSERT(strncmp("hello errworld\n", output, 15) == 0);
+
+ /* check the content of stderr_file */
+ r = uv_fs_read(NULL, &fs_req, stderr_file, &buf, 1, 0, NULL);
+ ASSERT(r >= 12);
+ uv_fs_req_cleanup(&fs_req);
+
+ r = uv_fs_close(NULL, &fs_req, stderr_file, NULL);
+ ASSERT(r == 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ printf("output is: %s", output);
+ ASSERT(strncmp("hello world\n", output, 12) == 0);
+
+ /* Cleanup. */
+ unlink("stdout_file");
+ unlink("stderr_file");
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+#else
+ RETURN_SKIP("Unix only test");
+#endif
+}
+
+
+TEST_IMPL(spawn_stdin) {
+ int r;
+ uv_pipe_t out;
+ uv_pipe_t in;
+ uv_write_t write_req;
+ uv_buf_t buf;
+ uv_stdio_container_t stdio[2];
+ char buffer[] = "hello-from-spawn_stdin";
+
+ init_process_options("spawn_helper3", exit_cb);
+
+ uv_pipe_init(uv_default_loop(), &out, 0);
+ uv_pipe_init(uv_default_loop(), &in, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*)&in;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+ options.stdio_count = 2;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ buf.base = buffer;
+ buf.len = sizeof(buffer);
+ r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 3); /* Once for process twice for the pipe. */
+ ASSERT(strcmp(buffer, output) == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_stdio_greater_than_3) {
+ int r;
+ uv_pipe_t pipe;
+ uv_stdio_container_t stdio[4];
+
+ init_process_options("spawn_helper5", exit_cb);
+
+ uv_pipe_init(uv_default_loop(), &pipe, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_IGNORE;
+ options.stdio[2].flags = UV_IGNORE;
+ options.stdio[3].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[3].data.stream = (uv_stream_t*)&pipe;
+ options.stdio_count = 4;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &pipe, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
+ printf("output from stdio[3] is: %s", output);
+ ASSERT(strcmp("fourth stdio!\n", output) == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_ignored_stdio) {
+ int r;
+
+ init_process_options("spawn_helper6", exit_cb);
+
+ options.stdio = NULL;
+ options.stdio_count = 0;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_and_kill) {
+ int r;
+
+ init_process_options("spawn_helper4", kill_cb);
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_timer_init(uv_default_loop(), &timer);
+ ASSERT(r == 0);
+
+ r = uv_timer_start(&timer, timer_cb, 500, 0);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 2); /* Once for process and once for timer. */
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_preserve_env) {
+ int r;
+ uv_pipe_t out;
+ uv_stdio_container_t stdio[2];
+
+ init_process_options("spawn_helper7", exit_cb);
+
+ uv_pipe_init(uv_default_loop(), &out, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*) &out;
+ options.stdio_count = 2;
+
+ r = putenv("ENV_TEST=testval");
+ ASSERT(r == 0);
+
+ /* Explicitly set options.env to NULL to test for env clobbering. */
+ options.env = NULL;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 2);
+
+ printf("output is: %s", output);
+ ASSERT(strcmp("testval", output) == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_detached) {
+ int r;
+
+ init_process_options("spawn_helper4", detach_failure_cb);
+
+ options.flags |= UV_PROCESS_DETACHED;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ uv_unref((uv_handle_t*)&process);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 0);
+
+ r = uv_kill(process.pid, 0);
+ ASSERT(r == 0);
+
+ r = uv_kill(process.pid, 15);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(spawn_and_kill_with_std) {
+ int r;
+ uv_pipe_t in, out, err;
+ uv_write_t write;
+ char message[] = "Nancy's joining me because the message this evening is "
+ "not my message but ours.";
+ uv_buf_t buf;
+ uv_stdio_container_t stdio[3];
+
+ init_process_options("spawn_helper4", kill_cb);
+
+ r = uv_pipe_init(uv_default_loop(), &in, 0);
+ ASSERT(r == 0);
+
+ r = uv_pipe_init(uv_default_loop(), &out, 0);
+ ASSERT(r == 0);
+
+ r = uv_pipe_init(uv_default_loop(), &err, 0);
+ ASSERT(r == 0);
+
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*)&in;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+ options.stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[2].data.stream = (uv_stream_t*)&err;
+ options.stdio_count = 3;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ buf = uv_buf_init(message, sizeof message);
+ r = uv_write(&write, (uv_stream_t*) &in, &buf, 1, write_cb);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &err, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ r = uv_timer_init(uv_default_loop(), &timer);
+ ASSERT(r == 0);
+
+ r = uv_timer_start(&timer, timer_cb, 500, 0);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 5); /* process x 1, timer x 1, stdio x 3. */
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_and_ping) {
+ uv_write_t write_req;
+ uv_pipe_t in, out;
+ uv_buf_t buf;
+ uv_stdio_container_t stdio[2];
+ int r;
+
+ init_process_options("spawn_helper3", exit_cb);
+ buf = uv_buf_init("TEST", 4);
+
+ uv_pipe_init(uv_default_loop(), &out, 0);
+ uv_pipe_init(uv_default_loop(), &in, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*)&in;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+ options.stdio_count = 2;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ /* Sending signum == 0 should check if the
+ * child process is still alive, not kill it.
+ */
+ r = uv_process_kill(&process, 0);
+ ASSERT(r == 0);
+
+ r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)&out, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(strcmp(output, "TEST") == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_same_stdout_stderr) {
+ uv_write_t write_req;
+ uv_pipe_t in, out;
+ uv_buf_t buf;
+ uv_stdio_container_t stdio[3];
+ int r;
+
+ init_process_options("spawn_helper3", exit_cb);
+ buf = uv_buf_init("TEST", 4);
+
+ uv_pipe_init(uv_default_loop(), &out, 0);
+ uv_pipe_init(uv_default_loop(), &in, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*)&in;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+ options.stdio_count = 2;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ /* Sending signum == 0 should check if the
+ * child process is still alive, not kill it.
+ */
+ r = uv_process_kill(&process, 0);
+ ASSERT(r == 0);
+
+ r = uv_write(&write_req, (uv_stream_t*)&in, &buf, 1, write_cb);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)&out, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(strcmp(output, "TEST") == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_closed_process_io) {
+ uv_pipe_t in;
+ uv_write_t write_req;
+ uv_buf_t buf;
+ uv_stdio_container_t stdio[2];
+ static char buffer[] = "hello-from-spawn_stdin\n";
+
+ init_process_options("spawn_helper3", exit_cb);
+
+ uv_pipe_init(uv_default_loop(), &in, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*) &in;
+ options.stdio_count = 1;
+
+ close(0); /* Close process stdin. */
+
+ ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
+
+ buf = uv_buf_init(buffer, sizeof(buffer));
+ ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb));
+
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 2); /* process, child stdin */
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(kill) {
+ int r;
+
+#ifdef _WIN32
+ no_term_signal = 1;
+#endif
+
+ init_process_options("spawn_helper4", kill_cb);
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ /* Sending signum == 0 should check if the
+ * child process is still alive, not kill it.
+ */
+ r = uv_kill(process.pid, 0);
+ ASSERT(r == 0);
+
+ /* Kill the process. */
+ r = uv_kill(process.pid, /* SIGTERM */ 15);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+#ifdef _WIN32
+TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) {
+ int r;
+ uv_pipe_t out;
+ char name[64];
+ HANDLE pipe_handle;
+ uv_stdio_container_t stdio[2];
+
+ init_process_options("spawn_helper2", exit_cb);
+
+ uv_pipe_init(uv_default_loop(), &out, 0);
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_IGNORE;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+ options.stdio_count = 2;
+
+ /* Create a pipe that'll cause a collision. */
+ snprintf(name,
+ sizeof(name),
+ "\\\\.\\pipe\\uv\\%p-%d",
+ &out,
+ GetCurrentProcessId());
+ pipe_handle = CreateNamedPipeA(name,
+ PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ 10,
+ 65536,
+ 65536,
+ 0,
+ NULL);
+ ASSERT(pipe_handle != INVALID_HANDLE_VALUE);
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
+ printf("output is: %s", output);
+ ASSERT(strcmp("hello world\n", output) == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+#if !defined(USING_UV_SHARED)
+int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr);
+WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target);
+
+TEST_IMPL(argument_escaping) {
+ const WCHAR* test_str[] = {
+ L"",
+ L"HelloWorld",
+ L"Hello World",
+ L"Hello\"World",
+ L"Hello World\\",
+ L"Hello\\\"World",
+ L"Hello\\World",
+ L"Hello\\\\World",
+ L"Hello World\\",
+ L"c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\""
+ };
+ const int count = sizeof(test_str) / sizeof(*test_str);
+ WCHAR** test_output;
+ WCHAR* command_line;
+ WCHAR** cracked;
+ size_t total_size = 0;
+ int i;
+ int num_args;
+ int result;
+
+ char* verbatim[] = {
+ "cmd.exe",
+ "/c",
+ "c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\"",
+ NULL
+ };
+ WCHAR* verbatim_output;
+ WCHAR* non_verbatim_output;
+
+ test_output = calloc(count, sizeof(WCHAR*));
+ ASSERT(test_output != NULL);
+ for (i = 0; i < count; ++i) {
+ test_output[i] = calloc(2 * (wcslen(test_str[i]) + 2), sizeof(WCHAR));
+ quote_cmd_arg(test_str[i], test_output[i]);
+ wprintf(L"input : %s\n", test_str[i]);
+ wprintf(L"output: %s\n", test_output[i]);
+ total_size += wcslen(test_output[i]) + 1;
+ }
+ command_line = calloc(total_size + 1, sizeof(WCHAR));
+ ASSERT(command_line != NULL);
+ for (i = 0; i < count; ++i) {
+ wcscat(command_line, test_output[i]);
+ wcscat(command_line, L" ");
+ }
+ command_line[total_size - 1] = L'\0';
+
+ wprintf(L"command_line: %s\n", command_line);
+
+ cracked = CommandLineToArgvW(command_line, &num_args);
+ for (i = 0; i < num_args; ++i) {
+ wprintf(L"%d: %s\t%s\n", i, test_str[i], cracked[i]);
+ ASSERT(wcscmp(test_str[i], cracked[i]) == 0);
+ }
+
+ LocalFree(cracked);
+ for (i = 0; i < count; ++i) {
+ free(test_output[i]);
+ }
+
+ result = make_program_args(verbatim, 1, &verbatim_output);
+ ASSERT(result == 0);
+ result = make_program_args(verbatim, 0, &non_verbatim_output);
+ ASSERT(result == 0);
+
+ wprintf(L" verbatim_output: %s\n", verbatim_output);
+ wprintf(L"non_verbatim_output: %s\n", non_verbatim_output);
+
+ ASSERT(wcscmp(verbatim_output,
+ L"cmd.exe /c c:\\path\\to\\node.exe --eval "
+ L"\"require('c:\\\\path\\\\to\\\\test.js')\"") == 0);
+ ASSERT(wcscmp(non_verbatim_output,
+ L"cmd.exe /c \"c:\\path\\to\\node.exe --eval "
+ L"\\\"require('c:\\\\path\\\\to\\\\test.js')\\\"\"") == 0);
+
+ free(verbatim_output);
+ free(non_verbatim_output);
+
+ return 0;
+}
+
+int make_program_env(char** env_block, WCHAR** dst_ptr);
+
+TEST_IMPL(environment_creation) {
+ int i;
+ char* environment[] = {
+ "FOO=BAR",
+ "SYSTEM=ROOT", /* substring of a supplied var name */
+ "SYSTEMROOTED=OMG", /* supplied var name is a substring */
+ "TEMP=C:\\Temp",
+ "INVALID",
+ "BAZ=QUX",
+ "B_Z=QUX",
+ "B\xe2\x82\xacZ=QUX",
+ "B\xf0\x90\x80\x82Z=QUX",
+ "B\xef\xbd\xa1Z=QUX",
+ "B\xf0\xa3\x91\x96Z=QUX",
+ "BAZ", /* repeat, invalid variable */
+ NULL
+ };
+ WCHAR* wenvironment[] = {
+ L"BAZ=QUX",
+ L"B_Z=QUX",
+ L"B\x20acZ=QUX",
+ L"B\xd800\xdc02Z=QUX",
+ L"B\xd84d\xdc56Z=QUX",
+ L"B\xff61Z=QUX",
+ L"FOO=BAR",
+ L"SYSTEM=ROOT", /* substring of a supplied var name */
+ L"SYSTEMROOTED=OMG", /* supplied var name is a substring */
+ L"TEMP=C:\\Temp",
+ };
+ WCHAR* from_env[] = {
+ /* list should be kept in sync with list
+ * in process.c, minus variables in wenvironment */
+ L"HOMEDRIVE",
+ L"HOMEPATH",
+ L"LOGONSERVER",
+ L"PATH",
+ L"USERDOMAIN",
+ L"USERNAME",
+ L"USERPROFILE",
+ L"SYSTEMDRIVE",
+ L"SYSTEMROOT",
+ L"WINDIR",
+ /* test for behavior in the absence of a
+ * required-environment variable: */
+ L"ZTHIS_ENV_VARIABLE_DOES_NOT_EXIST",
+ };
+ int found_in_loc_env[ARRAY_SIZE(wenvironment)] = {0};
+ int found_in_usr_env[ARRAY_SIZE(from_env)] = {0};
+ WCHAR *expected[ARRAY_SIZE(from_env)];
+ int result;
+ WCHAR* str;
+ WCHAR* prev;
+ WCHAR* env;
+
+ for (i = 0; i < ARRAY_SIZE(from_env); i++) {
+ /* copy expected additions to environment locally */
+ size_t len = GetEnvironmentVariableW(from_env[i], NULL, 0);
+ if (len == 0) {
+ found_in_usr_env[i] = 1;
+ str = malloc(1 * sizeof(WCHAR));
+ *str = 0;
+ expected[i] = str;
+ } else {
+ size_t name_len = wcslen(from_env[i]);
+ str = malloc((name_len+1+len) * sizeof(WCHAR));
+ wmemcpy(str, from_env[i], name_len);
+ expected[i] = str;
+ str += name_len;
+ *str++ = L'=';
+ GetEnvironmentVariableW(from_env[i], str, len);
+ }
+ }
+
+ result = make_program_env(environment, &env);
+ ASSERT(result == 0);
+
+ for (str = env, prev = NULL; *str; prev = str, str += wcslen(str) + 1) {
+ int found = 0;
+#if 0
+ _cputws(str);
+ putchar('\n');
+#endif
+ for (i = 0; i < ARRAY_SIZE(wenvironment) && !found; i++) {
+ if (!wcscmp(str, wenvironment[i])) {
+ ASSERT(!found_in_loc_env[i]);
+ found_in_loc_env[i] = 1;
+ found = 1;
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE(expected) && !found; i++) {
+ if (!wcscmp(str, expected[i])) {
+ ASSERT(!found_in_usr_env[i]);
+ found_in_usr_env[i] = 1;
+ found = 1;
+ }
+ }
+ if (prev) { /* verify sort order -- requires Vista */
+#if _WIN32_WINNT >= 0x0600 && \
+ (!defined(__MINGW32__) || defined(__MINGW64_VERSION_MAJOR))
+ ASSERT(CompareStringOrdinal(prev, -1, str, -1, TRUE) == 1);
+#endif
+ }
+ ASSERT(found); /* verify that we expected this variable */
+ }
+
+ /* verify that we found all expected variables */
+ for (i = 0; i < ARRAY_SIZE(wenvironment); i++) {
+ ASSERT(found_in_loc_env[i]);
+ }
+ for (i = 0; i < ARRAY_SIZE(expected); i++) {
+ ASSERT(found_in_usr_env[i]);
+ }
+
+ return 0;
+}
+#endif
+
+/* Regression test for issue #909 */
+TEST_IMPL(spawn_with_an_odd_path) {
+ int r;
+
+ char newpath[2048];
+ char *path = getenv("PATH");
+ ASSERT(path != NULL);
+ snprintf(newpath, 2048, ";.;%s", path);
+ SetEnvironmentVariable("PATH", newpath);
+
+ init_process_options("", exit_cb);
+ options.file = options.args[0] = "program-that-had-better-not-exist";
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == UV_ENOENT || r == UV_EACCES);
+ ASSERT(0 == uv_is_active((uv_handle_t*) &process));
+ uv_close((uv_handle_t*) &process, NULL);
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif
+
+#ifndef _WIN32
+TEST_IMPL(spawn_setuid_setgid) {
+ int r;
+ struct passwd* pw;
+
+ /* if not root, then this will fail. */
+ uv_uid_t uid = getuid();
+ if (uid != 0) {
+ fprintf(stderr, "spawn_setuid_setgid skipped: not root\n");
+ return 0;
+ }
+
+ init_process_options("spawn_helper1", exit_cb);
+
+ /* become the "nobody" user. */
+ pw = getpwnam("nobody");
+ ASSERT(pw != NULL);
+ options.uid = pw->pw_uid;
+ options.gid = pw->pw_gid;
+ options.flags = UV_PROCESS_SETUID | UV_PROCESS_SETGID;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ if (r == UV_EACCES)
+ RETURN_SKIP("user 'nobody' cannot access the test runner");
+
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif
+
+
+#ifndef _WIN32
+TEST_IMPL(spawn_setuid_fails) {
+ int r;
+
+ /* if root, become nobody. */
+ uv_uid_t uid = getuid();
+ if (uid == 0) {
+ struct passwd* pw;
+ pw = getpwnam("nobody");
+ ASSERT(pw != NULL);
+ ASSERT(0 == setgid(pw->pw_gid));
+ ASSERT(0 == setuid(pw->pw_uid));
+ }
+
+ init_process_options("spawn_helper1", fail_cb);
+
+ options.flags |= UV_PROCESS_SETUID;
+ options.uid = 0;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == UV_EPERM);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_setgid_fails) {
+ int r;
+
+ /* if root, become nobody. */
+ uv_uid_t uid = getuid();
+ if (uid == 0) {
+ struct passwd* pw;
+ pw = getpwnam("nobody");
+ ASSERT(pw != NULL);
+ ASSERT(0 == setgid(pw->pw_gid));
+ ASSERT(0 == setuid(pw->pw_uid));
+ }
+
+ init_process_options("spawn_helper1", fail_cb);
+
+ options.flags |= UV_PROCESS_SETGID;
+ options.gid = 0;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == UV_EPERM);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif
+
+
+#ifdef _WIN32
+
+static void exit_cb_unexpected(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ ASSERT(0 && "should not have been called");
+}
+
+
+TEST_IMPL(spawn_setuid_fails) {
+ int r;
+
+ init_process_options("spawn_helper1", exit_cb_unexpected);
+
+ options.flags |= UV_PROCESS_SETUID;
+ options.uid = (uv_uid_t) -42424242;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == UV_ENOTSUP);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(spawn_setgid_fails) {
+ int r;
+
+ init_process_options("spawn_helper1", exit_cb_unexpected);
+
+ options.flags |= UV_PROCESS_SETGID;
+ options.gid = (uv_gid_t) -42424242;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == UV_ENOTSUP);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif
+
+
+TEST_IMPL(spawn_auto_unref) {
+ init_process_options("spawn_helper1", NULL);
+ ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ ASSERT(0 == uv_is_closing((uv_handle_t*) &process));
+ uv_close((uv_handle_t*) &process, NULL);
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ ASSERT(1 == uv_is_closing((uv_handle_t*) &process));
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+#ifndef _WIN32
+TEST_IMPL(spawn_fs_open) {
+ int fd;
+ uv_fs_t fs_req;
+ uv_pipe_t in;
+ uv_write_t write_req;
+ uv_buf_t buf;
+ uv_stdio_container_t stdio[1];
+
+ fd = uv_fs_open(NULL, &fs_req, "/dev/null", O_RDWR, 0, NULL);
+ ASSERT(fd >= 0);
+ uv_fs_req_cleanup(&fs_req);
+
+ init_process_options("spawn_helper8", exit_cb);
+
+ ASSERT(0 == uv_pipe_init(uv_default_loop(), &in, 0));
+
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*) &in;
+ options.stdio_count = 1;
+
+ ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
+
+ buf = uv_buf_init((char*) &fd, sizeof(fd));
+ ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &in, &buf, 1, write_cb));
+
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ ASSERT(0 == uv_fs_close(NULL, &fs_req, fd, NULL));
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 2); /* One for `in`, one for process */
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif /* !_WIN32 */
+
+
+#ifndef _WIN32
+TEST_IMPL(closed_fd_events) {
+ uv_stdio_container_t stdio[3];
+ uv_pipe_t pipe_handle;
+ int fd[2];
+
+ /* create a pipe and share it with a child process */
+ ASSERT(0 == pipe(fd));
+
+ /* spawn_helper4 blocks indefinitely. */
+ init_process_options("spawn_helper4", exit_cb);
+ options.stdio_count = 3;
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_INHERIT_FD;
+ options.stdio[0].data.fd = fd[0];
+ options.stdio[1].flags = UV_IGNORE;
+ options.stdio[2].flags = UV_IGNORE;
+
+ ASSERT(0 == uv_spawn(uv_default_loop(), &process, &options));
+ uv_unref((uv_handle_t*) &process);
+
+ /* read from the pipe with uv */
+ ASSERT(0 == uv_pipe_init(uv_default_loop(), &pipe_handle, 0));
+ ASSERT(0 == uv_pipe_open(&pipe_handle, fd[0]));
+ fd[0] = -1;
+
+ ASSERT(0 == uv_read_start((uv_stream_t*) &pipe_handle, on_alloc, on_read_once));
+
+ ASSERT(1 == write(fd[1], "", 1));
+
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
+
+ /* should have received just one byte */
+ ASSERT(output_used == 1);
+
+ /* close the pipe and see if we still get events */
+ uv_close((uv_handle_t*) &pipe_handle, close_cb);
+
+ ASSERT(1 == write(fd[1], "", 1));
+
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &timer));
+ ASSERT(0 == uv_timer_start(&timer, timer_counter_cb, 10, 0));
+
+ /* see if any spurious events interrupt the timer */
+ if (1 == uv_run(uv_default_loop(), UV_RUN_ONCE))
+ /* have to run again to really trigger the timer */
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
+
+ ASSERT(timer_counter == 1);
+
+ /* cleanup */
+ ASSERT(0 == uv_process_kill(&process, /* SIGTERM */ 15));
+ ASSERT(0 == close(fd[1]));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif /* !_WIN32 */
+
+TEST_IMPL(spawn_reads_child_path) {
+ int r;
+ int len;
+ char file[64];
+ char path[1024];
+ char* env[3];
+
+ /* Need to carry over the dynamic linker path when the test runner is
+ * linked against libuv.so, see https://github.com/libuv/libuv/issues/85.
+ */
+#if defined(__APPLE__)
+ static const char dyld_path_var[] = "DYLD_LIBRARY_PATH";
+#else
+ static const char dyld_path_var[] = "LD_LIBRARY_PATH";
+#endif
+
+ /* Set up the process, but make sure that the file to run is relative and */
+ /* requires a lookup into PATH */
+ init_process_options("spawn_helper1", exit_cb);
+
+ /* Set up the PATH env variable */
+ for (len = strlen(exepath);
+ exepath[len - 1] != '/' && exepath[len - 1] != '\\';
+ len--);
+ strcpy(file, exepath + len);
+ exepath[len] = 0;
+ strcpy(path, "PATH=");
+ strcpy(path + 5, exepath);
+
+ env[0] = path;
+ env[1] = getenv(dyld_path_var);
+ env[2] = NULL;
+
+ if (env[1] != NULL) {
+ static char buf[1024 + sizeof(dyld_path_var)];
+ snprintf(buf, sizeof(buf), "%s=%s", dyld_path_var, env[1]);
+ env[1] = buf;
+ }
+
+ options.file = file;
+ options.args[0] = file;
+ options.env = env;
+
+ r = uv_spawn(uv_default_loop(), &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#ifndef _WIN32
+static int mpipe(int *fds) {
+ if (pipe(fds) == -1)
+ return -1;
+ if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
+ fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
+ close(fds[0]);
+ close(fds[1]);
+ return -1;
+ }
+ return 0;
+}
+#else
+static int mpipe(int *fds) {
+ SECURITY_ATTRIBUTES attr;
+ HANDLE readh, writeh;
+ attr.nLength = sizeof(attr);
+ attr.lpSecurityDescriptor = NULL;
+ attr.bInheritHandle = FALSE;
+ if (!CreatePipe(&readh, &writeh, &attr, 0))
+ return -1;
+ fds[0] = _open_osfhandle((intptr_t)readh, 0);
+ fds[1] = _open_osfhandle((intptr_t)writeh, 0);
+ if (fds[0] == -1 || fds[1] == -1) {
+ CloseHandle(readh);
+ CloseHandle(writeh);
+ return -1;
+ }
+ return 0;
+}
+#endif /* !_WIN32 */
+
+TEST_IMPL(spawn_inherit_streams) {
+ uv_process_t child_req;
+ uv_stdio_container_t child_stdio[2];
+ int fds_stdin[2];
+ int fds_stdout[2];
+ uv_pipe_t pipe_stdin_child;
+ uv_pipe_t pipe_stdout_child;
+ uv_pipe_t pipe_stdin_parent;
+ uv_pipe_t pipe_stdout_parent;
+ unsigned char ubuf[OUTPUT_SIZE - 1];
+ uv_buf_t buf;
+ unsigned int i;
+ int r;
+ uv_write_t write_req;
+ uv_loop_t* loop;
+
+ init_process_options("spawn_helper9", exit_cb);
+
+ loop = uv_default_loop();
+ ASSERT(uv_pipe_init(loop, &pipe_stdin_child, 0) == 0);
+ ASSERT(uv_pipe_init(loop, &pipe_stdout_child, 0) == 0);
+ ASSERT(uv_pipe_init(loop, &pipe_stdin_parent, 0) == 0);
+ ASSERT(uv_pipe_init(loop, &pipe_stdout_parent, 0) == 0);
+
+ ASSERT(mpipe(fds_stdin) != -1);
+ ASSERT(mpipe(fds_stdout) != -1);
+
+ ASSERT(uv_pipe_open(&pipe_stdin_child, fds_stdin[0]) == 0);
+ ASSERT(uv_pipe_open(&pipe_stdout_child, fds_stdout[1]) == 0);
+ ASSERT(uv_pipe_open(&pipe_stdin_parent, fds_stdin[1]) == 0);
+ ASSERT(uv_pipe_open(&pipe_stdout_parent, fds_stdout[0]) == 0);
+
+ child_stdio[0].flags = UV_INHERIT_STREAM;
+ child_stdio[0].data.stream = (uv_stream_t *)&pipe_stdin_child;
+
+ child_stdio[1].flags = UV_INHERIT_STREAM;
+ child_stdio[1].data.stream = (uv_stream_t *)&pipe_stdout_child;
+
+ options.stdio = child_stdio;
+ options.stdio_count = 2;
+
+ ASSERT(uv_spawn(loop, &child_req, &options) == 0);
+
+ uv_close((uv_handle_t*)&pipe_stdin_child, NULL);
+ uv_close((uv_handle_t*)&pipe_stdout_child, NULL);
+
+ buf = uv_buf_init((char*)ubuf, sizeof ubuf);
+ for (i = 0; i < sizeof ubuf; ++i)
+ ubuf[i] = i & 255u;
+ memset(output, 0, sizeof ubuf);
+
+ r = uv_write(&write_req,
+ (uv_stream_t*)&pipe_stdin_parent,
+ &buf,
+ 1,
+ write_cb);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)&pipe_stdout_parent, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 3);
+
+ r = memcmp(ubuf, output, sizeof ubuf);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+/* Helper for child process of spawn_inherit_streams */
+#ifndef _WIN32
+int spawn_stdin_stdout(void) {
+ char buf[1024];
+ char* pbuf;
+ for (;;) {
+ ssize_t r, w, c;
+ do {
+ r = read(0, buf, sizeof buf);
+ } while (r == -1 && errno == EINTR);
+ if (r == 0) {
+ return 1;
+ }
+ ASSERT(r > 0);
+ c = r;
+ pbuf = buf;
+ while (c) {
+ do {
+ w = write(1, pbuf, (size_t)c);
+ } while (w == -1 && errno == EINTR);
+ ASSERT(w >= 0);
+ pbuf = pbuf + w;
+ c = c - w;
+ }
+ }
+ return 2;
+}
+#else
+int spawn_stdin_stdout(void) {
+ char buf[1024];
+ char* pbuf;
+ HANDLE h_stdin = GetStdHandle(STD_INPUT_HANDLE);
+ HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ ASSERT(h_stdin != INVALID_HANDLE_VALUE);
+ ASSERT(h_stdout != INVALID_HANDLE_VALUE);
+ for (;;) {
+ DWORD n_read;
+ DWORD n_written;
+ DWORD to_write;
+ if (!ReadFile(h_stdin, buf, sizeof buf, &n_read, NULL)) {
+ ASSERT(GetLastError() == ERROR_BROKEN_PIPE);
+ return 1;
+ }
+ to_write = n_read;
+ pbuf = buf;
+ while (to_write) {
+ ASSERT(WriteFile(h_stdout, pbuf, to_write, &n_written, NULL));
+ to_write -= n_written;
+ pbuf += n_written;
+ }
+ }
+ return 2;
+}
+#endif /* !_WIN32 */
diff --git a/3rdparty/libuv/test/test-stdio-over-pipes.c b/3rdparty/libuv/test/test-stdio-over-pipes.c
new file mode 100644
index 00000000000..15744761049
--- /dev/null
+++ b/3rdparty/libuv/test/test-stdio-over-pipes.c
@@ -0,0 +1,255 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+
+static char exepath[1024];
+static size_t exepath_size = 1024;
+static char* args[3];
+static uv_process_options_t options;
+static int close_cb_called;
+static int exit_cb_called;
+static int on_read_cb_called;
+static int after_write_cb_called;
+static uv_pipe_t in;
+static uv_pipe_t out;
+static uv_loop_t* loop;
+#define OUTPUT_SIZE 1024
+static char output[OUTPUT_SIZE];
+static int output_used;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void exit_cb(uv_process_t* process,
+ int64_t exit_status,
+ int term_signal) {
+ printf("exit_cb\n");
+ exit_cb_called++;
+ ASSERT(exit_status == 0);
+ ASSERT(term_signal == 0);
+ uv_close((uv_handle_t*)process, close_cb);
+ uv_close((uv_handle_t*)&in, close_cb);
+ uv_close((uv_handle_t*)&out, close_cb);
+}
+
+
+static void init_process_options(char* test, uv_exit_cb exit_cb) {
+ int r = uv_exepath(exepath, &exepath_size);
+ ASSERT(r == 0);
+ exepath[exepath_size] = '\0';
+ args[0] = exepath;
+ args[1] = test;
+ args[2] = NULL;
+ options.file = exepath;
+ options.args = args;
+ options.exit_cb = exit_cb;
+}
+
+
+static void on_alloc(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ buf->base = output + output_used;
+ buf->len = OUTPUT_SIZE - output_used;
+}
+
+
+static void after_write(uv_write_t* req, int status) {
+ if (status) {
+ fprintf(stderr, "uv_write error: %s\n", uv_strerror(status));
+ ASSERT(0);
+ }
+
+ /* Free the read/write buffer and the request */
+ free(req);
+
+ after_write_cb_called++;
+}
+
+
+static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* rdbuf) {
+ uv_write_t* req;
+ uv_buf_t wrbuf;
+ int r;
+
+ ASSERT(nread > 0 || nread == UV_EOF);
+
+ if (nread > 0) {
+ output_used += nread;
+ if (output_used == 12) {
+ ASSERT(memcmp("hello world\n", output, 12) == 0);
+ wrbuf = uv_buf_init(output, output_used);
+ req = malloc(sizeof(*req));
+ r = uv_write(req, (uv_stream_t*)&in, &wrbuf, 1, after_write);
+ ASSERT(r == 0);
+ }
+ }
+
+ on_read_cb_called++;
+}
+
+
+TEST_IMPL(stdio_over_pipes) {
+ int r;
+ uv_process_t process;
+ uv_stdio_container_t stdio[2];
+
+ loop = uv_default_loop();
+
+ init_process_options("stdio_over_pipes_helper", exit_cb);
+
+ uv_pipe_init(loop, &out, 0);
+ uv_pipe_init(loop, &in, 0);
+
+ options.stdio = stdio;
+ options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
+ options.stdio[0].data.stream = (uv_stream_t*)&in;
+ options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
+ options.stdio[1].data.stream = (uv_stream_t*)&out;
+ options.stdio_count = 2;
+
+ r = uv_spawn(loop, &process, &options);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(on_read_cb_called > 1);
+ ASSERT(after_write_cb_called == 1);
+ ASSERT(exit_cb_called == 1);
+ ASSERT(close_cb_called == 3);
+ ASSERT(memcmp("hello world\n", output, 12) == 0);
+ ASSERT(output_used == 12);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+/* Everything here runs in a child process. */
+
+static int on_pipe_read_called;
+static int after_write_called;
+static uv_pipe_t stdin_pipe;
+static uv_pipe_t stdout_pipe;
+
+static void on_pipe_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ ASSERT(nread > 0);
+ ASSERT(memcmp("hello world\n", buf->base, nread) == 0);
+ on_pipe_read_called++;
+
+ free(buf->base);
+
+ uv_close((uv_handle_t*)&stdin_pipe, close_cb);
+ uv_close((uv_handle_t*)&stdout_pipe, close_cb);
+}
+
+
+static void after_pipe_write(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+ after_write_called++;
+}
+
+
+static void on_read_alloc(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ buf->base = malloc(suggested_size);
+ buf->len = suggested_size;
+}
+
+
+int stdio_over_pipes_helper(void) {
+ /* Write several buffers to test that the write order is preserved. */
+ char* buffers[] = {
+ "he",
+ "ll",
+ "o ",
+ "wo",
+ "rl",
+ "d",
+ "\n"
+ };
+
+ uv_write_t write_req[ARRAY_SIZE(buffers)];
+ uv_buf_t buf[ARRAY_SIZE(buffers)];
+ unsigned int i;
+ int r;
+ uv_loop_t* loop = uv_default_loop();
+
+ ASSERT(UV_NAMED_PIPE == uv_guess_handle(0));
+ ASSERT(UV_NAMED_PIPE == uv_guess_handle(1));
+
+ r = uv_pipe_init(loop, &stdin_pipe, 0);
+ ASSERT(r == 0);
+ r = uv_pipe_init(loop, &stdout_pipe, 0);
+ ASSERT(r == 0);
+
+ uv_pipe_open(&stdin_pipe, 0);
+ uv_pipe_open(&stdout_pipe, 1);
+
+ /* Unref both stdio handles to make sure that all writes complete. */
+ uv_unref((uv_handle_t*)&stdin_pipe);
+ uv_unref((uv_handle_t*)&stdout_pipe);
+
+ for (i = 0; i < ARRAY_SIZE(buffers); i++) {
+ buf[i] = uv_buf_init((char*)buffers[i], strlen(buffers[i]));
+ }
+
+ for (i = 0; i < ARRAY_SIZE(buffers); i++) {
+ r = uv_write(&write_req[i], (uv_stream_t*)&stdout_pipe, &buf[i], 1,
+ after_pipe_write);
+ ASSERT(r == 0);
+ }
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(after_write_called == 7);
+ ASSERT(on_pipe_read_called == 0);
+ ASSERT(close_cb_called == 0);
+
+ uv_ref((uv_handle_t*)&stdout_pipe);
+ uv_ref((uv_handle_t*)&stdin_pipe);
+
+ r = uv_read_start((uv_stream_t*)&stdin_pipe, on_read_alloc, on_pipe_read);
+ ASSERT(r == 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(after_write_called == 7);
+ ASSERT(on_pipe_read_called == 1);
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-bind-error.c b/3rdparty/libuv/test/test-tcp-bind-error.c
new file mode 100644
index 00000000000..10ed68e10ec
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-bind-error.c
@@ -0,0 +1,216 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+TEST_IMPL(tcp_bind_error_addrinuse) {
+ struct sockaddr_in addr;
+ uv_tcp_t server1, server2;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+ r = uv_tcp_init(uv_default_loop(), &server1);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server1, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_tcp_init(uv_default_loop(), &server2);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server2, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&server1, 128, NULL);
+ ASSERT(r == 0);
+ r = uv_listen((uv_stream_t*)&server2, 128, NULL);
+ ASSERT(r == UV_EADDRINUSE);
+
+ uv_close((uv_handle_t*)&server1, close_cb);
+ uv_close((uv_handle_t*)&server2, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_bind_error_addrnotavail_1) {
+ struct sockaddr_in addr;
+ uv_tcp_t server;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.255.255.255", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ /* It seems that Linux is broken here - bind succeeds. */
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0 || r == UV_EADDRNOTAVAIL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_bind_error_addrnotavail_2) {
+ struct sockaddr_in addr;
+ uv_tcp_t server;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("4.4.4.4", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == UV_EADDRNOTAVAIL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_bind_error_fault) {
+ char garbage[] =
+ "blah blah blah blah blah blah blah blah blah blah blah blah";
+ struct sockaddr_in* garbage_addr;
+ uv_tcp_t server;
+ int r;
+
+ garbage_addr = (struct sockaddr_in*) &garbage;
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) garbage_addr, 0);
+ ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+/* Notes: On Linux uv_bind(server, NULL) will segfault the program. */
+
+TEST_IMPL(tcp_bind_error_inval) {
+ struct sockaddr_in addr1;
+ struct sockaddr_in addr2;
+ uv_tcp_t server;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr1));
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT_2, &addr2));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr1, 0);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr2, 0);
+ ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_bind_localhost_ok) {
+ struct sockaddr_in addr;
+ uv_tcp_t server;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_bind_invalid_flags) {
+ struct sockaddr_in addr;
+ uv_tcp_t server;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, UV_TCP_IPV6ONLY);
+ ASSERT(r == UV_EINVAL);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_listen_without_bind) {
+ int r;
+ uv_tcp_t server;
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_listen((uv_stream_t*)&server, 128, NULL);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-bind6-error.c b/3rdparty/libuv/test/test-tcp-bind6-error.c
new file mode 100644
index 00000000000..b762bcb3d1b
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-bind6-error.c
@@ -0,0 +1,176 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+TEST_IMPL(tcp_bind6_error_addrinuse) {
+ struct sockaddr_in6 addr;
+ uv_tcp_t server1, server2;
+ int r;
+
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+ ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server1);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server1, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_tcp_init(uv_default_loop(), &server2);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server2, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&server1, 128, NULL);
+ ASSERT(r == 0);
+ r = uv_listen((uv_stream_t*)&server2, 128, NULL);
+ ASSERT(r == UV_EADDRINUSE);
+
+ uv_close((uv_handle_t*)&server1, close_cb);
+ uv_close((uv_handle_t*)&server2, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_bind6_error_addrnotavail) {
+ struct sockaddr_in6 addr;
+ uv_tcp_t server;
+ int r;
+
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+ ASSERT(0 == uv_ip6_addr("4:4:4:4:4:4:4:4", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == UV_EADDRNOTAVAIL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_bind6_error_fault) {
+ char garbage[] =
+ "blah blah blah blah blah blah blah blah blah blah blah blah";
+ struct sockaddr_in6* garbage_addr;
+ uv_tcp_t server;
+ int r;
+
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+ garbage_addr = (struct sockaddr_in6*) &garbage;
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) garbage_addr, 0);
+ ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+/* Notes: On Linux uv_bind6(server, NULL) will segfault the program. */
+
+TEST_IMPL(tcp_bind6_error_inval) {
+ struct sockaddr_in6 addr1;
+ struct sockaddr_in6 addr2;
+ uv_tcp_t server;
+ int r;
+
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+ ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr1));
+ ASSERT(0 == uv_ip6_addr("::", TEST_PORT_2, &addr2));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr1, 0);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr2, 0);
+ ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_bind6_localhost_ok) {
+ struct sockaddr_in6 addr;
+ uv_tcp_t server;
+ int r;
+
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+ ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-close-accept.c b/3rdparty/libuv/test/test-tcp-close-accept.c
new file mode 100644
index 00000000000..5517aaf99e6
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-close-accept.c
@@ -0,0 +1,188 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* this test is Unix only */
+#ifndef _WIN32
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static struct sockaddr_in addr;
+static uv_tcp_t tcp_server;
+static uv_tcp_t tcp_outgoing[2];
+static uv_tcp_t tcp_incoming[ARRAY_SIZE(tcp_outgoing)];
+static uv_connect_t connect_reqs[ARRAY_SIZE(tcp_outgoing)];
+static uv_tcp_t tcp_check;
+static uv_connect_t tcp_check_req;
+static uv_write_t write_reqs[ARRAY_SIZE(tcp_outgoing)];
+static unsigned int got_connections;
+static unsigned int close_cb_called;
+static unsigned int write_cb_called;
+static unsigned int read_cb_called;
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+ write_cb_called++;
+}
+
+static void connect_cb(uv_connect_t* req, int status) {
+ unsigned int i;
+ uv_buf_t buf;
+ uv_stream_t* outgoing;
+
+ if (req == &tcp_check_req) {
+ ASSERT(status != 0);
+
+ /* Close check and incoming[0], time to finish test */
+ uv_close((uv_handle_t*) &tcp_incoming[0], close_cb);
+ uv_close((uv_handle_t*) &tcp_check, close_cb);
+ return;
+ }
+
+ ASSERT(status == 0);
+ ASSERT(connect_reqs <= req);
+ ASSERT(req <= connect_reqs + ARRAY_SIZE(connect_reqs));
+ i = req - connect_reqs;
+
+ buf = uv_buf_init("x", 1);
+ outgoing = (uv_stream_t*) &tcp_outgoing[i];
+ ASSERT(0 == uv_write(&write_reqs[i], outgoing, &buf, 1, write_cb));
+}
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ static char slab[1];
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
+ uv_loop_t* loop;
+ unsigned int i;
+
+ /* Only first stream should receive read events */
+ ASSERT(stream == (uv_stream_t*) &tcp_incoming[0]);
+ ASSERT(0 == uv_read_stop(stream));
+ ASSERT(1 == nread);
+
+ loop = stream->loop;
+ read_cb_called++;
+
+ /* Close all active incomings, except current one */
+ for (i = 1; i < got_connections; i++)
+ uv_close((uv_handle_t*) &tcp_incoming[i], close_cb);
+
+ /* Create new fd that should be one of the closed incomings */
+ ASSERT(0 == uv_tcp_init(loop, &tcp_check));
+ ASSERT(0 == uv_tcp_connect(&tcp_check_req,
+ &tcp_check,
+ (const struct sockaddr*) &addr,
+ connect_cb));
+ ASSERT(0 == uv_read_start((uv_stream_t*) &tcp_check, alloc_cb, read_cb));
+
+ /* Close server, so no one will connect to it */
+ uv_close((uv_handle_t*) &tcp_server, close_cb);
+}
+
+static void connection_cb(uv_stream_t* server, int status) {
+ unsigned int i;
+ uv_tcp_t* incoming;
+
+ ASSERT(server == (uv_stream_t*) &tcp_server);
+
+ /* Ignore tcp_check connection */
+ if (got_connections == ARRAY_SIZE(tcp_incoming))
+ return;
+
+ /* Accept everyone */
+ incoming = &tcp_incoming[got_connections++];
+ ASSERT(0 == uv_tcp_init(server->loop, incoming));
+ ASSERT(0 == uv_accept(server, (uv_stream_t*) incoming));
+
+ if (got_connections != ARRAY_SIZE(tcp_incoming))
+ return;
+
+ /* Once all clients are accepted - start reading */
+ for (i = 0; i < ARRAY_SIZE(tcp_incoming); i++) {
+ incoming = &tcp_incoming[i];
+ ASSERT(0 == uv_read_start((uv_stream_t*) incoming, alloc_cb, read_cb));
+ }
+}
+
+TEST_IMPL(tcp_close_accept) {
+ unsigned int i;
+ uv_loop_t* loop;
+ uv_tcp_t* client;
+
+ /*
+ * A little explanation of what goes on below:
+ *
+ * We'll create server and connect to it using two clients, each writing one
+ * byte once connected.
+ *
+ * When all clients will be accepted by server - we'll start reading from them
+ * and, on first client's first byte, will close second client and server.
+ * After that, we'll immediately initiate new connection to server using
+ * tcp_check handle (thus, reusing fd from second client).
+ *
+ * In this situation uv__io_poll()'s event list should still contain read
+ * event for second client, and, if not cleaned up properly, `tcp_check` will
+ * receive stale event of second incoming and invoke `connect_cb` with zero
+ * status.
+ */
+
+ loop = uv_default_loop();
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ ASSERT(0 == uv_tcp_init(loop, &tcp_server));
+ ASSERT(0 == uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0));
+ ASSERT(0 == uv_listen((uv_stream_t*) &tcp_server,
+ ARRAY_SIZE(tcp_outgoing),
+ connection_cb));
+
+ for (i = 0; i < ARRAY_SIZE(tcp_outgoing); i++) {
+ client = tcp_outgoing + i;
+
+ ASSERT(0 == uv_tcp_init(loop, client));
+ ASSERT(0 == uv_tcp_connect(&connect_reqs[i],
+ client,
+ (const struct sockaddr*) &addr,
+ connect_cb));
+ }
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(ARRAY_SIZE(tcp_outgoing) == got_connections);
+ ASSERT((ARRAY_SIZE(tcp_outgoing) + 2) == close_cb_called);
+ ASSERT(ARRAY_SIZE(tcp_outgoing) == write_cb_called);
+ ASSERT(1 == read_cb_called);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* !_WIN32 */
diff --git a/3rdparty/libuv/test/test-tcp-close-while-connecting.c b/3rdparty/libuv/test/test-tcp-close-while-connecting.c
new file mode 100644
index 00000000000..2c39b652b61
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-close-while-connecting.c
@@ -0,0 +1,86 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_timer_t timer1_handle;
+static uv_timer_t timer2_handle;
+static uv_tcp_t tcp_handle;
+
+static int connect_cb_called;
+static int timer1_cb_called;
+static int close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ ASSERT(status == UV_ECANCELED);
+ uv_timer_stop(&timer2_handle);
+ connect_cb_called++;
+}
+
+
+static void timer1_cb(uv_timer_t* handle) {
+ uv_close((uv_handle_t*)handle, close_cb);
+ uv_close((uv_handle_t*)&tcp_handle, close_cb);
+ timer1_cb_called++;
+}
+
+
+static void timer2_cb(uv_timer_t* handle) {
+ ASSERT(0 && "should not be called");
+}
+
+
+TEST_IMPL(tcp_close_while_connecting) {
+ uv_connect_t connect_req;
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+ ASSERT(0 == uv_ip4_addr("1.2.3.4", TEST_PORT, &addr));
+ ASSERT(0 == uv_tcp_init(loop, &tcp_handle));
+ r = uv_tcp_connect(&connect_req,
+ &tcp_handle,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ if (r == UV_ENETUNREACH)
+ RETURN_SKIP("Network unreachable.");
+ ASSERT(r == 0);
+ ASSERT(0 == uv_timer_init(loop, &timer1_handle));
+ ASSERT(0 == uv_timer_start(&timer1_handle, timer1_cb, 50, 0));
+ ASSERT(0 == uv_timer_init(loop, &timer2_handle));
+ ASSERT(0 == uv_timer_start(&timer2_handle, timer2_cb, 86400 * 1000, 0));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(timer1_cb_called == 1);
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-close.c b/3rdparty/libuv/test/test-tcp-close.c
new file mode 100644
index 00000000000..e65885aa556
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-close.c
@@ -0,0 +1,136 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <errno.h>
+#include <string.h> /* memset */
+
+#define NUM_WRITE_REQS 32
+
+static uv_tcp_t tcp_handle;
+static uv_connect_t connect_req;
+
+static int write_cb_called;
+static int close_cb_called;
+
+static void connect_cb(uv_connect_t* req, int status);
+static void write_cb(uv_write_t* req, int status);
+static void close_cb(uv_handle_t* handle);
+
+
+static void connect_cb(uv_connect_t* conn_req, int status) {
+ uv_write_t* req;
+ uv_buf_t buf;
+ int i, r;
+
+ buf = uv_buf_init("PING", 4);
+ for (i = 0; i < NUM_WRITE_REQS; i++) {
+ req = malloc(sizeof *req);
+ ASSERT(req != NULL);
+
+ r = uv_write(req, (uv_stream_t*)&tcp_handle, &buf, 1, write_cb);
+ ASSERT(r == 0);
+ }
+
+ uv_close((uv_handle_t*)&tcp_handle, close_cb);
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ /* write callbacks should run before the close callback */
+ ASSERT(close_cb_called == 0);
+ ASSERT(req->handle == (uv_stream_t*)&tcp_handle);
+ write_cb_called++;
+ free(req);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle == (uv_handle_t*)&tcp_handle);
+ close_cb_called++;
+}
+
+
+static void connection_cb(uv_stream_t* server, int status) {
+ ASSERT(status == 0);
+}
+
+
+static void start_server(uv_loop_t* loop, uv_tcp_t* handle) {
+ struct sockaddr_in addr;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_init(loop, handle);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(handle, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)handle, 128, connection_cb);
+ ASSERT(r == 0);
+
+ uv_unref((uv_handle_t*)handle);
+}
+
+
+/* Check that pending write requests have their callbacks
+ * invoked when the handle is closed.
+ */
+TEST_IMPL(tcp_close) {
+ struct sockaddr_in addr;
+ uv_tcp_t tcp_server;
+ uv_loop_t* loop;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ loop = uv_default_loop();
+
+ /* We can't use the echo server, it doesn't handle ECONNRESET. */
+ start_server(loop, &tcp_server);
+
+ r = uv_tcp_init(loop, &tcp_handle);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(&connect_req,
+ &tcp_handle,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+
+ ASSERT(write_cb_called == 0);
+ ASSERT(close_cb_called == 0);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ printf("%d of %d write reqs seen\n", write_cb_called, NUM_WRITE_REQS);
+
+ ASSERT(write_cb_called == NUM_WRITE_REQS);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-connect-error-after-write.c b/3rdparty/libuv/test/test-tcp-connect-error-after-write.c
new file mode 100644
index 00000000000..3f2e3572da9
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-connect-error-after-write.c
@@ -0,0 +1,98 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int connect_cb_called;
+static int write_cb_called;
+static int close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ ASSERT(status < 0);
+ connect_cb_called++;
+ uv_close((uv_handle_t*)req->handle, close_cb);
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(status < 0);
+ write_cb_called++;
+}
+
+
+/*
+ * Try to connect to an address on which nothing listens, get ECONNREFUSED
+ * (uv errno 12) and get connect_cb() called once with status != 0.
+ * Related issue: https://github.com/joyent/libuv/issues/443
+ */
+TEST_IMPL(tcp_connect_error_after_write) {
+ uv_connect_t connect_req;
+ struct sockaddr_in addr;
+ uv_write_t write_req;
+ uv_tcp_t conn;
+ uv_buf_t buf;
+ int r;
+
+#ifdef _WIN32
+ fprintf(stderr, "This test is disabled on Windows for now.\n");
+ fprintf(stderr, "See https://github.com/joyent/libuv/issues/444\n");
+ return 0; /* windows slackers... */
+#endif
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ buf = uv_buf_init("TEST", 4);
+
+ r = uv_tcp_init(uv_default_loop(), &conn);
+ ASSERT(r == 0);
+
+ r = uv_write(&write_req, (uv_stream_t*)&conn, &buf, 1, write_cb);
+ ASSERT(r == UV_EBADF);
+
+ r = uv_tcp_connect(&connect_req,
+ &conn,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+
+ r = uv_write(&write_req, (uv_stream_t*)&conn, &buf, 1, write_cb);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(write_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-connect-error.c b/3rdparty/libuv/test/test-tcp-connect-error.c
new file mode 100644
index 00000000000..eab1eeb2545
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-connect-error.c
@@ -0,0 +1,73 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int connect_cb_called = 0;
+static int close_cb_called = 0;
+
+
+
+static void connect_cb(uv_connect_t* handle, int status) {
+ ASSERT(handle != NULL);
+ connect_cb_called++;
+}
+
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+TEST_IMPL(tcp_connect_error_fault) {
+ const char garbage[] =
+ "blah blah blah blah blah blah blah blah blah blah blah blah";
+ const struct sockaddr_in* garbage_addr;
+ uv_tcp_t server;
+ int r;
+ uv_connect_t req;
+
+ garbage_addr = (const struct sockaddr_in*) &garbage;
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_connect(&req,
+ &server,
+ (const struct sockaddr*) garbage_addr,
+ connect_cb);
+ ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(connect_cb_called == 0);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-connect-timeout.c b/3rdparty/libuv/test/test-tcp-connect-timeout.c
new file mode 100644
index 00000000000..081424b8002
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-connect-timeout.c
@@ -0,0 +1,91 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int connect_cb_called;
+static int close_cb_called;
+
+static uv_connect_t connect_req;
+static uv_timer_t timer;
+static uv_tcp_t conn;
+
+static void connect_cb(uv_connect_t* req, int status);
+static void timer_cb(uv_timer_t* handle);
+static void close_cb(uv_handle_t* handle);
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ ASSERT(req == &connect_req);
+ ASSERT(status == UV_ECANCELED);
+ connect_cb_called++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(handle == &timer);
+ uv_close((uv_handle_t*)&conn, close_cb);
+ uv_close((uv_handle_t*)&timer, close_cb);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle == (uv_handle_t*)&conn || handle == (uv_handle_t*)&timer);
+ close_cb_called++;
+}
+
+
+/* Verify that connecting to an unreachable address or port doesn't hang
+ * the event loop.
+ */
+TEST_IMPL(tcp_connect_timeout) {
+ struct sockaddr_in addr;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("8.8.8.8", 9999, &addr));
+
+ r = uv_timer_init(uv_default_loop(), &timer);
+ ASSERT(r == 0);
+
+ r = uv_timer_start(&timer, timer_cb, 50, 0);
+ ASSERT(r == 0);
+
+ r = uv_tcp_init(uv_default_loop(), &conn);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(&connect_req,
+ &conn,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ if (r == UV_ENETUNREACH)
+ RETURN_SKIP("Network unreachable.");
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-connect6-error.c b/3rdparty/libuv/test/test-tcp-connect6-error.c
new file mode 100644
index 00000000000..91ac0a3a101
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-connect6-error.c
@@ -0,0 +1,71 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static int connect_cb_called = 0;
+static int close_cb_called = 0;
+
+
+static void connect_cb(uv_connect_t* handle, int status) {
+ ASSERT(handle != NULL);
+ connect_cb_called++;
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+TEST_IMPL(tcp_connect6_error_fault) {
+ const char garbage[] =
+ "blah blah blah blah blah blah blah blah blah blah blah blah";
+ const struct sockaddr_in6* garbage_addr;
+ uv_tcp_t server;
+ int r;
+ uv_connect_t req;
+
+ garbage_addr = (const struct sockaddr_in6*) &garbage;
+
+ r = uv_tcp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+ r = uv_tcp_connect(&req,
+ &server,
+ (const struct sockaddr*) garbage_addr,
+ connect_cb);
+ ASSERT(r == UV_EINVAL);
+
+ uv_close((uv_handle_t*)&server, close_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(connect_cb_called == 0);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-create-socket-early.c b/3rdparty/libuv/test/test-tcp-create-socket-early.c
new file mode 100644
index 00000000000..65650adcc27
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-create-socket-early.c
@@ -0,0 +1,206 @@
+/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <string.h>
+
+#ifdef _WIN32
+# define INVALID_FD (INVALID_HANDLE_VALUE)
+#else
+# define INVALID_FD (-1)
+#endif
+
+
+static void on_connect(uv_connect_t* req, int status) {
+ ASSERT(status == 0);
+ uv_close((uv_handle_t*) req->handle, NULL);
+}
+
+
+static void on_connection(uv_stream_t* server, int status) {
+ uv_tcp_t* handle;
+ int r;
+
+ ASSERT(status == 0);
+
+ handle = malloc(sizeof(*handle));
+ ASSERT(handle != NULL);
+
+ r = uv_tcp_init_ex(server->loop, handle, AF_INET);
+ ASSERT(r == 0);
+
+ r = uv_accept(server, (uv_stream_t*)handle);
+ ASSERT(r == UV_EBUSY);
+
+ uv_close((uv_handle_t*) server, NULL);
+ uv_close((uv_handle_t*) handle, (uv_close_cb)free);
+}
+
+
+static void tcp_listener(uv_loop_t* loop, uv_tcp_t* server) {
+ struct sockaddr_in addr;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_tcp_init(loop, server);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*) server, 128, on_connection);
+ ASSERT(r == 0);
+}
+
+
+static void tcp_connector(uv_loop_t* loop, uv_tcp_t* client, uv_connect_t* req) {
+ struct sockaddr_in server_addr;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &server_addr));
+
+ r = uv_tcp_init(loop, client);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(req,
+ client,
+ (const struct sockaddr*) &server_addr,
+ on_connect);
+ ASSERT(r == 0);
+}
+
+
+TEST_IMPL(tcp_create_early) {
+ struct sockaddr_in addr;
+ struct sockaddr_in sockname;
+ uv_tcp_t client;
+ uv_os_fd_t fd;
+ int r, namelen;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_init_ex(uv_default_loop(), &client, AF_INET);
+ ASSERT(r == 0);
+
+ r = uv_fileno((const uv_handle_t*) &client, &fd);
+ ASSERT(r == 0);
+ ASSERT(fd != INVALID_FD);
+
+ /* Windows returns WSAEINVAL if the socket is not bound */
+#ifndef _WIN32
+ namelen = sizeof sockname;
+ r = uv_tcp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
+ ASSERT(r == 0);
+ ASSERT(sockname.sin_family == AF_INET);
+#endif
+
+ r = uv_tcp_bind(&client, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ namelen = sizeof sockname;
+ r = uv_tcp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
+ ASSERT(r == 0);
+ ASSERT(memcmp(&addr.sin_addr,
+ &sockname.sin_addr,
+ sizeof(addr.sin_addr)) == 0);
+
+ uv_close((uv_handle_t*) &client, NULL);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_create_early_bad_bind) {
+ struct sockaddr_in addr;
+ uv_tcp_t client;
+ uv_os_fd_t fd;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_init_ex(uv_default_loop(), &client, AF_INET6);
+ ASSERT(r == 0);
+
+ r = uv_fileno((const uv_handle_t*) &client, &fd);
+ ASSERT(r == 0);
+ ASSERT(fd != INVALID_FD);
+
+ /* Windows returns WSAEINVAL if the socket is not bound */
+#ifndef _WIN32
+ {
+ int namelen;
+ struct sockaddr_in6 sockname;
+ namelen = sizeof sockname;
+ r = uv_tcp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
+ ASSERT(r == 0);
+ ASSERT(sockname.sin6_family == AF_INET6);
+ }
+#endif
+
+ r = uv_tcp_bind(&client, (const struct sockaddr*) &addr, 0);
+#ifndef _WIN32
+ ASSERT(r == UV_EINVAL);
+#else
+ ASSERT(r == UV_EFAULT);
+#endif
+
+ uv_close((uv_handle_t*) &client, NULL);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_create_early_bad_domain) {
+ uv_tcp_t client;
+ int r;
+
+ r = uv_tcp_init_ex(uv_default_loop(), &client, 47);
+ ASSERT(r == UV_EINVAL);
+
+ r = uv_tcp_init_ex(uv_default_loop(), &client, 1024);
+ ASSERT(r == UV_EINVAL);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_create_early_accept) {
+ uv_tcp_t client, server;
+ uv_connect_t connect_req;
+
+ tcp_listener(uv_default_loop(), &server);
+ tcp_connector(uv_default_loop(), &client, &connect_req);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-flags.c b/3rdparty/libuv/test/test-tcp-flags.c
new file mode 100644
index 00000000000..68afb39f456
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-flags.c
@@ -0,0 +1,52 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+TEST_IMPL(tcp_flags) {
+ uv_loop_t* loop;
+ uv_tcp_t handle;
+ int r;
+
+ loop = uv_default_loop();
+
+ r = uv_tcp_init(loop, &handle);
+ ASSERT(r == 0);
+
+ r = uv_tcp_nodelay(&handle, 1);
+ ASSERT(r == 0);
+
+ r = uv_tcp_keepalive(&handle, 1, 60);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*)&handle, NULL);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-oob.c b/3rdparty/libuv/test/test-tcp-oob.c
new file mode 100644
index 00000000000..fc011ee495f
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-oob.c
@@ -0,0 +1,128 @@
+/* Copyright Fedor Indutny. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#if !defined(_WIN32)
+
+#include "uv.h"
+#include "task.h"
+
+#include <errno.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+static uv_tcp_t server_handle;
+static uv_tcp_t client_handle;
+static uv_tcp_t peer_handle;
+static uv_idle_t idle;
+static uv_connect_t connect_req;
+static int ticks;
+static const int kMaxTicks = 10;
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char storage[1024];
+ *buf = uv_buf_init(storage, sizeof(storage));
+}
+
+
+static void idle_cb(uv_idle_t* idle) {
+ if (++ticks < kMaxTicks)
+ return;
+
+ uv_close((uv_handle_t*) &server_handle, NULL);
+ uv_close((uv_handle_t*) &client_handle, NULL);
+ uv_close((uv_handle_t*) &peer_handle, NULL);
+ uv_close((uv_handle_t*) idle, NULL);
+}
+
+
+static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) {
+ ASSERT(nread > 0);
+ ASSERT(0 == uv_idle_start(&idle, idle_cb));
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ ASSERT(req->handle == (uv_stream_t*) &client_handle);
+ ASSERT(0 == status);
+}
+
+
+static void connection_cb(uv_stream_t* handle, int status) {
+ int r;
+ uv_os_fd_t fd;
+
+ ASSERT(0 == status);
+ ASSERT(0 == uv_accept(handle, (uv_stream_t*) &peer_handle));
+ ASSERT(0 == uv_read_start((uv_stream_t*) &peer_handle, alloc_cb, read_cb));
+
+ /* Send some OOB data */
+ ASSERT(0 == uv_fileno((uv_handle_t*) &client_handle, &fd));
+
+ ASSERT(0 == uv_stream_set_blocking((uv_stream_t*) &client_handle, 1));
+
+ /* The problem triggers only on a second message, it seem that xnu is not
+ * triggering `kevent()` for the first one
+ */
+ do {
+ r = send(fd, "hello", 5, MSG_OOB);
+ } while (r < 0 && errno == EINTR);
+ ASSERT(5 == r);
+
+ do {
+ r = send(fd, "hello", 5, MSG_OOB);
+ } while (r < 0 && errno == EINTR);
+ ASSERT(5 == r);
+
+ ASSERT(0 == uv_stream_set_blocking((uv_stream_t*) &client_handle, 0));
+}
+
+
+TEST_IMPL(tcp_oob) {
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ loop = uv_default_loop();
+
+ ASSERT(0 == uv_tcp_init(loop, &server_handle));
+ ASSERT(0 == uv_tcp_init(loop, &client_handle));
+ ASSERT(0 == uv_tcp_init(loop, &peer_handle));
+ ASSERT(0 == uv_idle_init(loop, &idle));
+ ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0));
+ ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 1, connection_cb));
+
+ /* Ensure two separate packets */
+ ASSERT(0 == uv_tcp_nodelay(&client_handle, 1));
+
+ ASSERT(0 == uv_tcp_connect(&connect_req,
+ &client_handle,
+ (const struct sockaddr*) &addr,
+ connect_cb));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ ASSERT(ticks == kMaxTicks);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif
diff --git a/3rdparty/libuv/test/test-tcp-open.c b/3rdparty/libuv/test/test-tcp-open.c
new file mode 100644
index 00000000000..6c8d43d0009
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-open.c
@@ -0,0 +1,220 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef _WIN32
+# include <unistd.h>
+#endif
+
+static int shutdown_cb_called = 0;
+static int connect_cb_called = 0;
+static int write_cb_called = 0;
+static int close_cb_called = 0;
+
+static uv_connect_t connect_req;
+static uv_shutdown_t shutdown_req;
+static uv_write_t write_req;
+
+
+static void startup(void) {
+#ifdef _WIN32
+ struct WSAData wsa_data;
+ int r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ ASSERT(r == 0);
+#endif
+}
+
+
+static uv_os_sock_t create_tcp_socket(void) {
+ uv_os_sock_t sock;
+
+ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+#ifdef _WIN32
+ ASSERT(sock != INVALID_SOCKET);
+#else
+ ASSERT(sock >= 0);
+#endif
+
+#ifndef _WIN32
+ {
+ /* Allow reuse of the port. */
+ int yes = 1;
+ int r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);
+ ASSERT(r == 0);
+ }
+#endif
+
+ return sock;
+}
+
+
+static void close_socket(uv_os_sock_t sock) {
+ int r;
+#ifdef _WIN32
+ r = closesocket(sock);
+#else
+ r = close(sock);
+#endif
+ ASSERT(r == 0);
+}
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ ASSERT(suggested_size <= sizeof(slab));
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+ ASSERT(req == &shutdown_req);
+ ASSERT(status == 0);
+
+ /* Now we wait for the EOF */
+ shutdown_cb_called++;
+}
+
+
+static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ ASSERT(tcp != NULL);
+
+ if (nread >= 0) {
+ ASSERT(nread == 4);
+ ASSERT(memcmp("PING", buf->base, nread) == 0);
+ }
+ else {
+ ASSERT(nread == UV_EOF);
+ printf("GOT EOF\n");
+ uv_close((uv_handle_t*)tcp, close_cb);
+ }
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(req != NULL);
+
+ if (status) {
+ fprintf(stderr, "uv_write error: %s\n", uv_strerror(status));
+ ASSERT(0);
+ }
+
+ write_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ uv_buf_t buf = uv_buf_init("PING", 4);
+ uv_stream_t* stream;
+ int r;
+
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+
+ stream = req->handle;
+ connect_cb_called++;
+
+ r = uv_write(&write_req, stream, &buf, 1, write_cb);
+ ASSERT(r == 0);
+
+ /* Shutdown on drain. */
+ r = uv_shutdown(&shutdown_req, stream, shutdown_cb);
+ ASSERT(r == 0);
+
+ /* Start reading */
+ r = uv_read_start(stream, alloc_cb, read_cb);
+ ASSERT(r == 0);
+}
+
+
+TEST_IMPL(tcp_open) {
+ struct sockaddr_in addr;
+ uv_tcp_t client;
+ uv_os_sock_t sock;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ startup();
+ sock = create_tcp_socket();
+
+ r = uv_tcp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ r = uv_tcp_open(&client, sock);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(&connect_req,
+ &client,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(shutdown_cb_called == 1);
+ ASSERT(connect_cb_called == 1);
+ ASSERT(write_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tcp_open_twice) {
+ uv_tcp_t client;
+ uv_os_sock_t sock1, sock2;
+ int r;
+
+ startup();
+ sock1 = create_tcp_socket();
+ sock2 = create_tcp_socket();
+
+ r = uv_tcp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ r = uv_tcp_open(&client, sock1);
+ ASSERT(r == 0);
+
+ r = uv_tcp_open(&client, sock2);
+ ASSERT(r == UV_EBUSY);
+ close_socket(sock2);
+
+ uv_close((uv_handle_t*) &client, NULL);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-read-stop.c b/3rdparty/libuv/test/test-tcp-read-stop.c
new file mode 100644
index 00000000000..488e8fb49a9
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-read-stop.c
@@ -0,0 +1,76 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_timer_t timer_handle;
+static uv_tcp_t tcp_handle;
+static uv_write_t write_req;
+
+
+static void fail_cb(void) {
+ ASSERT(0 && "fail_cb called");
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ uv_close((uv_handle_t*) &timer_handle, NULL);
+ uv_close((uv_handle_t*) &tcp_handle, NULL);
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ uv_buf_t buf = uv_buf_init("PING", 4);
+ ASSERT(0 == uv_write(&write_req,
+ (uv_stream_t*) &tcp_handle,
+ &buf,
+ 1,
+ write_cb));
+ ASSERT(0 == uv_read_stop((uv_stream_t*) &tcp_handle));
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ ASSERT(0 == status);
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 50, 0));
+ ASSERT(0 == uv_read_start((uv_stream_t*) &tcp_handle,
+ (uv_alloc_cb) fail_cb,
+ (uv_read_cb) fail_cb));
+}
+
+
+TEST_IMPL(tcp_read_stop) {
+ uv_connect_t connect_req;
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle));
+ ASSERT(0 == uv_tcp_init(uv_default_loop(), &tcp_handle));
+ ASSERT(0 == uv_tcp_connect(&connect_req,
+ &tcp_handle,
+ (const struct sockaddr*) &addr,
+ connect_cb));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ MAKE_VALGRIND_HAPPY();
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-shutdown-after-write.c b/3rdparty/libuv/test/test-tcp-shutdown-after-write.c
new file mode 100644
index 00000000000..463b4b0d79c
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-shutdown-after-write.c
@@ -0,0 +1,138 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static void write_cb(uv_write_t* req, int status);
+static void shutdown_cb(uv_shutdown_t* req, int status);
+
+static uv_tcp_t conn;
+static uv_timer_t timer;
+static uv_connect_t connect_req;
+static uv_write_t write_req;
+static uv_shutdown_t shutdown_req;
+
+static int connect_cb_called;
+static int write_cb_called;
+static int shutdown_cb_called;
+
+static int conn_close_cb_called;
+static int timer_close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ if (handle == (uv_handle_t*)&conn)
+ conn_close_cb_called++;
+ else if (handle == (uv_handle_t*)&timer)
+ timer_close_cb_called++;
+ else
+ ASSERT(0 && "bad handle in close_cb");
+}
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[64];
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ uv_buf_t buf;
+ int r;
+
+ uv_close((uv_handle_t*)handle, close_cb);
+
+ buf = uv_buf_init("TEST", 4);
+ r = uv_write(&write_req, (uv_stream_t*)&conn, &buf, 1, write_cb);
+ ASSERT(r == 0);
+
+ r = uv_shutdown(&shutdown_req, (uv_stream_t*)&conn, shutdown_cb);
+ ASSERT(r == 0);
+}
+
+
+static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) {
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ int r;
+
+ ASSERT(status == 0);
+ connect_cb_called++;
+
+ r = uv_read_start((uv_stream_t*)&conn, alloc_cb, read_cb);
+ ASSERT(r == 0);
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+ write_cb_called++;
+}
+
+
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+ ASSERT(status == 0);
+ shutdown_cb_called++;
+ uv_close((uv_handle_t*)&conn, close_cb);
+}
+
+
+TEST_IMPL(tcp_shutdown_after_write) {
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ loop = uv_default_loop();
+
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r == 0);
+
+ r = uv_timer_start(&timer, timer_cb, 125, 0);
+ ASSERT(r == 0);
+
+ r = uv_tcp_init(loop, &conn);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(&connect_req,
+ &conn,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(write_cb_called == 1);
+ ASSERT(shutdown_cb_called == 1);
+ ASSERT(conn_close_cb_called == 1);
+ ASSERT(timer_close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-try-write.c b/3rdparty/libuv/test/test-tcp-try-write.c
new file mode 100644
index 00000000000..97a1d6e3d57
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-try-write.c
@@ -0,0 +1,135 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAX_BYTES 1024 * 1024
+
+static uv_tcp_t server;
+static uv_tcp_t client;
+static uv_tcp_t incoming;
+static int connect_cb_called;
+static int close_cb_called;
+static int connection_cb_called;
+static int bytes_read;
+static int bytes_written;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ int r;
+ uv_buf_t buf;
+ ASSERT(status == 0);
+ connect_cb_called++;
+
+ do {
+ buf = uv_buf_init("PING", 4);
+ r = uv_try_write((uv_stream_t*) &client, &buf, 1);
+ ASSERT(r > 0 || r == UV_EAGAIN);
+ if (r > 0) {
+ bytes_written += r;
+ break;
+ }
+ } while (1);
+
+ do {
+ buf = uv_buf_init("", 0);
+ r = uv_try_write((uv_stream_t*) &client, &buf, 1);
+ } while (r != 0);
+ uv_close((uv_handle_t*) &client, close_cb);
+}
+
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ static char base[1024];
+
+ buf->base = base;
+ buf->len = sizeof(base);
+}
+
+
+static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ if (nread < 0) {
+ uv_close((uv_handle_t*) tcp, close_cb);
+ uv_close((uv_handle_t*) &server, close_cb);
+ return;
+ }
+
+ bytes_read += nread;
+}
+
+
+static void connection_cb(uv_stream_t* tcp, int status) {
+ ASSERT(status == 0);
+
+ ASSERT(0 == uv_tcp_init(tcp->loop, &incoming));
+ ASSERT(0 == uv_accept(tcp, (uv_stream_t*) &incoming));
+
+ connection_cb_called++;
+ ASSERT(0 == uv_read_start((uv_stream_t*) &incoming, alloc_cb, read_cb));
+}
+
+
+static void start_server(void) {
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ ASSERT(0 == uv_tcp_init(uv_default_loop(), &server));
+ ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) &addr, 0));
+ ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, connection_cb));
+}
+
+
+TEST_IMPL(tcp_try_write) {
+ uv_connect_t connect_req;
+ struct sockaddr_in addr;
+
+ start_server();
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ ASSERT(0 == uv_tcp_init(uv_default_loop(), &client));
+ ASSERT(0 == uv_tcp_connect(&connect_req,
+ &client,
+ (struct sockaddr*) &addr,
+ connect_cb));
+
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(close_cb_called == 3);
+ ASSERT(connection_cb_called == 1);
+ ASSERT(bytes_read == bytes_written);
+ ASSERT(bytes_written > 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-unexpected-read.c b/3rdparty/libuv/test/test-tcp-unexpected-read.c
new file mode 100644
index 00000000000..c7b981456be
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-unexpected-read.c
@@ -0,0 +1,117 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_check_t check_handle;
+static uv_timer_t timer_handle;
+static uv_tcp_t server_handle;
+static uv_tcp_t client_handle;
+static uv_tcp_t peer_handle;
+static uv_write_t write_req;
+static uv_connect_t connect_req;
+
+static unsigned long ticks; /* event loop ticks */
+
+
+static void check_cb(uv_check_t* handle) {
+ ticks++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ uv_close((uv_handle_t*) &check_handle, NULL);
+ uv_close((uv_handle_t*) &timer_handle, NULL);
+ uv_close((uv_handle_t*) &server_handle, NULL);
+ uv_close((uv_handle_t*) &client_handle, NULL);
+ uv_close((uv_handle_t*) &peer_handle, NULL);
+}
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ ASSERT(0 && "alloc_cb should not have been called");
+}
+
+
+static void read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) {
+ ASSERT(0 && "read_cb should not have been called");
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ ASSERT(req->handle == (uv_stream_t*) &client_handle);
+ ASSERT(0 == status);
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(req->handle == (uv_stream_t*) &peer_handle);
+ ASSERT(0 == status);
+}
+
+
+static void connection_cb(uv_stream_t* handle, int status) {
+ uv_buf_t buf;
+
+ buf = uv_buf_init("PING", 4);
+
+ ASSERT(0 == status);
+ ASSERT(0 == uv_accept(handle, (uv_stream_t*) &peer_handle));
+ ASSERT(0 == uv_read_start((uv_stream_t*) &peer_handle, alloc_cb, read_cb));
+ ASSERT(0 == uv_write(&write_req, (uv_stream_t*) &peer_handle,
+ &buf, 1, write_cb));
+}
+
+
+TEST_IMPL(tcp_unexpected_read) {
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ loop = uv_default_loop();
+
+ ASSERT(0 == uv_timer_init(loop, &timer_handle));
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1000, 0));
+ ASSERT(0 == uv_check_init(loop, &check_handle));
+ ASSERT(0 == uv_check_start(&check_handle, check_cb));
+ ASSERT(0 == uv_tcp_init(loop, &server_handle));
+ ASSERT(0 == uv_tcp_init(loop, &client_handle));
+ ASSERT(0 == uv_tcp_init(loop, &peer_handle));
+ ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0));
+ ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 1, connection_cb));
+ ASSERT(0 == uv_tcp_connect(&connect_req,
+ &client_handle,
+ (const struct sockaddr*) &addr,
+ connect_cb));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ /* This is somewhat inexact but the idea is that the event loop should not
+ * start busy looping when the server sends a message and the client isn't
+ * reading.
+ */
+ ASSERT(ticks <= 20);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-write-after-connect.c b/3rdparty/libuv/test/test-tcp-write-after-connect.c
new file mode 100644
index 00000000000..aa03228f134
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-write-after-connect.c
@@ -0,0 +1,68 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _WIN32
+
+#include "uv.h"
+#include "task.h"
+
+uv_loop_t loop;
+uv_tcp_t tcp_client;
+uv_connect_t connection_request;
+uv_write_t write_request;
+uv_buf_t buf = { "HELLO", 4 };
+
+
+static void write_cb(uv_write_t *req, int status) {
+ ASSERT(status == UV_ECANCELED);
+ uv_close((uv_handle_t*) req->handle, NULL);
+}
+
+
+static void connect_cb(uv_connect_t *req, int status) {
+ ASSERT(status == UV_ECONNREFUSED);
+}
+
+
+TEST_IMPL(tcp_write_after_connect) {
+ struct sockaddr_in sa;
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &sa));
+ ASSERT(0 == uv_loop_init(&loop));
+ ASSERT(0 == uv_tcp_init(&loop, &tcp_client));
+
+ ASSERT(0 == uv_tcp_connect(&connection_request,
+ &tcp_client,
+ (const struct sockaddr *)
+ &sa,
+ connect_cb));
+
+ ASSERT(0 == uv_write(&write_request,
+ (uv_stream_t *)&tcp_client,
+ &buf, 1,
+ write_cb));
+
+ uv_run(&loop, UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif
diff --git a/3rdparty/libuv/test/test-tcp-write-fail.c b/3rdparty/libuv/test/test-tcp-write-fail.c
new file mode 100644
index 00000000000..5256a9f4a79
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-write-fail.c
@@ -0,0 +1,115 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef _WIN32
+# include <unistd.h>
+#endif
+
+
+static int connect_cb_called = 0;
+static int write_cb_called = 0;
+static int close_cb_called = 0;
+
+static uv_connect_t connect_req;
+static uv_write_t write_req;
+
+
+static void close_socket(uv_tcp_t* sock) {
+ uv_os_fd_t fd;
+ int r;
+
+ r = uv_fileno((uv_handle_t*)sock, &fd);
+ ASSERT(r == 0);
+#ifdef _WIN32
+ r = closesocket((uv_os_sock_t)fd);
+#else
+ r = close(fd);
+#endif
+ ASSERT(r == 0);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(req != NULL);
+
+ ASSERT(status != 0);
+ fprintf(stderr, "uv_write error: %s\n", uv_strerror(status));
+ write_cb_called++;
+
+ uv_close((uv_handle_t*)(req->handle), close_cb);
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ uv_buf_t buf;
+ uv_stream_t* stream;
+ int r;
+
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+
+ stream = req->handle;
+ connect_cb_called++;
+
+ /* close the socket, the hard way */
+ close_socket((uv_tcp_t*)stream);
+
+ buf = uv_buf_init("hello\n", 6);
+ r = uv_write(&write_req, stream, &buf, 1, write_cb);
+ ASSERT(r == 0);
+}
+
+
+TEST_IMPL(tcp_write_fail) {
+ struct sockaddr_in addr;
+ uv_tcp_t client;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_tcp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(&connect_req,
+ &client,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(write_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-write-queue-order.c b/3rdparty/libuv/test/test-tcp-write-queue-order.c
new file mode 100644
index 00000000000..aa4d2acc24a
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-write-queue-order.c
@@ -0,0 +1,137 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "uv.h"
+#include "task.h"
+
+#define REQ_COUNT 10000
+
+static uv_timer_t timer;
+static uv_tcp_t server;
+static uv_tcp_t client;
+static uv_tcp_t incoming;
+static int connect_cb_called;
+static int close_cb_called;
+static int connection_cb_called;
+static int write_callbacks;
+static int write_cancelled_callbacks;
+static int write_error_callbacks;
+
+static uv_write_t write_requests[REQ_COUNT];
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+void timer_cb(uv_timer_t* handle) {
+ uv_close((uv_handle_t*) &client, close_cb);
+ uv_close((uv_handle_t*) &server, close_cb);
+ uv_close((uv_handle_t*) &incoming, close_cb);
+}
+
+void write_cb(uv_write_t* req, int status) {
+ if (status == 0)
+ write_callbacks++;
+ else if (status == UV_ECANCELED)
+ write_cancelled_callbacks++;
+ else
+ write_error_callbacks++;
+}
+
+static void connect_cb(uv_connect_t* req, int status) {
+ static char base[1024];
+ int r;
+ int i;
+ uv_buf_t buf;
+
+ ASSERT(status == 0);
+ connect_cb_called++;
+
+ buf = uv_buf_init(base, sizeof(base));
+
+ for (i = 0; i < REQ_COUNT; i++) {
+ r = uv_write(&write_requests[i],
+ req->handle,
+ &buf,
+ 1,
+ write_cb);
+ ASSERT(r == 0);
+ }
+}
+
+
+static void connection_cb(uv_stream_t* tcp, int status) {
+ ASSERT(status == 0);
+
+ ASSERT(0 == uv_tcp_init(tcp->loop, &incoming));
+ ASSERT(0 == uv_accept(tcp, (uv_stream_t*) &incoming));
+
+ connection_cb_called++;
+}
+
+
+static void start_server(void) {
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ ASSERT(0 == uv_tcp_init(uv_default_loop(), &server));
+ ASSERT(0 == uv_tcp_bind(&server, (struct sockaddr*) &addr, 0));
+ ASSERT(0 == uv_listen((uv_stream_t*) &server, 128, connection_cb));
+}
+
+
+TEST_IMPL(tcp_write_queue_order) {
+ uv_connect_t connect_req;
+ struct sockaddr_in addr;
+
+ start_server();
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ ASSERT(0 == uv_tcp_init(uv_default_loop(), &client));
+ ASSERT(0 == uv_tcp_connect(&connect_req,
+ &client,
+ (struct sockaddr*) &addr,
+ connect_cb));
+
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &timer));
+ ASSERT(0 == uv_timer_start(&timer, timer_cb, 100, 0));
+
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(connection_cb_called == 1);
+ ASSERT(write_callbacks > 0);
+ ASSERT(write_cancelled_callbacks > 0);
+ ASSERT(write_callbacks +
+ write_error_callbacks +
+ write_cancelled_callbacks == REQ_COUNT);
+ ASSERT(close_cb_called == 3);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-write-to-half-open-connection.c b/3rdparty/libuv/test/test-tcp-write-to-half-open-connection.c
new file mode 100644
index 00000000000..2fa2ae72253
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-write-to-half-open-connection.c
@@ -0,0 +1,141 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void connection_cb(uv_stream_t* server, int status);
+static void connect_cb(uv_connect_t* req, int status);
+static void write_cb(uv_write_t* req, int status);
+static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
+static void alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf);
+
+static uv_tcp_t tcp_server;
+static uv_tcp_t tcp_client;
+static uv_tcp_t tcp_peer; /* client socket as accept()-ed by server */
+static uv_connect_t connect_req;
+static uv_write_t write_req;
+
+static int write_cb_called;
+static int read_cb_called;
+
+static void connection_cb(uv_stream_t* server, int status) {
+ int r;
+ uv_buf_t buf;
+
+ ASSERT(server == (uv_stream_t*)&tcp_server);
+ ASSERT(status == 0);
+
+ r = uv_tcp_init(server->loop, &tcp_peer);
+ ASSERT(r == 0);
+
+ r = uv_accept(server, (uv_stream_t*)&tcp_peer);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)&tcp_peer, alloc_cb, read_cb);
+ ASSERT(r == 0);
+
+ buf.base = "hello\n";
+ buf.len = 6;
+
+ r = uv_write(&write_req, (uv_stream_t*)&tcp_peer, &buf, 1, write_cb);
+ ASSERT(r == 0);
+}
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[1024];
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
+ if (nread < 0) {
+ fprintf(stderr, "read_cb error: %s\n", uv_err_name(nread));
+ ASSERT(nread == UV_ECONNRESET || nread == UV_EOF);
+
+ uv_close((uv_handle_t*)&tcp_server, NULL);
+ uv_close((uv_handle_t*)&tcp_peer, NULL);
+ }
+
+ read_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+
+ /* Close the client. */
+ uv_close((uv_handle_t*)&tcp_client, NULL);
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+ write_cb_called++;
+}
+
+
+TEST_IMPL(tcp_write_to_half_open_connection) {
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ loop = uv_default_loop();
+ ASSERT(loop != NULL);
+
+ r = uv_tcp_init(loop, &tcp_server);
+ ASSERT(r == 0);
+
+ r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_listen((uv_stream_t*)&tcp_server, 1, connection_cb);
+ ASSERT(r == 0);
+
+ r = uv_tcp_init(loop, &tcp_client);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(&connect_req,
+ &tcp_client,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(write_cb_called > 0);
+ ASSERT(read_cb_called > 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tcp-writealot.c b/3rdparty/libuv/test/test-tcp-writealot.c
new file mode 100644
index 00000000000..6cfe2ebb18d
--- /dev/null
+++ b/3rdparty/libuv/test/test-tcp-writealot.c
@@ -0,0 +1,176 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#define WRITES 3
+#define CHUNKS_PER_WRITE 4096
+#define CHUNK_SIZE 10024 /* 10 kb */
+
+#define TOTAL_BYTES (WRITES * CHUNKS_PER_WRITE * CHUNK_SIZE)
+
+static char* send_buffer;
+
+static int shutdown_cb_called = 0;
+static int connect_cb_called = 0;
+static int write_cb_called = 0;
+static int close_cb_called = 0;
+static size_t bytes_sent = 0;
+static size_t bytes_sent_done = 0;
+static size_t bytes_received_done = 0;
+
+static uv_connect_t connect_req;
+static uv_shutdown_t shutdown_req;
+static uv_write_t write_reqs[WRITES];
+
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ buf->base = malloc(size);
+ buf->len = size;
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+ uv_tcp_t* tcp;
+
+ ASSERT(req == &shutdown_req);
+ ASSERT(status == 0);
+
+ tcp = (uv_tcp_t*)(req->handle);
+
+ /* The write buffer should be empty by now. */
+ ASSERT(tcp->write_queue_size == 0);
+
+ /* Now we wait for the EOF */
+ shutdown_cb_called++;
+
+ /* We should have had all the writes called already. */
+ ASSERT(write_cb_called == WRITES);
+}
+
+
+static void read_cb(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
+ ASSERT(tcp != NULL);
+
+ if (nread >= 0) {
+ bytes_received_done += nread;
+ }
+ else {
+ ASSERT(nread == UV_EOF);
+ printf("GOT EOF\n");
+ uv_close((uv_handle_t*)tcp, close_cb);
+ }
+
+ free(buf->base);
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(req != NULL);
+
+ if (status) {
+ fprintf(stderr, "uv_write error: %s\n", uv_strerror(status));
+ ASSERT(0);
+ }
+
+ bytes_sent_done += CHUNKS_PER_WRITE * CHUNK_SIZE;
+ write_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ uv_buf_t send_bufs[CHUNKS_PER_WRITE];
+ uv_stream_t* stream;
+ int i, j, r;
+
+ ASSERT(req == &connect_req);
+ ASSERT(status == 0);
+
+ stream = req->handle;
+ connect_cb_called++;
+
+ /* Write a lot of data */
+ for (i = 0; i < WRITES; i++) {
+ uv_write_t* write_req = write_reqs + i;
+
+ for (j = 0; j < CHUNKS_PER_WRITE; j++) {
+ send_bufs[j] = uv_buf_init(send_buffer + bytes_sent, CHUNK_SIZE);
+ bytes_sent += CHUNK_SIZE;
+ }
+
+ r = uv_write(write_req, stream, send_bufs, CHUNKS_PER_WRITE, write_cb);
+ ASSERT(r == 0);
+ }
+
+ /* Shutdown on drain. */
+ r = uv_shutdown(&shutdown_req, stream, shutdown_cb);
+ ASSERT(r == 0);
+
+ /* Start reading */
+ r = uv_read_start(stream, alloc_cb, read_cb);
+ ASSERT(r == 0);
+}
+
+
+TEST_IMPL(tcp_writealot) {
+ struct sockaddr_in addr;
+ uv_tcp_t client;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ send_buffer = calloc(1, TOTAL_BYTES);
+ ASSERT(send_buffer != NULL);
+
+ r = uv_tcp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(&connect_req,
+ &client,
+ (const struct sockaddr*) &addr,
+ connect_cb);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(shutdown_cb_called == 1);
+ ASSERT(connect_cb_called == 1);
+ ASSERT(write_cb_called == WRITES);
+ ASSERT(close_cb_called == 1);
+ ASSERT(bytes_sent == TOTAL_BYTES);
+ ASSERT(bytes_sent_done == TOTAL_BYTES);
+ ASSERT(bytes_received_done == TOTAL_BYTES);
+
+ free(send_buffer);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-thread-equal.c b/3rdparty/libuv/test/test-thread-equal.c
new file mode 100644
index 00000000000..27c07ee2c7d
--- /dev/null
+++ b/3rdparty/libuv/test/test-thread-equal.c
@@ -0,0 +1,45 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+uv_thread_t main_thread_id;
+uv_thread_t subthreads[2];
+
+static void check_thread(void* arg) {
+ uv_thread_t *thread_id = arg;
+ uv_thread_t self_id = uv_thread_self();
+ ASSERT(uv_thread_equal(&main_thread_id, &self_id) == 0);
+ *thread_id = uv_thread_self();
+}
+
+TEST_IMPL(thread_equal) {
+ uv_thread_t threads[2];
+ main_thread_id = uv_thread_self();
+ ASSERT(0 != uv_thread_equal(&main_thread_id, &main_thread_id));
+ ASSERT(0 == uv_thread_create(threads + 0, check_thread, subthreads + 0));
+ ASSERT(0 == uv_thread_create(threads + 1, check_thread, subthreads + 1));
+ ASSERT(0 == uv_thread_join(threads + 0));
+ ASSERT(0 == uv_thread_join(threads + 1));
+ ASSERT(0 == uv_thread_equal(subthreads + 0, subthreads + 1));
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-thread.c b/3rdparty/libuv/test/test-thread.c
new file mode 100644
index 00000000000..7f3321aa06d
--- /dev/null
+++ b/3rdparty/libuv/test/test-thread.c
@@ -0,0 +1,211 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> /* memset */
+
+struct getaddrinfo_req {
+ uv_thread_t thread_id;
+ unsigned int counter;
+ uv_loop_t* loop;
+ uv_getaddrinfo_t handle;
+};
+
+
+struct fs_req {
+ uv_thread_t thread_id;
+ unsigned int counter;
+ uv_loop_t* loop;
+ uv_fs_t handle;
+};
+
+
+struct test_thread {
+ uv_thread_t thread_id;
+ volatile int thread_called;
+};
+
+static void getaddrinfo_do(struct getaddrinfo_req* req);
+static void getaddrinfo_cb(uv_getaddrinfo_t* handle,
+ int status,
+ struct addrinfo* res);
+static void fs_do(struct fs_req* req);
+static void fs_cb(uv_fs_t* handle);
+
+static volatile int thread_called;
+static uv_key_t tls_key;
+
+
+static void getaddrinfo_do(struct getaddrinfo_req* req) {
+ int r;
+
+ r = uv_getaddrinfo(req->loop,
+ &req->handle,
+ getaddrinfo_cb,
+ "localhost",
+ NULL,
+ NULL);
+ ASSERT(r == 0);
+}
+
+
+static void getaddrinfo_cb(uv_getaddrinfo_t* handle,
+ int status,
+ struct addrinfo* res) {
+ struct getaddrinfo_req* req;
+
+ ASSERT(status == 0);
+
+ req = container_of(handle, struct getaddrinfo_req, handle);
+ uv_freeaddrinfo(res);
+
+ if (--req->counter)
+ getaddrinfo_do(req);
+}
+
+
+static void fs_do(struct fs_req* req) {
+ int r;
+
+ r = uv_fs_stat(req->loop, &req->handle, ".", fs_cb);
+ ASSERT(r == 0);
+}
+
+
+static void fs_cb(uv_fs_t* handle) {
+ struct fs_req* req = container_of(handle, struct fs_req, handle);
+
+ uv_fs_req_cleanup(handle);
+
+ if (--req->counter)
+ fs_do(req);
+}
+
+
+static void do_work(void* arg) {
+ struct getaddrinfo_req getaddrinfo_reqs[16];
+ struct fs_req fs_reqs[16];
+ uv_loop_t* loop;
+ size_t i;
+ int r;
+ struct test_thread* thread = arg;
+
+ loop = malloc(sizeof *loop);
+ ASSERT(loop != NULL);
+ ASSERT(0 == uv_loop_init(loop));
+
+ for (i = 0; i < ARRAY_SIZE(getaddrinfo_reqs); i++) {
+ struct getaddrinfo_req* req = getaddrinfo_reqs + i;
+ req->counter = 16;
+ req->loop = loop;
+ getaddrinfo_do(req);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(fs_reqs); i++) {
+ struct fs_req* req = fs_reqs + i;
+ req->counter = 16;
+ req->loop = loop;
+ fs_do(req);
+ }
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_loop_close(loop));
+ free(loop);
+ thread->thread_called = 1;
+}
+
+
+static void thread_entry(void* arg) {
+ ASSERT(arg == (void *) 42);
+ thread_called++;
+}
+
+
+TEST_IMPL(thread_create) {
+ uv_thread_t tid;
+ int r;
+
+ r = uv_thread_create(&tid, thread_entry, (void *) 42);
+ ASSERT(r == 0);
+
+ r = uv_thread_join(&tid);
+ ASSERT(r == 0);
+
+ ASSERT(thread_called == 1);
+
+ return 0;
+}
+
+
+/* Hilariously bad test name. Run a lot of tasks in the thread pool and verify
+ * that each "finished" callback is run in its originating thread.
+ */
+TEST_IMPL(threadpool_multiple_event_loops) {
+ struct test_thread threads[8];
+ size_t i;
+ int r;
+
+ memset(threads, 0, sizeof(threads));
+
+ for (i = 0; i < ARRAY_SIZE(threads); i++) {
+ r = uv_thread_create(&threads[i].thread_id, do_work, &threads[i]);
+ ASSERT(r == 0);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(threads); i++) {
+ r = uv_thread_join(&threads[i].thread_id);
+ ASSERT(r == 0);
+ ASSERT(threads[i].thread_called);
+ }
+
+ return 0;
+}
+
+
+static void tls_thread(void* arg) {
+ ASSERT(NULL == uv_key_get(&tls_key));
+ uv_key_set(&tls_key, arg);
+ ASSERT(arg == uv_key_get(&tls_key));
+ uv_key_set(&tls_key, NULL);
+ ASSERT(NULL == uv_key_get(&tls_key));
+}
+
+
+TEST_IMPL(thread_local_storage) {
+ char name[] = "main";
+ uv_thread_t threads[2];
+ ASSERT(0 == uv_key_create(&tls_key));
+ ASSERT(NULL == uv_key_get(&tls_key));
+ uv_key_set(&tls_key, name);
+ ASSERT(name == uv_key_get(&tls_key));
+ ASSERT(0 == uv_thread_create(threads + 0, tls_thread, threads + 0));
+ ASSERT(0 == uv_thread_create(threads + 1, tls_thread, threads + 1));
+ ASSERT(0 == uv_thread_join(threads + 0));
+ ASSERT(0 == uv_thread_join(threads + 1));
+ uv_key_delete(&tls_key);
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-threadpool-cancel.c b/3rdparty/libuv/test/test-threadpool-cancel.c
new file mode 100644
index 00000000000..784c1739f6d
--- /dev/null
+++ b/3rdparty/libuv/test/test-threadpool-cancel.c
@@ -0,0 +1,362 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#define INIT_CANCEL_INFO(ci, what) \
+ do { \
+ (ci)->reqs = (what); \
+ (ci)->nreqs = ARRAY_SIZE(what); \
+ (ci)->stride = sizeof((what)[0]); \
+ } \
+ while (0)
+
+struct cancel_info {
+ void* reqs;
+ unsigned nreqs;
+ unsigned stride;
+ uv_timer_t timer_handle;
+};
+
+static uv_cond_t signal_cond;
+static uv_mutex_t signal_mutex;
+static uv_mutex_t wait_mutex;
+static unsigned num_threads;
+static unsigned fs_cb_called;
+static unsigned work_cb_called;
+static unsigned done_cb_called;
+static unsigned done2_cb_called;
+static unsigned timer_cb_called;
+
+
+static void work_cb(uv_work_t* req) {
+ uv_mutex_lock(&signal_mutex);
+ uv_cond_signal(&signal_cond);
+ uv_mutex_unlock(&signal_mutex);
+
+ uv_mutex_lock(&wait_mutex);
+ uv_mutex_unlock(&wait_mutex);
+
+ work_cb_called++;
+}
+
+
+static void done_cb(uv_work_t* req, int status) {
+ done_cb_called++;
+ free(req);
+}
+
+
+static void saturate_threadpool(void) {
+ uv_work_t* req;
+
+ ASSERT(0 == uv_cond_init(&signal_cond));
+ ASSERT(0 == uv_mutex_init(&signal_mutex));
+ ASSERT(0 == uv_mutex_init(&wait_mutex));
+
+ uv_mutex_lock(&signal_mutex);
+ uv_mutex_lock(&wait_mutex);
+
+ for (num_threads = 0; /* empty */; num_threads++) {
+ req = malloc(sizeof(*req));
+ ASSERT(req != NULL);
+ ASSERT(0 == uv_queue_work(uv_default_loop(), req, work_cb, done_cb));
+
+ /* Expect to get signalled within 350 ms, otherwise assume that
+ * the thread pool is saturated. As with any timing dependent test,
+ * this is obviously not ideal.
+ */
+ if (uv_cond_timedwait(&signal_cond,
+ &signal_mutex,
+ (uint64_t) (350 * 1e6))) {
+ ASSERT(0 == uv_cancel((uv_req_t*) req));
+ break;
+ }
+ }
+}
+
+
+static void unblock_threadpool(void) {
+ uv_mutex_unlock(&signal_mutex);
+ uv_mutex_unlock(&wait_mutex);
+}
+
+
+static void cleanup_threadpool(void) {
+ ASSERT(done_cb_called == num_threads + 1); /* +1 == cancelled work req. */
+ ASSERT(work_cb_called == num_threads);
+
+ uv_cond_destroy(&signal_cond);
+ uv_mutex_destroy(&signal_mutex);
+ uv_mutex_destroy(&wait_mutex);
+}
+
+
+static void fs_cb(uv_fs_t* req) {
+ ASSERT(req->result == UV_ECANCELED);
+ uv_fs_req_cleanup(req);
+ fs_cb_called++;
+}
+
+
+static void getaddrinfo_cb(uv_getaddrinfo_t* req,
+ int status,
+ struct addrinfo* res) {
+ ASSERT(status == UV_EAI_CANCELED);
+ ASSERT(res == NULL);
+ uv_freeaddrinfo(res); /* Should not crash. */
+}
+
+
+static void getnameinfo_cb(uv_getnameinfo_t* handle,
+ int status,
+ const char* hostname,
+ const char* service) {
+ ASSERT(status == UV_EAI_CANCELED);
+ ASSERT(hostname == NULL);
+ ASSERT(service == NULL);
+}
+
+
+static void work2_cb(uv_work_t* req) {
+ ASSERT(0 && "work2_cb called");
+}
+
+
+static void done2_cb(uv_work_t* req, int status) {
+ ASSERT(status == UV_ECANCELED);
+ done2_cb_called++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ struct cancel_info* ci;
+ uv_req_t* req;
+ unsigned i;
+
+ ci = container_of(handle, struct cancel_info, timer_handle);
+
+ for (i = 0; i < ci->nreqs; i++) {
+ req = (uv_req_t*) ((char*) ci->reqs + i * ci->stride);
+ ASSERT(0 == uv_cancel(req));
+ }
+
+ uv_close((uv_handle_t*) &ci->timer_handle, NULL);
+ unblock_threadpool();
+ timer_cb_called++;
+}
+
+
+static void nop_work_cb(uv_work_t* req) {
+}
+
+
+static void nop_done_cb(uv_work_t* req, int status) {
+ req->data = "OK";
+}
+
+
+TEST_IMPL(threadpool_cancel_getaddrinfo) {
+ uv_getaddrinfo_t reqs[4];
+ struct cancel_info ci;
+ struct addrinfo hints;
+ uv_loop_t* loop;
+ int r;
+
+ INIT_CANCEL_INFO(&ci, reqs);
+ loop = uv_default_loop();
+ saturate_threadpool();
+
+ r = uv_getaddrinfo(loop, reqs + 0, getaddrinfo_cb, "fail", NULL, NULL);
+ ASSERT(r == 0);
+
+ r = uv_getaddrinfo(loop, reqs + 1, getaddrinfo_cb, NULL, "fail", NULL);
+ ASSERT(r == 0);
+
+ r = uv_getaddrinfo(loop, reqs + 2, getaddrinfo_cb, "fail", "fail", NULL);
+ ASSERT(r == 0);
+
+ r = uv_getaddrinfo(loop, reqs + 3, getaddrinfo_cb, "fail", NULL, &hints);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_timer_init(loop, &ci.timer_handle));
+ ASSERT(0 == uv_timer_start(&ci.timer_handle, timer_cb, 10, 0));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(1 == timer_cb_called);
+
+ cleanup_threadpool();
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(threadpool_cancel_getnameinfo) {
+ uv_getnameinfo_t reqs[4];
+ struct sockaddr_in addr4;
+ struct cancel_info ci;
+ uv_loop_t* loop;
+ int r;
+
+ r = uv_ip4_addr("127.0.0.1", 80, &addr4);
+ ASSERT(r == 0);
+
+ INIT_CANCEL_INFO(&ci, reqs);
+ loop = uv_default_loop();
+ saturate_threadpool();
+
+ r = uv_getnameinfo(loop, reqs + 0, getnameinfo_cb, (const struct sockaddr*)&addr4, 0);
+ ASSERT(r == 0);
+
+ r = uv_getnameinfo(loop, reqs + 1, getnameinfo_cb, (const struct sockaddr*)&addr4, 0);
+ ASSERT(r == 0);
+
+ r = uv_getnameinfo(loop, reqs + 2, getnameinfo_cb, (const struct sockaddr*)&addr4, 0);
+ ASSERT(r == 0);
+
+ r = uv_getnameinfo(loop, reqs + 3, getnameinfo_cb, (const struct sockaddr*)&addr4, 0);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_timer_init(loop, &ci.timer_handle));
+ ASSERT(0 == uv_timer_start(&ci.timer_handle, timer_cb, 10, 0));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(1 == timer_cb_called);
+
+ cleanup_threadpool();
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(threadpool_cancel_work) {
+ struct cancel_info ci;
+ uv_work_t reqs[16];
+ uv_loop_t* loop;
+ unsigned i;
+
+ INIT_CANCEL_INFO(&ci, reqs);
+ loop = uv_default_loop();
+ saturate_threadpool();
+
+ for (i = 0; i < ARRAY_SIZE(reqs); i++)
+ ASSERT(0 == uv_queue_work(loop, reqs + i, work2_cb, done2_cb));
+
+ ASSERT(0 == uv_timer_init(loop, &ci.timer_handle));
+ ASSERT(0 == uv_timer_start(&ci.timer_handle, timer_cb, 10, 0));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(1 == timer_cb_called);
+ ASSERT(ARRAY_SIZE(reqs) == done2_cb_called);
+
+ cleanup_threadpool();
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(threadpool_cancel_fs) {
+ struct cancel_info ci;
+ uv_fs_t reqs[26];
+ uv_loop_t* loop;
+ unsigned n;
+ uv_buf_t iov;
+
+ INIT_CANCEL_INFO(&ci, reqs);
+ loop = uv_default_loop();
+ saturate_threadpool();
+ iov = uv_buf_init(NULL, 0);
+
+ /* Needs to match ARRAY_SIZE(fs_reqs). */
+ n = 0;
+ ASSERT(0 == uv_fs_chmod(loop, reqs + n++, "/", 0, fs_cb));
+ ASSERT(0 == uv_fs_chown(loop, reqs + n++, "/", 0, 0, fs_cb));
+ ASSERT(0 == uv_fs_close(loop, reqs + n++, 0, fs_cb));
+ ASSERT(0 == uv_fs_fchmod(loop, reqs + n++, 0, 0, fs_cb));
+ ASSERT(0 == uv_fs_fchown(loop, reqs + n++, 0, 0, 0, fs_cb));
+ ASSERT(0 == uv_fs_fdatasync(loop, reqs + n++, 0, fs_cb));
+ ASSERT(0 == uv_fs_fstat(loop, reqs + n++, 0, fs_cb));
+ ASSERT(0 == uv_fs_fsync(loop, reqs + n++, 0, fs_cb));
+ ASSERT(0 == uv_fs_ftruncate(loop, reqs + n++, 0, 0, fs_cb));
+ ASSERT(0 == uv_fs_futime(loop, reqs + n++, 0, 0, 0, fs_cb));
+ ASSERT(0 == uv_fs_link(loop, reqs + n++, "/", "/", fs_cb));
+ ASSERT(0 == uv_fs_lstat(loop, reqs + n++, "/", fs_cb));
+ ASSERT(0 == uv_fs_mkdir(loop, reqs + n++, "/", 0, fs_cb));
+ ASSERT(0 == uv_fs_open(loop, reqs + n++, "/", 0, 0, fs_cb));
+ ASSERT(0 == uv_fs_read(loop, reqs + n++, 0, &iov, 1, 0, fs_cb));
+ ASSERT(0 == uv_fs_scandir(loop, reqs + n++, "/", 0, fs_cb));
+ ASSERT(0 == uv_fs_readlink(loop, reqs + n++, "/", fs_cb));
+ ASSERT(0 == uv_fs_realpath(loop, reqs + n++, "/", fs_cb));
+ ASSERT(0 == uv_fs_rename(loop, reqs + n++, "/", "/", fs_cb));
+ ASSERT(0 == uv_fs_mkdir(loop, reqs + n++, "/", 0, fs_cb));
+ ASSERT(0 == uv_fs_sendfile(loop, reqs + n++, 0, 0, 0, 0, fs_cb));
+ ASSERT(0 == uv_fs_stat(loop, reqs + n++, "/", fs_cb));
+ ASSERT(0 == uv_fs_symlink(loop, reqs + n++, "/", "/", 0, fs_cb));
+ ASSERT(0 == uv_fs_unlink(loop, reqs + n++, "/", fs_cb));
+ ASSERT(0 == uv_fs_utime(loop, reqs + n++, "/", 0, 0, fs_cb));
+ ASSERT(0 == uv_fs_write(loop, reqs + n++, 0, &iov, 1, 0, fs_cb));
+ ASSERT(n == ARRAY_SIZE(reqs));
+
+ ASSERT(0 == uv_timer_init(loop, &ci.timer_handle));
+ ASSERT(0 == uv_timer_start(&ci.timer_handle, timer_cb, 10, 0));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(n == fs_cb_called);
+ ASSERT(1 == timer_cb_called);
+
+ cleanup_threadpool();
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(threadpool_cancel_single) {
+ uv_loop_t* loop;
+ uv_work_t req;
+ int cancelled;
+ int i;
+
+ loop = uv_default_loop();
+ for (i = 0; i < 5000; i++) {
+ req.data = NULL;
+ ASSERT(0 == uv_queue_work(loop, &req, nop_work_cb, nop_done_cb));
+
+ cancelled = uv_cancel((uv_req_t*) &req);
+ if (cancelled == 0)
+ break;
+
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ }
+
+ if (cancelled != 0) {
+ fputs("Failed to cancel a work req in 5,000 iterations, giving up.\n",
+ stderr);
+ return 1;
+ }
+
+ ASSERT(req.data == NULL);
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(req.data != NULL); /* Should have been updated by nop_done_cb(). */
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-threadpool.c b/3rdparty/libuv/test/test-threadpool.c
new file mode 100644
index 00000000000..e3d17d7546f
--- /dev/null
+++ b/3rdparty/libuv/test/test-threadpool.c
@@ -0,0 +1,76 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static int work_cb_count;
+static int after_work_cb_count;
+static uv_work_t work_req;
+static char data;
+
+
+static void work_cb(uv_work_t* req) {
+ ASSERT(req == &work_req);
+ ASSERT(req->data == &data);
+ work_cb_count++;
+}
+
+
+static void after_work_cb(uv_work_t* req, int status) {
+ ASSERT(status == 0);
+ ASSERT(req == &work_req);
+ ASSERT(req->data == &data);
+ after_work_cb_count++;
+}
+
+
+TEST_IMPL(threadpool_queue_work_simple) {
+ int r;
+
+ work_req.data = &data;
+ r = uv_queue_work(uv_default_loop(), &work_req, work_cb, after_work_cb);
+ ASSERT(r == 0);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(work_cb_count == 1);
+ ASSERT(after_work_cb_count == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(threadpool_queue_work_einval) {
+ int r;
+
+ work_req.data = &data;
+ r = uv_queue_work(uv_default_loop(), &work_req, NULL, after_work_cb);
+ ASSERT(r == UV_EINVAL);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(work_cb_count == 0);
+ ASSERT(after_work_cb_count == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-timer-again.c b/3rdparty/libuv/test/test-timer-again.c
new file mode 100644
index 00000000000..f93c509be5d
--- /dev/null
+++ b/3rdparty/libuv/test/test-timer-again.c
@@ -0,0 +1,141 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+static int close_cb_called = 0;
+static int repeat_1_cb_called = 0;
+static int repeat_2_cb_called = 0;
+
+static int repeat_2_cb_allowed = 0;
+
+static uv_timer_t dummy, repeat_1, repeat_2;
+
+static uint64_t start_time;
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+
+ close_cb_called++;
+}
+
+
+static void repeat_1_cb(uv_timer_t* handle) {
+ int r;
+
+ ASSERT(handle == &repeat_1);
+ ASSERT(uv_timer_get_repeat((uv_timer_t*)handle) == 50);
+
+ fprintf(stderr, "repeat_1_cb called after %ld ms\n",
+ (long int)(uv_now(uv_default_loop()) - start_time));
+ fflush(stderr);
+
+ repeat_1_cb_called++;
+
+ r = uv_timer_again(&repeat_2);
+ ASSERT(r == 0);
+
+ if (repeat_1_cb_called == 10) {
+ uv_close((uv_handle_t*)handle, close_cb);
+ /* We're not calling uv_timer_again on repeat_2 any more, so after this */
+ /* timer_2_cb is expected. */
+ repeat_2_cb_allowed = 1;
+ return;
+ }
+}
+
+
+static void repeat_2_cb(uv_timer_t* handle) {
+ ASSERT(handle == &repeat_2);
+ ASSERT(repeat_2_cb_allowed);
+
+ fprintf(stderr, "repeat_2_cb called after %ld ms\n",
+ (long int)(uv_now(uv_default_loop()) - start_time));
+ fflush(stderr);
+
+ repeat_2_cb_called++;
+
+ if (uv_timer_get_repeat(&repeat_2) == 0) {
+ ASSERT(0 == uv_is_active((uv_handle_t*) handle));
+ uv_close((uv_handle_t*)handle, close_cb);
+ return;
+ }
+
+ fprintf(stderr, "uv_timer_get_repeat %ld ms\n",
+ (long int)uv_timer_get_repeat(&repeat_2));
+ fflush(stderr);
+ ASSERT(uv_timer_get_repeat(&repeat_2) == 100);
+
+ /* This shouldn't take effect immediately. */
+ uv_timer_set_repeat(&repeat_2, 0);
+}
+
+
+TEST_IMPL(timer_again) {
+ int r;
+
+ start_time = uv_now(uv_default_loop());
+ ASSERT(0 < start_time);
+
+ /* Verify that it is not possible to uv_timer_again a never-started timer. */
+ r = uv_timer_init(uv_default_loop(), &dummy);
+ ASSERT(r == 0);
+ r = uv_timer_again(&dummy);
+ ASSERT(r == UV_EINVAL);
+ uv_unref((uv_handle_t*)&dummy);
+
+ /* Start timer repeat_1. */
+ r = uv_timer_init(uv_default_loop(), &repeat_1);
+ ASSERT(r == 0);
+ r = uv_timer_start(&repeat_1, repeat_1_cb, 50, 0);
+ ASSERT(r == 0);
+ ASSERT(uv_timer_get_repeat(&repeat_1) == 0);
+
+ /* Actually make repeat_1 repeating. */
+ uv_timer_set_repeat(&repeat_1, 50);
+ ASSERT(uv_timer_get_repeat(&repeat_1) == 50);
+
+ /*
+ * Start another repeating timer. It'll be again()ed by the repeat_1 so
+ * it should not time out until repeat_1 stops.
+ */
+ r = uv_timer_init(uv_default_loop(), &repeat_2);
+ ASSERT(r == 0);
+ r = uv_timer_start(&repeat_2, repeat_2_cb, 100, 100);
+ ASSERT(r == 0);
+ ASSERT(uv_timer_get_repeat(&repeat_2) == 100);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(repeat_1_cb_called == 10);
+ ASSERT(repeat_2_cb_called == 2);
+ ASSERT(close_cb_called == 2);
+
+ fprintf(stderr, "Test took %ld ms (expected ~700 ms)\n",
+ (long int)(uv_now(uv_default_loop()) - start_time));
+ fflush(stderr);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-timer-from-check.c b/3rdparty/libuv/test/test-timer-from-check.c
new file mode 100644
index 00000000000..a18c7e1fb99
--- /dev/null
+++ b/3rdparty/libuv/test/test-timer-from-check.c
@@ -0,0 +1,80 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_prepare_t prepare_handle;
+static uv_check_t check_handle;
+static uv_timer_t timer_handle;
+
+static int prepare_cb_called;
+static int check_cb_called;
+static int timer_cb_called;
+
+
+static void prepare_cb(uv_prepare_t* handle) {
+ ASSERT(0 == uv_prepare_stop(&prepare_handle));
+ ASSERT(0 == prepare_cb_called);
+ ASSERT(1 == check_cb_called);
+ ASSERT(0 == timer_cb_called);
+ prepare_cb_called++;
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(0 == uv_timer_stop(&timer_handle));
+ ASSERT(1 == prepare_cb_called);
+ ASSERT(1 == check_cb_called);
+ ASSERT(0 == timer_cb_called);
+ timer_cb_called++;
+}
+
+
+static void check_cb(uv_check_t* handle) {
+ ASSERT(0 == uv_check_stop(&check_handle));
+ ASSERT(0 == uv_timer_stop(&timer_handle)); /* Runs before timer_cb. */
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 50, 0));
+ ASSERT(0 == uv_prepare_start(&prepare_handle, prepare_cb));
+ ASSERT(0 == prepare_cb_called);
+ ASSERT(0 == check_cb_called);
+ ASSERT(0 == timer_cb_called);
+ check_cb_called++;
+}
+
+
+TEST_IMPL(timer_from_check) {
+ ASSERT(0 == uv_prepare_init(uv_default_loop(), &prepare_handle));
+ ASSERT(0 == uv_check_init(uv_default_loop(), &check_handle));
+ ASSERT(0 == uv_check_start(&check_handle, check_cb));
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle));
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 50, 0));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ ASSERT(1 == prepare_cb_called);
+ ASSERT(1 == check_cb_called);
+ ASSERT(1 == timer_cb_called);
+ uv_close((uv_handle_t*) &prepare_handle, NULL);
+ uv_close((uv_handle_t*) &check_handle, NULL);
+ uv_close((uv_handle_t*) &timer_handle, NULL);
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-timer.c b/3rdparty/libuv/test/test-timer.c
new file mode 100644
index 00000000000..aba050fd64c
--- /dev/null
+++ b/3rdparty/libuv/test/test-timer.c
@@ -0,0 +1,303 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+
+static int once_cb_called = 0;
+static int once_close_cb_called = 0;
+static int repeat_cb_called = 0;
+static int repeat_close_cb_called = 0;
+static int order_cb_called = 0;
+static uint64_t start_time;
+static uv_timer_t tiny_timer;
+static uv_timer_t huge_timer1;
+static uv_timer_t huge_timer2;
+
+
+static void once_close_cb(uv_handle_t* handle) {
+ printf("ONCE_CLOSE_CB\n");
+
+ ASSERT(handle != NULL);
+ ASSERT(0 == uv_is_active(handle));
+
+ once_close_cb_called++;
+}
+
+
+static void once_cb(uv_timer_t* handle) {
+ printf("ONCE_CB %d\n", once_cb_called);
+
+ ASSERT(handle != NULL);
+ ASSERT(0 == uv_is_active((uv_handle_t*) handle));
+
+ once_cb_called++;
+
+ uv_close((uv_handle_t*)handle, once_close_cb);
+
+ /* Just call this randomly for the code coverage. */
+ uv_update_time(uv_default_loop());
+}
+
+
+static void repeat_close_cb(uv_handle_t* handle) {
+ printf("REPEAT_CLOSE_CB\n");
+
+ ASSERT(handle != NULL);
+
+ repeat_close_cb_called++;
+}
+
+
+static void repeat_cb(uv_timer_t* handle) {
+ printf("REPEAT_CB\n");
+
+ ASSERT(handle != NULL);
+ ASSERT(1 == uv_is_active((uv_handle_t*) handle));
+
+ repeat_cb_called++;
+
+ if (repeat_cb_called == 5) {
+ uv_close((uv_handle_t*)handle, repeat_close_cb);
+ }
+}
+
+
+static void never_cb(uv_timer_t* handle) {
+ FATAL("never_cb should never be called");
+}
+
+
+TEST_IMPL(timer) {
+ uv_timer_t once_timers[10];
+ uv_timer_t *once;
+ uv_timer_t repeat, never;
+ unsigned int i;
+ int r;
+
+ start_time = uv_now(uv_default_loop());
+ ASSERT(0 < start_time);
+
+ /* Let 10 timers time out in 500 ms total. */
+ for (i = 0; i < ARRAY_SIZE(once_timers); i++) {
+ once = once_timers + i;
+ r = uv_timer_init(uv_default_loop(), once);
+ ASSERT(r == 0);
+ r = uv_timer_start(once, once_cb, i * 50, 0);
+ ASSERT(r == 0);
+ }
+
+ /* The 11th timer is a repeating timer that runs 4 times */
+ r = uv_timer_init(uv_default_loop(), &repeat);
+ ASSERT(r == 0);
+ r = uv_timer_start(&repeat, repeat_cb, 100, 100);
+ ASSERT(r == 0);
+
+ /* The 12th timer should not do anything. */
+ r = uv_timer_init(uv_default_loop(), &never);
+ ASSERT(r == 0);
+ r = uv_timer_start(&never, never_cb, 100, 100);
+ ASSERT(r == 0);
+ r = uv_timer_stop(&never);
+ ASSERT(r == 0);
+ uv_unref((uv_handle_t*)&never);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(once_cb_called == 10);
+ ASSERT(once_close_cb_called == 10);
+ printf("repeat_cb_called %d\n", repeat_cb_called);
+ ASSERT(repeat_cb_called == 5);
+ ASSERT(repeat_close_cb_called == 1);
+
+ ASSERT(500 <= uv_now(uv_default_loop()) - start_time);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(timer_start_twice) {
+ uv_timer_t once;
+ int r;
+
+ r = uv_timer_init(uv_default_loop(), &once);
+ ASSERT(r == 0);
+ r = uv_timer_start(&once, never_cb, 86400 * 1000, 0);
+ ASSERT(r == 0);
+ r = uv_timer_start(&once, once_cb, 10, 0);
+ ASSERT(r == 0);
+ r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ ASSERT(once_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(timer_init) {
+ uv_timer_t handle;
+
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &handle));
+ ASSERT(0 == uv_timer_get_repeat(&handle));
+ ASSERT(0 == uv_is_active((uv_handle_t*) &handle));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+static void order_cb_a(uv_timer_t *handle) {
+ ASSERT(order_cb_called++ == *(int*)handle->data);
+}
+
+
+static void order_cb_b(uv_timer_t *handle) {
+ ASSERT(order_cb_called++ == *(int*)handle->data);
+}
+
+
+TEST_IMPL(timer_order) {
+ int first;
+ int second;
+ uv_timer_t handle_a;
+ uv_timer_t handle_b;
+
+ first = 0;
+ second = 1;
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &handle_a));
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &handle_b));
+
+ /* Test for starting handle_a then handle_b */
+ handle_a.data = &first;
+ ASSERT(0 == uv_timer_start(&handle_a, order_cb_a, 0, 0));
+ handle_b.data = &second;
+ ASSERT(0 == uv_timer_start(&handle_b, order_cb_b, 0, 0));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ ASSERT(order_cb_called == 2);
+
+ ASSERT(0 == uv_timer_stop(&handle_a));
+ ASSERT(0 == uv_timer_stop(&handle_b));
+
+ /* Test for starting handle_b then handle_a */
+ order_cb_called = 0;
+ handle_b.data = &first;
+ ASSERT(0 == uv_timer_start(&handle_b, order_cb_b, 0, 0));
+
+ handle_a.data = &second;
+ ASSERT(0 == uv_timer_start(&handle_a, order_cb_a, 0, 0));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+
+ ASSERT(order_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+static void tiny_timer_cb(uv_timer_t* handle) {
+ ASSERT(handle == &tiny_timer);
+ uv_close((uv_handle_t*) &tiny_timer, NULL);
+ uv_close((uv_handle_t*) &huge_timer1, NULL);
+ uv_close((uv_handle_t*) &huge_timer2, NULL);
+}
+
+
+TEST_IMPL(timer_huge_timeout) {
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &tiny_timer));
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &huge_timer1));
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &huge_timer2));
+ ASSERT(0 == uv_timer_start(&tiny_timer, tiny_timer_cb, 1, 0));
+ ASSERT(0 == uv_timer_start(&huge_timer1, tiny_timer_cb, 0xffffffffffffLL, 0));
+ ASSERT(0 == uv_timer_start(&huge_timer2, tiny_timer_cb, (uint64_t) -1, 0));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+static void huge_repeat_cb(uv_timer_t* handle) {
+ static int ncalls;
+
+ if (ncalls == 0)
+ ASSERT(handle == &huge_timer1);
+ else
+ ASSERT(handle == &tiny_timer);
+
+ if (++ncalls == 10) {
+ uv_close((uv_handle_t*) &tiny_timer, NULL);
+ uv_close((uv_handle_t*) &huge_timer1, NULL);
+ }
+}
+
+
+TEST_IMPL(timer_huge_repeat) {
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &tiny_timer));
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &huge_timer1));
+ ASSERT(0 == uv_timer_start(&tiny_timer, huge_repeat_cb, 2, 2));
+ ASSERT(0 == uv_timer_start(&huge_timer1, huge_repeat_cb, 1, (uint64_t) -1));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+static unsigned int timer_run_once_timer_cb_called;
+
+
+static void timer_run_once_timer_cb(uv_timer_t* handle) {
+ timer_run_once_timer_cb_called++;
+}
+
+
+TEST_IMPL(timer_run_once) {
+ uv_timer_t timer_handle;
+
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle));
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_run_once_timer_cb, 0, 0));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
+ ASSERT(1 == timer_run_once_timer_cb_called);
+
+ ASSERT(0 == uv_timer_start(&timer_handle, timer_run_once_timer_cb, 1, 0));
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
+ ASSERT(2 == timer_run_once_timer_cb_called);
+
+ uv_close((uv_handle_t*) &timer_handle, NULL);
+ ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(timer_null_callback) {
+ uv_timer_t handle;
+
+ ASSERT(0 == uv_timer_init(uv_default_loop(), &handle));
+ ASSERT(UV_EINVAL == uv_timer_start(&handle, NULL, 100, 100));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-tty.c b/3rdparty/libuv/test/test-tty.c
new file mode 100644
index 00000000000..b844959d526
--- /dev/null
+++ b/3rdparty/libuv/test/test-tty.c
@@ -0,0 +1,184 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#ifdef _WIN32
+# include <io.h>
+# include <windows.h>
+#else /* Unix */
+# include <fcntl.h>
+# include <unistd.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+
+
+TEST_IMPL(tty) {
+ int r, width, height;
+ int ttyin_fd, ttyout_fd;
+ uv_tty_t tty_in, tty_out;
+ uv_loop_t* loop = uv_default_loop();
+
+ /* Make sure we have an FD that refers to a tty */
+#ifdef _WIN32
+ HANDLE handle;
+ handle = CreateFileA("conin$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ ASSERT(handle != INVALID_HANDLE_VALUE);
+ ttyin_fd = _open_osfhandle((intptr_t) handle, 0);
+
+ handle = CreateFileA("conout$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ ASSERT(handle != INVALID_HANDLE_VALUE);
+ ttyout_fd = _open_osfhandle((intptr_t) handle, 0);
+
+#else /* unix */
+ ttyin_fd = open("/dev/tty", O_RDONLY, 0);
+ if (ttyin_fd < 0) {
+ fprintf(stderr, "Cannot open /dev/tty as read-only: %s\n", strerror(errno));
+ fflush(stderr);
+ return TEST_SKIP;
+ }
+
+ ttyout_fd = open("/dev/tty", O_WRONLY, 0);
+ if (ttyout_fd < 0) {
+ fprintf(stderr, "Cannot open /dev/tty as write-only: %s\n", strerror(errno));
+ fflush(stderr);
+ return TEST_SKIP;
+ }
+#endif
+
+ ASSERT(ttyin_fd >= 0);
+ ASSERT(ttyout_fd >= 0);
+
+ ASSERT(UV_UNKNOWN_HANDLE == uv_guess_handle(-1));
+
+ ASSERT(UV_TTY == uv_guess_handle(ttyin_fd));
+ ASSERT(UV_TTY == uv_guess_handle(ttyout_fd));
+
+ r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */
+ ASSERT(r == 0);
+
+ r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */
+ ASSERT(r == 0);
+
+ r = uv_tty_get_winsize(&tty_out, &width, &height);
+ ASSERT(r == 0);
+
+ printf("width=%d height=%d\n", width, height);
+
+ if (width == 0 && height == 0) {
+ /* Some environments such as containers or Jenkins behave like this
+ * sometimes */
+ MAKE_VALGRIND_HAPPY();
+ return TEST_SKIP;
+ }
+
+ /*
+ * Is it a safe assumption that most people have terminals larger than
+ * 10x10?
+ */
+ ASSERT(width > 10);
+ ASSERT(height > 10);
+
+ /* Turn on raw mode. */
+ r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW);
+ ASSERT(r == 0);
+
+ /* Turn off raw mode. */
+ r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_NORMAL);
+ ASSERT(r == 0);
+
+ /* Calling uv_tty_reset_mode() repeatedly should not clobber errno. */
+ errno = 0;
+ ASSERT(0 == uv_tty_reset_mode());
+ ASSERT(0 == uv_tty_reset_mode());
+ ASSERT(0 == uv_tty_reset_mode());
+ ASSERT(0 == errno);
+
+ /* TODO check the actual mode! */
+
+ uv_close((uv_handle_t*) &tty_in, NULL);
+ uv_close((uv_handle_t*) &tty_out, NULL);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(tty_file) {
+#ifndef _WIN32
+ uv_loop_t loop;
+ uv_tty_t tty;
+ int fd;
+
+ ASSERT(0 == uv_loop_init(&loop));
+
+ fd = open("test/fixtures/empty_file", O_RDONLY);
+ if (fd != -1) {
+ ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1));
+ ASSERT(0 == close(fd));
+ }
+
+/* Bug on AIX where '/dev/random' returns 1 from isatty() */
+#ifndef _AIX
+ fd = open("/dev/random", O_RDONLY);
+ if (fd != -1) {
+ ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1));
+ ASSERT(0 == close(fd));
+ }
+#endif /* _AIX */
+
+ fd = open("/dev/zero", O_RDONLY);
+ if (fd != -1) {
+ ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1));
+ ASSERT(0 == close(fd));
+ }
+
+ fd = open("/dev/tty", O_RDONLY);
+ if (fd != -1) {
+ ASSERT(0 == uv_tty_init(&loop, &tty, fd, 1));
+ ASSERT(0 == close(fd));
+ uv_close((uv_handle_t*) &tty, NULL);
+ }
+
+ ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT));
+ ASSERT(0 == uv_loop_close(&loop));
+
+ MAKE_VALGRIND_HAPPY();
+#endif
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-bind.c b/3rdparty/libuv/test/test-udp-bind.c
new file mode 100644
index 00000000000..a1e080ee70c
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-bind.c
@@ -0,0 +1,93 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+TEST_IMPL(udp_bind) {
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+ uv_udp_t h1, h2;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ loop = uv_default_loop();
+
+ r = uv_udp_init(loop, &h1);
+ ASSERT(r == 0);
+
+ r = uv_udp_init(loop, &h2);
+ ASSERT(r == 0);
+
+ r = uv_udp_bind(&h1, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_udp_bind(&h2, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == UV_EADDRINUSE);
+
+ uv_close((uv_handle_t*) &h1, NULL);
+ uv_close((uv_handle_t*) &h2, NULL);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(udp_bind_reuseaddr) {
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+ uv_udp_t h1, h2;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ loop = uv_default_loop();
+
+ r = uv_udp_init(loop, &h1);
+ ASSERT(r == 0);
+
+ r = uv_udp_init(loop, &h2);
+ ASSERT(r == 0);
+
+ r = uv_udp_bind(&h1, (const struct sockaddr*) &addr, UV_UDP_REUSEADDR);
+ ASSERT(r == 0);
+
+ r = uv_udp_bind(&h2, (const struct sockaddr*) &addr, UV_UDP_REUSEADDR);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*) &h1, NULL);
+ uv_close((uv_handle_t*) &h2, NULL);
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-create-socket-early.c b/3rdparty/libuv/test/test-udp-create-socket-early.c
new file mode 100644
index 00000000000..3d0152428b8
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-create-socket-early.c
@@ -0,0 +1,132 @@
+/* Copyright (c) 2015 Saúl Ibarra Corretgé <saghul@gmail.com>.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <string.h>
+
+#ifdef _WIN32
+# define INVALID_FD (INVALID_HANDLE_VALUE)
+#else
+# define INVALID_FD (-1)
+#endif
+
+
+TEST_IMPL(udp_create_early) {
+ struct sockaddr_in addr;
+ struct sockaddr_in sockname;
+ uv_udp_t client;
+ uv_os_fd_t fd;
+ int r, namelen;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_udp_init_ex(uv_default_loop(), &client, AF_INET);
+ ASSERT(r == 0);
+
+ r = uv_fileno((const uv_handle_t*) &client, &fd);
+ ASSERT(r == 0);
+ ASSERT(fd != INVALID_FD);
+
+ /* Windows returns WSAEINVAL if the socket is not bound */
+#ifndef _WIN32
+ namelen = sizeof sockname;
+ r = uv_udp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
+ ASSERT(r == 0);
+ ASSERT(sockname.sin_family == AF_INET);
+#endif
+
+ r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ namelen = sizeof sockname;
+ r = uv_udp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
+ ASSERT(r == 0);
+ ASSERT(memcmp(&addr.sin_addr,
+ &sockname.sin_addr,
+ sizeof(addr.sin_addr)) == 0);
+
+ uv_close((uv_handle_t*) &client, NULL);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(udp_create_early_bad_bind) {
+ struct sockaddr_in addr;
+ uv_udp_t client;
+ uv_os_fd_t fd;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_udp_init_ex(uv_default_loop(), &client, AF_INET6);
+ ASSERT(r == 0);
+
+ r = uv_fileno((const uv_handle_t*) &client, &fd);
+ ASSERT(r == 0);
+ ASSERT(fd != INVALID_FD);
+
+ /* Windows returns WSAEINVAL if the socket is not bound */
+#ifndef _WIN32
+ {
+ int namelen;
+ struct sockaddr_in6 sockname;
+ namelen = sizeof sockname;
+ r = uv_udp_getsockname(&client, (struct sockaddr*) &sockname, &namelen);
+ ASSERT(r == 0);
+ ASSERT(sockname.sin6_family == AF_INET6);
+ }
+#endif
+
+ r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0);
+#ifndef _WIN32
+ ASSERT(r == UV_EINVAL);
+#else
+ ASSERT(r == UV_EFAULT);
+#endif
+
+ uv_close((uv_handle_t*) &client, NULL);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(udp_create_early_bad_domain) {
+ uv_udp_t client;
+ int r;
+
+ r = uv_udp_init_ex(uv_default_loop(), &client, 47);
+ ASSERT(r == UV_EINVAL);
+
+ r = uv_udp_init_ex(uv_default_loop(), &client, 1024);
+ ASSERT(r == UV_EINVAL);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-dgram-too-big.c b/3rdparty/libuv/test/test-udp-dgram-too-big.c
new file mode 100644
index 00000000000..bd44c425287
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-dgram-too-big.c
@@ -0,0 +1,91 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &handle_)
+
+#define CHECK_REQ(req) \
+ ASSERT((req) == &req_);
+
+static uv_udp_t handle_;
+static uv_udp_send_t req_;
+
+static int send_cb_called;
+static int close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ CHECK_HANDLE(handle);
+ close_cb_called++;
+}
+
+
+static void send_cb(uv_udp_send_t* req, int status) {
+ CHECK_REQ(req);
+ CHECK_HANDLE(req->handle);
+
+ ASSERT(status == UV_EMSGSIZE);
+
+ uv_close((uv_handle_t*)req->handle, close_cb);
+ send_cb_called++;
+}
+
+
+TEST_IMPL(udp_dgram_too_big) {
+ char dgram[65536]; /* 64K MTU is unlikely, even on localhost */
+ struct sockaddr_in addr;
+ uv_buf_t buf;
+ int r;
+
+ memset(dgram, 42, sizeof dgram); /* silence valgrind */
+
+ r = uv_udp_init(uv_default_loop(), &handle_);
+ ASSERT(r == 0);
+
+ buf = uv_buf_init(dgram, sizeof dgram);
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_udp_send(&req_,
+ &handle_,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ send_cb);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+ ASSERT(send_cb_called == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(send_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-ipv6.c b/3rdparty/libuv/test/test-udp-ipv6.c
new file mode 100644
index 00000000000..1b0db78b8ef
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-ipv6.c
@@ -0,0 +1,193 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __FreeBSD__
+#include <sys/sysctl.h>
+#endif
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &server \
+ || (uv_udp_t*)(handle) == &client \
+ || (uv_timer_t*)(handle) == &timeout)
+
+#define CHECK_REQ(req) \
+ ASSERT((req) == &req_);
+
+static uv_udp_t client;
+static uv_udp_t server;
+static uv_udp_send_t req_;
+static uv_timer_t timeout;
+
+static int send_cb_called;
+static int recv_cb_called;
+static int close_cb_called;
+
+#ifdef __FreeBSD__
+static int can_ipv6_ipv4_dual() {
+ int v6only;
+ size_t size = sizeof(int);
+
+ if (sysctlbyname("net.inet6.ip6.v6only", &v6only, &size, NULL, 0))
+ return 0;
+
+ return v6only != 1;
+}
+#endif
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ CHECK_HANDLE(handle);
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ CHECK_HANDLE(handle);
+ close_cb_called++;
+}
+
+
+static void send_cb(uv_udp_send_t* req, int status) {
+ CHECK_REQ(req);
+ CHECK_HANDLE(req->handle);
+ ASSERT(status == 0);
+ send_cb_called++;
+}
+
+
+static void ipv6_recv_fail(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ ASSERT(0 && "this function should not have been called");
+}
+
+
+static void ipv6_recv_ok(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ CHECK_HANDLE(handle);
+ ASSERT(nread >= 0);
+
+ if (nread)
+ recv_cb_called++;
+}
+
+
+static void timeout_cb(uv_timer_t* timer) {
+ uv_close((uv_handle_t*)&server, close_cb);
+ uv_close((uv_handle_t*)&client, close_cb);
+ uv_close((uv_handle_t*)&timeout, close_cb);
+}
+
+
+static void do_test(uv_udp_recv_cb recv_cb, int bind_flags) {
+ struct sockaddr_in6 addr6;
+ struct sockaddr_in addr;
+ uv_buf_t buf;
+ int r;
+
+ ASSERT(0 == uv_ip6_addr("::0", TEST_PORT, &addr6));
+
+ r = uv_udp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ r = uv_udp_bind(&server, (const struct sockaddr*) &addr6, bind_flags);
+ ASSERT(r == 0);
+
+ r = uv_udp_recv_start(&server, alloc_cb, recv_cb);
+ ASSERT(r == 0);
+
+ r = uv_udp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ buf = uv_buf_init("PING", 4);
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_udp_send(&req_,
+ &client,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ send_cb);
+ ASSERT(r == 0);
+
+ r = uv_timer_init(uv_default_loop(), &timeout);
+ ASSERT(r == 0);
+
+ r = uv_timer_start(&timeout, timeout_cb, 500, 0);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+ ASSERT(send_cb_called == 0);
+ ASSERT(recv_cb_called == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 3);
+
+ MAKE_VALGRIND_HAPPY();
+}
+
+
+TEST_IMPL(udp_dual_stack) {
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+#ifdef __FreeBSD__
+ if (!can_ipv6_ipv4_dual())
+ RETURN_SKIP("IPv6-IPv4 dual stack not supported");
+#endif
+
+ do_test(ipv6_recv_ok, 0);
+
+ ASSERT(recv_cb_called == 1);
+ ASSERT(send_cb_called == 1);
+
+ return 0;
+}
+
+
+TEST_IMPL(udp_ipv6_only) {
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+ do_test(ipv6_recv_fail, UV_UDP_IPV6ONLY);
+
+ ASSERT(recv_cb_called == 0);
+ ASSERT(send_cb_called == 1);
+
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-multicast-interface.c b/3rdparty/libuv/test/test-udp-multicast-interface.c
new file mode 100644
index 00000000000..71001a77e03
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-multicast-interface.c
@@ -0,0 +1,99 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
+
+static uv_udp_t server;
+static uv_udp_t client;
+
+static int sv_send_cb_called;
+static int close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ CHECK_HANDLE(handle);
+ close_cb_called++;
+}
+
+
+static void sv_send_cb(uv_udp_send_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0 || status == UV_ENETUNREACH);
+ CHECK_HANDLE(req->handle);
+
+ sv_send_cb_called++;
+
+ uv_close((uv_handle_t*) req->handle, close_cb);
+}
+
+
+TEST_IMPL(udp_multicast_interface) {
+ int r;
+ uv_udp_send_t req;
+ uv_buf_t buf;
+ struct sockaddr_in addr;
+ struct sockaddr_in baddr;
+
+ ASSERT(0 == uv_ip4_addr("239.255.0.1", TEST_PORT, &addr));
+
+ r = uv_udp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &baddr));
+ r = uv_udp_bind(&server, (const struct sockaddr*)&baddr, 0);
+ ASSERT(r == 0);
+
+ r = uv_udp_set_multicast_interface(&server, "0.0.0.0");
+ ASSERT(r == 0);
+
+ /* server sends "PING" */
+ buf = uv_buf_init("PING", 4);
+ r = uv_udp_send(&req,
+ &server,
+ &buf,
+ 1,
+ (const struct sockaddr*)&addr,
+ sv_send_cb);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+ ASSERT(sv_send_cb_called == 0);
+
+ /* run the loop till all events are processed */
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(sv_send_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ ASSERT(client.send_queue_size == 0);
+ ASSERT(server.send_queue_size == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-multicast-interface6.c b/3rdparty/libuv/test/test-udp-multicast-interface6.c
new file mode 100644
index 00000000000..d3881e83bb1
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-multicast-interface6.c
@@ -0,0 +1,103 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
+
+static uv_udp_t server;
+static uv_udp_t client;
+
+static int sv_send_cb_called;
+static int close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ CHECK_HANDLE(handle);
+ close_cb_called++;
+}
+
+
+static void sv_send_cb(uv_udp_send_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+ CHECK_HANDLE(req->handle);
+
+ sv_send_cb_called++;
+
+ uv_close((uv_handle_t*) req->handle, close_cb);
+}
+
+
+TEST_IMPL(udp_multicast_interface6) {
+ int r;
+ uv_udp_send_t req;
+ uv_buf_t buf;
+ struct sockaddr_in6 addr;
+ struct sockaddr_in6 baddr;
+
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+ ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr));
+
+ r = uv_udp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_ip6_addr("::", 0, &baddr));
+ r = uv_udp_bind(&server, (const struct sockaddr*)&baddr, 0);
+ ASSERT(r == 0);
+
+#if defined(__APPLE__) || defined(__FreeBSD__)
+ r = uv_udp_set_multicast_interface(&server, "::1%lo0");
+#else
+ r = uv_udp_set_multicast_interface(&server, NULL);
+#endif
+ ASSERT(r == 0);
+
+ /* server sends "PING" */
+ buf = uv_buf_init("PING", 4);
+ r = uv_udp_send(&req,
+ &server,
+ &buf,
+ 1,
+ (const struct sockaddr*)&addr,
+ sv_send_cb);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+ ASSERT(sv_send_cb_called == 0);
+
+ /* run the loop till all events are processed */
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(sv_send_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-multicast-join.c b/3rdparty/libuv/test/test-udp-multicast-join.c
new file mode 100644
index 00000000000..6110a8d922a
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-multicast-join.c
@@ -0,0 +1,150 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
+
+static uv_udp_t server;
+static uv_udp_t client;
+
+static int cl_recv_cb_called;
+
+static int sv_send_cb_called;
+
+static int close_cb_called;
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ CHECK_HANDLE(handle);
+ ASSERT(suggested_size <= sizeof(slab));
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ CHECK_HANDLE(handle);
+ close_cb_called++;
+}
+
+
+static void sv_send_cb(uv_udp_send_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+ CHECK_HANDLE(req->handle);
+
+ sv_send_cb_called++;
+
+ uv_close((uv_handle_t*) req->handle, close_cb);
+}
+
+
+static void cl_recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ CHECK_HANDLE(handle);
+ ASSERT(flags == 0);
+
+ cl_recv_cb_called++;
+
+ if (nread < 0) {
+ ASSERT(0 && "unexpected error");
+ }
+
+ if (nread == 0) {
+ /* Returning unused buffer */
+ /* Don't count towards cl_recv_cb_called */
+ ASSERT(addr == NULL);
+ return;
+ }
+
+ ASSERT(addr != NULL);
+ ASSERT(nread == 4);
+ ASSERT(!memcmp("PING", buf->base, nread));
+
+ /* we are done with the client handle, we can close it */
+ uv_close((uv_handle_t*) &client, close_cb);
+}
+
+
+TEST_IMPL(udp_multicast_join) {
+ int r;
+ uv_udp_send_t req;
+ uv_buf_t buf;
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_udp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ r = uv_udp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ /* bind to the desired port */
+ r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ /* join the multicast channel */
+ r = uv_udp_set_membership(&client, "239.255.0.1", NULL, UV_JOIN_GROUP);
+ if (r == UV_ENODEV)
+ RETURN_SKIP("No multicast support.");
+ ASSERT(r == 0);
+
+ r = uv_udp_recv_start(&client, alloc_cb, cl_recv_cb);
+ ASSERT(r == 0);
+
+ buf = uv_buf_init("PING", 4);
+
+ /* server sends "PING" */
+ r = uv_udp_send(&req,
+ &server,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ sv_send_cb);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+ ASSERT(cl_recv_cb_called == 0);
+ ASSERT(sv_send_cb_called == 0);
+
+ /* run the loop till all events are processed */
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(cl_recv_cb_called == 1);
+ ASSERT(sv_send_cb_called == 1);
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-multicast-join6.c b/3rdparty/libuv/test/test-udp-multicast-join6.c
new file mode 100644
index 00000000000..f635bdb9e14
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-multicast-join6.c
@@ -0,0 +1,161 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
+
+static uv_udp_t server;
+static uv_udp_t client;
+
+static int cl_recv_cb_called;
+
+static int sv_send_cb_called;
+
+static int close_cb_called;
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ CHECK_HANDLE(handle);
+ ASSERT(suggested_size <= sizeof(slab));
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ CHECK_HANDLE(handle);
+ close_cb_called++;
+}
+
+
+static void sv_send_cb(uv_udp_send_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+ CHECK_HANDLE(req->handle);
+
+ sv_send_cb_called++;
+
+ uv_close((uv_handle_t*) req->handle, close_cb);
+}
+
+
+static void cl_recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ CHECK_HANDLE(handle);
+ ASSERT(flags == 0);
+
+ cl_recv_cb_called++;
+
+ if (nread < 0) {
+ ASSERT(0 && "unexpected error");
+ }
+
+ if (nread == 0) {
+ /* Returning unused buffer */
+ /* Don't count towards cl_recv_cb_called */
+ ASSERT(addr == NULL);
+ return;
+ }
+
+ ASSERT(addr != NULL);
+ ASSERT(nread == 4);
+ ASSERT(!memcmp("PING", buf->base, nread));
+
+ /* we are done with the client handle, we can close it */
+ uv_close((uv_handle_t*) &client, close_cb);
+}
+
+
+TEST_IMPL(udp_multicast_join6) {
+ int r;
+ uv_udp_send_t req;
+ uv_buf_t buf;
+ struct sockaddr_in6 addr;
+
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+ ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr));
+
+ r = uv_udp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ r = uv_udp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ /* bind to the desired port */
+ r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ /* join the multicast channel */
+#if defined(__APPLE__) || defined(_AIX)
+ r = uv_udp_set_membership(&client, "ff02::1", "::1%lo0", UV_JOIN_GROUP);
+#else
+ r = uv_udp_set_membership(&client, "ff02::1", NULL, UV_JOIN_GROUP);
+#endif
+ if (r == UV_ENODEV) {
+ MAKE_VALGRIND_HAPPY();
+ RETURN_SKIP("No ipv6 multicast route");
+ }
+
+ ASSERT(r == 0);
+
+ r = uv_udp_recv_start(&client, alloc_cb, cl_recv_cb);
+ ASSERT(r == 0);
+
+ buf = uv_buf_init("PING", 4);
+
+ /* server sends "PING" */
+ r = uv_udp_send(&req,
+ &server,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ sv_send_cb);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+ ASSERT(cl_recv_cb_called == 0);
+ ASSERT(sv_send_cb_called == 0);
+
+ /* run the loop till all events are processed */
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(cl_recv_cb_called == 1);
+ ASSERT(sv_send_cb_called == 1);
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-multicast-ttl.c b/3rdparty/libuv/test/test-udp-multicast-ttl.c
new file mode 100644
index 00000000000..7f1af9b9dd9
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-multicast-ttl.c
@@ -0,0 +1,94 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
+
+static uv_udp_t server;
+static uv_udp_t client;
+
+static int sv_send_cb_called;
+static int close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ CHECK_HANDLE(handle);
+ close_cb_called++;
+}
+
+
+static void sv_send_cb(uv_udp_send_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0 || status == UV_ENETUNREACH);
+ CHECK_HANDLE(req->handle);
+
+ sv_send_cb_called++;
+
+ uv_close((uv_handle_t*) req->handle, close_cb);
+}
+
+
+TEST_IMPL(udp_multicast_ttl) {
+ int r;
+ uv_udp_send_t req;
+ uv_buf_t buf;
+ struct sockaddr_in addr;
+
+ r = uv_udp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", 0, &addr));
+ r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_udp_set_multicast_ttl(&server, 32);
+ ASSERT(r == 0);
+
+ /* server sends "PING" */
+ buf = uv_buf_init("PING", 4);
+ ASSERT(0 == uv_ip4_addr("239.255.0.1", TEST_PORT, &addr));
+ r = uv_udp_send(&req,
+ &server,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ sv_send_cb);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+ ASSERT(sv_send_cb_called == 0);
+
+ /* run the loop till all events are processed */
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(sv_send_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-open.c b/3rdparty/libuv/test/test-udp-open.c
new file mode 100644
index 00000000000..4d77f45d367
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-open.c
@@ -0,0 +1,204 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef _WIN32
+# include <unistd.h>
+#endif
+
+static int send_cb_called = 0;
+static int close_cb_called = 0;
+
+static uv_udp_send_t send_req;
+
+
+static void startup(void) {
+#ifdef _WIN32
+ struct WSAData wsa_data;
+ int r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ ASSERT(r == 0);
+#endif
+}
+
+
+static uv_os_sock_t create_udp_socket(void) {
+ uv_os_sock_t sock;
+
+ sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+#ifdef _WIN32
+ ASSERT(sock != INVALID_SOCKET);
+#else
+ ASSERT(sock >= 0);
+#endif
+
+#ifndef _WIN32
+ {
+ /* Allow reuse of the port. */
+ int yes = 1;
+ int r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);
+ ASSERT(r == 0);
+ }
+#endif
+
+ return sock;
+}
+
+
+static void close_socket(uv_os_sock_t sock) {
+ int r;
+#ifdef _WIN32
+ r = closesocket(sock);
+#else
+ r = close(sock);
+#endif
+ ASSERT(r == 0);
+}
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ ASSERT(suggested_size <= sizeof(slab));
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(handle != NULL);
+ close_cb_called++;
+}
+
+
+static void recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ int r;
+
+ if (nread < 0) {
+ ASSERT(0 && "unexpected error");
+ }
+
+ if (nread == 0) {
+ /* Returning unused buffer */
+ /* Don't count towards sv_recv_cb_called */
+ ASSERT(addr == NULL);
+ return;
+ }
+
+ ASSERT(flags == 0);
+
+ ASSERT(addr != NULL);
+ ASSERT(nread == 4);
+ ASSERT(memcmp("PING", buf->base, nread) == 0);
+
+ r = uv_udp_recv_stop(handle);
+ ASSERT(r == 0);
+
+ uv_close((uv_handle_t*) handle, close_cb);
+}
+
+
+static void send_cb(uv_udp_send_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+
+ send_cb_called++;
+}
+
+
+TEST_IMPL(udp_open) {
+ struct sockaddr_in addr;
+ uv_buf_t buf = uv_buf_init("PING", 4);
+ uv_udp_t client;
+ uv_os_sock_t sock;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ startup();
+ sock = create_udp_socket();
+
+ r = uv_udp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ r = uv_udp_open(&client, sock);
+ ASSERT(r == 0);
+
+ r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_udp_recv_start(&client, alloc_cb, recv_cb);
+ ASSERT(r == 0);
+
+ r = uv_udp_send(&send_req,
+ &client,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ send_cb);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(send_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ ASSERT(client.send_queue_size == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(udp_open_twice) {
+ uv_udp_t client;
+ uv_os_sock_t sock1, sock2;
+ int r;
+
+ startup();
+ sock1 = create_udp_socket();
+ sock2 = create_udp_socket();
+
+ r = uv_udp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ r = uv_udp_open(&client, sock1);
+ ASSERT(r == 0);
+
+ r = uv_udp_open(&client, sock2);
+ ASSERT(r == UV_EBUSY);
+ close_socket(sock2);
+
+ uv_close((uv_handle_t*) &client, NULL);
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-options.c b/3rdparty/libuv/test/test-udp-options.c
new file mode 100644
index 00000000000..0da1786f506
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-options.c
@@ -0,0 +1,126 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+static int udp_options_test(const struct sockaddr* addr) {
+ static int invalid_ttls[] = { -1, 0, 256 };
+ uv_loop_t* loop;
+ uv_udp_t h;
+ int i, r;
+
+ loop = uv_default_loop();
+
+ r = uv_udp_init(loop, &h);
+ ASSERT(r == 0);
+
+ uv_unref((uv_handle_t*)&h); /* don't keep the loop alive */
+
+ r = uv_udp_bind(&h, addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_udp_set_broadcast(&h, 1);
+ r |= uv_udp_set_broadcast(&h, 1);
+ r |= uv_udp_set_broadcast(&h, 0);
+ r |= uv_udp_set_broadcast(&h, 0);
+ ASSERT(r == 0);
+
+ /* values 1-255 should work */
+ for (i = 1; i <= 255; i++) {
+ r = uv_udp_set_ttl(&h, i);
+ ASSERT(r == 0);
+ }
+
+ for (i = 0; i < (int) ARRAY_SIZE(invalid_ttls); i++) {
+ r = uv_udp_set_ttl(&h, invalid_ttls[i]);
+ ASSERT(r == UV_EINVAL);
+ }
+
+ r = uv_udp_set_multicast_loop(&h, 1);
+ r |= uv_udp_set_multicast_loop(&h, 1);
+ r |= uv_udp_set_multicast_loop(&h, 0);
+ r |= uv_udp_set_multicast_loop(&h, 0);
+ ASSERT(r == 0);
+
+ /* values 0-255 should work */
+ for (i = 0; i <= 255; i++) {
+ r = uv_udp_set_multicast_ttl(&h, i);
+ ASSERT(r == 0);
+ }
+
+ /* anything >255 should fail */
+ r = uv_udp_set_multicast_ttl(&h, 256);
+ ASSERT(r == UV_EINVAL);
+ /* don't test ttl=-1, it's a valid value on some platforms */
+
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
+TEST_IMPL(udp_options) {
+ struct sockaddr_in addr;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+ return udp_options_test((const struct sockaddr*) &addr);
+}
+
+
+TEST_IMPL(udp_options6) {
+ struct sockaddr_in6 addr;
+
+ if (!can_ipv6())
+ RETURN_SKIP("IPv6 not supported");
+
+ ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr));
+ return udp_options_test((const struct sockaddr*) &addr);
+}
+
+
+TEST_IMPL(udp_no_autobind) {
+ uv_loop_t* loop;
+ uv_udp_t h;
+
+ loop = uv_default_loop();
+
+ ASSERT(0 == uv_udp_init(loop, &h));
+ ASSERT(UV_EBADF == uv_udp_set_multicast_ttl(&h, 32));
+ ASSERT(UV_EBADF == uv_udp_set_broadcast(&h, 1));
+ ASSERT(UV_EBADF == uv_udp_set_ttl(&h, 1));
+ ASSERT(UV_EBADF == uv_udp_set_multicast_loop(&h, 1));
+ ASSERT(UV_EBADF == uv_udp_set_multicast_interface(&h, "0.0.0.0"));
+
+ uv_close((uv_handle_t*) &h, NULL);
+
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-send-and-recv.c b/3rdparty/libuv/test/test-udp-send-and-recv.c
new file mode 100644
index 00000000000..633a16727b2
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-send-and-recv.c
@@ -0,0 +1,214 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
+
+static uv_udp_t server;
+static uv_udp_t client;
+
+static int cl_send_cb_called;
+static int cl_recv_cb_called;
+
+static int sv_send_cb_called;
+static int sv_recv_cb_called;
+
+static int close_cb_called;
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ CHECK_HANDLE(handle);
+ ASSERT(suggested_size <= sizeof(slab));
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ CHECK_HANDLE(handle);
+ ASSERT(1 == uv_is_closing(handle));
+ close_cb_called++;
+}
+
+
+static void cl_recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ CHECK_HANDLE(handle);
+ ASSERT(flags == 0);
+
+ if (nread < 0) {
+ ASSERT(0 && "unexpected error");
+ }
+
+ if (nread == 0) {
+ /* Returning unused buffer */
+ /* Don't count towards cl_recv_cb_called */
+ ASSERT(addr == NULL);
+ return;
+ }
+
+ ASSERT(addr != NULL);
+ ASSERT(nread == 4);
+ ASSERT(!memcmp("PONG", buf->base, nread));
+
+ cl_recv_cb_called++;
+
+ uv_close((uv_handle_t*) handle, close_cb);
+}
+
+
+static void cl_send_cb(uv_udp_send_t* req, int status) {
+ int r;
+
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+ CHECK_HANDLE(req->handle);
+
+ r = uv_udp_recv_start(req->handle, alloc_cb, cl_recv_cb);
+ ASSERT(r == 0);
+
+ cl_send_cb_called++;
+}
+
+
+static void sv_send_cb(uv_udp_send_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+ CHECK_HANDLE(req->handle);
+
+ uv_close((uv_handle_t*) req->handle, close_cb);
+ free(req);
+
+ sv_send_cb_called++;
+}
+
+
+static void sv_recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* rcvbuf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ uv_udp_send_t* req;
+ uv_buf_t sndbuf;
+ int r;
+
+ if (nread < 0) {
+ ASSERT(0 && "unexpected error");
+ }
+
+ if (nread == 0) {
+ /* Returning unused buffer */
+ /* Don't count towards sv_recv_cb_called */
+ ASSERT(addr == NULL);
+ return;
+ }
+
+ CHECK_HANDLE(handle);
+ ASSERT(flags == 0);
+
+ ASSERT(addr != NULL);
+ ASSERT(nread == 4);
+ ASSERT(!memcmp("PING", rcvbuf->base, nread));
+
+ /* FIXME? `uv_udp_recv_stop` does what it says: recv_cb is not called
+ * anymore. That's problematic because the read buffer won't be returned
+ * either... Not sure I like that but it's consistent with `uv_read_stop`.
+ */
+ r = uv_udp_recv_stop(handle);
+ ASSERT(r == 0);
+
+ req = malloc(sizeof *req);
+ ASSERT(req != NULL);
+
+ sndbuf = uv_buf_init("PONG", 4);
+ r = uv_udp_send(req, handle, &sndbuf, 1, addr, sv_send_cb);
+ ASSERT(r == 0);
+
+ sv_recv_cb_called++;
+}
+
+
+TEST_IMPL(udp_send_and_recv) {
+ struct sockaddr_in addr;
+ uv_udp_send_t req;
+ uv_buf_t buf;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_udp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_udp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ /* client sends "PING", expects "PONG" */
+ buf = uv_buf_init("PING", 4);
+
+ r = uv_udp_send(&req,
+ &client,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ cl_send_cb);
+ ASSERT(r == 0);
+
+ ASSERT(close_cb_called == 0);
+ ASSERT(cl_send_cb_called == 0);
+ ASSERT(cl_recv_cb_called == 0);
+ ASSERT(sv_send_cb_called == 0);
+ ASSERT(sv_recv_cb_called == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(cl_send_cb_called == 1);
+ ASSERT(cl_recv_cb_called == 1);
+ ASSERT(sv_send_cb_called == 1);
+ ASSERT(sv_recv_cb_called == 1);
+ ASSERT(close_cb_called == 2);
+
+ ASSERT(client.send_queue_size == 0);
+ ASSERT(server.send_queue_size == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-send-immediate.c b/3rdparty/libuv/test/test-udp-send-immediate.c
new file mode 100644
index 00000000000..0999f6b3425
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-send-immediate.c
@@ -0,0 +1,148 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
+
+static uv_udp_t server;
+static uv_udp_t client;
+
+static int cl_send_cb_called;
+static int sv_recv_cb_called;
+static int close_cb_called;
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ CHECK_HANDLE(handle);
+ ASSERT(suggested_size <= sizeof(slab));
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ CHECK_HANDLE(handle);
+ ASSERT(1 == uv_is_closing(handle));
+ close_cb_called++;
+}
+
+
+static void cl_send_cb(uv_udp_send_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+ CHECK_HANDLE(req->handle);
+
+ cl_send_cb_called++;
+}
+
+
+static void sv_recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* rcvbuf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ if (nread < 0) {
+ ASSERT(0 && "unexpected error");
+ }
+
+ if (nread == 0) {
+ /* Returning unused buffer */
+ /* Don't count towards sv_recv_cb_called */
+ ASSERT(addr == NULL);
+ return;
+ }
+
+ CHECK_HANDLE(handle);
+ ASSERT(flags == 0);
+
+ ASSERT(addr != NULL);
+ ASSERT(nread == 4);
+ ASSERT(memcmp("PING", rcvbuf->base, nread) == 0 ||
+ memcmp("PANG", rcvbuf->base, nread) == 0);
+
+ if (++sv_recv_cb_called == 2) {
+ uv_close((uv_handle_t*) &server, close_cb);
+ uv_close((uv_handle_t*) &client, close_cb);
+ }
+}
+
+
+TEST_IMPL(udp_send_immediate) {
+ struct sockaddr_in addr;
+ uv_udp_send_t req1, req2;
+ uv_buf_t buf;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_udp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_udp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ /* client sends "PING", then "PANG" */
+ buf = uv_buf_init("PING", 4);
+
+ r = uv_udp_send(&req1,
+ &client,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ cl_send_cb);
+ ASSERT(r == 0);
+
+ buf = uv_buf_init("PANG", 4);
+
+ r = uv_udp_send(&req2,
+ &client,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ cl_send_cb);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(cl_send_cb_called == 2);
+ ASSERT(sv_recv_cb_called == 2);
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-send-unreachable.c b/3rdparty/libuv/test/test-udp-send-unreachable.c
new file mode 100644
index 00000000000..c6500320d78
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-send-unreachable.c
@@ -0,0 +1,150 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &client)
+
+static uv_udp_t client;
+static uv_timer_t timer;
+
+static int send_cb_called;
+static int recv_cb_called;
+static int close_cb_called;
+static int alloc_cb_called;
+static int timer_cb_called;
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ CHECK_HANDLE(handle);
+ ASSERT(suggested_size <= sizeof(slab));
+ buf->base = slab;
+ buf->len = sizeof(slab);
+ alloc_cb_called++;
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ ASSERT(1 == uv_is_closing(handle));
+ close_cb_called++;
+}
+
+
+static void send_cb(uv_udp_send_t* req, int status) {
+ ASSERT(req != NULL);
+ ASSERT(status == 0);
+ CHECK_HANDLE(req->handle);
+ send_cb_called++;
+}
+
+
+static void recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* rcvbuf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ CHECK_HANDLE(handle);
+ recv_cb_called++;
+
+ if (nread < 0) {
+ ASSERT(0 && "unexpected error");
+ } else if (nread == 0) {
+ /* Returning unused buffer */
+ ASSERT(addr == NULL);
+ } else {
+ ASSERT(addr != NULL);
+ }
+}
+
+
+static void timer_cb(uv_timer_t* h) {
+ ASSERT(h == &timer);
+ timer_cb_called++;
+ uv_close((uv_handle_t*) &client, close_cb);
+ uv_close((uv_handle_t*) h, close_cb);
+}
+
+
+TEST_IMPL(udp_send_unreachable) {
+ struct sockaddr_in addr;
+ struct sockaddr_in addr2;
+ uv_udp_send_t req1, req2;
+ uv_buf_t buf;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT_2, &addr2));
+
+ r = uv_timer_init( uv_default_loop(), &timer );
+ ASSERT(r == 0);
+
+ r = uv_timer_start( &timer, timer_cb, 1000, 0 );
+ ASSERT(r == 0);
+
+ r = uv_udp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ r = uv_udp_bind(&client, (const struct sockaddr*) &addr2, 0);
+ ASSERT(r == 0);
+
+ r = uv_udp_recv_start(&client, alloc_cb, recv_cb);
+ ASSERT(r == 0);
+
+ /* client sends "PING", then "PANG" */
+ buf = uv_buf_init("PING", 4);
+
+ r = uv_udp_send(&req1,
+ &client,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ send_cb);
+ ASSERT(r == 0);
+
+ buf = uv_buf_init("PANG", 4);
+
+ r = uv_udp_send(&req2,
+ &client,
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ send_cb);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(send_cb_called == 2);
+ ASSERT(recv_cb_called == alloc_cb_called);
+ ASSERT(timer_cb_called == 1);
+ ASSERT(close_cb_called == 2);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-udp-try-send.c b/3rdparty/libuv/test/test-udp-try-send.c
new file mode 100644
index 00000000000..7b6de365487
--- /dev/null
+++ b/3rdparty/libuv/test/test-udp-try-send.c
@@ -0,0 +1,133 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _WIN32
+
+TEST_IMPL(udp_try_send) {
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#else /* !_WIN32 */
+
+#define CHECK_HANDLE(handle) \
+ ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client)
+
+static uv_udp_t server;
+static uv_udp_t client;
+
+static int sv_recv_cb_called;
+
+static int close_cb_called;
+
+
+static void alloc_cb(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf) {
+ static char slab[65536];
+ CHECK_HANDLE(handle);
+ ASSERT(suggested_size <= sizeof(slab));
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ CHECK_HANDLE(handle);
+ ASSERT(uv_is_closing(handle));
+ close_cb_called++;
+}
+
+
+static void sv_recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* rcvbuf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ ASSERT(nread > 0);
+
+ if (nread == 0) {
+ ASSERT(addr == NULL);
+ return;
+ }
+
+ ASSERT(nread == 4);
+ ASSERT(addr != NULL);
+
+ ASSERT(memcmp("EXIT", rcvbuf->base, nread) == 0);
+ uv_close((uv_handle_t*) handle, close_cb);
+ uv_close((uv_handle_t*) &client, close_cb);
+
+ sv_recv_cb_called++;
+}
+
+
+TEST_IMPL(udp_try_send) {
+ struct sockaddr_in addr;
+ static char buffer[64 * 1024];
+ uv_buf_t buf;
+ int r;
+
+ ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
+
+ r = uv_udp_init(uv_default_loop(), &server);
+ ASSERT(r == 0);
+
+ r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0);
+ ASSERT(r == 0);
+
+ r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+
+ r = uv_udp_init(uv_default_loop(), &client);
+ ASSERT(r == 0);
+
+ buf = uv_buf_init(buffer, sizeof(buffer));
+ r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &addr);
+ ASSERT(r == UV_EMSGSIZE);
+
+ buf = uv_buf_init("EXIT", 4);
+ r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &addr);
+ ASSERT(r == 4);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 2);
+ ASSERT(sv_recv_cb_called == 1);
+
+ ASSERT(client.send_queue_size == 0);
+ ASSERT(server.send_queue_size == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+#endif /* !_WIN32 */
diff --git a/3rdparty/libuv/test/test-walk-handles.c b/3rdparty/libuv/test/test-walk-handles.c
new file mode 100644
index 00000000000..4b0ca6ebc55
--- /dev/null
+++ b/3rdparty/libuv/test/test-walk-handles.c
@@ -0,0 +1,77 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static char magic_cookie[] = "magic cookie";
+static int seen_timer_handle;
+static uv_timer_t timer;
+
+
+static void walk_cb(uv_handle_t* handle, void* arg) {
+ ASSERT(arg == (void*)magic_cookie);
+
+ if (handle == (uv_handle_t*)&timer) {
+ seen_timer_handle++;
+ } else {
+ ASSERT(0 && "unexpected handle");
+ }
+}
+
+
+static void timer_cb(uv_timer_t* handle) {
+ ASSERT(handle == &timer);
+
+ uv_walk(handle->loop, walk_cb, magic_cookie);
+ uv_close((uv_handle_t*)handle, NULL);
+}
+
+
+TEST_IMPL(walk_handles) {
+ uv_loop_t* loop;
+ int r;
+
+ loop = uv_default_loop();
+
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r == 0);
+
+ r = uv_timer_start(&timer, timer_cb, 1, 0);
+ ASSERT(r == 0);
+
+ /* Start event loop, expect to see the timer handle in walk_cb. */
+ ASSERT(seen_timer_handle == 0);
+ r = uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(r == 0);
+ ASSERT(seen_timer_handle == 1);
+
+ /* Loop is finished, walk_cb should not see our timer handle. */
+ seen_timer_handle = 0;
+ uv_walk(loop, walk_cb, magic_cookie);
+ ASSERT(seen_timer_handle == 0);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/test/test-watcher-cross-stop.c b/3rdparty/libuv/test/test-watcher-cross-stop.c
new file mode 100644
index 00000000000..910ed0fb613
--- /dev/null
+++ b/3rdparty/libuv/test/test-watcher-cross-stop.c
@@ -0,0 +1,103 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+#include <string.h>
+#include <errno.h>
+
+/* NOTE: Number should be big enough to trigger this problem */
+static uv_udp_t sockets[2500];
+static uv_udp_send_t reqs[ARRAY_SIZE(sockets)];
+static char slab[1];
+static unsigned int recv_cb_called;
+static unsigned int send_cb_called;
+static unsigned int close_cb_called;
+
+static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
+ buf->base = slab;
+ buf->len = sizeof(slab);
+}
+
+
+static void recv_cb(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags) {
+ recv_cb_called++;
+}
+
+
+static void send_cb(uv_udp_send_t* req, int status) {
+ send_cb_called++;
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+TEST_IMPL(watcher_cross_stop) {
+ uv_loop_t* loop = uv_default_loop();
+ unsigned int i;
+ struct sockaddr_in addr;
+ uv_buf_t buf;
+ char big_string[1024];
+
+ TEST_FILE_LIMIT(ARRAY_SIZE(sockets) + 32);
+
+ ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
+ memset(big_string, 'A', sizeof(big_string));
+ buf = uv_buf_init(big_string, sizeof(big_string));
+
+ for (i = 0; i < ARRAY_SIZE(sockets); i++) {
+ ASSERT(0 == uv_udp_init(loop, &sockets[i]));
+ ASSERT(0 == uv_udp_bind(&sockets[i],
+ (const struct sockaddr*) &addr,
+ UV_UDP_REUSEADDR));
+ ASSERT(0 == uv_udp_recv_start(&sockets[i], alloc_cb, recv_cb));
+ ASSERT(0 == uv_udp_send(&reqs[i],
+ &sockets[i],
+ &buf,
+ 1,
+ (const struct sockaddr*) &addr,
+ send_cb));
+ }
+
+ while (recv_cb_called == 0)
+ uv_run(loop, UV_RUN_ONCE);
+
+ for (i = 0; i < ARRAY_SIZE(sockets); i++)
+ uv_close((uv_handle_t*) &sockets[i], close_cb);
+
+ ASSERT(recv_cb_called > 0);
+
+ uv_run(loop, UV_RUN_DEFAULT);
+
+ ASSERT(ARRAY_SIZE(sockets) == send_cb_called);
+ ASSERT(ARRAY_SIZE(sockets) == close_cb_called);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
diff --git a/3rdparty/libuv/uv.gyp b/3rdparty/libuv/uv.gyp
new file mode 100644
index 00000000000..635a234ea6e
--- /dev/null
+++ b/3rdparty/libuv/uv.gyp
@@ -0,0 +1,508 @@
+{
+ 'target_defaults': {
+ 'conditions': [
+ ['OS != "win"', {
+ 'defines': [
+ '_LARGEFILE_SOURCE',
+ '_FILE_OFFSET_BITS=64',
+ ],
+ 'conditions': [
+ ['OS=="solaris"', {
+ 'cflags': [ '-pthreads' ],
+ }],
+ ['OS not in "solaris android"', {
+ 'cflags': [ '-pthread' ],
+ }],
+ ],
+ }],
+ ],
+ 'xcode_settings': {
+ 'WARNING_CFLAGS': [ '-Wall', '-Wextra', '-Wno-unused-parameter' ],
+ 'OTHER_CFLAGS': [ '-g', '--std=gnu89', '-pedantic' ],
+ }
+ },
+
+ 'targets': [
+ {
+ 'target_name': 'libuv',
+ 'type': '<(uv_library)',
+ 'include_dirs': [
+ 'include',
+ 'src/',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [ 'include' ],
+ 'conditions': [
+ ['OS != "win"', {
+ 'defines': [
+ '_LARGEFILE_SOURCE',
+ '_FILE_OFFSET_BITS=64',
+ ],
+ }],
+ ['OS in "mac ios"', {
+ 'defines': [ '_DARWIN_USE_64_BIT_INODE=1' ],
+ }],
+ ['OS == "linux"', {
+ 'defines': [ '_POSIX_C_SOURCE=200112' ],
+ }],
+ ],
+ },
+ 'sources': [
+ 'common.gypi',
+ 'include/uv.h',
+ 'include/tree.h',
+ 'include/uv-errno.h',
+ 'include/uv-threadpool.h',
+ 'include/uv-version.h',
+ 'src/fs-poll.c',
+ 'src/heap-inl.h',
+ 'src/inet.c',
+ 'src/queue.h',
+ 'src/threadpool.c',
+ 'src/uv-common.c',
+ 'src/uv-common.h',
+ 'src/version.c'
+ ],
+ 'conditions': [
+ [ 'OS=="win"', {
+ 'defines': [
+ '_WIN32_WINNT=0x0600',
+ '_GNU_SOURCE',
+ ],
+ 'sources': [
+ 'include/uv-win.h',
+ 'src/win/async.c',
+ 'src/win/atomicops-inl.h',
+ 'src/win/core.c',
+ 'src/win/dl.c',
+ 'src/win/error.c',
+ 'src/win/fs.c',
+ 'src/win/fs-event.c',
+ 'src/win/getaddrinfo.c',
+ 'src/win/getnameinfo.c',
+ 'src/win/handle.c',
+ 'src/win/handle-inl.h',
+ 'src/win/internal.h',
+ 'src/win/loop-watcher.c',
+ 'src/win/pipe.c',
+ 'src/win/thread.c',
+ 'src/win/poll.c',
+ 'src/win/process.c',
+ 'src/win/process-stdio.c',
+ 'src/win/req.c',
+ 'src/win/req-inl.h',
+ 'src/win/signal.c',
+ 'src/win/stream.c',
+ 'src/win/stream-inl.h',
+ 'src/win/tcp.c',
+ 'src/win/tty.c',
+ 'src/win/timer.c',
+ 'src/win/udp.c',
+ 'src/win/util.c',
+ 'src/win/winapi.c',
+ 'src/win/winapi.h',
+ 'src/win/winsock.c',
+ 'src/win/winsock.h',
+ ],
+ 'conditions': [
+ ['MSVS_VERSION < "2015"', {
+ 'sources': [
+ 'src/win/snprintf.c'
+ ]
+ }]
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '-ladvapi32',
+ '-liphlpapi',
+ '-lpsapi',
+ '-lshell32',
+ '-luserenv',
+ '-lws2_32'
+ ],
+ },
+ }, { # Not Windows i.e. POSIX
+ 'cflags': [
+ '-g',
+ '--std=gnu89',
+ '-pedantic',
+ '-Wall',
+ '-Wextra',
+ '-Wno-unused-parameter',
+ ],
+ 'sources': [
+ 'include/uv-unix.h',
+ 'include/uv-linux.h',
+ 'include/uv-sunos.h',
+ 'include/uv-darwin.h',
+ 'include/uv-bsd.h',
+ 'include/uv-aix.h',
+ 'src/unix/async.c',
+ 'src/unix/atomic-ops.h',
+ 'src/unix/core.c',
+ 'src/unix/dl.c',
+ 'src/unix/fs.c',
+ 'src/unix/getaddrinfo.c',
+ 'src/unix/getnameinfo.c',
+ 'src/unix/internal.h',
+ 'src/unix/loop.c',
+ 'src/unix/loop-watcher.c',
+ 'src/unix/pipe.c',
+ 'src/unix/poll.c',
+ 'src/unix/process.c',
+ 'src/unix/signal.c',
+ 'src/unix/spinlock.h',
+ 'src/unix/stream.c',
+ 'src/unix/tcp.c',
+ 'src/unix/thread.c',
+ 'src/unix/timer.c',
+ 'src/unix/tty.c',
+ 'src/unix/udp.c',
+ ],
+ 'link_settings': {
+ 'libraries': [ '-lm' ],
+ 'conditions': [
+ ['OS=="solaris"', {
+ 'ldflags': [ '-pthreads' ],
+ }],
+ ['OS != "solaris" and OS != "android"', {
+ 'ldflags': [ '-pthread' ],
+ }],
+ ],
+ },
+ 'conditions': [
+ ['uv_library=="shared_library"', {
+ 'cflags': [ '-fPIC' ],
+ }],
+ ['uv_library=="shared_library" and OS!="mac"', {
+ # This will cause gyp to set soname
+ # Must correspond with UV_VERSION_MAJOR
+ # in include/uv-version.h
+ 'product_extension': 'so.1',
+ }],
+ ],
+ }],
+ [ 'OS in "linux mac ios android"', {
+ 'sources': [ 'src/unix/proctitle.c' ],
+ }],
+ [ 'OS in "mac ios"', {
+ 'sources': [
+ 'src/unix/darwin.c',
+ 'src/unix/fsevents.c',
+ 'src/unix/darwin-proctitle.c',
+ ],
+ 'defines': [
+ '_DARWIN_USE_64_BIT_INODE=1',
+ '_DARWIN_UNLIMITED_SELECT=1',
+ ]
+ }],
+ [ 'OS!="mac"', {
+ # Enable on all platforms except OS X. The antique gcc/clang that
+ # ships with Xcode emits waaaay too many false positives.
+ 'cflags': [ '-Wstrict-aliasing' ],
+ }],
+ [ 'OS=="linux"', {
+ 'defines': [ '_GNU_SOURCE' ],
+ 'sources': [
+ 'src/unix/linux-core.c',
+ 'src/unix/linux-inotify.c',
+ 'src/unix/linux-syscalls.c',
+ 'src/unix/linux-syscalls.h',
+ ],
+ 'link_settings': {
+ 'libraries': [ '-ldl', '-lrt' ],
+ },
+ }],
+ [ 'OS=="android"', {
+ 'sources': [
+ 'src/unix/linux-core.c',
+ 'src/unix/linux-inotify.c',
+ 'src/unix/linux-syscalls.c',
+ 'src/unix/linux-syscalls.h',
+ 'src/unix/pthread-fixes.c',
+ 'src/unix/android-ifaddrs.c'
+ ],
+ 'link_settings': {
+ 'libraries': [ '-ldl' ],
+ },
+ }],
+ [ 'OS=="solaris"', {
+ 'sources': [ 'src/unix/sunos.c' ],
+ 'defines': [
+ '__EXTENSIONS__',
+ '_XOPEN_SOURCE=500',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '-lkstat',
+ '-lnsl',
+ '-lsendfile',
+ '-lsocket',
+ ],
+ },
+ }],
+ [ 'OS=="aix"', {
+ 'sources': [ 'src/unix/aix.c' ],
+ 'defines': [
+ '_ALL_SOURCE',
+ '_XOPEN_SOURCE=500',
+ '_LINUX_SOURCE_COMPAT',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '-lperfstat',
+ ],
+ },
+ }],
+ [ 'OS=="freebsd" or OS=="dragonflybsd"', {
+ 'sources': [ 'src/unix/freebsd.c' ],
+ }],
+ [ 'OS=="openbsd"', {
+ 'sources': [ 'src/unix/openbsd.c' ],
+ }],
+ [ 'OS=="netbsd"', {
+ 'sources': [ 'src/unix/netbsd.c' ],
+ }],
+ [ 'OS in "freebsd dragonflybsd openbsd netbsd".split()', {
+ 'link_settings': {
+ 'libraries': [ '-lkvm' ],
+ },
+ }],
+ [ 'OS in "ios mac freebsd dragonflybsd openbsd netbsd".split()', {
+ 'sources': [ 'src/unix/kqueue.c' ],
+ }],
+ ['uv_library=="shared_library"', {
+ 'defines': [ 'BUILDING_UV_SHARED=1' ]
+ }],
+ ]
+ },
+
+ {
+ 'target_name': 'run-tests',
+ 'type': 'executable',
+ 'dependencies': [ 'libuv' ],
+ 'sources': [
+ 'test/blackhole-server.c',
+ 'test/echo-server.c',
+ 'test/run-tests.c',
+ 'test/runner.c',
+ 'test/runner.h',
+ 'test/test-get-loadavg.c',
+ 'test/task.h',
+ 'test/test-active.c',
+ 'test/test-async.c',
+ 'test/test-async-null-cb.c',
+ 'test/test-callback-stack.c',
+ 'test/test-callback-order.c',
+ 'test/test-close-fd.c',
+ 'test/test-close-order.c',
+ 'test/test-connection-fail.c',
+ 'test/test-cwd-and-chdir.c',
+ 'test/test-default-loop-close.c',
+ 'test/test-delayed-accept.c',
+ 'test/test-error.c',
+ 'test/test-embed.c',
+ 'test/test-emfile.c',
+ 'test/test-fail-always.c',
+ 'test/test-fs.c',
+ 'test/test-fs-event.c',
+ 'test/test-get-currentexe.c',
+ 'test/test-get-memory.c',
+ 'test/test-getaddrinfo.c',
+ 'test/test-getnameinfo.c',
+ 'test/test-getsockname.c',
+ 'test/test-handle-fileno.c',
+ 'test/test-homedir.c',
+ 'test/test-hrtime.c',
+ 'test/test-idle.c',
+ 'test/test-ip6-addr.c',
+ 'test/test-ipc.c',
+ 'test/test-ipc-send-recv.c',
+ 'test/test-list.h',
+ 'test/test-loop-handles.c',
+ 'test/test-loop-alive.c',
+ 'test/test-loop-close.c',
+ 'test/test-loop-stop.c',
+ 'test/test-loop-time.c',
+ 'test/test-loop-configure.c',
+ 'test/test-walk-handles.c',
+ 'test/test-watcher-cross-stop.c',
+ 'test/test-multiple-listen.c',
+ 'test/test-osx-select.c',
+ 'test/test-pass-always.c',
+ 'test/test-ping-pong.c',
+ 'test/test-pipe-bind-error.c',
+ 'test/test-pipe-connect-error.c',
+ 'test/test-pipe-connect-multiple.c',
+ 'test/test-pipe-connect-prepare.c',
+ 'test/test-pipe-getsockname.c',
+ 'test/test-pipe-pending-instances.c',
+ 'test/test-pipe-sendmsg.c',
+ 'test/test-pipe-server-close.c',
+ 'test/test-pipe-close-stdout-read-stdin.c',
+ 'test/test-pipe-set-non-blocking.c',
+ 'test/test-platform-output.c',
+ 'test/test-poll.c',
+ 'test/test-poll-close.c',
+ 'test/test-poll-close-doesnt-corrupt-stack.c',
+ 'test/test-poll-closesocket.c',
+ 'test/test-process-title.c',
+ 'test/test-queue-foreach-delete.c',
+ 'test/test-ref.c',
+ 'test/test-run-nowait.c',
+ 'test/test-run-once.c',
+ 'test/test-semaphore.c',
+ 'test/test-shutdown-close.c',
+ 'test/test-shutdown-eof.c',
+ 'test/test-shutdown-twice.c',
+ 'test/test-signal.c',
+ 'test/test-signal-multiple-loops.c',
+ 'test/test-socket-buffer-size.c',
+ 'test/test-spawn.c',
+ 'test/test-fs-poll.c',
+ 'test/test-stdio-over-pipes.c',
+ 'test/test-tcp-bind-error.c',
+ 'test/test-tcp-bind6-error.c',
+ 'test/test-tcp-close.c',
+ 'test/test-tcp-close-accept.c',
+ 'test/test-tcp-close-while-connecting.c',
+ 'test/test-tcp-create-socket-early.c',
+ 'test/test-tcp-connect-error-after-write.c',
+ 'test/test-tcp-shutdown-after-write.c',
+ 'test/test-tcp-flags.c',
+ 'test/test-tcp-connect-error.c',
+ 'test/test-tcp-connect-timeout.c',
+ 'test/test-tcp-connect6-error.c',
+ 'test/test-tcp-open.c',
+ 'test/test-tcp-write-to-half-open-connection.c',
+ 'test/test-tcp-write-after-connect.c',
+ 'test/test-tcp-writealot.c',
+ 'test/test-tcp-write-fail.c',
+ 'test/test-tcp-try-write.c',
+ 'test/test-tcp-unexpected-read.c',
+ 'test/test-tcp-oob.c',
+ 'test/test-tcp-read-stop.c',
+ 'test/test-tcp-write-queue-order.c',
+ 'test/test-threadpool.c',
+ 'test/test-threadpool-cancel.c',
+ 'test/test-thread-equal.c',
+ 'test/test-mutexes.c',
+ 'test/test-thread.c',
+ 'test/test-barrier.c',
+ 'test/test-condvar.c',
+ 'test/test-timer-again.c',
+ 'test/test-timer-from-check.c',
+ 'test/test-timer.c',
+ 'test/test-tty.c',
+ 'test/test-udp-bind.c',
+ 'test/test-udp-create-socket-early.c',
+ 'test/test-udp-dgram-too-big.c',
+ 'test/test-udp-ipv6.c',
+ 'test/test-udp-open.c',
+ 'test/test-udp-options.c',
+ 'test/test-udp-send-and-recv.c',
+ 'test/test-udp-send-immediate.c',
+ 'test/test-udp-send-unreachable.c',
+ 'test/test-udp-multicast-join.c',
+ 'test/test-udp-multicast-join6.c',
+ 'test/test-dlerror.c',
+ 'test/test-udp-multicast-ttl.c',
+ 'test/test-ip4-addr.c',
+ 'test/test-ip6-addr.c',
+ 'test/test-udp-multicast-interface.c',
+ 'test/test-udp-multicast-interface6.c',
+ 'test/test-udp-try-send.c',
+ ],
+ 'conditions': [
+ [ 'OS=="win"', {
+ 'sources': [
+ 'test/runner-win.c',
+ 'test/runner-win.h'
+ ],
+ 'libraries': [ '-lws2_32' ]
+ }, { # POSIX
+ 'defines': [ '_GNU_SOURCE' ],
+ 'sources': [
+ 'test/runner-unix.c',
+ 'test/runner-unix.h',
+ ],
+ }],
+ [ 'OS=="solaris"', { # make test-fs.c compile, needs _POSIX_C_SOURCE
+ 'defines': [
+ '__EXTENSIONS__',
+ '_XOPEN_SOURCE=500',
+ ],
+ }],
+ [ 'OS=="aix"', { # make test-fs.c compile, needs _POSIX_C_SOURCE
+ 'defines': [
+ '_ALL_SOURCE',
+ '_XOPEN_SOURCE=500',
+ ],
+ }],
+ ['uv_library=="shared_library"', {
+ 'defines': [ 'USING_UV_SHARED=1' ]
+ }],
+ ],
+ 'msvs-settings': {
+ 'VCLinkerTool': {
+ 'SubSystem': 1, # /subsystem:console
+ },
+ },
+ },
+
+ {
+ 'target_name': 'run-benchmarks',
+ 'type': 'executable',
+ 'dependencies': [ 'libuv' ],
+ 'sources': [
+ 'test/benchmark-async.c',
+ 'test/benchmark-async-pummel.c',
+ 'test/benchmark-fs-stat.c',
+ 'test/benchmark-getaddrinfo.c',
+ 'test/benchmark-list.h',
+ 'test/benchmark-loop-count.c',
+ 'test/benchmark-million-async.c',
+ 'test/benchmark-million-timers.c',
+ 'test/benchmark-multi-accept.c',
+ 'test/benchmark-ping-pongs.c',
+ 'test/benchmark-pound.c',
+ 'test/benchmark-pump.c',
+ 'test/benchmark-sizes.c',
+ 'test/benchmark-spawn.c',
+ 'test/benchmark-thread.c',
+ 'test/benchmark-tcp-write-batch.c',
+ 'test/benchmark-udp-pummel.c',
+ 'test/dns-server.c',
+ 'test/echo-server.c',
+ 'test/blackhole-server.c',
+ 'test/run-benchmarks.c',
+ 'test/runner.c',
+ 'test/runner.h',
+ 'test/task.h',
+ ],
+ 'conditions': [
+ [ 'OS=="win"', {
+ 'sources': [
+ 'test/runner-win.c',
+ 'test/runner-win.h',
+ ],
+ 'libraries': [ '-lws2_32' ]
+ }, { # POSIX
+ 'defines': [ '_GNU_SOURCE' ],
+ 'sources': [
+ 'test/runner-unix.c',
+ 'test/runner-unix.h',
+ ]
+ }],
+ ['uv_library=="shared_library"', {
+ 'defines': [ 'USING_UV_SHARED=1' ]
+ }],
+ ],
+ 'msvs-settings': {
+ 'VCLinkerTool': {
+ 'SubSystem': 1, # /subsystem:console
+ },
+ },
+ },
+ ]
+}
diff --git a/3rdparty/libuv/vcbuild.bat b/3rdparty/libuv/vcbuild.bat
new file mode 100644
index 00000000000..696f0db30e1
--- /dev/null
+++ b/3rdparty/libuv/vcbuild.bat
@@ -0,0 +1,153 @@
+@echo off
+
+cd %~dp0
+
+if /i "%1"=="help" goto help
+if /i "%1"=="--help" goto help
+if /i "%1"=="-help" goto help
+if /i "%1"=="/help" goto help
+if /i "%1"=="?" goto help
+if /i "%1"=="-?" goto help
+if /i "%1"=="--?" goto help
+if /i "%1"=="/?" goto help
+
+@rem Process arguments.
+set config=
+set target=Build
+set noprojgen=
+set nobuild=
+set run=
+set target_arch=ia32
+set vs_toolset=x86
+set platform=WIN32
+set library=static_library
+
+:next-arg
+if "%1"=="" goto args-done
+if /i "%1"=="debug" set config=Debug&goto arg-ok
+if /i "%1"=="release" set config=Release&goto arg-ok
+if /i "%1"=="test" set run=run-tests.exe&goto arg-ok
+if /i "%1"=="bench" set run=run-benchmarks.exe&goto arg-ok
+if /i "%1"=="clean" set target=Clean&goto arg-ok
+if /i "%1"=="noprojgen" set noprojgen=1&goto arg-ok
+if /i "%1"=="nobuild" set nobuild=1&goto arg-ok
+if /i "%1"=="x86" set target_arch=ia32&set platform=WIN32&set vs_toolset=x86&goto arg-ok
+if /i "%1"=="ia32" set target_arch=ia32&set platform=WIN32&set vs_toolset=x86&goto arg-ok
+if /i "%1"=="x64" set target_arch=x64&set platform=x64&set vs_toolset=x64&goto arg-ok
+if /i "%1"=="shared" set library=shared_library&goto arg-ok
+if /i "%1"=="static" set library=static_library&goto arg-ok
+:arg-ok
+shift
+goto next-arg
+:args-done
+
+if defined WindowsSDKDir goto select-target
+if defined VCINSTALLDIR goto select-target
+
+@rem Look for Visual Studio 2015
+if not defined VS140COMNTOOLS goto vc-set-2013
+if not exist "%VS140COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2013
+call "%VS140COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset%
+set GYP_MSVS_VERSION=2015
+goto select-target
+
+:vc-set-2013
+@rem Look for Visual Studio 2013
+if not defined VS120COMNTOOLS goto vc-set-2012
+if not exist "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2012
+call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset%
+set GYP_MSVS_VERSION=2013
+goto select-target
+
+:vc-set-2012
+@rem Look for Visual Studio 2012
+if not defined VS110COMNTOOLS goto vc-set-2010
+if not exist "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2010
+call "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset%
+set GYP_MSVS_VERSION=2012
+goto select-target
+
+:vc-set-2010
+@rem Look for Visual Studio 2010
+if not defined VS100COMNTOOLS goto vc-set-2008
+if not exist "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2008
+call "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset%
+set GYP_MSVS_VERSION=2010
+goto select-target
+
+:vc-set-2008
+@rem Look for Visual Studio 2008
+if not defined VS90COMNTOOLS goto vc-set-notfound
+if not exist "%VS90COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-notfound
+call "%VS90COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset%
+set GYP_MSVS_VERSION=2008
+goto select-target
+
+:vc-set-notfound
+echo Warning: Visual Studio not found
+
+:select-target
+if not "%config%"=="" goto project-gen
+if "%run%"=="run-tests.exe" set config=Debug& goto project-gen
+if "%run%"=="run-benchmarks.exe" set config=Release& goto project-gen
+set config=Debug
+
+:project-gen
+@rem Skip project generation if requested.
+if defined noprojgen goto msbuild
+
+@rem Generate the VS project.
+if exist build\gyp goto have_gyp
+echo git clone https://chromium.googlesource.com/external/gyp build/gyp
+git clone https://chromium.googlesource.com/external/gyp build/gyp
+if errorlevel 1 goto gyp_install_failed
+goto have_gyp
+
+:gyp_install_failed
+echo Failed to download gyp. Make sure you have git installed, or
+echo manually install gyp into %~dp0build\gyp.
+exit /b 1
+
+:have_gyp
+if not defined PYTHON set PYTHON=python
+"%PYTHON%" gyp_uv.py -Dtarget_arch=%target_arch% -Duv_library=%library%
+if errorlevel 1 goto create-msvs-files-failed
+if not exist uv.sln goto create-msvs-files-failed
+echo Project files generated.
+
+:msbuild
+@rem Skip project generation if requested.
+if defined nobuild goto run
+
+@rem Check if VS build env is available
+if defined VCINSTALLDIR goto msbuild-found
+if defined WindowsSDKDir goto msbuild-found
+echo Build skipped. To build, this file needs to run from VS cmd prompt.
+goto run
+
+@rem Build the sln with msbuild.
+:msbuild-found
+msbuild uv.sln /t:%target% /p:Configuration=%config% /p:Platform="%platform%" /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo
+if errorlevel 1 exit /b 1
+
+:run
+@rem Run tests if requested.
+if "%run%"=="" goto exit
+if not exist %config%\%run% goto exit
+echo running '%config%\%run%'
+%config%\%run%
+goto exit
+
+:create-msvs-files-failed
+echo Failed to create vc project files.
+exit /b 1
+
+:help
+echo vcbuild.bat [debug/release] [test/bench] [clean] [noprojgen] [nobuild] [x86/x64] [static/shared]
+echo Examples:
+echo vcbuild.bat : builds debug build
+echo vcbuild.bat test : builds debug build and runs tests
+echo vcbuild.bat release bench: builds release build and runs benchmarks
+goto exit
+
+:exit
diff --git a/3rdparty/lua-zlib/.gitattributes b/3rdparty/lua-zlib/.gitattributes
new file mode 100644
index 00000000000..54be6288857
--- /dev/null
+++ b/3rdparty/lua-zlib/.gitattributes
@@ -0,0 +1 @@
+lua_zlib.c export-subst ident
diff --git a/3rdparty/lua-zlib/CMakeLists.txt b/3rdparty/lua-zlib/CMakeLists.txt
new file mode 100644
index 00000000000..1cda6b7532b
--- /dev/null
+++ b/3rdparty/lua-zlib/CMakeLists.txt
@@ -0,0 +1,62 @@
+# Copyright (C) 2007-2009 LuaDist.
+# Submitted by David Manura
+# Redistribution and use of this file is allowed according to the
+# terms of the MIT license.
+# For details see the COPYRIGHT file distributed with LuaDist.
+# Please note that the package source code is licensed under its own
+# license.
+
+PROJECT(lua-zlib C)
+CMAKE_MINIMUM_REQUIRED (VERSION 2.6)
+
+option(USE_LUA "Use Lua (also called 'C' Lua) includes (default)" ON)
+option(USE_LUAJIT "Use LuaJIT includes instead of 'C' Lua ones (recommended, if you're using LuaJIT, but disabled by default)")
+set(USE_LUA_VERSION 5.1 CACHE STRING "Set the Lua version to use (default: 5.1)")
+
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
+
+if(USE_LUAJIT)
+# Find luajit
+ find_package(LuaJIT REQUIRED)
+ set(USE_LUA OFF)
+# / Find lua
+endif()
+
+if(USE_LUA)
+# Find lua
+ find_package(Lua ${USE_LUA_VERSION} EXACT REQUIRED)
+# / Find lua
+endif()
+
+
+# Basic configurations
+ SET(INSTALL_CMOD share/lua/cmod CACHE PATH "Directory to install Lua binary modules (configure lua via LUA_CPATH)")
+# / configs
+
+# Find zlib
+ FIND_PACKAGE(ZLIB REQUIRED)
+# / Find zlib
+
+# Define how to build zlib.so:
+ INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIRS} ${LUA_INCLUDE_DIR})
+ ADD_LIBRARY(cmod_zlib MODULE
+ lua_zlib.c zlib.def)
+ SET_TARGET_PROPERTIES(cmod_zlib PROPERTIES PREFIX "")
+ SET_TARGET_PROPERTIES(cmod_zlib PROPERTIES OUTPUT_NAME zlib)
+ TARGET_LINK_LIBRARIES(cmod_zlib ${ZLIB_LIBRARIES})
+# / build zlib.so
+
+# Define how to test zlib.so:
+ INCLUDE(CTest)
+ SET(LUA_BIN "lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}")
+ FIND_PROGRAM(LUA NAMES ${LUA_BIN} lua luajit lua.bat)
+ ADD_TEST(basic ${LUA} ${CMAKE_CURRENT_SOURCE_DIR}/test.lua ${CMAKE_CURRENT_SOURCE_DIR}/ ${CMAKE_CURRENT_BINARY_DIR}/)
+ SET_TESTS_PROPERTIES(basic
+ PROPERTIES
+ FAIL_REGULAR_EXPRESSION
+ "not ok")
+# / test zlib.so
+
+# Where to install stuff
+ INSTALL (TARGETS cmod_zlib DESTINATION ${INSTALL_CMOD})
+# / Where to install.
diff --git a/3rdparty/lua-zlib/Makefile b/3rdparty/lua-zlib/Makefile
new file mode 100644
index 00000000000..801ea0436f2
--- /dev/null
+++ b/3rdparty/lua-zlib/Makefile
@@ -0,0 +1,62 @@
+# This Makefile is based on LuaSec's Makefile. Thanks to the LuaSec developers.
+# Inform the location to intall the modules
+LUAPATH ?= /usr/share/lua/5.1
+LUACPATH ?= /usr/lib/lua/5.1
+INCDIR ?= -I/usr/include/lua5.1
+LIBDIR ?= -L/usr/lib
+
+# For Mac OS X: set the system version
+MACOSX_VERSION = 10.4
+
+CMOD = zlib.so
+OBJS = lua_zlib.o
+
+LIBS = -lz -llua -lm
+WARN = -Wall -pedantic
+
+BSD_CFLAGS = -O2 -fPIC $(WARN) $(INCDIR) $(DEFS)
+BSD_LDFLAGS = -O -shared -fPIC $(LIBDIR)
+
+LNX_CFLAGS = -O2 -fPIC $(WARN) $(INCDIR) $(DEFS)
+LNX_LDFLAGS = -O -shared -fPIC $(LIBDIR)
+
+MAC_ENV = env MACOSX_DEPLOYMENT_TARGET='$(MACVER)'
+MAC_CFLAGS = -O2 -fPIC -fno-common $(WARN) $(INCDIR) $(DEFS)
+MAC_LDFLAGS = -bundle -undefined dynamic_lookup -fPIC $(LIBDIR)
+
+CC = gcc
+LD = $(MYENV) gcc
+CFLAGS = $(MYCFLAGS)
+LDFLAGS = $(MYLDFLAGS)
+
+.PHONY: all clean install none linux bsd macosx
+
+all:
+ @echo "Usage: $(MAKE) <platform>"
+ @echo " * linux"
+ @echo " * bsd"
+ @echo " * macosx"
+
+install: $(CMOD)
+ cp $(CMOD) $(LUACPATH)
+
+uninstall:
+ rm $(LUACPATH)/zlib.so
+
+linux:
+ @$(MAKE) $(CMOD) MYCFLAGS="$(LNX_CFLAGS)" MYLDFLAGS="$(LNX_LDFLAGS)" INCDIR="$(INCDIR)" LIBDIR="$(LIBDIR)" DEFS="$(DEFS)"
+
+bsd:
+ @$(MAKE) $(CMOD) MYCFLAGS="$(BSD_CFLAGS)" MYLDFLAGS="$(BSD_LDFLAGS)" INCDIR="$(INCDIR)" LIBDIR="$(LIBDIR)" DEFS="$(DEFS)"
+
+macosx:
+ @$(MAKE) $(CMOD) MYCFLAGS="$(MAC_CFLAGS)" MYLDFLAGS="$(MAC_LDFLAGS)" MYENV="$(MAC_ENV)" INCDIR="$(INCDIR)" LIBDIR="$(LIBDIR)" DEFS="$(DEFS)"
+
+clean:
+ rm -f $(OBJS) $(CMOD)
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(DEFS) $(INCDIR) -o $@ $<
+
+$(CMOD): $(OBJS)
+ $(LD) $(LDFLAGS) $(LIBDIR) $(OBJS) $(LIBS) -o $@
diff --git a/3rdparty/lua-zlib/README b/3rdparty/lua-zlib/README
new file mode 100644
index 00000000000..8c1ef8d5f8d
--- /dev/null
+++ b/3rdparty/lua-zlib/README
@@ -0,0 +1,151 @@
+**********************************************************************
+* Author : Brian Maher <maherb at brimworks dot com>
+* Library : lua_zlib - Lua 5.1 interface to zlib
+*
+* The MIT License
+*
+* Copyright (c) 2009 Brian Maher
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+* THE SOFTWARE.
+**********************************************************************
+
+To use this library, you need zlib, get it here:
+ http://www.gzip.org/zlib/
+
+To build this library, you can use CMake and get it here:
+ http://www.cmake.org/cmake/resources/software.html
+
+...or you can use GNU Make.
+ make <platform>
+
+Loading the library:
+
+ If you built the library as a loadable package
+ [local] zlib = require 'zlib'
+
+ If you compiled the package statically into your application, call
+ the function "luaopen_zlib(L)". It will create a table with the zlib
+ functions and leave it on the stack.
+
+-- zlib functions --
+
+int major, int minor, int patch = zlib.version()
+
+ returns numeric zlib version for the major, minor, and patch
+ levels of the version dynamically linked in.
+
+function stream = zlib.deflate([ int compression_level ], [ int window_size ])
+
+ If no compression_level is provided uses Z_DEFAULT_COMPRESSION (6),
+ compression level is a number from 1-9 where zlib.BEST_SPEED is 1
+ and zlib.BEST_COMPRESSION is 9.
+
+ Returns a "stream" function that compresses (or deflates) all
+ strings passed in. Specifically, use it as such:
+
+ string deflated, bool eof, int bytes_in, int bytes_out =
+ stream(string input [, 'sync' | 'full' | 'finish'])
+
+ Takes input and deflates and returns a portion of it,
+ optionally forcing a flush.
+
+ A 'sync' flush will force all pending output to be flushed to
+ the return value and the output is aligned on a byte boundary,
+ so that the decompressor can get all input data available so
+ far. Flushing may degrade compression for some compression
+ algorithms and so it should be used only when necessary.
+
+ A 'full' flush will flush all output as with 'sync', and the
+ compression state is reset so that decompression can restart
+ from this point if previous compressed data has been damaged
+ or if random access is desired. Using Z_FULL_FLUSH too often
+ can seriously degrade the compression.
+
+ A 'finish' flush will force all pending output to be processed
+ and results in the stream become unusable. Any future
+ attempts to print anything other than the empty string will
+ result in an error that begins with IllegalState.
+
+ The eof result is true if 'finish' was specified, otherwise
+ it is false.
+
+ The bytes_in is how many bytes of input have been passed to
+ stream, and bytes_out is the number of bytes returned in
+ deflated string chunks.
+
+function stream = zlib.inflate([int windowBits])
+
+ Returns a "stream" function that decompresses (or inflates) all
+ strings passed in. Optionally specify a windowBits argument
+ that is passed to inflateInit2(), see zlib.h for details about
+ this argument. By default, gzip header detection is done, and
+ the max window size is used.
+
+ The "stream" function should be used as such:
+
+ string inflated, bool eof, int bytes_in, int bytes_out =
+ stream(string input)
+
+ Takes input and inflates and returns a portion of it. If it
+ detects the end of a deflation stream, then total will be the
+ total number of bytes read from input and all future calls to
+ stream() with a non empty string will result in an error that
+ begins with IllegalState.
+
+ No flush options are provided since the maximal amount of
+ input is always processed.
+
+ eof will be true when the input string is determined to be at
+ the "end of the file".
+
+ The bytes_in is how many bytes of input have been passed to
+ stream, and bytes_out is the number of bytes returned in
+ inflated string chunks.
+
+
+function compute_checksum = zlib.adler32()
+function compute_checksum = zlib.crc32()
+
+ Create a new checksum computation function using either the
+ adler32 or crc32 algorithms. This resulting function should be
+ used as such:
+
+ int checksum = compute_checksum(string input |
+ function compute_checksum)
+
+ The compute_checksum function takes as input either a string
+ that is logically getting appended to or another
+ compute_checksum function that is logically getting appended.
+ The result is the updated checksum.
+
+ For example, these uses will all result in the same checksum:
+
+ -- All in one call:
+ local csum = zlib.crc32()("one two")
+
+ -- Multiple calls:
+ local compute = zlib.crc32()
+ compute("one")
+ assert(csum == compute(" two"))
+
+ -- Multiple compute_checksums joined:
+ local compute1, compute2 = zlib.crc32(), zlib.crc32()
+ compute1("one")
+ compute2(" two")
+ assert(csum == compute1(compute2))
diff --git a/3rdparty/lua-zlib/amnon_david.gz b/3rdparty/lua-zlib/amnon_david.gz
new file mode 100644
index 00000000000..c56de231d1a
--- /dev/null
+++ b/3rdparty/lua-zlib/amnon_david.gz
Binary files differ
diff --git a/3rdparty/lua-zlib/cmake/Modules/FindLuaJIT.cmake b/3rdparty/lua-zlib/cmake/Modules/FindLuaJIT.cmake
new file mode 100644
index 00000000000..e626a5a1d94
--- /dev/null
+++ b/3rdparty/lua-zlib/cmake/Modules/FindLuaJIT.cmake
@@ -0,0 +1,63 @@
+# Locate LuaJIT library
+# This module defines
+# LUAJIT_FOUND, if false, do not try to link to Lua
+# LUA_LIBRARIES
+# LUA_INCLUDE_DIR, where to find lua.h
+# LUAJIT_VERSION_STRING, the version of Lua found (since CMake 2.8.8)
+
+## Copied from default CMake FindLua51.cmake
+
+find_path(LUA_INCLUDE_DIR luajit.h
+ HINTS
+ ENV LUA_DIR
+ PATH_SUFFIXES include/luajit-2.0 include
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+ /opt
+)
+
+find_library(LUA_LIBRARY
+ NAMES luajit-5.1
+ HINTS
+ ENV LUA_DIR
+ PATH_SUFFIXES lib
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+)
+
+if(LUA_LIBRARY)
+ # include the math library for Unix
+ if(UNIX AND NOT APPLE)
+ find_library(LUA_MATH_LIBRARY m)
+ set( LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}" CACHE STRING "Lua Libraries")
+ # For Windows and Mac, don't need to explicitly include the math library
+ else()
+ set( LUA_LIBRARIES "${LUA_LIBRARY}" CACHE STRING "Lua Libraries")
+ endif()
+endif()
+
+if(LUA_INCLUDE_DIR AND EXISTS "${LUA_INCLUDE_DIR}/luajit.h")
+ file(STRINGS "${LUA_INCLUDE_DIR}/luajit.h" luajit_version_str REGEX "^#define[ \t]+LUAJIT_VERSION[ \t]+\"LuaJIT .+\"")
+
+ string(REGEX REPLACE "^#define[ \t]+LUAJIT_VERSION[ \t]+\"LuaJIT ([^\"]+)\".*" "\\1" LUAJIT_VERSION_STRING "${luajit_version_str}")
+ unset(luajit_version_str)
+endif()
+
+include(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if
+# all listed variables are TRUE
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LuaJIT
+ REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR
+ VERSION_VAR LUAJIT_VERSION_STRING)
+
+mark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARIES LUA_LIBRARY LUA_MATH_LIBRARY)
+
diff --git a/3rdparty/lua-zlib/lua_zlib.c b/3rdparty/lua-zlib/lua_zlib.c
new file mode 100644
index 00000000000..b619258c75f
--- /dev/null
+++ b/3rdparty/lua-zlib/lua_zlib.c
@@ -0,0 +1,401 @@
+#include <ctype.h>
+#include <lauxlib.h>
+#include <lua.h>
+#include <stdlib.h>
+#include <string.h>
+#include <zlib.h>
+
+/*
+ * ** compatibility with Lua 5.2
+ * */
+#if (LUA_VERSION_NUM >= 502)
+#undef luaL_register
+#define luaL_register(L,n,f) \
+ { if ((n) == NULL) luaL_setfuncs(L,f,0); else luaL_newlib(L,f); }
+
+#endif
+
+#if (LUA_VERSION_NUM >= 503)
+#undef luaL_optint
+#define luaL_optint(L,n,d) ((int)luaL_optinteger(L,(n),(d)))
+#endif
+
+#define DEF_MEM_LEVEL 8
+
+typedef uLong (*checksum_t) (uLong crc, const Bytef *buf, uInt len);
+typedef uLong (*checksum_combine_t)(uLong crc1, uLong crc2, z_off_t len2);
+
+
+static int lz_deflate(lua_State *L);
+static int lz_deflate_delete(lua_State *L);
+static int lz_inflate_delete(lua_State *L);
+static int lz_inflate(lua_State *L);
+static int lz_checksum(lua_State *L);
+static int lz_checksum_new(lua_State *L, checksum_t checksum, checksum_combine_t combine);
+static int lz_adler32(lua_State *L);
+static int lz_crc32(lua_State *L);
+
+static int lz_version(lua_State *L) {
+ const char* version = zlibVersion();
+ int count = strlen(version) + 1;
+ char* cur = (char*)memcpy(lua_newuserdata(L, count),
+ version, count);
+
+ count = 0;
+ while ( *cur ) {
+ char* begin = cur;
+ /* Find all digits: */
+ while ( isdigit(*cur) ) cur++;
+ if ( begin != cur ) {
+ int is_end = *cur == '\0';
+ *cur = '\0';
+ lua_pushnumber(L, atoi(begin));
+ count++;
+ if ( is_end ) break;
+ cur++;
+ }
+ while ( *cur && ! isdigit(*cur) ) cur++;
+ }
+
+ return count;
+}
+
+static int lz_assert(lua_State *L, int result, const z_stream* stream, const char* file, int line) {
+ /* Both of these are "normal" return codes: */
+ if ( result == Z_OK || result == Z_STREAM_END ) return result;
+ switch ( result ) {
+ case Z_NEED_DICT:
+ lua_pushfstring(L, "RequiresDictionary: input stream requires a dictionary to be deflated (%s) at %s line %d",
+ stream->msg, file, line);
+ break;
+ case Z_STREAM_ERROR:
+ lua_pushfstring(L, "InternalError: inconsistent internal zlib stream (%s) at %s line %d",
+ stream->msg, file, line);
+ break;
+ case Z_DATA_ERROR:
+ lua_pushfstring(L, "InvalidInput: input string does not conform to zlib format or checksum failed at %s line %d",
+ file, line);
+ break;
+ case Z_MEM_ERROR:
+ lua_pushfstring(L, "OutOfMemory: not enough memory (%s) at %s line %d",
+ stream->msg, file, line);
+ break;
+ case Z_BUF_ERROR:
+ lua_pushfstring(L, "InternalError: no progress possible (%s) at %s line %d",
+ stream->msg, file, line);
+ break;
+ case Z_VERSION_ERROR:
+ lua_pushfstring(L, "IncompatibleLibrary: built with version %s, but dynamically linked with version %s (%s) at %s line %d",
+ ZLIB_VERSION, zlibVersion(), stream->msg, file, line);
+ break;
+ default:
+ lua_pushfstring(L, "ZLibError: unknown code %d (%s) at %s line %d",
+ result, stream->msg, file, line);
+ }
+ lua_error(L);
+ return result;
+}
+
+/**
+ * @upvalue z_stream - Memory for the z_stream.
+ * @upvalue remainder - Any remainder from the last deflate call.
+ *
+ * @param string - "print" to deflate stream.
+ * @param int - flush output buffer? Z_SYNC_FLUSH, Z_FULL_FLUSH, or Z_FINISH.
+ *
+ * if no params, terminates the stream (as if we got empty string and Z_FINISH).
+ */
+static int lz_filter_impl(lua_State *L, int (*filter)(z_streamp, int), int (*end)(z_streamp), const char* name) {
+ int flush = Z_NO_FLUSH, result;
+ z_stream* stream;
+ luaL_Buffer buff;
+ size_t avail_in;
+
+ if ( filter == deflate ) {
+ const char *const opts[] = { "none", "sync", "full", "finish", NULL };
+ flush = luaL_checkoption(L, 2, opts[0], opts);
+ if ( flush ) flush++;
+ /* Z_NO_FLUSH(0) Z_SYNC_FLUSH(2), Z_FULL_FLUSH(3), Z_FINISH (4) */
+
+ /* No arguments or nil, we are terminating the stream: */
+ if ( lua_gettop(L) == 0 || lua_isnil(L, 1) ) {
+ flush = Z_FINISH;
+ }
+ }
+
+ stream = (z_stream*)lua_touserdata(L, lua_upvalueindex(1));
+ if ( stream == NULL ) {
+ if ( lua_gettop(L) >= 1 && lua_isstring(L, 1) ) {
+ lua_pushfstring(L, "IllegalState: calling %s function when stream was previously closed", name);
+ lua_error(L);
+ }
+ lua_pushstring(L, "");
+ lua_pushboolean(L, 1);
+ return 2; /* Ignore duplicate calls to "close". */
+ }
+
+ luaL_buffinit(L, &buff);
+
+ if ( lua_gettop(L) > 1 ) lua_pushvalue(L, 1);
+
+ if ( lua_isstring(L, lua_upvalueindex(2)) ) {
+ lua_pushvalue(L, lua_upvalueindex(2));
+ if ( lua_gettop(L) > 1 && lua_isstring(L, -2) ) {
+ lua_concat(L, 2);
+ }
+ }
+
+ /* Do the actual deflate'ing: */
+ if (lua_gettop(L) > 0) {
+ stream->next_in = (unsigned char*)lua_tolstring(L, -1, &avail_in);
+ } else {
+ stream->next_in = NULL;
+ avail_in = 0;
+ }
+ stream->avail_in = avail_in;
+
+ if ( ! stream->avail_in && ! flush ) {
+ /* Passed empty string, make it a noop instead of erroring out. */
+ lua_pushstring(L, "");
+ lua_pushboolean(L, 0);
+ lua_pushinteger(L, stream->total_in);
+ lua_pushinteger(L, stream->total_out);
+ return 4;
+ }
+
+ do {
+ stream->next_out = (unsigned char*)luaL_prepbuffer(&buff);
+ stream->avail_out = LUAL_BUFFERSIZE;
+ result = filter(stream, flush);
+ if ( Z_BUF_ERROR != result ) {
+ /* Ignore Z_BUF_ERROR since that just indicates that we
+ * need a larger buffer in order to proceed. Thanks to
+ * Tobias Markmann for finding this bug!
+ */
+ lz_assert(L, result, stream, __FILE__, __LINE__);
+ }
+ luaL_addsize(&buff, LUAL_BUFFERSIZE - stream->avail_out);
+ } while ( stream->avail_out == 0 );
+
+ /* Need to do this before we alter the stack: */
+ luaL_pushresult(&buff);
+
+ /* Save remainder in lua_upvalueindex(2): */
+ if ( NULL != stream->next_in ) {
+ lua_pushlstring(L, (char*)stream->next_in, stream->avail_in);
+ lua_replace(L, lua_upvalueindex(2));
+ }
+
+ /* "close" the stream/remove finalizer: */
+ if ( result == Z_STREAM_END ) {
+ /* Clear-out the metatable so end is not called twice: */
+ lua_pushnil(L);
+ lua_setmetatable(L, lua_upvalueindex(1));
+
+ /* nil the upvalue: */
+ lua_pushnil(L);
+ lua_replace(L, lua_upvalueindex(1));
+
+ /* Close the stream: */
+ lz_assert(L, end(stream), stream, __FILE__, __LINE__);
+
+ lua_pushboolean(L, 1);
+ } else {
+ lua_pushboolean(L, 0);
+ }
+ lua_pushinteger(L, stream->total_in);
+ lua_pushinteger(L, stream->total_out);
+ return 4;
+}
+
+static void lz_create_deflate_mt(lua_State *L) {
+ luaL_newmetatable(L, "lz.deflate.meta"); /* {} */
+
+ lua_pushcfunction(L, lz_deflate_delete);
+ lua_setfield(L, -2, "__gc");
+
+ lua_pop(L, 1); /* <empty> */
+}
+
+static int lz_deflate_new(lua_State *L) {
+ int level = luaL_optint(L, 1, Z_DEFAULT_COMPRESSION);
+ int window_size = luaL_optint(L, 2, MAX_WBITS);
+
+ /* Allocate the stream: */
+ z_stream* stream = (z_stream*)lua_newuserdata(L, sizeof(z_stream));
+
+ stream->zalloc = Z_NULL;
+ stream->zfree = Z_NULL;
+
+ int result = deflateInit2(stream, level, Z_DEFLATED, window_size,
+ DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+
+ lz_assert(L, result, stream, __FILE__, __LINE__);
+
+ /* Don't allow destructor to execute unless deflateInit2 was successful: */
+ luaL_getmetatable(L, "lz.deflate.meta");
+ lua_setmetatable(L, -2);
+
+ lua_pushnil(L);
+ lua_pushcclosure(L, lz_deflate, 2);
+ return 1;
+}
+
+static int lz_deflate(lua_State *L) {
+ return lz_filter_impl(L, deflate, deflateEnd, "deflate");
+}
+
+static int lz_deflate_delete(lua_State *L) {
+ z_stream* stream = (z_stream*)lua_touserdata(L, 1);
+
+ /* Ignore errors. */
+ deflateEnd(stream);
+
+ return 0;
+}
+
+
+static void lz_create_inflate_mt(lua_State *L) {
+ luaL_newmetatable(L, "lz.inflate.meta"); /* {} */
+
+ lua_pushcfunction(L, lz_inflate_delete);
+ lua_setfield(L, -2, "__gc");
+
+ lua_pop(L, 1); /* <empty> */
+}
+
+static int lz_inflate_new(lua_State *L) {
+ /* Allocate the stream */
+ z_stream* stream = (z_stream*)lua_newuserdata(L, sizeof(z_stream));
+
+ /* By default, we will do gzip header detection w/ max window size */
+ int window_size = lua_isnumber(L, 1) ? lua_tointeger(L, 1) : MAX_WBITS + 32;
+
+ stream->zalloc = Z_NULL;
+ stream->zfree = Z_NULL;
+ stream->next_in = Z_NULL;
+ stream->avail_in = 0;
+
+ lz_assert(L, inflateInit2(stream, window_size), stream, __FILE__, __LINE__);
+
+ /* Don't allow destructor to execute unless deflateInit was successful: */
+ luaL_getmetatable(L, "lz.inflate.meta");
+ lua_setmetatable(L, -2);
+
+ lua_pushnil(L);
+ lua_pushcclosure(L, lz_inflate, 2);
+ return 1;
+}
+
+static int lz_inflate(lua_State *L) {
+ return lz_filter_impl(L, inflate, inflateEnd, "inflate");
+}
+
+static int lz_inflate_delete(lua_State *L) {
+ z_stream* stream = (z_stream*)lua_touserdata(L, 1);
+
+ /* Ignore errors: */
+ inflateEnd(stream);
+
+ return 0;
+}
+
+static int lz_checksum(lua_State *L) {
+ if ( lua_gettop(L) <= 0 ) {
+ lua_pushvalue(L, lua_upvalueindex(3));
+ lua_pushvalue(L, lua_upvalueindex(4));
+ } else if ( lua_isfunction(L, 1) ) {
+ checksum_combine_t combine = (checksum_combine_t)
+ lua_touserdata(L, lua_upvalueindex(2));
+
+ lua_pushvalue(L, 1);
+ lua_call(L, 0, 2);
+ if ( ! lua_isnumber(L, -2) || ! lua_isnumber(L, -1) ) {
+ luaL_argerror(L, 1, "expected function to return two numbers");
+ }
+
+ /* Calculate and replace the checksum */
+ lua_pushnumber(L,
+ combine(lua_tonumber(L, lua_upvalueindex(3)),
+ lua_tonumber(L, -2),
+ lua_tonumber(L, -1)));
+ lua_pushvalue(L, -1);
+ lua_replace(L, lua_upvalueindex(3));
+
+ /* Calculate and replace the length */
+ lua_pushnumber(L,
+ lua_tonumber(L, lua_upvalueindex(4)) + lua_tonumber(L, -2));
+ lua_pushvalue(L, -1);
+ lua_replace(L, lua_upvalueindex(4));
+ } else {
+ const Bytef* str;
+ size_t len;
+
+ checksum_t checksum = (checksum_t)
+ lua_touserdata(L, lua_upvalueindex(1));
+ str = (const Bytef*)luaL_checklstring(L, 1, &len);
+
+ /* Calculate and replace the checksum */
+ lua_pushnumber(L,
+ checksum(lua_tonumber(L, lua_upvalueindex(3)),
+ str,
+ len));
+ lua_pushvalue(L, -1);
+ lua_replace(L, lua_upvalueindex(3));
+
+ /* Calculate and replace the length */
+ lua_pushnumber(L,
+ lua_tonumber(L, lua_upvalueindex(4)) + len);
+ lua_pushvalue(L, -1);
+ lua_replace(L, lua_upvalueindex(4));
+ }
+ return 2;
+}
+
+static int lz_checksum_new(lua_State *L, checksum_t checksum, checksum_combine_t combine) {
+ lua_pushlightuserdata(L, checksum);
+ lua_pushlightuserdata(L, combine);
+ lua_pushnumber(L, checksum(0L, Z_NULL, 0));
+ lua_pushnumber(L, 0);
+ lua_pushcclosure(L, lz_checksum, 4);
+ return 1;
+}
+
+static int lz_adler32(lua_State *L) {
+ return lz_checksum_new(L, adler32, adler32_combine);
+}
+
+static int lz_crc32(lua_State *L) {
+ return lz_checksum_new(L, crc32, crc32_combine);
+}
+
+static const luaL_Reg zlib_functions[] = {
+ { "deflate", lz_deflate_new },
+ { "inflate", lz_inflate_new },
+ { "adler32", lz_adler32 },
+ { "crc32", lz_crc32 },
+ { "version", lz_version },
+ { NULL, NULL }
+};
+
+#define SETLITERAL(n,v) (lua_pushliteral(L, n), lua_pushliteral(L, v), lua_settable(L, -3))
+#define SETINT(n,v) (lua_pushliteral(L, n), lua_pushinteger(L, v), lua_settable(L, -3))
+
+LUALIB_API int luaopen_zlib(lua_State * const L) {
+ lz_create_deflate_mt(L);
+ lz_create_inflate_mt(L);
+
+ luaL_register(L, "zlib", zlib_functions);
+
+ SETINT("BEST_SPEED", Z_BEST_SPEED);
+ SETINT("BEST_COMPRESSION", Z_BEST_COMPRESSION);
+
+ SETLITERAL("_COPYRIGHT", "Copyright (c) 2009-2010 Brian Maher");
+ SETLITERAL("_DESCRIPTION", "Yet another binding to the zlib library");
+ SETLITERAL("_VERSION", "lua-zlib $Id$ $Format:%d$");
+
+ /* Expose this to lua so we can do a test: */
+ SETINT("_TEST_BUFSIZ", LUAL_BUFFERSIZE);
+
+ return 1;
+}
diff --git a/3rdparty/lua-zlib/rockspec b/3rdparty/lua-zlib/rockspec
new file mode 100644
index 00000000000..d248bc099ed
--- /dev/null
+++ b/3rdparty/lua-zlib/rockspec
@@ -0,0 +1,35 @@
+package = "lua-zlib"
+version = "0.3-1"
+source = {
+ url = "git://github.com/brimworks/lua-zlib.git",
+ tag = "v0.4",
+}
+description = {
+ summary = "Simple streaming interface to zlib for Lua.",
+ detailed = [[
+ Simple streaming interface to zlib for Lua.
+ Consists of two functions: inflate and deflate.
+ Both functions return "stream functions" (takes a buffer of input and returns a buffer of output).
+ This project is hosted on github.
+ ]],
+ homepage = "https://github.com/brimworks/lua-zlib",
+ license = "MIT"
+}
+dependencies = {
+ "lua >= 5.1, < 5.3"
+}
+external_dependencies = {
+ ZLIB = {
+ header = "zlib.h"
+ }
+}
+
+build = {
+ type = "builtin",
+ modules = {
+ zlib = {
+ sources = { "lua_zlib.c" };
+ libraries = { "z" },
+ };
+ }
+}
diff --git a/3rdparty/lua-zlib/tap.lua b/3rdparty/lua-zlib/tap.lua
new file mode 100644
index 00000000000..05266a9c997
--- /dev/null
+++ b/3rdparty/lua-zlib/tap.lua
@@ -0,0 +1,24 @@
+local tap_module = {}
+
+local os = require("os")
+
+local counter = 1
+local failed = false
+
+function tap_module.ok(assert_true, desc)
+ local msg = ( assert_true and "ok " or "not ok " ) .. counter
+ if ( not assert_true ) then
+ failed = true
+ end
+ if ( desc ) then
+ msg = msg .. " - " .. desc
+ end
+ print(msg)
+ counter = counter + 1
+end
+
+function tap_module.exit()
+ os.exit(failed and 1 or 0)
+end
+
+return tap_module
diff --git a/3rdparty/lua-zlib/test.lua b/3rdparty/lua-zlib/test.lua
new file mode 100644
index 00000000000..d64e1835506
--- /dev/null
+++ b/3rdparty/lua-zlib/test.lua
@@ -0,0 +1,198 @@
+print "1..9"
+
+local src_dir, build_dir = ...
+package.path = (src_dir or "./") .. "?.lua;" .. package.path
+package.cpath = (build_dir or "./") .. "?.so;" .. package.cpath
+
+local tap = require("tap")
+local lz = require("zlib")
+local ok = tap.ok
+local table = require("table")
+local io = require("io")
+
+function main()
+ test_stats()
+ test_buff_err()
+ test_small_inputs()
+ test_basic()
+ test_large()
+ test_no_input()
+ test_invalid_input()
+ test_streaming()
+ test_illegal_state()
+ test_checksum()
+ test_version()
+ test_tom_macwright()
+ test_amnon_david()
+end
+
+function test_tom_macwright()
+ local deflated =
+ assert(io.open(src_dir.. "/tom_macwright.gz")):read("*a")
+
+ local inflated = lz.inflate()(deflated)
+
+ local expected_inflated =
+ assert(io.open(src_dir.. "/tom_macwright.out")):read("*a")
+
+ ok(expected_inflated == inflated, "Tom MacWright Test")
+end
+
+function test_amnon_david()
+ local body = assert(io.open(src_dir.."/amnon_david.gz")):read("*a")
+
+ local inflate = lz.inflate()
+ local inflated, eof, bytes_in, bytes_out = inflate(body)
+
+ local deflate = lz.deflate()
+ local deflated, eof, bytes_in, bytes_out = deflate(inflated, "full")
+end
+
+function test_stats()
+ local string = ("one"):rep(20)
+ local deflated, eof, bin, bout = lz.deflate()(string, 'finish')
+ ok(eof == true, "eof is true (" .. tostring(eof) .. ")");
+ ok(bin > bout, "bytes in is greater than bytes out?")
+ ok(#deflated == bout, "bytes out is the same size as deflated string length")
+ ok(#string == bin, "bytes in is the same size as the input string length")
+end
+
+-- Thanks to Tobias Markmann for the bug report! We are trying to
+-- force inflate() to return a Z_BUF_ERROR (which should be recovered
+-- from). For some reason this only happens when the input is exactly
+-- LUAL_BUFFERSIZE (at least on my machine).
+function test_buff_err()
+ local text = ("X"):rep(lz._TEST_BUFSIZ);
+
+ local deflated = lz.deflate()(text, 'finish')
+
+ for i=1,#deflated do
+ lz.inflate()(deflated:sub(1,i))
+ end
+end
+
+function test_small_inputs()
+ local text = ("X"):rep(lz._TEST_BUFSIZ);
+
+ local deflated = lz.deflate()(text, 'finish')
+
+ local inflated = {}
+ local inflator = lz.inflate()
+ for i=1,#deflated do
+ local part = inflator(deflated:sub(i,i))
+ table.insert(inflated, part)
+ end
+ inflated = table.concat(inflated)
+ ok(inflated == text, "Expected " .. #text .. " Xs got " .. #inflated)
+end
+
+function test_basic()
+ local test_string = "abcdefghijklmnopqrstuv"
+
+ ok(lz.inflate()(lz.deflate()(), "finish") == "")
+
+ -- Input to deflate is same as output to inflate:
+ local deflated = lz.deflate()(test_string, "finish")
+ local inflated = lz.inflate()(deflated, "finish")
+
+ ok(test_string == inflated, "'" .. tostring(test_string) .. "' == '" .. tostring(inflated) .. "'")
+end
+
+function test_large()
+ -- Try a larger string:
+ local numbers = ""
+ for i=1, 100 do numbers = numbers .. string.format("%3d", i) end
+ local numbers_table = {}
+ for i=1, 10000 do numbers_table[i] = numbers end
+ local test_string = table.concat(numbers_table, "\n")
+
+ local deflated = lz.deflate()(test_string, "finish")
+ local inflated = lz.inflate()(deflated, "finish")
+ ok(test_string == inflated, "large string")
+end
+
+function test_no_input()
+ local stream = lz.deflate()
+ local deflated = stream("")
+ deflated = deflated .. stream("")
+ deflated = deflated .. stream(nil, "finish")
+ ok("" == lz.inflate()(deflated, "finish"), "empty string")
+end
+
+function test_invalid_input()
+ local stream = lz.inflate()
+ local isok, err = pcall(
+ function()
+ stream("bad input")
+ end)
+ ok(not isok)
+ ok(string.find(err, "^InvalidInput"),
+ string.format("InvalidInput error (%s)", err))
+end
+
+function test_streaming()
+ local shrink = lz.deflate(lz.BEST_COMPRESSION)
+ local enlarge = lz.inflate()
+ local expected = {}
+ local got = {}
+ local chant = "Isn't He great, isn't He wonderful?\n"
+ for i=1,100 do
+ if ( i == 100 ) then
+ chant = nil
+ print "EOF round"
+ end
+ local shrink_part, shrink_eof = shrink(chant)
+ local enlarge_part, enlarge_eof = enlarge(shrink_part)
+ if ( i == 100 ) then
+ if not shrink_eof then error("expected eof after shrinking flush") end
+ if not enlarge_eof then error("expected eof after enlarging") end
+ else
+ if shrink_eof then error("unexpected eof after shrinking") end
+ if enlarge_eof then error("unexpected eof after enlarging") end
+ end
+ if enlarge_part then table.insert(got, enlarge_part) end
+ if chant then table.insert(expected, chant) end
+ end
+ ok(table.concat(got) == table.concat(expected), "streaming works")
+end
+
+function test_illegal_state()
+ local stream = lz.deflate()
+ stream("abc")
+ stream() -- eof/close
+
+ local _, emsg = pcall(
+ function()
+ stream("printing on 'closed' handle")
+ end)
+ ok(string.find(emsg, "^IllegalState"),
+ string.format("IllegalState error (%s)", emsg))
+
+ local enlarge = lz.inflate()
+end
+
+function test_checksum()
+ for _, factory in pairs{lz.crc32, lz.adler32} do
+ local csum = factory()("one two")
+
+ -- Multiple calls:
+ local compute = factory()
+ compute("one")
+ assert(csum == compute(" two"))
+
+ -- Multiple compute_checksums joined:
+ local compute1, compute2 = factory(), factory()
+ compute1("one")
+ compute2(" two")
+ assert(csum == compute1(compute2))
+ end
+end
+
+function test_version()
+ local major, minor, patch = lz.version()
+ ok(1 == major, "major version 1 == " .. major);
+ ok(type(minor) == "number", "minor version is number (" .. minor .. ")")
+ ok(type(patch) == "number", "patch version is number (" .. patch .. ")")
+end
+
+main()
diff --git a/3rdparty/lua-zlib/tom_macwright.gz b/3rdparty/lua-zlib/tom_macwright.gz
new file mode 100644
index 00000000000..bb9060b2535
--- /dev/null
+++ b/3rdparty/lua-zlib/tom_macwright.gz
@@ -0,0 +1,4 @@
+xŽ[
+Â0EýÎ*f–Igò(ˆèüüN“éL#mÄí[\‚—‡scÉy®Ðê*=&òNŒïƒ:'–…I˜1Yi[ØpŒ£z…U–
+Žóä¼íR?0J§îzãQê­ñÖ%I…wÊ
+÷’áâcÇ©Â)‡øù͢ÃülbÉgФÉ!·¤áˆŒ¨vºŸ¬ò§®®K‚½¾ ”E¶F}šÊHÙ \ No newline at end of file
diff --git a/3rdparty/lua-zlib/tom_macwright.out b/3rdparty/lua-zlib/tom_macwright.out
new file mode 100644
index 00000000000..ca88bcb6c2d
--- /dev/null
+++ b/3rdparty/lua-zlib/tom_macwright.out
Binary files differ
diff --git a/3rdparty/lua-zlib/zlib.def b/3rdparty/lua-zlib/zlib.def
new file mode 100644
index 00000000000..d6c5a916b64
--- /dev/null
+++ b/3rdparty/lua-zlib/zlib.def
@@ -0,0 +1,2 @@
+EXPORTS
+luaopen_zlib
diff --git a/3rdparty/luafilesystem/.travis.yml b/3rdparty/luafilesystem/.travis.yml
new file mode 100644
index 00000000000..67b5812e09e
--- /dev/null
+++ b/3rdparty/luafilesystem/.travis.yml
@@ -0,0 +1,33 @@
+language: c
+
+env:
+ global:
+ - LUAROCKS=2.2.0-rc1
+ matrix:
+ - LUA=lua5.1
+ - LUA=lua5.2
+ - LUA=lua5.3
+ - LUA=luajit
+
+branches:
+ only:
+ - master
+
+before_install:
+ - bash .travis/setup_lua.sh
+ - sudo pip install cpp-coveralls
+
+install:
+ - sudo luarocks make rockspecs/luafilesystem-cvs-3.rockspec CFLAGS="-O2 -fPIC -ftest-coverage -fprofile-arcs" LIBFLAG="-shared --coverage"
+
+script:
+ - cd tests
+ - sudo lua test.lua
+
+after_success:
+ - coveralls -b .. -r .. -E usr
+
+notifications:
+ email:
+ on_success: change
+ on_failure: always
diff --git a/3rdparty/luafilesystem/.travis/platform.sh b/3rdparty/luafilesystem/.travis/platform.sh
new file mode 100644
index 00000000000..4a3af0d487e
--- /dev/null
+++ b/3rdparty/luafilesystem/.travis/platform.sh
@@ -0,0 +1,15 @@
+if [ -z "$PLATFORM" ]; then
+ PLATFORM=$TRAVIS_OS_NAME;
+fi
+
+if [ "$PLATFORM" == "osx" ]; then
+ PLATFORM="macosx";
+fi
+
+if [ -z "$PLATFORM" ]; then
+ if [ "$(uname)" == "Linux" ]; then
+ PLATFORM="linux";
+ else
+ PLATFORM="macosx";
+ fi;
+fi
diff --git a/3rdparty/luafilesystem/.travis/setup_lua.sh b/3rdparty/luafilesystem/.travis/setup_lua.sh
new file mode 100644
index 00000000000..373e24d979b
--- /dev/null
+++ b/3rdparty/luafilesystem/.travis/setup_lua.sh
@@ -0,0 +1,101 @@
+#! /bin/bash
+
+# A script for setting up environment for travis-ci testing.
+# Sets up Lua and Luarocks.
+# LUA must be "lua5.1", "lua5.2" or "luajit".
+# luajit2.0 - master v2.0
+# luajit2.1 - master v2.1
+
+LUAJIT_BASE="LuaJIT-2.0.3"
+
+source .travis/platform.sh
+
+LUAJIT="no"
+
+if [ "$PLATFORM" == "macosx" ]; then
+ if [ "$LUA" == "luajit" ]; then
+ LUAJIT="yes";
+ fi
+ if [ "$LUA" == "luajit2.0" ]; then
+ LUAJIT="yes";
+ fi
+ if [ "$LUA" == "luajit2.1" ]; then
+ LUAJIT="yes";
+ fi;
+elif [ "$(expr substr $LUA 1 6)" == "luajit" ]; then
+ LUAJIT="yes";
+fi
+
+if [ "$LUAJIT" == "yes" ]; then
+
+ if [ "$LUA" == "luajit" ]; then
+ curl http://luajit.org/download/$LUAJIT_BASE.tar.gz | tar xz;
+ else
+ git clone http://luajit.org/git/luajit-2.0.git $LUAJIT_BASE;
+ fi
+
+ cd $LUAJIT_BASE
+
+ if [ "$LUA" == "luajit2.1" ]; then
+ git checkout v2.1;
+ fi
+
+ make && sudo make install
+
+ if [ "$LUA" == "luajit2.1" ]; then
+ sudo ln -s /usr/local/bin/luajit-2.1.0-alpha /usr/local/bin/luajit
+ sudo ln -s /usr/local/bin/luajit /usr/local/bin/lua;
+ else
+ sudo ln -s /usr/local/bin/luajit /usr/local/bin/lua;
+ fi;
+
+else
+ if [ "$LUA" == "lua5.1" ]; then
+ curl http://www.lua.org/ftp/lua-5.1.5.tar.gz | tar xz
+ cd lua-5.1.5;
+ elif [ "$LUA" == "lua5.2" ]; then
+ curl http://www.lua.org/ftp/lua-5.2.3.tar.gz | tar xz
+ cd lua-5.2.3;
+ elif [ "$LUA" == "lua5.3" ]; then
+ curl http://www.lua.org/work/lua-5.3.0-beta.tar.gz | tar xz
+ cd lua-5.3.0-beta;
+ fi
+ sudo make $PLATFORM install;
+fi
+
+cd $TRAVIS_BUILD_DIR;
+
+LUAROCKS_BASE=luarocks-$LUAROCKS
+
+# curl http://luarocks.org/releases/$LUAROCKS_BASE.tar.gz | tar xz
+
+git clone https://github.com/keplerproject/luarocks.git $LUAROCKS_BASE
+cd $LUAROCKS_BASE
+
+git checkout v$LUAROCKS
+
+if [ "$LUA" == "luajit" ]; then
+ ./configure --lua-suffix=jit --with-lua-include=/usr/local/include/luajit-2.0;
+elif [ "$LUA" == "luajit2.0" ]; then
+ ./configure --lua-suffix=jit --with-lua-include=/usr/local/include/luajit-2.0;
+elif [ "$LUA" == "luajit2.1" ]; then
+ ./configure --lua-suffix=jit --with-lua-include=/usr/local/include/luajit-2.1;
+else
+ ./configure;
+fi
+
+make build && sudo make install
+
+cd $TRAVIS_BUILD_DIR
+
+rm -rf $LUAROCKS_BASE
+
+if [ "$LUAJIT" == "yes" ]; then
+ rm -rf $LUAJIT_BASE;
+elif [ "$LUA" == "lua5.1" ]; then
+ rm -rf lua-5.1.5;
+elif [ "$LUA" == "lua5.2" ]; then
+ rm -rf lua-5.2.3;
+elif [ "$LUA" == "lua5.3" ]; then
+ rm -rf lua-5.3.0-beta;
+fi
diff --git a/3rdparty/luafilesystem/LICENSE b/3rdparty/luafilesystem/LICENSE
new file mode 100644
index 00000000000..8475345a64e
--- /dev/null
+++ b/3rdparty/luafilesystem/LICENSE
@@ -0,0 +1,21 @@
+Copyright © 2003-2014 Kepler Project.
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+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 AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/3rdparty/luafilesystem/Makefile b/3rdparty/luafilesystem/Makefile
new file mode 100644
index 00000000000..b834a4d51ab
--- /dev/null
+++ b/3rdparty/luafilesystem/Makefile
@@ -0,0 +1,25 @@
+# $Id: Makefile,v 1.36 2009/09/21 17:02:44 mascarenhas Exp $
+
+T= lfs
+
+CONFIG= ./config
+
+include $(CONFIG)
+
+SRCS= src/$T.c
+OBJS= src/$T.o
+
+lib: src/lfs.so
+
+src/lfs.so: $(OBJS)
+ MACOSX_DEPLOYMENT_TARGET="10.3"; export MACOSX_DEPLOYMENT_TARGET; $(CC) $(CFLAGS) $(LIB_OPTION) -o src/lfs.so $(OBJS)
+
+test: lib
+ LUA_CPATH=./src/?.so lua tests/test.lua
+
+install:
+ mkdir -p $(LUA_LIBDIR)
+ cp src/lfs.so $(LUA_LIBDIR)
+
+clean:
+ rm -f src/lfs.so $(OBJS)
diff --git a/3rdparty/luafilesystem/Makefile.win b/3rdparty/luafilesystem/Makefile.win
new file mode 100644
index 00000000000..65cab812408
--- /dev/null
+++ b/3rdparty/luafilesystem/Makefile.win
@@ -0,0 +1,25 @@
+# $Id: Makefile.win,v 1.11 2008/05/07 19:06:37 carregal Exp $
+
+T= lfs
+
+include config.win
+
+SRCS= src\$T.c
+OBJS= src\$T.obj
+
+lib: src\lfs.dll
+
+.c.obj:
+ $(CC) /c /Fo$@ $(CFLAGS) $<
+
+src\lfs.dll: $(OBJS)
+ link /dll /def:src\$T.def /out:src\lfs.dll $(OBJS) "$(LUA_LIB)"
+ IF EXIST src\lfs.dll.manifest mt -manifest src\lfs.dll.manifest -outputresource:src\lfs.dll;2
+
+install: src\lfs.dll
+ IF NOT EXIST "$(LUA_LIBDIR)" mkdir "$(LUA_LIBDIR)"
+ copy src\lfs.dll "$(LUA_LIBDIR)"
+
+clean:
+ del src\lfs.dll $(OBJS) src\$T.lib src\$T.exp
+ IF EXIST src\lfs.dll.manifest del src\lfs.dll.manifest \ No newline at end of file
diff --git a/3rdparty/luafilesystem/README b/3rdparty/luafilesystem/README
new file mode 100644
index 00000000000..9d37a4e2513
--- /dev/null
+++ b/3rdparty/luafilesystem/README
@@ -0,0 +1,23 @@
+LuaFileSystem - File System Library for Lua
+Copyright 2003-2015 Kepler Project
+
+http://keplerproject.github.io/luafilesystem
+
+Description
+-----------
+LuaFileSystem is a Lua library developed to complement the set of functions
+related to file systems offered by the standard Lua distribution.
+
+LuaFileSystem offers a portable way to access the underlying directory structure and file attributes.
+LuaFileSystem is free software and uses the same license as Lua 5.1
+
+LuaRocks Installation
+---------------------
+
+```
+luarocks install luafilesystem
+```
+
+Documentation
+-------------
+Please check the documentation at doc/us/ for more information.
diff --git a/3rdparty/luafilesystem/config b/3rdparty/luafilesystem/config
new file mode 100644
index 00000000000..cfd4c6a6d3e
--- /dev/null
+++ b/3rdparty/luafilesystem/config
@@ -0,0 +1,24 @@
+# Installation directories
+
+# Default installation prefix
+PREFIX=/usr/local
+
+# System's libraries directory (where binary libraries are installed)
+LUA_LIBDIR= $(PREFIX)/lib/lua/5.1
+
+# Lua includes directory
+LUA_INC= $(PREFIX)/include
+
+# OS dependent
+LIB_OPTION= -shared #for Linux
+#LIB_OPTION= -bundle -undefined dynamic_lookup #for MacOS X
+
+LIBNAME= $T.so.$V
+
+# Compilation directives
+WARN= -O2 -Wall -fPIC -W -Waggregate-return -Wcast-align -Wmissing-prototypes -Wnested-externs -Wshadow -Wwrite-strings -pedantic
+INCS= -I$(LUA_INC)
+CFLAGS= $(WARN) $(INCS)
+CC= gcc
+
+# $Id: config,v 1.21 2007/10/27 22:42:32 carregal Exp $
diff --git a/3rdparty/luafilesystem/config.win b/3rdparty/luafilesystem/config.win
new file mode 100644
index 00000000000..50e81f64206
--- /dev/null
+++ b/3rdparty/luafilesystem/config.win
@@ -0,0 +1,19 @@
+# Installation directories
+# System's libraries directory (where binary libraries are installed)
+LUA_LIBDIR= "c:\lua5.1"
+
+# Lua includes directory
+LUA_INC= "c:\lua5.1\include"
+
+# Lua library
+LUA_LIB= "c:\lua5.1\lua5.1.lib"
+
+LIBNAME= $T.dll
+
+# Compilation directives
+WARN= /O2
+INCS= /I$(LUA_INC)
+CFLAGS= /MD $(WARN) $(INCS)
+CC= cl
+
+# $Id: config.win,v 1.7 2008/03/25 17:39:29 mascarenhas Exp $
diff --git a/3rdparty/luafilesystem/doc/us/doc.css b/3rdparty/luafilesystem/doc/us/doc.css
new file mode 100644
index 00000000000..e816a7e2c63
--- /dev/null
+++ b/3rdparty/luafilesystem/doc/us/doc.css
@@ -0,0 +1,212 @@
+body {
+ margin-left: 1em;
+ margin-right: 1em;
+ font-family: arial, helvetica, geneva, sans-serif;
+ background-color:#ffffff; margin:0px;
+}
+
+code {
+ font-family: "Andale Mono", monospace;
+}
+
+tt {
+ font-family: "Andale Mono", monospace;
+}
+
+body, td, th { font-size: 11pt; }
+
+h1, h2, h3, h4 { margin-left: 0em; }
+
+textarea, pre, tt { font-size:10pt; }
+body, td, th { color:#000000; }
+small { font-size:0.85em; }
+h1 { font-size:1.5em; }
+h2 { font-size:1.25em; }
+h3 { font-size:1.15em; }
+h4 { font-size:1.06em; }
+
+a:link { font-weight:bold; color: #004080; text-decoration: none; }
+a:visited { font-weight:bold; color: #006699; text-decoration: none; }
+a:link:hover { text-decoration:underline; }
+hr { color:#cccccc }
+img { border-width: 0px; }
+
+h3 { padding-top: 1em; }
+
+p { margin-left: 1em; }
+
+p.name {
+ font-family: "Andale Mono", monospace;
+ padding-top: 1em;
+ margin-left: 0em;
+}
+
+blockquote { margin-left: 3em; }
+
+.example {
+ background-color: rgb(245, 245, 245);
+ border-top-width: 1px;
+ border-right-width: 1px;
+ border-bottom-width: 1px;
+ border-left-width: 1px;
+ border-top-style: solid;
+ border-right-style: solid;
+ border-bottom-style: solid;
+ border-left-style: solid;
+ border-top-color: silver;
+ border-right-color: silver;
+ border-bottom-color: silver;
+ border-left-color: silver;
+ padding: 1em;
+ margin-left: 1em;
+ margin-right: 1em;
+ font-family: "Andale Mono", monospace;
+ font-size: smaller;
+}
+
+hr {
+ margin-left: 0em;
+ background: #00007f;
+ border: 0px;
+ height: 1px;
+}
+
+ul { list-style-type: disc; }
+
+table.index { border: 1px #00007f; }
+table.index td { text-align: left; vertical-align: top; }
+table.index ul { padding-top: 0em; margin-top: 0em; }
+
+table {
+ border: 1px solid black;
+ border-collapse: collapse;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+th {
+ border: 1px solid black;
+ padding: 0.5em;
+}
+
+td {
+ border: 1px solid black;
+ padding: 0.5em;
+}
+div.header, div.footer { margin-left: 0em; }
+
+#container {
+ margin-left: 1em;
+ margin-right: 1em;
+ background-color: #f0f0f0;
+}
+
+#product {
+ text-align: center;
+ border-bottom: 1px solid #cccccc;
+ background-color: #ffffff;
+}
+
+#product big {
+ font-size: 2em;
+}
+
+#product_logo {
+}
+
+#product_name {
+}
+
+#product_description {
+}
+
+#main {
+ background-color: #f0f0f0;
+ border-left: 2px solid #cccccc;
+}
+
+#navigation {
+ float: left;
+ width: 12em;
+ margin: 0;
+ vertical-align: top;
+ background-color: #f0f0f0;
+ overflow:visible;
+}
+
+#navigation h1 {
+ background-color:#e7e7e7;
+ font-size:1.1em;
+ color:#000000;
+ text-align:left;
+ margin:0px;
+ padding:0.2em;
+ border-top:1px solid #dddddd;
+ border-bottom:1px solid #dddddd;
+}
+
+#navigation ul {
+ font-size:1em;
+ list-style-type: none;
+ padding: 0;
+ margin: 1px;
+}
+
+#navigation li {
+ text-indent: -1em;
+ margin: 0em 0em 0em 0.5em;
+ display: block;
+ padding: 3px 0px 0px 12px;
+}
+
+#navigation li li a {
+ padding: 0px 3px 0px -1em;
+}
+
+#content {
+ margin-left: 12em;
+ padding: 1em;
+ border-left: 2px solid #cccccc;
+ border-right: 2px solid #cccccc;
+ background-color: #ffffff;
+}
+
+#about {
+ clear: both;
+ margin: 0;
+ padding: 5px;
+ border-top: 2px solid #cccccc;
+ background-color: #ffffff;
+}
+
+@media print {
+ body {
+ font: 10pt "Times New Roman", "TimeNR", Times, serif;
+ }
+ a {
+ font-weight:bold; color: #004080; text-decoration: underline;
+ }
+ #main {
+ background-color: #ffffff; border-left: 0px;
+ }
+ #container {
+ margin-left: 2%; margin-right: 2%; background-color: #ffffff;
+ }
+ #content {
+ margin-left: 0px; padding: 1em; border-left: 0px; border-right: 0px; background-color: #ffffff;
+ }
+ #navigation {
+ display: none;
+ }
+ #product_logo {
+ display: none;
+ }
+ #about img {
+ display: none;
+ }
+ .example {
+ font-family: "Andale Mono", monospace;
+ font-size: 8pt;
+ page-break-inside: avoid;
+ }
+}
diff --git a/3rdparty/luafilesystem/doc/us/examples.html b/3rdparty/luafilesystem/doc/us/examples.html
new file mode 100644
index 00000000000..2c1644cb8a0
--- /dev/null
+++ b/3rdparty/luafilesystem/doc/us/examples.html
@@ -0,0 +1,103 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>LuaFileSystem</title>
+ <link rel="stylesheet" href="doc.css" type="text/css"/>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+</head>
+
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo">
+ <a href="http://www.keplerproject.org">
+ <img alt="LuaFileSystem" src="luafilesystem.png"/>
+ </a>
+ </div>
+ <div id="product_name"><big><strong>LuaFileSystem</strong></big></div>
+ <div id="product_description">File System Library for the Lua Programming Language</div>
+</div> <!-- id="product" -->
+
+<div id="main">
+
+<div id="navigation">
+<h1>LuaFileSystem</h1>
+ <ul>
+ <li><a href="index.html">Home</a>
+ <ul>
+ <li><a href="index.html#overview">Overview</a></li>
+ <li><a href="index.html#status">Status</a></li>
+ <li><a href="index.html#download">Download</a></li>
+ <li><a href="index.html#history">History</a></li>
+ <li><a href="index.html#credits">Credits</a></li>
+ <li><a href="index.html#contact">Contact us</a></li>
+ </ul>
+ </li>
+ <li><a href="manual.html">Manual</a>
+ <ul>
+ <li><a href="manual.html#introduction">Introduction</a></li>
+ <li><a href="manual.html#building">Building</a></li>
+ <li><a href="manual.html#installation">Installation</a></li>
+ <li><a href="manual.html#reference">Reference</a></li>
+ </ul>
+ </li>
+ <li><strong>Examples</strong></li>
+ <li><a href="https://github.com/keplerproject/luafilesystem">Project</a>
+ <ul>
+ <li><a href="https://github.com/keplerproject/luafilesystem/issues">Bug Tracker</a></li>
+ <li><a href="https://github.com/keplerproject/luafilesystem">Git</a></li>
+ </ul>
+ </li>
+ <li><a href="license.html">License</a></li>
+ </ul>
+</div> <!-- id="navigation" -->
+
+<div id="content">
+
+<h2><a name="example"></a>Examples</h2>
+
+<h3>Directory iterator</h3>
+
+<p>The following example iterates over a directory and recursively lists the
+attributes for each file inside it.</p>
+
+<pre class="example">
+local lfs = require"lfs"
+
+function attrdir (path)
+ for file in lfs.dir(path) do
+ if file ~= "." and file ~= ".." then
+ local f = path..'/'..file
+ print ("\t "..f)
+ local attr = lfs.attributes (f)
+ assert (type(attr) == "table")
+ if attr.mode == "directory" then
+ attrdir (f)
+ else
+ for name, value in pairs(attr) do
+ print (name, value)
+ end
+ end
+ end
+ end
+end
+
+attrdir (".")
+</pre>
+
+</div> <!-- id="content" -->
+
+</div> <!-- id="main" -->
+
+<div id="about">
+ <p><a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.0!</a></p>
+ <p><small>$Id: examples.html,v 1.8 2007/12/14 15:28:04 carregal Exp $</small></p>
+</div> <!-- id="about" -->
+
+</div> <!-- id="container" -->
+
+</body>
+</html>
diff --git a/3rdparty/luafilesystem/doc/us/index.html b/3rdparty/luafilesystem/doc/us/index.html
new file mode 100644
index 00000000000..2bb7f5d2cbb
--- /dev/null
+++ b/3rdparty/luafilesystem/doc/us/index.html
@@ -0,0 +1,218 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>LuaFileSystem</title>
+ <link rel="stylesheet" href="doc.css" type="text/css"/>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+</head>
+
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo">
+ <a href="http://www.keplerproject.org">
+ <img alt="LuaFileSystem" src="luafilesystem.png"/>
+ </a>
+ </div>
+ <div id="product_name"><big><strong>LuaFileSystem</strong></big></div>
+ <div id="product_description">File System Library for the Lua Programming Language</div>
+</div> <!-- id="product" -->
+
+<div id="main">
+
+<div id="navigation">
+<h1>LuaFileSystem</h1>
+ <ul>
+ <li><strong>Home</strong>
+ <ul>
+ <li><a href="index.html#overview">Overview</a></li>
+ <li><a href="index.html#status">Status</a></li>
+ <li><a href="index.html#download">Download</a></li>
+ <li><a href="index.html#history">History</a></li>
+ <li><a href="index.html#credits">Credits</a></li>
+ <li><a href="index.html#contact">Contact us</a></li>
+ </ul>
+ </li>
+ <li><a href="manual.html">Manual</a>
+ <ul>
+ <li><a href="manual.html#introduction">Introduction</a></li>
+ <li><a href="manual.html#building">Building</a></li>
+ <li><a href="manual.html#installation">Installation</a></li>
+ <li><a href="manual.html#reference">Reference</a></li>
+ </ul>
+ </li>
+ <li><a href="examples.html">Examples</a></li>
+ <li><a href="https://github.com/keplerproject/luafilesystem">Project</a>
+ <ul>
+ <li><a href="https://github.com/keplerproject/luafilesystem/issues">Bug Tracker</a></li>
+ <li><a href="https://github.com/keplerproject/luafilesystem">Git</a></li>
+ </ul>
+ </li>
+ <li><a href="license.html">License</a></li>
+ </ul>
+</div> <!-- id="navigation" -->
+
+<div id="content">
+
+<h2><a name="overview"></a>Overview</h2>
+
+<p>LuaFileSystem is a <a href="http://www.lua.org">Lua</a> library
+developed to complement the set of functions related to file
+systems offered by the standard Lua distribution.</p>
+
+<p>LuaFileSystem offers a portable way to access
+the underlying directory structure and file attributes.</p>
+
+<p>LuaFileSystem is free software and uses the same
+<a href="license.html">license</a> as Lua 5.1.</p>
+
+<h2><a name="status"></a>Status</h2>
+
+<p>Current version is 1.6.3. It works with Lua 5.1, 5.2 and 5.3.</p>
+
+<h2><a name="download"></a>Download</h2>
+
+<p>LuaFileSystem source can be downloaded from its
+<a href="http://github.com/keplerproject/luafilesystem">Github</a>
+page.</p>
+
+<h2><a name="history"></a>History</h2>
+
+<dl class="history">
+ <dt><strong>Version 1.6.3</strong> [15/Jan/2015]</dt>
+ <dd><ul>
+ <li>Lua 5.3 support.</li>
+ <li>Assorted bugfixes.</li>
+ </ul></dd>
+
+ <dt><strong>Version 1.6.2</strong> [??/Oct/2012]</dt>
+ <dd><ul>
+ <li>Full Lua 5.2 compatibility (with Lua 5.1 fallbacks)</li>
+ </ul></dd>
+
+ <dt><strong>Version 1.6.1</strong> [01/Oct/2012]</dt>
+ <dd><ul>
+ <li>fix build for Lua 5.2</li>
+ </ul></dd>
+
+ <dt><strong>Version 1.6.0</strong> [26/Sep/2012]</dt>
+ <dd><ul>
+ <li>getcwd fix for Android</li>
+ <li>support for Lua 5.2</li>
+ <li>add lfs.link</li>
+ <li>other bug fixes</li>
+ </ul></dd>
+
+ <dt><strong>Version 1.5.0</strong> [20/Oct/2009]</dt>
+ <dd><ul>
+ <li>Added explicit next and close methods to second return value of lfs.dir
+(the directory object), for explicit iteration or explicit closing.</li>
+ <li>Added directory locking via lfs.lock_dir function (see the <a href="manual.html">manual</a>).</li>
+ </ul></dd>
+ <dt><strong>Version 1.4.2</strong> [03/Feb/2009]</dt>
+ <dd>
+ <ul>
+ <li>fixed bug [<a href="http://luaforge.net/tracker/?func=detail&amp;group_id=66&amp;aid=13198&amp;atid=356">#13198</a>]
+ lfs.attributes(filename, 'size') overflow on files > 2 Gb again (bug report and patch by KUBO Takehiro).</li>
+ <li>fixed bug [<a href="http://luaforge.net/tracker/?group_id=66&amp;atid=356&amp;func=detail&amp;aid=39794">#39794</a>]
+ Compile error on Solaris 10 (bug report and patch by Aaron B).</li>
+ <li>fixed compilation problems with Borland C.</li>
+ </ul>
+ </dd>
+
+ <dt><strong>Version 1.4.1</strong> [07/May/2008]</dt>
+ <dd>
+ <ul>
+ <li>documentation review</li>
+ <li>fixed Windows compilation issues</li>
+ <li>fixed bug in the Windows tests (patch by Shmuel Zeigerman)</li>
+ <li>fixed bug [<a href="http://luaforge.net/tracker/?func=detail&amp;group_id=66&amp;aid=2185&amp;atid=356">#2185</a>]
+ <code>lfs.attributes(filename, 'size')</code> overflow on files > 2 Gb
+ </li>
+ </ul>
+ </dd>
+
+ <dt><strong>Version 1.4.0</strong> [13/Feb/2008]</dt>
+ <dd>
+ <ul>
+ <li>added function
+ <a href="manual.html#setmode"><code>lfs.setmode</code></a>
+ (works only in Windows systems).</li>
+ <li><a href="manual.html#attributes"><code>lfs.attributes</code></a>
+ raises an error if attribute does not exist</li>
+ </ul>
+ </dd>
+
+ <dt><strong>Version 1.3.0</strong> [26/Oct/2007]</dt>
+ <dd>
+ <ul>
+ <li>added function
+ <a href="manual.html#symlinkattributes"><code>lfs.symlinkattributes</code></a>
+ (works only in non Windows systems).</li>
+ </ul>
+ </dd>
+
+ <dt><strong>Version 1.2.1</strong> [08/May/2007]</dt>
+ <dd>
+ <ul>
+ <li>compatible only with Lua 5.1 (Lua 5.0 support was dropped)</li>
+ </ul>
+ </dd>
+
+ <dt><strong>Version 1.2</strong> [15/Mar/2006]</dt>
+ <dd>
+ <ul>
+ <li>added optional argument to
+ <a href="manual.html#attributes"><code>lfs.attributes</code></a></li>
+ <li>added function
+ <a href="manual.html#rmdir"><code>lfs.rmdir</code></a></li>
+ <li>bug correction on <a href="manual.html#dir"><code>lfs.dir</code></a></li>
+ </ul>
+ </dd>
+
+ <dt><strong>Version 1.1</strong> [30/May/2005]</dt>
+ <dd>
+ <ul>
+ <li>added function <a href="manual.html#touch"><code>lfs.touch</code></a>.</li>
+ </ul>
+ </dd>
+
+ <dt><strong>Version 1.0</strong> [21/Jan/2005]</dt>
+ <dd />
+
+ <dt><strong>Version 1.0 Beta</strong> [10/Nov/2004]</dt>
+ <dd />
+</dl>
+
+<h2><a name="credits"></a>Credits</h2>
+
+<p>LuaFileSystem was designed by Roberto Ierusalimschy,
+Andr&eacute; Carregal and Tom&aacute;s Guisasola as part of the
+<a href="http://www.keplerproject.org">Kepler Project</a>,
+which holds its copyright. LuaFileSystem is currently maintained by F&aacute;bio Mascarenhas.</p>
+
+<h2><a name="contact"></a>Contact us</h2>
+
+<p>For more information please
+<a href="mailto:info-NO-SPAM-THANKS@keplerproject.org">contact us</a>.
+Comments are welcome!</p>
+
+<p>You can also reach other Kepler developers and users on the Kepler Project
+<a href="http://luaforge.net/mail/?group_id=104">mailing list</a>.</p>
+
+</div> <!-- id="content" -->
+
+</div> <!-- id="main" -->
+
+<div id="about">
+ <p><a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.0!</a></p>
+ <p><small>$Id: index.html,v 1.44 2009/02/04 21:21:33 carregal Exp $</small></p>
+</div> <!-- id="about" -->
+
+</div> <!-- id="container" -->
+
+</body>
+</html>
diff --git a/3rdparty/luafilesystem/doc/us/license.html b/3rdparty/luafilesystem/doc/us/license.html
new file mode 100644
index 00000000000..30033817229
--- /dev/null
+++ b/3rdparty/luafilesystem/doc/us/license.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>LuaFileSystem</title>
+ <link rel="stylesheet" href="doc.css" type="text/css"/>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+</head>
+
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo">
+ <a href="http://www.keplerproject.org">
+ <img alt="LuaFileSystem" src="luafilesystem.png"/>
+ </a>
+ </div>
+ <div id="product_name"><big><strong>LuaFileSystem</strong></big></div>
+ <div id="product_description">File System Library for the Lua Programming Language</div>
+</div> <!-- id="product" -->
+
+<div id="main">
+
+<div id="navigation">
+<h1>LuaFileSystem</h1>
+ <ul>
+ <li><a href="index.html">Home</a>
+ <ul>
+ <li><a href="index.html#overview">Overview</a></li>
+ <li><a href="index.html#status">Status</a></li>
+ <li><a href="index.html#download">Download</a></li>
+ <li><a href="index.html#history">History</a></li>
+ <li><a href="index.html#credits">Credits</a></li>
+ <li><a href="index.html#contact">Contact us</a></li>
+ </ul>
+ </li>
+ <li><a href="manual.html">Manual</a>
+ <ul>
+ <li><a href="manual.html#introduction">Introduction</a></li>
+ <li><a href="manual.html#building">Building</a></li>
+ <li><a href="manual.html#installation">Installation</a></li>
+ <li><a href="manual.html#reference">Reference</a></li>
+ </ul>
+ </li>
+ <li><a href="examples.html">Examples</a></li>
+ <li><a href="https://github.com/keplerproject/luafilesystem">Project</a>
+ <ul>
+ <li><a href="https://github.com/keplerproject/luafilesystem/issues/">Bug Tracker</a></li>
+ <li><a href="https://github.com/keplerproject/luafilesystem">Git</a></li>
+ </ul>
+ </li>
+ <li><strong>License</strong></li>
+ </ul>
+</div> <!-- id="navigation" -->
+
+<div id="content">
+
+<h1>License</h1>
+
+<p>
+LuaFileSystem is free software: it can be used for both academic
+and commercial purposes at absolutely no cost. There are no
+royalties or GNU-like "copyleft" restrictions. LuaFileSystem
+qualifies as
+<a href="http://www.opensource.org/docs/definition.html">Open Source</a>
+software.
+Its licenses are compatible with
+<a href="http://www.gnu.org/licenses/gpl.html">GPL</a>.
+LuaFileSystem is not in the public domain and the
+<a href="http://www.keplerproject.org">Kepler Project</a>
+keep its copyright.
+The legal details are below.
+</p>
+
+<p>The spirit of the license is that you are free to use
+LuaFileSystem for any purpose at no cost without having to ask us.
+The only requirement is that if you do use LuaFileSystem, then you
+should give us credit by including the appropriate copyright notice
+somewhere in your product or its documentation.</p>
+
+<p>The LuaFileSystem library is designed and implemented by Roberto
+Ierusalimschy, Andr&eacute; Carregal and Tom&aacute;s Guisasola.
+The implementation is not derived from licensed software.</p>
+
+<hr/>
+<p>Copyright &copy; 2003 Kepler Project.</p>
+
+<p>Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:</p>
+
+<p>The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.</p>
+
+<p>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 AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.</p>
+
+</div> <!-- id="content" -->
+
+</div> <!-- id="main" -->
+
+<div id="about">
+ <p><a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.0!</a></p>
+ <p><small>$Id: license.html,v 1.13 2008/02/11 22:42:21 carregal Exp $</small></p>
+</div><!-- id="about" -->
+
+</div><!-- id="container" -->
+
+</body>
+</html>
diff --git a/3rdparty/luafilesystem/doc/us/luafilesystem.png b/3rdparty/luafilesystem/doc/us/luafilesystem.png
new file mode 100644
index 00000000000..e1dd8c65b52
--- /dev/null
+++ b/3rdparty/luafilesystem/doc/us/luafilesystem.png
Binary files differ
diff --git a/3rdparty/luafilesystem/doc/us/manual.html b/3rdparty/luafilesystem/doc/us/manual.html
new file mode 100644
index 00000000000..33c1cbea573
--- /dev/null
+++ b/3rdparty/luafilesystem/doc/us/manual.html
@@ -0,0 +1,280 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>LuaFileSystem</title>
+ <link rel="stylesheet" href="doc.css" type="text/css"/>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+</head>
+
+<body>
+
+<div id="container">
+
+<div id="product">
+ <div id="product_logo">
+ <a href="http://www.keplerproject.org"><img alt="LuaFileSystem" src="luafilesystem.png"/></a>
+ </div>
+ <div id="product_name"><big><strong>LuaFileSystem</strong></big></div>
+ <div id="product_description">File System Library for the Lua Programming Language</div>
+</div> <!-- id="product" -->
+
+<div id="main">
+
+<div id="navigation">
+<h1>LuaFileSystem</h1>
+ <ul>
+ <li><a href="index.html">Home</a>
+ <ul>
+ <li><a href="index.html#overview">Overview</a></li>
+ <li><a href="index.html#status">Status</a></li>
+ <li><a href="index.html#download">Download</a></li>
+ <li><a href="index.html#history">History</a></li>
+ <li><a href="index.html#credits">Credits</a></li>
+ <li><a href="index.html#contact">Contact us</a></li>
+ </ul>
+ </li>
+ <li><strong>Manual</strong>
+ <ul>
+ <li><a href="manual.html#introduction">Introduction</a></li>
+ <li><a href="manual.html#building">Building</a></li>
+ <li><a href="manual.html#installation">Installation</a></li>
+ <li><a href="manual.html#reference">Reference</a></li>
+ </ul>
+ </li>
+ <li><a href="examples.html">Examples</a></li>
+ <li><a href="https://github.com/keplerproject/luafilesystem">Project</a>
+ <ul>
+ <li><a href="https://github.com/keplerproject/luafilesystem/issues">Bug Tracker</a></li>
+ <li><a href="https://github.com/keplerproject/luafilesystem">Git</a></li>
+ </ul>
+ </li>
+ <li><a href="license.html">License</a></li>
+ </ul>
+</div> <!-- id="navigation" -->
+
+<div id="content">
+
+<h2><a name="introduction"></a>Introduction</h2>
+
+<p>LuaFileSystem is a <a href="http://www.lua.org">Lua</a> library
+developed to complement the set of functions related to file
+systems offered by the standard Lua distribution.</p>
+
+<p>LuaFileSystem offers a portable way to access
+the underlying directory structure and file attributes.</p>
+
+<h2><a name="building"></a>Building</h2>
+
+<p>
+LuaFileSystem should be built with Lua 5.1 so the language library
+and header files for the target version must be installed properly.
+</p>
+
+<p>
+LuaFileSystem offers a Makefile and a separate configuration file,
+<code>config</code>,
+which should be edited to suit your installation before running
+<code>make</code>.
+The file has some definitions like paths to the external libraries,
+compiler options and the like.
+</p>
+
+<p>On Windows, the C runtime used to compile LuaFileSystem must be the same
+runtime that Lua uses, or some LuaFileSystem functions will not work.</p>
+
+<h2><a name="installation"></a>Installation</h2>
+
+<p>The easiest way to install LuaFileSystem is to use LuaRocks:</p>
+
+<pre class="example">
+luarocks install luafilesystem
+</pre>
+
+<p>If you prefer to install LuaFileSystem manually, the compiled binary should be copied to a directory in your
+<a href="http://www.lua.org/manual/5.1/manual.html#pdf-package.cpath">C path</a>.</p>
+
+<h2><a name="reference"></a>Reference</h2>
+
+<p>
+LuaFileSystem offers the following functions:
+</p>
+
+<dl class="reference">
+ <dt><a name="attributes"></a><strong><code>lfs.attributes (filepath [, aname])</code></strong></dt>
+ <dd>Returns a table with the file attributes corresponding to
+ <code>filepath</code> (or <code>nil</code> followed by an error message
+ in case of error).
+ If the second optional argument is given, then only the value of the
+ named attribute is returned (this use is equivalent to
+ <code>lfs.attributes(filepath).aname</code>, but the table is not created
+ and only one attribute is retrieved from the O.S.).
+ The attributes are described as follows;
+ attribute <code>mode</code> is a string, all the others are numbers,
+ and the time related attributes use the same time reference of
+ <a href="http://www.lua.org/manual/5.1/manual.html#pdf-os.time"><code>os.time</code></a>:
+ <dl>
+ <dt><strong><code>dev</code></strong></dt>
+ <dd>on Unix systems, this represents the device that the inode resides on. On Windows systems,
+ represents the drive number of the disk containing the file</dd>
+
+ <dt><strong><code>ino</code></strong></dt>
+ <dd>on Unix systems, this represents the inode number. On Windows systems this has no meaning</dd>
+
+ <dt><strong><code>mode</code></strong></dt>
+ <dd>string representing the associated protection mode (the values could be
+ <code>file</code>, <code>directory</code>, <code>link</code>, <code>socket</code>,
+ <code>named pipe</code>, <code>char device</code>, <code>block device</code> or
+ <code>other</code>)</dd>
+
+ <dt><strong><code>nlink</code></strong></dt>
+ <dd>number of hard links to the file</dd>
+
+ <dt><strong><code>uid</code></strong></dt>
+ <dd>user-id of owner (Unix only, always 0 on Windows)</dd>
+
+ <dt><strong><code>gid</code></strong></dt>
+ <dd>group-id of owner (Unix only, always 0 on Windows)</dd>
+
+ <dt><strong><code>rdev</code></strong></dt>
+ <dd>on Unix systems, represents the device type, for special file inodes.
+ On Windows systems represents the same as <code>dev</code></dd>
+
+ <dt><strong><code>access</code></strong></dt>
+ <dd>time of last access</dd>
+
+ <dt><strong><code>modification</code></strong></dt>
+ <dd>time of last data modification</dd>
+
+ <dt><strong><code>change</code></strong></dt>
+ <dd>time of last file status change</dd>
+
+ <dt><strong><code>size</code></strong></dt>
+ <dd>file size, in bytes</dd>
+
+ <dt><strong><code>blocks</code></strong></dt>
+ <dd>block allocated for file; (Unix only)</dd>
+
+ <dt><strong><code>blksize</code></strong></dt>
+ <dd>optimal file system I/O blocksize; (Unix only)</dd>
+ </dl>
+ This function uses <code>stat</code> internally thus if the given
+ <code>filepath</code> is a symbolic link, it is followed (if it points to
+ another link the chain is followed recursively) and the information
+ is about the file it refers to.
+ To obtain information about the link itself, see function
+ <a href="#symlinkattributes">lfs.symlinkattributes</a>.
+ </dd>
+
+ <dt><a name="chdir"></a><strong><code>lfs.chdir (path)</code></strong></dt>
+ <dd>Changes the current working directory to the given
+ <code>path</code>.<br />
+ Returns <code>true</code> in case of success or <code>nil</code> plus an
+ error string.</dd>
+
+ <dt><a name="chdir"></a><strong><code>lfs.lock_dir(path, [seconds_stale])</code></strong></dt>
+ <dd>Creates a lockfile (called lockfile.lfs) in <code>path</code> if it does not
+ exist and returns the lock. If the lock already exists checks if
+ it's stale, using the second parameter (default for the second
+ parameter is <code>INT_MAX</code>, which in practice means the lock will never
+ be stale. To free the the lock call <code>lock:free()</code>. <br/>
+ In case of any errors it returns nil and the error message. In
+ particular, if the lock exists and is not stale it returns the
+ "File exists" message.</dd>
+
+ <dt><a name="getcwd"></a><strong><code>lfs.currentdir ()</code></strong></dt>
+ <dd>Returns a string with the current working directory or <code>nil</code>
+ plus an error string.</dd>
+
+ <dt><a name="dir"></a><strong><code>iter, dir_obj = lfs.dir (path)</code></strong></dt>
+ <dd>
+ Lua iterator over the entries of a given directory.
+ Each time the iterator is called with <code>dir_obj</code> it returns a directory entry's name as a string, or
+ <code>nil</code> if there are no more entries. You can also iterate by calling <code>dir_obj:next()</code>, and
+ explicitly close the directory before the iteration finished with <code>dir_obj:close()</code>.
+ Raises an error if <code>path</code> is not a directory.
+ </dd>
+
+ <dt><a name="lock"></a><strong><code>lfs.lock (filehandle, mode[, start[, length]])</code></strong></dt>
+ <dd>Locks a file or a part of it. This function works on <em>open files</em>; the
+ file handle should be specified as the first argument.
+ The string <code>mode</code> could be either
+ <code>r</code> (for a read/shared lock) or <code>w</code> (for a
+ write/exclusive lock). The optional arguments <code>start</code>
+ and <code>length</code> can be used to specify a starting point and
+ its length; both should be numbers.<br />
+ Returns <code>true</code> if the operation was successful; in
+ case of error, it returns <code>nil</code> plus an error string.
+ </dd>
+
+ <dt><a name="link"></a><strong><code>lfs.link (old, new[, symlink])</code></strong></dt>
+ <dd>Creates a link. The first argument is the object to link to
+ and the second is the name of the link. If the optional third
+ argument is true, the link will by a symbolic link (by default, a
+ hard link is created).
+ </dd>
+
+ <dt><a name="mkdir"></a><strong><code>lfs.mkdir (dirname)</code></strong></dt>
+ <dd>Creates a new directory. The argument is the name of the new
+ directory.<br />
+ Returns <code>true</code> if the operation was successful;
+ in case of error, it returns <code>nil</code> plus an error string.
+ </dd>
+
+ <dt><a name="rmdir"></a><strong><code>lfs.rmdir (dirname)</code></strong></dt>
+ <dd>Removes an existing directory. The argument is the name of the directory.<br />
+ Returns <code>true</code> if the operation was successful;
+ in case of error, it returns <code>nil</code> plus an error string.</dd>
+
+ <dt><a name="setmode"></a><strong><code>lfs.setmode (file, mode)</code></strong></dt>
+ <dd>Sets the writing mode for a file. The mode string can be either <code>"binary"</code> or <code>"text"</code>.
+ Returns <code>true</code> followed the previous mode string for the file, or
+ <code>nil</code> followed by an error string in case of errors.
+ On non-Windows platforms, where the two modes are identical,
+ setting the mode has no effect, and the mode is always returned as <code>binary</code>.
+ </dd>
+
+ <dt><a name="symlinkattributes"></a><strong><code>lfs.symlinkattributes (filepath [, aname])</code></strong></dt>
+ <dd>Identical to <a href="#attributes">lfs.attributes</a> except that
+ it obtains information about the link itself (not the file it refers to).
+ On Windows this function does not yet support links, and is identical to
+ <code>lfs.attributes</code>.
+ </dd>
+
+ <dt><a name="touch"></a><strong><code>lfs.touch (filepath [, atime [, mtime]])</code></strong></dt>
+ <dd>Set access and modification times of a file. This function is
+ a bind to <code>utime</code> function. The first argument is the
+ filename, the second argument (<code>atime</code>) is the access time,
+ and the third argument (<code>mtime</code>) is the modification time.
+ Both times are provided in seconds (which should be generated with
+ Lua standard function <code>os.time</code>).
+ If the modification time is omitted, the access time provided is used;
+ if both times are omitted, the current time is used.<br />
+ Returns <code>true</code> if the operation was successful;
+ in case of error, it returns <code>nil</code> plus an error string.
+ </dd>
+
+ <dt><a name="unlock"></a><strong><code>lfs.unlock (filehandle[, start[, length]])</code></strong></dt>
+ <dd>Unlocks a file or a part of it. This function works on
+ <em>open files</em>; the file handle should be specified as the first
+ argument. The optional arguments <code>start</code> and
+ <code>length</code> can be used to specify a starting point and its
+ length; both should be numbers.<br />
+ Returns <code>true</code> if the operation was successful;
+ in case of error, it returns <code>nil</code> plus an error string.
+ </dd>
+</dl>
+
+</div> <!-- id="content" -->
+
+</div> <!-- id="main" -->
+
+<div id="about">
+ <p><a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.0!</a></p>
+ <p><small>$Id: manual.html,v 1.45 2009/06/03 20:53:55 mascarenhas Exp $</small></p>
+</div> <!-- id="about" -->
+
+</div> <!-- id="container" -->
+
+</body>
+</html>
diff --git a/3rdparty/luafilesystem/rockspecs/luafilesystem-1.3.0-1.rockspec b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.3.0-1.rockspec
new file mode 100644
index 00000000000..d4d484f68a7
--- /dev/null
+++ b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.3.0-1.rockspec
@@ -0,0 +1,27 @@
+package = "LuaFileSystem"
+version = "1.3.0-1"
+source = {
+ url = "http://luaforge.net/frs/download.php/2679/luafilesystem-1.3.0.tar.gz"
+}
+description = {
+ summary = "File System Library for the Lua Programming Language",
+ detailed = [[
+ LuaFileSystem is a Lua library developed to complement the set of
+ functions related to file systems offered by the standard Lua
+ distribution. LuaFileSystem offers a portable way to access the
+ underlying directory structure and file attributes.
+ ]]
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "make",
+ build_variables = {
+ LUA_INC = "$(LUA_INCDIR)",
+ LIB_OPTION = "$(LIBFLAG)"
+ },
+ install_variables = {
+ LUA_LIBDIR = "$(LIBDIR)"
+ }
+}
diff --git a/3rdparty/luafilesystem/rockspecs/luafilesystem-1.4.0-1.rockspec b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.4.0-1.rockspec
new file mode 100644
index 00000000000..b6936182394
--- /dev/null
+++ b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.4.0-1.rockspec
@@ -0,0 +1,27 @@
+package = "LuaFileSystem"
+version = "1.4.0-1"
+source = {
+ url = "http://luaforge.net/frs/download.php/3158/luafilesystem-1.4.0.tar.gz"
+}
+description = {
+ summary = "File System Library for the Lua Programming Language",
+ detailed = [[
+ LuaFileSystem is a Lua library developed to complement the set of
+ functions related to file systems offered by the standard Lua
+ distribution. LuaFileSystem offers a portable way to access the
+ underlying directory structure and file attributes.
+ ]]
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "make",
+ build_variables = {
+ LUA_INC = "$(LUA_INCDIR)",
+ LIB_OPTION = "$(LIBFLAG)"
+ },
+ install_variables = {
+ LUA_LIBDIR = "$(LIBDIR)"
+ }
+}
diff --git a/3rdparty/luafilesystem/rockspecs/luafilesystem-1.4.0-2.rockspec b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.4.0-2.rockspec
new file mode 100644
index 00000000000..f7ed871527f
--- /dev/null
+++ b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.4.0-2.rockspec
@@ -0,0 +1,43 @@
+package = "LuaFileSystem"
+version = "1.4.0-2"
+source = {
+ url = "http://luaforge.net/frs/download.php/3158/luafilesystem-1.4.0.tar.gz"
+}
+description = {
+ summary = "File System Library for the Lua Programming Language",
+ detailed = [[
+ LuaFileSystem is a Lua library developed to complement the set of
+ functions related to file systems offered by the standard Lua
+ distribution. LuaFileSystem offers a portable way to access the
+ underlying directory structure and file attributes.
+ ]]
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ platforms = {
+ unix = {
+ type = "make",
+ build_variables = {
+ LIB_OPTION = "$(LIBFLAG)",
+ CFLAGS = "$(CFLAGS) -I$(LUA_INCDIR)",
+ },
+ install_variables = {
+ LUA_LIBDIR = "$(LIBDIR)"
+ }
+ },
+ win32 = {
+ type = "make",
+ build_variables = {
+ LUA_LIB = "$(LUA_LIBDIR)\\lua5.1.lib",
+ CFLAGS = "/MD $(CFLAGS) /I$(LUA_INCDIR)",
+ },
+ install_variables = {
+ LUA_LIBDIR = "$(LIBDIR)",
+ LUA_DIR = "$(LUADIR)",
+ BIN_DIR = "$(BINDIR)"
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/3rdparty/luafilesystem/rockspecs/luafilesystem-1.4.1-1.rockspec b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.4.1-1.rockspec
new file mode 100644
index 00000000000..db3a3ebb6df
--- /dev/null
+++ b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.4.1-1.rockspec
@@ -0,0 +1,43 @@
+package = "LuaFileSystem"
+version = "1.4.1-1"
+source = {
+ url = "http://luaforge.net/frs/download.php/3345/luafilesystem-1.4.1.tar.gz",
+}
+description = {
+ summary = "File System Library for the Lua Programming Language",
+ detailed = [[
+ LuaFileSystem is a Lua library developed to complement the set of
+ functions related to file systems offered by the standard Lua
+ distribution. LuaFileSystem offers a portable way to access the
+ underlying directory structure and file attributes.
+ ]]
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ platforms = {
+ unix = {
+ type = "make",
+ build_variables = {
+ LIB_OPTION = "$(LIBFLAG)",
+ CFLAGS = "$(CFLAGS) -I$(LUA_INCDIR) $(STAT64)",
+ },
+ install_variables = {
+ LUA_LIBDIR = "$(LIBDIR)"
+ }
+ },
+ win32 = {
+ type = "make",
+ build_variables = {
+ LUA_LIB = "$(LUA_LIBDIR)\\lua5.1.lib",
+ CFLAGS = "/MD $(CFLAGS) /I$(LUA_INCDIR)",
+ },
+ install_variables = {
+ LUA_LIBDIR = "$(LIBDIR)",
+ LUA_DIR = "$(LUADIR)",
+ BIN_DIR = "$(BINDIR)"
+ }
+ }
+ }
+}
diff --git a/3rdparty/luafilesystem/rockspecs/luafilesystem-1.4.1rc1-1.rockspec b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.4.1rc1-1.rockspec
new file mode 100644
index 00000000000..1194711715b
--- /dev/null
+++ b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.4.1rc1-1.rockspec
@@ -0,0 +1,43 @@
+package = "LuaFileSystem"
+version = "1.4.1rc1-1"
+source = {
+ url = "http://luafilesystem.luaforge.net/luafilesystem-1.4.1rc1.tar.gz",
+}
+description = {
+ summary = "File System Library for the Lua Programming Language",
+ detailed = [[
+ LuaFileSystem is a Lua library developed to complement the set of
+ functions related to file systems offered by the standard Lua
+ distribution. LuaFileSystem offers a portable way to access the
+ underlying directory structure and file attributes.
+ ]]
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ platforms = {
+ unix = {
+ type = "make",
+ build_variables = {
+ LIB_OPTION = "$(LIBFLAG)",
+ CFLAGS = "$(CFLAGS) -I$(LUA_INCDIR) $(STAT64)",
+ },
+ install_variables = {
+ LUA_LIBDIR = "$(LIBDIR)"
+ }
+ },
+ win32 = {
+ type = "make",
+ build_variables = {
+ LUA_LIB = "$(LUA_LIBDIR)\\lua5.1.lib",
+ CFLAGS = "/MD $(CFLAGS) /I$(LUA_INCDIR)",
+ },
+ install_variables = {
+ LUA_LIBDIR = "$(LIBDIR)",
+ LUA_DIR = "$(LUADIR)",
+ BIN_DIR = "$(BINDIR)"
+ }
+ }
+ }
+}
diff --git a/3rdparty/luafilesystem/rockspecs/luafilesystem-1.4.2-1.rockspec b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.4.2-1.rockspec
new file mode 100644
index 00000000000..7cfe92b78ef
--- /dev/null
+++ b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.4.2-1.rockspec
@@ -0,0 +1,26 @@
+package = "LuaFileSystem"
+
+version = "1.4.2-1"
+
+source = {
+ url = "http://luaforge.net/frs/download.php/3931/luafilesystem-1.4.2.tar.gz",
+}
+
+description = {
+ summary = "File System Library for the Lua Programming Language",
+ detailed = [[
+ LuaFileSystem is a Lua library developed to complement the set of
+ functions related to file systems offered by the standard Lua
+ distribution. LuaFileSystem offers a portable way to access the
+ underlying directory structure and file attributes.
+ ]]
+}
+
+dependencies = {
+ "lua >= 5.1"
+}
+
+build = {
+ type = "module",
+ modules = { lfs = "src/lfs.c" }
+} \ No newline at end of file
diff --git a/3rdparty/luafilesystem/rockspecs/luafilesystem-1.5.0-1.rockspec b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.5.0-1.rockspec
new file mode 100644
index 00000000000..1170ad25c90
--- /dev/null
+++ b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.5.0-1.rockspec
@@ -0,0 +1,27 @@
+package = "LuaFileSystem"
+
+version = "1.5.0-1"
+
+source = {
+ url = "http://cloud.github.com/downloads/keplerproject/luafilesystem/luafilesystem-1.5.0.tar.gz",
+}
+
+description = {
+ summary = "File System Library for the Lua Programming Language",
+ detailed = [[
+ LuaFileSystem is a Lua library developed to complement the set of
+ functions related to file systems offered by the standard Lua
+ distribution. LuaFileSystem offers a portable way to access the
+ underlying directory structure and file attributes.
+ ]]
+}
+
+dependencies = {
+ "lua >= 5.1"
+}
+
+build = {
+ type = "module",
+ modules = { lfs = "src/lfs.c" },
+ copy_directories = { "doc", "tests" }
+}
diff --git a/3rdparty/luafilesystem/rockspecs/luafilesystem-1.6.0-1.rockspec b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.6.0-1.rockspec
new file mode 100644
index 00000000000..82d349cf016
--- /dev/null
+++ b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.6.0-1.rockspec
@@ -0,0 +1,27 @@
+package = "LuaFileSystem"
+
+version = "1.6.0-1"
+
+source = {
+ url = "https://github.com/downloads/keplerproject/luafilesystem/luafilesystem-1.6.0.tar.gz",
+}
+
+description = {
+ summary = "File System Library for the Lua Programming Language",
+ detailed = [[
+ LuaFileSystem is a Lua library developed to complement the set of
+ functions related to file systems offered by the standard Lua
+ distribution. LuaFileSystem offers a portable way to access the
+ underlying directory structure and file attributes.
+ ]]
+}
+
+dependencies = {
+ "lua >= 5.1"
+}
+
+build = {
+ type = "builtin",
+ modules = { lfs = "src/lfs.c" },
+ copy_directories = { "doc", "tests" }
+}
diff --git a/3rdparty/luafilesystem/rockspecs/luafilesystem-1.6.1-1.rockspec b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.6.1-1.rockspec
new file mode 100644
index 00000000000..7f45e332c44
--- /dev/null
+++ b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.6.1-1.rockspec
@@ -0,0 +1,27 @@
+package = "LuaFileSystem"
+
+version = "1.6.1-1"
+
+source = {
+ url = "https://github.com/downloads/keplerproject/luafilesystem/luafilesystem-1.6.1.tar.gz",
+}
+
+description = {
+ summary = "File System Library for the Lua Programming Language",
+ detailed = [[
+ LuaFileSystem is a Lua library developed to complement the set of
+ functions related to file systems offered by the standard Lua
+ distribution. LuaFileSystem offers a portable way to access the
+ underlying directory structure and file attributes.
+ ]]
+}
+
+dependencies = {
+ "lua >= 5.1"
+}
+
+build = {
+ type = "builtin",
+ modules = { lfs = "src/lfs.c" },
+ copy_directories = { "doc", "tests" }
+}
diff --git a/3rdparty/luafilesystem/rockspecs/luafilesystem-1.6.2-1.rockspec b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.6.2-1.rockspec
new file mode 100644
index 00000000000..1c11efc89e1
--- /dev/null
+++ b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.6.2-1.rockspec
@@ -0,0 +1,27 @@
+package = "LuaFileSystem"
+
+version = "1.6.2-1"
+
+source = {
+ url = "https://github.com/downloads/keplerproject/luafilesystem/luafilesystem-1.6.2.tar.gz",
+}
+
+description = {
+ summary = "File System Library for the Lua Programming Language",
+ detailed = [[
+ LuaFileSystem is a Lua library developed to complement the set of
+ functions related to file systems offered by the standard Lua
+ distribution. LuaFileSystem offers a portable way to access the
+ underlying directory structure and file attributes.
+ ]]
+}
+
+dependencies = {
+ "lua >= 5.1"
+}
+
+build = {
+ type = "builtin",
+ modules = { lfs = "src/lfs.c" },
+ copy_directories = { "doc", "tests" }
+}
diff --git a/3rdparty/luafilesystem/rockspecs/luafilesystem-1.6.3-1.rockspec b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.6.3-1.rockspec
new file mode 100644
index 00000000000..89b25d42fe3
--- /dev/null
+++ b/3rdparty/luafilesystem/rockspecs/luafilesystem-1.6.3-1.rockspec
@@ -0,0 +1,28 @@
+package = "LuaFileSystem"
+version = "1.6.3-1"
+source = {
+ url = "git://github.com/keplerproject/luafilesystem",
+ tag = "v_1_6_3",
+}
+description = {
+ summary = "File System Library for the Lua Programming Language",
+ detailed = [[
+ LuaFileSystem is a Lua library developed to complement the set of
+ functions related to file systems offered by the standard Lua
+ distribution. LuaFileSystem offers a portable way to access the
+ underlying directory structure and file attributes.
+ ]],
+ license = "MIT/X11",
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ type = "builtin",
+ modules = {
+ lfs = "src/lfs.c"
+ },
+ copy_directories = {
+ "doc", "tests"
+ }
+}
diff --git a/3rdparty/luafilesystem/rockspecs/luafilesystem-cvs-1.rockspec b/3rdparty/luafilesystem/rockspecs/luafilesystem-cvs-1.rockspec
new file mode 100644
index 00000000000..a02d4f14e71
--- /dev/null
+++ b/3rdparty/luafilesystem/rockspecs/luafilesystem-cvs-1.rockspec
@@ -0,0 +1,44 @@
+package = "LuaFileSystem"
+version = "cvs-1"
+source = {
+ url = "cvs://:pserver:anonymous:@cvs.luaforge.net:/cvsroot/luafilesystem",
+ cvs_tag = "HEAD"
+}
+description = {
+ summary = "File System Library for the Lua Programming Language",
+ detailed = [[
+ LuaFileSystem is a Lua library developed to complement the set of
+ functions related to file systems offered by the standard Lua
+ distribution. LuaFileSystem offers a portable way to access the
+ underlying directory structure and file attributes.
+ ]]
+}
+dependencies = {
+ "lua >= 5.1"
+}
+build = {
+ platforms = {
+ unix = {
+ type = "make",
+ build_variables = {
+ LIB_OPTION = "$(LIBFLAG)",
+ CFLAGS = "$(CFLAGS) -I$(LUA_INCDIR)",
+ },
+ install_variables = {
+ LUA_LIBDIR = "$(LIBDIR)"
+ }
+ },
+ win32 = {
+ type = "make",
+ build_variables = {
+ LUA_LIB = "$(LUA_LIBDIR)\\lua5.1.lib",
+ CFLAGS = "$(CFLAGS) /I$(LUA_INCDIR)",
+ },
+ install_variables = {
+ LUA_LIBDIR = "$(LIBDIR)",
+ LUA_DIR = "$(LUADIR)",
+ BIN_DIR = "$(BINDIR)"
+ }
+ }
+ }
+}
diff --git a/3rdparty/luafilesystem/rockspecs/luafilesystem-cvs-2.rockspec b/3rdparty/luafilesystem/rockspecs/luafilesystem-cvs-2.rockspec
new file mode 100644
index 00000000000..651c7cf1317
--- /dev/null
+++ b/3rdparty/luafilesystem/rockspecs/luafilesystem-cvs-2.rockspec
@@ -0,0 +1,26 @@
+package = "LuaFileSystem"
+
+version = "cvs-2"
+
+source = {
+ url = "git://github.com/keplerproject/luafilesystem.git",
+}
+
+description = {
+ summary = "File System Library for the Lua Programming Language",
+ detailed = [[
+ LuaFileSystem is a Lua library developed to complement the set of
+ functions related to file systems offered by the standard Lua
+ distribution. LuaFileSystem offers a portable way to access the
+ underlying directory structure and file attributes.
+ ]]
+}
+
+dependencies = {
+ "lua >= 5.1"
+}
+
+build = {
+ type = "module",
+ modules = { lfs = "src/lfs.c" }
+}
diff --git a/3rdparty/luafilesystem/rockspecs/luafilesystem-cvs-3.rockspec b/3rdparty/luafilesystem/rockspecs/luafilesystem-cvs-3.rockspec
new file mode 100644
index 00000000000..a4388cd7619
--- /dev/null
+++ b/3rdparty/luafilesystem/rockspecs/luafilesystem-cvs-3.rockspec
@@ -0,0 +1,27 @@
+package = "LuaFileSystem"
+
+version = "cvs-3"
+
+source = {
+ url = "git://github.com/keplerproject/luafilesystem.git",
+}
+
+description = {
+ summary = "File System Library for the Lua Programming Language",
+ detailed = [[
+ LuaFileSystem is a Lua library developed to complement the set of
+ functions related to file systems offered by the standard Lua
+ distribution. LuaFileSystem offers a portable way to access the
+ underlying directory structure and file attributes.
+ ]]
+}
+
+dependencies = {
+ "lua >= 5.1, < 5.4"
+}
+
+build = {
+ type = "builtin",
+ modules = { lfs = "src/lfs.c" },
+ copy_directories = { "doc", "tests" }
+}
diff --git a/3rdparty/luafilesystem/src/.gitignore b/3rdparty/luafilesystem/src/.gitignore
new file mode 100644
index 00000000000..9d22eb46a9c
--- /dev/null
+++ b/3rdparty/luafilesystem/src/.gitignore
@@ -0,0 +1,2 @@
+*.o
+*.so
diff --git a/3rdparty/luafilesystem/src/lfs.c b/3rdparty/luafilesystem/src/lfs.c
new file mode 100644
index 00000000000..ac483fa067b
--- /dev/null
+++ b/3rdparty/luafilesystem/src/lfs.c
@@ -0,0 +1,906 @@
+/*
+** LuaFileSystem
+** Copyright Kepler Project 2003 (http://www.keplerproject.org/luafilesystem)
+**
+** File system manipulation library.
+** This library offers these functions:
+** lfs.attributes (filepath [, attributename])
+** lfs.chdir (path)
+** lfs.currentdir ()
+** lfs.dir (path)
+** lfs.lock (fh, mode)
+** lfs.lock_dir (path)
+** lfs.mkdir (path)
+** lfs.rmdir (path)
+** lfs.setmode (filepath, mode)
+** lfs.symlinkattributes (filepath [, attributename]) -- thanks to Sam Roberts
+** lfs.touch (filepath [, atime [, mtime]])
+** lfs.unlock (fh)
+**
+** $Id: lfs.c,v 1.61 2009/07/04 02:10:16 mascarenhas Exp $
+*/
+
+#ifndef LFS_DO_NOT_USE_LARGE_FILE
+#ifndef _WIN32
+#ifndef _AIX
+#define _FILE_OFFSET_BITS 64 /* Linux, Solaris and HP-UX */
+#else
+#define _LARGE_FILES 1 /* AIX */
+#endif
+#endif
+#endif
+
+#ifndef LFS_DO_NOT_USE_LARGE_FILE
+#define _LARGEFILE64_SOURCE
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/stat.h>
+
+#ifdef _WIN32
+#include <direct.h>
+#include <windows.h>
+#include <io.h>
+#include <sys/locking.h>
+#ifdef __BORLANDC__
+ #include <utime.h>
+#else
+ #include <sys/utime.h>
+#endif
+#include <fcntl.h>
+#else
+#include <unistd.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <utime.h>
+#endif
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+#include "lfs.h"
+
+#define LFS_VERSION "1.6.3"
+#define LFS_LIBNAME "lfs"
+
+#if LUA_VERSION_NUM >= 503 /* Lua 5.3 */
+
+#ifndef luaL_optlong
+#define luaL_optlong luaL_optinteger
+#endif
+
+#endif
+
+#if LUA_VERSION_NUM < 502
+# define luaL_newlib(L,l) (lua_newtable(L), luaL_register(L,NULL,l))
+#endif
+
+/* Define 'strerror' for systems that do not implement it */
+#ifdef NO_STRERROR
+#define strerror(_) "System unable to describe the error"
+#endif
+
+/* Define 'getcwd' for systems that do not implement it */
+#ifdef NO_GETCWD
+#define getcwd(p,s) NULL
+#define getcwd_error "Function 'getcwd' not provided by system"
+#else
+#define getcwd_error strerror(errno)
+ #ifdef _WIN32
+ /* MAX_PATH seems to be 260. Seems kind of small. Is there a better one? */
+ #define LFS_MAXPATHLEN MAX_PATH
+ #else
+ /* For MAXPATHLEN: */
+ #include <sys/param.h>
+ #define LFS_MAXPATHLEN MAXPATHLEN
+ #endif
+#endif
+
+#define DIR_METATABLE "directory metatable"
+typedef struct dir_data {
+ int closed;
+#ifdef _WIN32
+ intptr_t hFile;
+ char pattern[MAX_PATH+1];
+#else
+ DIR *dir;
+#endif
+} dir_data;
+
+#define LOCK_METATABLE "lock metatable"
+
+#ifdef _WIN32
+ #ifdef __BORLANDC__
+ #define lfs_setmode(L,file,m) ((void)L, setmode(_fileno(file), m))
+ #define STAT_STRUCT struct stati64
+ #else
+ #define lfs_setmode(L,file,m) ((void)L, _setmode(_fileno(file), m))
+ #define STAT_STRUCT struct _stati64
+ #endif
+#define STAT_FUNC _stati64
+#define LSTAT_FUNC STAT_FUNC
+#else
+#define _O_TEXT 0
+#define _O_BINARY 0
+#define lfs_setmode(L,file,m) ((void)L, (void)file, (void)m, 0)
+#define STAT_STRUCT struct stat
+#define STAT_FUNC stat
+#define LSTAT_FUNC lstat
+#endif
+
+/*
+** Utility functions
+*/
+static int pusherror(lua_State *L, const char *info)
+{
+ lua_pushnil(L);
+ if (info==NULL)
+ lua_pushstring(L, strerror(errno));
+ else
+ lua_pushfstring(L, "%s: %s", info, strerror(errno));
+ lua_pushinteger(L, errno);
+ return 3;
+}
+
+#ifndef _WIN32
+static int pushresult(lua_State *L, int i, const char *info)
+{
+ if (i==-1)
+ return pusherror(L, info);
+ lua_pushinteger(L, i);
+ return 1;
+}
+#endif
+/*
+** This function changes the working (current) directory
+*/
+static int change_dir (lua_State *L) {
+ const char *path = luaL_checkstring(L, 1);
+ if (chdir(path)) {
+ lua_pushnil (L);
+ lua_pushfstring (L,"Unable to change working directory to '%s'\n%s\n",
+ path, chdir_error);
+ return 2;
+ } else {
+ lua_pushboolean (L, 1);
+ return 1;
+ }
+}
+
+/*
+** This function returns the current directory
+** If unable to get the current directory, it returns nil
+** and a string describing the error
+*/
+static int get_dir (lua_State *L) {
+ char *path;
+ /* Passing (NULL, 0) is not guaranteed to work. Use a temp buffer and size instead. */
+ char buf[LFS_MAXPATHLEN];
+ if ((path = getcwd(buf, LFS_MAXPATHLEN)) == NULL) {
+ lua_pushnil(L);
+ lua_pushstring(L, getcwd_error);
+ return 2;
+ }
+ else {
+ lua_pushstring(L, path);
+ return 1;
+ }
+}
+
+/*
+** Check if the given element on the stack is a file and returns it.
+*/
+static FILE *check_file (lua_State *L, int idx, const char *funcname) {
+#if LUA_VERSION_NUM == 501
+ FILE **fh = (FILE **)luaL_checkudata (L, idx, "FILE*");
+ if (*fh == NULL) {
+ luaL_error (L, "%s: closed file", funcname);
+ return 0;
+ } else
+ return *fh;
+#elif LUA_VERSION_NUM >= 502 && LUA_VERSION_NUM <= 503
+ luaL_Stream *fh = (luaL_Stream *)luaL_checkudata (L, idx, "FILE*");
+ if (fh->closef == 0 || fh->f == NULL) {
+ luaL_error (L, "%s: closed file", funcname);
+ return 0;
+ } else
+ return fh->f;
+#else
+#error unsupported Lua version
+#endif
+}
+
+
+/*
+**
+*/
+static int _file_lock (lua_State *L, FILE *fh, const char *mode, const long start, long len, const char *funcname) {
+ int code;
+#ifdef _WIN32
+ /* lkmode valid values are:
+ LK_LOCK Locks the specified bytes. If the bytes cannot be locked, the program immediately tries again after 1 second. If, after 10 attempts, the bytes cannot be locked, the constant returns an error.
+ LK_NBLCK Locks the specified bytes. If the bytes cannot be locked, the constant returns an error.
+ LK_NBRLCK Same as _LK_NBLCK.
+ LK_RLCK Same as _LK_LOCK.
+ LK_UNLCK Unlocks the specified bytes, which must have been previously locked.
+
+ Regions should be locked only briefly and should be unlocked before closing a file or exiting the program.
+
+ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__locking.asp
+ */
+ int lkmode;
+ switch (*mode) {
+ case 'r': lkmode = LK_NBLCK; break;
+ case 'w': lkmode = LK_NBLCK; break;
+ case 'u': lkmode = LK_UNLCK; break;
+ default : return luaL_error (L, "%s: invalid mode", funcname);
+ }
+ if (!len) {
+ fseek (fh, 0L, SEEK_END);
+ len = ftell (fh);
+ }
+ fseek (fh, start, SEEK_SET);
+#ifdef __BORLANDC__
+ code = locking (fileno(fh), lkmode, len);
+#else
+ code = _locking (fileno(fh), lkmode, len);
+#endif
+#else
+ struct flock f;
+ switch (*mode) {
+ case 'w': f.l_type = F_WRLCK; break;
+ case 'r': f.l_type = F_RDLCK; break;
+ case 'u': f.l_type = F_UNLCK; break;
+ default : return luaL_error (L, "%s: invalid mode", funcname);
+ }
+ f.l_whence = SEEK_SET;
+ f.l_start = (off_t)start;
+ f.l_len = (off_t)len;
+ code = fcntl (fileno(fh), F_SETLK, &f);
+#endif
+ return (code != -1);
+}
+
+#ifdef _WIN32
+typedef struct lfs_Lock {
+ HANDLE fd;
+} lfs_Lock;
+static int lfs_lock_dir(lua_State *L) {
+ size_t pathl; HANDLE fd;
+ lfs_Lock *lock;
+ char *ln;
+ const char *lockfile = "/lockfile.lfs";
+ const char *path = luaL_checklstring(L, 1, &pathl);
+ ln = (char*)malloc(pathl + strlen(lockfile) + 1);
+ if(!ln) {
+ lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2;
+ }
+ strcpy(ln, path); strcat(ln, lockfile);
+ if((fd = CreateFile(ln, GENERIC_WRITE, 0, NULL, CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL)) == INVALID_HANDLE_VALUE) {
+ int en = GetLastError();
+ free(ln); lua_pushnil(L);
+ if(en == ERROR_FILE_EXISTS || en == ERROR_SHARING_VIOLATION)
+ lua_pushstring(L, "File exists");
+ else
+ lua_pushstring(L, strerror(en));
+ return 2;
+ }
+ free(ln);
+ lock = (lfs_Lock*)lua_newuserdata(L, sizeof(lfs_Lock));
+ lock->fd = fd;
+ luaL_getmetatable (L, LOCK_METATABLE);
+ lua_setmetatable (L, -2);
+ return 1;
+}
+static int lfs_unlock_dir(lua_State *L) {
+ lfs_Lock *lock = (lfs_Lock *)luaL_checkudata(L, 1, LOCK_METATABLE);
+ if(lock->fd != INVALID_HANDLE_VALUE) {
+ CloseHandle(lock->fd);
+ lock->fd=INVALID_HANDLE_VALUE;
+ }
+ return 0;
+}
+#else
+typedef struct lfs_Lock {
+ char *ln;
+} lfs_Lock;
+static int lfs_lock_dir(lua_State *L) {
+ lfs_Lock *lock;
+ size_t pathl;
+ char *ln;
+ const char *lockfile = "/lockfile.lfs";
+ const char *path = luaL_checklstring(L, 1, &pathl);
+ lock = (lfs_Lock*)lua_newuserdata(L, sizeof(lfs_Lock));
+ ln = (char*)malloc(pathl + strlen(lockfile) + 1);
+ if(!ln) {
+ lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2;
+ }
+ strcpy(ln, path); strcat(ln, lockfile);
+ if(symlink("lock", ln) == -1) {
+ free(ln); lua_pushnil(L);
+ lua_pushstring(L, strerror(errno)); return 2;
+ }
+ lock->ln = ln;
+ luaL_getmetatable (L, LOCK_METATABLE);
+ lua_setmetatable (L, -2);
+ return 1;
+}
+static int lfs_unlock_dir(lua_State *L) {
+ lfs_Lock *lock = (lfs_Lock *)luaL_checkudata(L, 1, LOCK_METATABLE);
+ if(lock->ln) {
+ unlink(lock->ln);
+ free(lock->ln);
+ lock->ln = NULL;
+ }
+ return 0;
+}
+#endif
+
+static int lfs_g_setmode (lua_State *L, FILE *f, int arg) {
+ static const int mode[] = {_O_BINARY, _O_TEXT};
+ static const char *const modenames[] = {"binary", "text", NULL};
+ int op = luaL_checkoption(L, arg, NULL, modenames);
+ int res = lfs_setmode(L, f, mode[op]);
+ if (res != -1) {
+ int i;
+ lua_pushboolean(L, 1);
+ for (i = 0; modenames[i] != NULL; i++) {
+ if (mode[i] == res) {
+ lua_pushstring(L, modenames[i]);
+ goto exit;
+ }
+ }
+ lua_pushnil(L);
+ exit:
+ return 2;
+ } else {
+ int en = errno;
+ lua_pushnil(L);
+ lua_pushfstring(L, "%s", strerror(en));
+ lua_pushinteger(L, en);
+ return 3;
+ }
+}
+
+static int lfs_f_setmode(lua_State *L) {
+ return lfs_g_setmode(L, check_file(L, 1, "setmode"), 2);
+}
+
+/*
+** Locks a file.
+** @param #1 File handle.
+** @param #2 String with lock mode ('w'rite, 'r'ead).
+** @param #3 Number with start position (optional).
+** @param #4 Number with length (optional).
+*/
+static int file_lock (lua_State *L) {
+ FILE *fh = check_file (L, 1, "lock");
+ const char *mode = luaL_checkstring (L, 2);
+ const long start = (long) luaL_optinteger (L, 3, 0);
+ long len = (long) luaL_optinteger (L, 4, 0);
+ if (_file_lock (L, fh, mode, start, len, "lock")) {
+ lua_pushboolean (L, 1);
+ return 1;
+ } else {
+ lua_pushnil (L);
+ lua_pushfstring (L, "%s", strerror(errno));
+ return 2;
+ }
+}
+
+
+/*
+** Unlocks a file.
+** @param #1 File handle.
+** @param #2 Number with start position (optional).
+** @param #3 Number with length (optional).
+*/
+static int file_unlock (lua_State *L) {
+ FILE *fh = check_file (L, 1, "unlock");
+ const long start = (long) luaL_optinteger (L, 2, 0);
+ long len = (long) luaL_optinteger (L, 3, 0);
+ if (_file_lock (L, fh, "u", start, len, "unlock")) {
+ lua_pushboolean (L, 1);
+ return 1;
+ } else {
+ lua_pushnil (L);
+ lua_pushfstring (L, "%s", strerror(errno));
+ return 2;
+ }
+}
+
+
+/*
+** Creates a link.
+** @param #1 Object to link to.
+** @param #2 Name of link.
+** @param #3 True if link is symbolic (optional).
+*/
+static int make_link(lua_State *L)
+{
+#ifndef _WIN32
+ const char *oldpath = luaL_checkstring(L, 1);
+ const char *newpath = luaL_checkstring(L, 2);
+ return pushresult(L,
+ (lua_toboolean(L,3) ? symlink : link)(oldpath, newpath), NULL);
+#else
+ return pusherror(L, "make_link is not supported on Windows");
+#endif
+}
+
+
+/*
+** Creates a directory.
+** @param #1 Directory path.
+*/
+static int make_dir (lua_State *L) {
+ const char *path = luaL_checkstring (L, 1);
+ int fail;
+#ifdef _WIN32
+ fail = _mkdir (path);
+#else
+ fail = mkdir (path, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
+ S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH );
+#endif
+ if (fail) {
+ lua_pushnil (L);
+ lua_pushfstring (L, "%s", strerror(errno));
+ return 2;
+ }
+ lua_pushboolean (L, 1);
+ return 1;
+}
+
+
+/*
+** Removes a directory.
+** @param #1 Directory path.
+*/
+static int remove_dir (lua_State *L) {
+ const char *path = luaL_checkstring (L, 1);
+ int fail;
+
+ fail = rmdir (path);
+
+ if (fail) {
+ lua_pushnil (L);
+ lua_pushfstring (L, "%s", strerror(errno));
+ return 2;
+ }
+ lua_pushboolean (L, 1);
+ return 1;
+}
+
+
+/*
+** Directory iterator
+*/
+static int dir_iter (lua_State *L) {
+#ifdef _WIN32
+ struct _finddata_t c_file;
+#else
+ struct dirent *entry;
+#endif
+ dir_data *d = (dir_data *)luaL_checkudata (L, 1, DIR_METATABLE);
+ luaL_argcheck (L, d->closed == 0, 1, "closed directory");
+#ifdef _WIN32
+ if (d->hFile == 0L) { /* first entry */
+ if ((d->hFile = _findfirst (d->pattern, &c_file)) == -1L) {
+ lua_pushnil (L);
+ lua_pushstring (L, strerror (errno));
+ d->closed = 1;
+ return 2;
+ } else {
+ lua_pushstring (L, c_file.name);
+ return 1;
+ }
+ } else { /* next entry */
+ if (_findnext (d->hFile, &c_file) == -1L) {
+ /* no more entries => close directory */
+ _findclose (d->hFile);
+ d->closed = 1;
+ return 0;
+ } else {
+ lua_pushstring (L, c_file.name);
+ return 1;
+ }
+ }
+#else
+ if ((entry = readdir (d->dir)) != NULL) {
+ lua_pushstring (L, entry->d_name);
+ return 1;
+ } else {
+ /* no more entries => close directory */
+ closedir (d->dir);
+ d->closed = 1;
+ return 0;
+ }
+#endif
+}
+
+
+/*
+** Closes directory iterators
+*/
+static int dir_close (lua_State *L) {
+ dir_data *d = (dir_data *)lua_touserdata (L, 1);
+#ifdef _WIN32
+ if (!d->closed && d->hFile) {
+ _findclose (d->hFile);
+ }
+#else
+ if (!d->closed && d->dir) {
+ closedir (d->dir);
+ }
+#endif
+ d->closed = 1;
+ return 0;
+}
+
+
+/*
+** Factory of directory iterators
+*/
+static int dir_iter_factory (lua_State *L) {
+ const char *path = luaL_checkstring (L, 1);
+ dir_data *d;
+ lua_pushcfunction (L, dir_iter);
+ d = (dir_data *) lua_newuserdata (L, sizeof(dir_data));
+ luaL_getmetatable (L, DIR_METATABLE);
+ lua_setmetatable (L, -2);
+ d->closed = 0;
+#ifdef _WIN32
+ d->hFile = 0L;
+ if (strlen(path) > MAX_PATH-2)
+ luaL_error (L, "path too long: %s", path);
+ else
+ sprintf (d->pattern, "%s/*", path);
+#else
+ d->dir = opendir (path);
+ if (d->dir == NULL)
+ luaL_error (L, "cannot open %s: %s", path, strerror (errno));
+#endif
+ return 2;
+}
+
+
+/*
+** Creates directory metatable.
+*/
+static int dir_create_meta (lua_State *L) {
+ luaL_newmetatable (L, DIR_METATABLE);
+
+ /* Method table */
+ lua_newtable(L);
+ lua_pushcfunction (L, dir_iter);
+ lua_setfield(L, -2, "next");
+ lua_pushcfunction (L, dir_close);
+ lua_setfield(L, -2, "close");
+
+ /* Metamethods */
+ lua_setfield(L, -2, "__index");
+ lua_pushcfunction (L, dir_close);
+ lua_setfield (L, -2, "__gc");
+ return 1;
+}
+
+
+/*
+** Creates lock metatable.
+*/
+static int lock_create_meta (lua_State *L) {
+ luaL_newmetatable (L, LOCK_METATABLE);
+
+ /* Method table */
+ lua_newtable(L);
+ lua_pushcfunction(L, lfs_unlock_dir);
+ lua_setfield(L, -2, "free");
+
+ /* Metamethods */
+ lua_setfield(L, -2, "__index");
+ lua_pushcfunction(L, lfs_unlock_dir);
+ lua_setfield(L, -2, "__gc");
+ return 1;
+}
+
+
+#ifdef _WIN32
+ #ifndef S_ISDIR
+ #define S_ISDIR(mode) (mode&_S_IFDIR)
+ #endif
+ #ifndef S_ISREG
+ #define S_ISREG(mode) (mode&_S_IFREG)
+ #endif
+ #ifndef S_ISLNK
+ #define S_ISLNK(mode) (0)
+ #endif
+ #ifndef S_ISSOCK
+ #define S_ISSOCK(mode) (0)
+ #endif
+ #ifndef S_ISFIFO
+ #define S_ISFIFO(mode) (0)
+ #endif
+ #ifndef S_ISCHR
+ #define S_ISCHR(mode) (mode&_S_IFCHR)
+ #endif
+ #ifndef S_ISBLK
+ #define S_ISBLK(mode) (0)
+ #endif
+#endif
+/*
+** Convert the inode protection mode to a string.
+*/
+#ifdef _WIN32
+static const char *mode2string (unsigned short mode) {
+#else
+static const char *mode2string (mode_t mode) {
+#endif
+ if ( S_ISREG(mode) )
+ return "file";
+ else if ( S_ISDIR(mode) )
+ return "directory";
+ else if ( S_ISLNK(mode) )
+ return "link";
+ else if ( S_ISSOCK(mode) )
+ return "socket";
+ else if ( S_ISFIFO(mode) )
+ return "named pipe";
+ else if ( S_ISCHR(mode) )
+ return "char device";
+ else if ( S_ISBLK(mode) )
+ return "block device";
+ else
+ return "other";
+}
+
+
+/*
+** Set access time and modification values for file
+*/
+static int file_utime (lua_State *L) {
+ const char *file = luaL_checkstring (L, 1);
+ struct utimbuf utb, *buf;
+
+ if (lua_gettop (L) == 1) /* set to current date/time */
+ buf = NULL;
+ else {
+ utb.actime = luaL_optnumber (L, 2, 0);
+ utb.modtime = (time_t) luaL_optinteger (L, 3, utb.actime);
+ buf = &utb;
+ }
+ if (utime (file, buf)) {
+ lua_pushnil (L);
+ lua_pushfstring (L, "%s", strerror (errno));
+ return 2;
+ }
+ lua_pushboolean (L, 1);
+ return 1;
+}
+
+
+/* inode protection mode */
+static void push_st_mode (lua_State *L, STAT_STRUCT *info) {
+ lua_pushstring (L, mode2string (info->st_mode));
+}
+/* device inode resides on */
+static void push_st_dev (lua_State *L, STAT_STRUCT *info) {
+ lua_pushinteger (L, (lua_Integer) info->st_dev);
+}
+/* inode's number */
+static void push_st_ino (lua_State *L, STAT_STRUCT *info) {
+ lua_pushinteger (L, (lua_Integer) info->st_ino);
+}
+/* number of hard links to the file */
+static void push_st_nlink (lua_State *L, STAT_STRUCT *info) {
+ lua_pushinteger (L, (lua_Integer)info->st_nlink);
+}
+/* user-id of owner */
+static void push_st_uid (lua_State *L, STAT_STRUCT *info) {
+ lua_pushinteger (L, (lua_Integer)info->st_uid);
+}
+/* group-id of owner */
+static void push_st_gid (lua_State *L, STAT_STRUCT *info) {
+ lua_pushinteger (L, (lua_Integer)info->st_gid);
+}
+/* device type, for special file inode */
+static void push_st_rdev (lua_State *L, STAT_STRUCT *info) {
+ lua_pushinteger (L, (lua_Integer) info->st_rdev);
+}
+/* time of last access */
+static void push_st_atime (lua_State *L, STAT_STRUCT *info) {
+ lua_pushinteger (L, (lua_Integer) info->st_atime);
+}
+/* time of last data modification */
+static void push_st_mtime (lua_State *L, STAT_STRUCT *info) {
+ lua_pushinteger (L, (lua_Integer) info->st_mtime);
+}
+/* time of last file status change */
+static void push_st_ctime (lua_State *L, STAT_STRUCT *info) {
+ lua_pushinteger (L, (lua_Integer) info->st_ctime);
+}
+/* file size, in bytes */
+static void push_st_size (lua_State *L, STAT_STRUCT *info) {
+ lua_pushinteger (L, (lua_Integer)info->st_size);
+}
+#ifndef _WIN32
+/* blocks allocated for file */
+static void push_st_blocks (lua_State *L, STAT_STRUCT *info) {
+ lua_pushinteger (L, (lua_Integer)info->st_blocks);
+}
+/* optimal file system I/O blocksize */
+static void push_st_blksize (lua_State *L, STAT_STRUCT *info) {
+ lua_pushinteger (L, (lua_Integer)info->st_blksize);
+}
+#endif
+
+ /*
+** Convert the inode protection mode to a permission list.
+*/
+
+#ifdef _WIN32
+static const char *perm2string (unsigned short mode) {
+ static char perms[10] = "---------";
+ int i;
+ for (i=0;i<9;i++) perms[i]='-';
+ if (mode & _S_IREAD)
+ { perms[0] = 'r'; perms[3] = 'r'; perms[6] = 'r'; }
+ if (mode & _S_IWRITE)
+ { perms[1] = 'w'; perms[4] = 'w'; perms[7] = 'w'; }
+ if (mode & _S_IEXEC)
+ { perms[2] = 'x'; perms[5] = 'x'; perms[8] = 'x'; }
+ return perms;
+}
+#else
+static const char *perm2string (mode_t mode) {
+ static char perms[10] = "---------";
+ int i;
+ for (i=0;i<9;i++) perms[i]='-';
+ if (mode & S_IRUSR) perms[0] = 'r';
+ if (mode & S_IWUSR) perms[1] = 'w';
+ if (mode & S_IXUSR) perms[2] = 'x';
+ if (mode & S_IRGRP) perms[3] = 'r';
+ if (mode & S_IWGRP) perms[4] = 'w';
+ if (mode & S_IXGRP) perms[5] = 'x';
+ if (mode & S_IROTH) perms[6] = 'r';
+ if (mode & S_IWOTH) perms[7] = 'w';
+ if (mode & S_IXOTH) perms[8] = 'x';
+ return perms;
+}
+#endif
+
+/* permssions string */
+static void push_st_perm (lua_State *L, STAT_STRUCT *info) {
+ lua_pushstring (L, perm2string (info->st_mode));
+}
+
+typedef void (*_push_function) (lua_State *L, STAT_STRUCT *info);
+
+struct _stat_members {
+ const char *name;
+ _push_function push;
+};
+
+struct _stat_members members[] = {
+ { "mode", push_st_mode },
+ { "dev", push_st_dev },
+ { "ino", push_st_ino },
+ { "nlink", push_st_nlink },
+ { "uid", push_st_uid },
+ { "gid", push_st_gid },
+ { "rdev", push_st_rdev },
+ { "access", push_st_atime },
+ { "modification", push_st_mtime },
+ { "change", push_st_ctime },
+ { "size", push_st_size },
+ { "permissions", push_st_perm },
+#ifndef _WIN32
+ { "blocks", push_st_blocks },
+ { "blksize", push_st_blksize },
+#endif
+ { NULL, NULL }
+};
+
+/*
+** Get file or symbolic link information
+*/
+static int _file_info_ (lua_State *L, int (*st)(const char*, STAT_STRUCT*)) {
+ STAT_STRUCT info;
+ const char *file = luaL_checkstring (L, 1);
+ int i;
+
+ if (st(file, &info)) {
+ lua_pushnil (L);
+ lua_pushfstring (L, "cannot obtain information from file `%s'", file);
+ return 2;
+ }
+ if (lua_isstring (L, 2)) {
+ const char *member = lua_tostring (L, 2);
+ for (i = 0; members[i].name; i++) {
+ if (strcmp(members[i].name, member) == 0) {
+ /* push member value and return */
+ members[i].push (L, &info);
+ return 1;
+ }
+ }
+ /* member not found */
+ return luaL_error(L, "invalid attribute name");
+ }
+ /* creates a table if none is given */
+ if (!lua_istable (L, 2)) {
+ lua_newtable (L);
+ }
+ /* stores all members in table on top of the stack */
+ for (i = 0; members[i].name; i++) {
+ lua_pushstring (L, members[i].name);
+ members[i].push (L, &info);
+ lua_rawset (L, -3);
+ }
+ return 1;
+}
+
+
+/*
+** Get file information using stat.
+*/
+static int file_info (lua_State *L) {
+ return _file_info_ (L, STAT_FUNC);
+}
+
+
+/*
+** Get symbolic link information using lstat.
+*/
+static int link_info (lua_State *L) {
+ return _file_info_ (L, LSTAT_FUNC);
+}
+
+
+/*
+** Assumes the table is on top of the stack.
+*/
+static void set_info (lua_State *L) {
+ lua_pushliteral (L, "_COPYRIGHT");
+ lua_pushliteral (L, "Copyright (C) 2003-2012 Kepler Project");
+ lua_settable (L, -3);
+ lua_pushliteral (L, "_DESCRIPTION");
+ lua_pushliteral (L, "LuaFileSystem is a Lua library developed to complement the set of functions related to file systems offered by the standard Lua distribution");
+ lua_settable (L, -3);
+ lua_pushliteral (L, "_VERSION");
+ lua_pushliteral (L, "LuaFileSystem "LFS_VERSION);
+ lua_settable (L, -3);
+}
+
+
+static const struct luaL_Reg fslib[] = {
+ {"attributes", file_info},
+ {"chdir", change_dir},
+ {"currentdir", get_dir},
+ {"dir", dir_iter_factory},
+ {"link", make_link},
+ {"lock", file_lock},
+ {"mkdir", make_dir},
+ {"rmdir", remove_dir},
+ {"symlinkattributes", link_info},
+ {"setmode", lfs_f_setmode},
+ {"touch", file_utime},
+ {"unlock", file_unlock},
+ {"lock_dir", lfs_lock_dir},
+ {NULL, NULL},
+};
+
+int luaopen_lfs (lua_State *L) {
+ dir_create_meta (L);
+ lock_create_meta (L);
+ luaL_newlib (L, fslib);
+ lua_pushvalue(L, -1);
+ lua_setglobal(L, LFS_LIBNAME);
+ set_info (L);
+ return 1;
+}
diff --git a/3rdparty/luafilesystem/src/lfs.def b/3rdparty/luafilesystem/src/lfs.def
new file mode 100644
index 00000000000..6c782eb6968
--- /dev/null
+++ b/3rdparty/luafilesystem/src/lfs.def
@@ -0,0 +1,4 @@
+LIBRARY lfs.dll
+VERSION 1.6
+EXPORTS
+luaopen_lfs
diff --git a/3rdparty/luafilesystem/src/lfs.h b/3rdparty/luafilesystem/src/lfs.h
new file mode 100644
index 00000000000..ea1720dba75
--- /dev/null
+++ b/3rdparty/luafilesystem/src/lfs.h
@@ -0,0 +1,34 @@
+/*
+** LuaFileSystem
+** Copyright Kepler Project 2003 (http://www.keplerproject.org/luafilesystem)
+**
+** $Id: lfs.h,v 1.5 2008/02/19 20:08:23 mascarenhas Exp $
+*/
+
+/* Define 'chdir' for systems that do not implement it */
+#ifdef NO_CHDIR
+#define chdir(p) (-1)
+#define chdir_error "Function 'chdir' not provided by system"
+#else
+#define chdir_error strerror(errno)
+
+#endif
+
+#ifdef _WIN32
+#define chdir(p) (_chdir(p))
+#define getcwd(d, s) (_getcwd(d, s))
+#define rmdir(p) (_rmdir(p))
+#ifndef fileno
+#define fileno(f) (_fileno(f))
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int luaopen_lfs (lua_State *L);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/3rdparty/luafilesystem/tests/test.lua b/3rdparty/luafilesystem/tests/test.lua
new file mode 100644
index 00000000000..abfbd4d9690
--- /dev/null
+++ b/3rdparty/luafilesystem/tests/test.lua
@@ -0,0 +1,175 @@
+#!/usr/bin/env lua5.1
+
+local tmp = "/tmp"
+local sep = string.match (package.config, "[^\n]+")
+local upper = ".."
+
+local lfs = require"lfs"
+print (lfs._VERSION)
+
+io.write(".")
+io.flush()
+
+function attrdir (path)
+ for file in lfs.dir(path) do
+ if file ~= "." and file ~= ".." then
+ local f = path..sep..file
+ print ("\t=> "..f.." <=")
+ local attr = lfs.attributes (f)
+ assert (type(attr) == "table")
+ if attr.mode == "directory" then
+ attrdir (f)
+ else
+ for name, value in pairs(attr) do
+ print (name, value)
+ end
+ end
+ end
+ end
+end
+
+-- Checking changing directories
+local current = assert (lfs.currentdir())
+local reldir = string.gsub (current, "^.*%"..sep.."([^"..sep.."])$", "%1")
+assert (lfs.chdir (upper), "could not change to upper directory")
+assert (lfs.chdir (reldir), "could not change back to current directory")
+assert (lfs.currentdir() == current, "error trying to change directories")
+assert (lfs.chdir ("this couldn't be an actual directory") == nil, "could change to a non-existent directory")
+
+io.write(".")
+io.flush()
+
+-- Changing creating and removing directories
+local tmpdir = current..sep.."lfs_tmp_dir"
+local tmpfile = tmpdir..sep.."tmp_file"
+-- Test for existence of a previous lfs_tmp_dir
+-- that may have resulted from an interrupted test execution and remove it
+if lfs.chdir (tmpdir) then
+ assert (lfs.chdir (upper), "could not change to upper directory")
+ assert (os.remove (tmpfile), "could not remove file from previous test")
+ assert (lfs.rmdir (tmpdir), "could not remove directory from previous test")
+end
+
+io.write(".")
+io.flush()
+
+-- tries to create a directory
+assert (lfs.mkdir (tmpdir), "could not make a new directory")
+local attrib, errmsg = lfs.attributes (tmpdir)
+if not attrib then
+ error ("could not get attributes of file `"..tmpdir.."':\n"..errmsg)
+end
+local f = io.open(tmpfile, "w")
+f:close()
+
+io.write(".")
+io.flush()
+
+-- Change access time
+local testdate = os.time({ year = 2007, day = 10, month = 2, hour=0})
+assert (lfs.touch (tmpfile, testdate))
+local new_att = assert (lfs.attributes (tmpfile))
+assert (new_att.access == testdate, "could not set access time")
+assert (new_att.modification == testdate, "could not set modification time")
+
+io.write(".")
+io.flush()
+
+-- Change access and modification time
+local testdate1 = os.time({ year = 2007, day = 10, month = 2, hour=0})
+local testdate2 = os.time({ year = 2007, day = 11, month = 2, hour=0})
+
+assert (lfs.touch (tmpfile, testdate2, testdate1))
+local new_att = assert (lfs.attributes (tmpfile))
+assert (new_att.access == testdate2, "could not set access time")
+assert (new_att.modification == testdate1, "could not set modification time")
+
+io.write(".")
+io.flush()
+
+-- Checking link (does not work on Windows)
+if lfs.link (tmpfile, "_a_link_for_test_", true) then
+ assert (lfs.attributes"_a_link_for_test_".mode == "file")
+ assert (lfs.symlinkattributes"_a_link_for_test_".mode == "link")
+ assert (lfs.link (tmpfile, "_a_hard_link_for_test_"))
+ assert (lfs.attributes (tmpfile, "nlink") == 2)
+ assert (os.remove"_a_link_for_test_")
+ assert (os.remove"_a_hard_link_for_test_")
+end
+
+io.write(".")
+io.flush()
+
+-- Checking text/binary modes (only has an effect in Windows)
+local f = io.open(tmpfile, "w")
+local result, mode = lfs.setmode(f, "binary")
+assert(result) -- on non-Windows platforms, mode is always returned as "binary"
+result, mode = lfs.setmode(f, "text")
+assert(result and mode == "binary")
+f:close()
+
+io.write(".")
+io.flush()
+
+-- Restore access time to current value
+assert (lfs.touch (tmpfile, attrib.access, attrib.modification))
+new_att = assert (lfs.attributes (tmpfile))
+assert (new_att.access == attrib.access)
+assert (new_att.modification == attrib.modification)
+
+io.write(".")
+io.flush()
+
+-- Check consistency of lfs.attributes values
+local attr = lfs.attributes (tmpfile)
+for key, value in pairs(attr) do
+ assert (value == lfs.attributes (tmpfile, key),
+ "lfs.attributes values not consistent")
+end
+
+-- Remove new file and directory
+assert (os.remove (tmpfile), "could not remove new file")
+assert (lfs.rmdir (tmpdir), "could not remove new directory")
+assert (lfs.mkdir (tmpdir..sep.."lfs_tmp_dir") == nil, "could create a directory inside a non-existent one")
+
+io.write(".")
+io.flush()
+
+-- Trying to get attributes of a non-existent file
+assert (lfs.attributes ("this couldn't be an actual file") == nil, "could get attributes of a non-existent file")
+assert (type(lfs.attributes (upper)) == "table", "couldn't get attributes of upper directory")
+
+io.write(".")
+io.flush()
+
+-- Stressing directory iterator
+count = 0
+for i = 1, 4000 do
+ for file in lfs.dir (tmp) do
+ count = count + 1
+ end
+end
+
+io.write(".")
+io.flush()
+
+-- Stressing directory iterator, explicit version
+count = 0
+for i = 1, 4000 do
+ local iter, dir = lfs.dir(tmp)
+ local file = dir:next()
+ while file do
+ count = count + 1
+ file = dir:next()
+ end
+ assert(not pcall(dir.next, dir))
+end
+
+io.write(".")
+io.flush()
+
+-- directory explicit close
+local iter, dir = lfs.dir(tmp)
+dir:close()
+assert(not pcall(dir.next, dir))
+print"Ok!"
diff --git a/3rdparty/luafilesystem/vc6/lfs.def b/3rdparty/luafilesystem/vc6/lfs.def
new file mode 100644
index 00000000000..55ec688d3c3
--- /dev/null
+++ b/3rdparty/luafilesystem/vc6/lfs.def
@@ -0,0 +1,5 @@
+LIBRARY lfs.dll
+DESCRIPTION "LuaFileSystem"
+VERSION 1.2
+EXPORTS
+luaopen_lfs
diff --git a/3rdparty/luafilesystem/vc6/luafilesystem.dsw b/3rdparty/luafilesystem/vc6/luafilesystem.dsw
new file mode 100644
index 00000000000..b4bb4b310f6
--- /dev/null
+++ b/3rdparty/luafilesystem/vc6/luafilesystem.dsw
@@ -0,0 +1,33 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "luafilesystem_dll"=.\luafilesystem_dll.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+ begin source code control
+ luafilesystem
+ ..
+ end source code control
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/3rdparty/luafilesystem/vc6/luafilesystem_dll.dsp b/3rdparty/luafilesystem/vc6/luafilesystem_dll.dsp
new file mode 100644
index 00000000000..efe6c720b6c
--- /dev/null
+++ b/3rdparty/luafilesystem/vc6/luafilesystem_dll.dsp
@@ -0,0 +1,127 @@
+# Microsoft Developer Studio Project File - Name="luafilesystem_dll" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=luafilesystem_dll - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "luafilesystem_dll.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "luafilesystem_dll.mak" CFG="luafilesystem_dll - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "luafilesystem_dll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "luafilesystem_dll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName "luafilesystem_dll"
+# PROP Scc_LocalPath ".."
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "luafilesystem_dll - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "../lib/vc6"
+# PROP Intermediate_Dir "luafilesystem_dll/Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LUAFILESYSTEM_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../external-src/lua50/include" /I "../../compat/src" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LUAFILESYSTEM_EXPORTS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x416 /d "NDEBUG"
+# ADD RSC /l 0x416 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 lua50.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"../bin/vc6/lfs.dll" /libpath:"../../external-src/lua50/lib/dll"
+# Begin Special Build Tool
+SOURCE="$(InputPath)"
+PostBuild_Cmds=cd ../bin/vc6 zip.exe luafilesystem-1.2-win32.zip lfs.dll
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "luafilesystem_dll - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "../lib/vc6"
+# PROP Intermediate_Dir "luafilesystem_dll/Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LUAFILESYSTEM_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../external-src/lua50/include" /I "../../compat/src" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LUAFILESYSTEM_EXPORTS" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x416 /d "_DEBUG"
+# ADD RSC /l 0x416 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 lua50.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"../bin/vc6/lfsd.dll" /pdbtype:sept /libpath:"../../external-src/lua50/lib/dll"
+
+!ENDIF
+
+# Begin Target
+
+# Name "luafilesystem_dll - Win32 Release"
+# Name "luafilesystem_dll - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE="..\..\compat\src\compat-5.1.c"
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\lfs.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\lfs.def
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE="..\..\compat\src\compat-5.1.h"
+# End Source File
+# Begin Source File
+
+SOURCE=..\src\lfs.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/3rdparty/luv/.ci/install.bat b/3rdparty/luv/.ci/install.bat
new file mode 100644
index 00000000000..1ee346dccc9
--- /dev/null
+++ b/3rdparty/luv/.ci/install.bat
@@ -0,0 +1,270 @@
+@echo off
+
+cd %APPVEYOR_BUILD_FOLDER%
+
+:: =========================================================
+:: Set some defaults. Infer some variables.
+::
+:: These are set globally
+if "%LUA_VER%" NEQ "" (
+ set LUA=lua
+ set LUA_SHORTV=%LUA_VER:~0,3%
+) else (
+ set LUA=luajit
+ set LJ_SHORTV=%LJ_VER:~0,3%
+ set LUA_SHORTV=5.1
+)
+
+:: defines LUA_DIR so Cmake can find this Lua install
+if "%LUA%"=="luajit" (
+ set LUA_DIR=c:\lua\%platform%\lj%LJ_SHORTV%
+) else (
+ set LUA_DIR=c:\lua\%platform%\%LUA_VER%
+)
+
+:: Now we declare a scope
+Setlocal EnableDelayedExpansion EnableExtensions
+
+if not defined LUAROCKS_URL set LUAROCKS_URL=http://keplerproject.github.io/luarocks/releases
+if not defined LUAROCKS_REPO set LUAROCKS_REPO=https://luarocks.org
+if not defined LUA_URL set LUA_URL=http://www.lua.org/ftp
+if defined NOCOMPAT (
+ set COMPATFLAG=--nocompat
+) else (
+ set COMPATFLAG=
+)
+if not defined LUAJIT_GIT_REPO set LUAJIT_GIT_REPO=https://github.com/LuaJIT/LuaJIT.git
+if not defined LUAJIT_URL set LUAJIT_URL=https://github.com/LuaJIT/LuaJIT/archive
+
+if not defined LR_EXTERNAL set LR_EXTERNAL=c:\external
+if not defined LUAROCKS_INSTALL set LUAROCKS_INSTALL=%LUA_DIR%\LuaRocks
+
+
+:: LuaRocks <= 2.2.2 used a versioned directory
+:: HEAD and newer versions do not, so act accordingly.
+if defined LR_ROOT goto :skiplrver
+
+if "%LUAROCKS_VER%" EQU "HEAD" (
+ set LR_ROOT=%LUAROCKS_INSTALL%
+ goto :skiplrver
+)
+set LR_ROOT=%LUAROCKS_INSTALL%
+if %LUAROCKS_VER:~0,1% LEQ 2 (
+ if %LUAROCKS_VER:~2,1% LEQ 2 (
+ if %LUAROCKS_VER:~4,1% LEQ 3 (
+ set LR_ROOT=%LUAROCKS_INSTALL%\!LUAROCKS_VER:~0,3!
+ )
+ )
+)
+:skiplrver
+
+if not defined LR_SYSTREE set LR_SYSTREE=%LUAROCKS_INSTALL%\systree
+
+if not defined SEVENZIP set SEVENZIP=7z
+::
+:: =========================================================
+
+:: first create some necessary directories:
+mkdir downloads 2>NUL
+
+:: Download and compile Lua (or LuaJIT)
+if "%LUA%"=="luajit" (
+ if not exist %LUA_DIR% (
+ if "%LJ_SHORTV%"=="2.1" (
+ :: Clone repository and checkout 2.1 branch
+ set lj_source_folder=%APPVEYOR_BUILD_FOLDER%\downloads\luajit-%LJ_VER%
+ if not exist !lj_source_folder! (
+ echo Cloning git repo %LUAJIT_GIT_REPO% !lj_source_folder!
+ git clone %LUAJIT_GIT_REPO% !lj_source_folder! || call :die "Failed to clone repository"
+ ) else (
+ cd !lj_source_folder!
+ git pull || call :die "Failed to update repository"
+ )
+ cd !lj_source_folder!\src
+ git checkout v2.1 || call :die
+ ) else (
+ set lj_source_folder=%APPVEYOR_BUILD_FOLDER%\downloads\luajit-%LJ_VER%
+ if not exist !lj_source_folder! (
+ echo Downloading... %LUAJIT_URL%/v%LJ_VER%.tar.gz
+ curl --location --silent --fail --max-time 120 --connect-timeout 30 %LUAJIT_URL%/v%LJ_VER%.tar.gz | %SEVENZIP% x -si -so -tgzip | %SEVENZIP% x -si -ttar -aoa -odownloads
+ )
+ cd !lj_source_folder!\src
+ )
+ :: Compiles LuaJIT
+ if "%Configuration%"=="MinGW" (
+ call mingw32-make
+ ) else (
+ call msvcbuild.bat
+ )
+
+ mkdir %LUA_DIR% 2> NUL
+ for %%a in (bin bin\lua bin\lua\jit include lib) do ( mkdir "%LUA_DIR%\%%a" )
+
+ for %%a in (luajit.exe lua51.dll) do ( move "!lj_source_folder!\src\%%a" "%LUA_DIR%\bin" )
+ copy "%LUA_DIR%\bin\luajit.exe" "%LUA_DIR%\bin\lua.exe"
+
+ move "!lj_source_folder!\src\lua51.lib" "%LUA_DIR%\lib"
+ for %%a in (lauxlib.h lua.h lua.hpp luaconf.h lualib.h luajit.h) do (
+ copy "!lj_source_folder!\src\%%a" "%LUA_DIR%\include"
+ )
+
+ copy "!lj_source_folder!\src\jit\*.lua" "%LUA_DIR%\bin\lua\jit"
+
+ ) else (
+ echo LuaJIT %LJ_VER% already installed at %LUA_DIR%
+ )
+) else (
+ if not exist %LUA_DIR% (
+ :: Download and compile Lua
+ if not exist downloads\lua-%LUA_VER% (
+ curl --silent --fail --max-time 120 --connect-timeout 30 %LUA_URL%/lua-%LUA_VER%.tar.gz | %SEVENZIP% x -si -so -tgzip | %SEVENZIP% x -si -ttar -aoa -odownloads
+ )
+
+ mkdir downloads\lua-%LUA_VER%\etc 2> NUL
+ copy %~dp0\winmake.bat downloads\lua-%LUA_VER%\etc\winmake.bat
+
+ cd downloads\lua-%LUA_VER%
+ call etc\winmake %COMPATFLAG%
+ call etc\winmake install %LUA_DIR%
+ ) else (
+ echo Lua %LUA_VER% already installed at %LUA_DIR%
+ )
+)
+
+if not exist %LUA_DIR%\bin\%LUA%.exe call :die "Missing Lua interpreter at %LUA_DIR%\bin\%LUA%.exe"
+
+set PATH=%LUA_DIR%\bin;%PATH%
+call !LUA! -v
+
+
+
+:: ==========================================================
+:: LuaRocks
+:: ==========================================================
+
+if not exist "%LR_ROOT%" (
+ :: Downloads and installs LuaRocks
+ cd %APPVEYOR_BUILD_FOLDER%
+
+ if %LUAROCKS_VER%==HEAD (
+ set lr_source_folder=%APPVEYOR_BUILD_FOLDER%\downloads\luarocks-%LUAROCKS_VER%-win32
+ if not exist !lr_source_folder! (
+ git clone https://github.com/keplerproject/luarocks.git --single-branch --depth 1 !lr_source_folder! || call :die "Failed to clone LuaRocks repository"
+ ) else (
+ cd !lr_source_folder!
+ git pull || call :die "Failed to update LuaRocks repository"
+ )
+ ) else (
+ if not exist downloads\luarocks-%LUAROCKS_VER%-win32.zip (
+ echo Downloading LuaRocks...
+ curl --silent --fail --max-time 120 --connect-timeout 30 --output downloads\luarocks-%LUAROCKS_VER%-win32.zip %LUAROCKS_URL%/luarocks-%LUAROCKS_VER%-win32.zip
+ %SEVENZIP% x -aoa -odownloads downloads\luarocks-%LUAROCKS_VER%-win32.zip
+ )
+ )
+
+ cd downloads\luarocks-%LUAROCKS_VER%-win32
+ if "%Configuration%"=="MinGW" (
+ call install.bat /LUA %LUA_DIR% /Q /LV %LUA_SHORTV% /P "%LUAROCKS_INSTALL%" /TREE "%LR_SYSTREE%" /MW
+ ) else (
+ call install.bat /LUA %LUA_DIR% /Q /LV %LUA_SHORTV% /P "%LUAROCKS_INSTALL%" /TREE "%LR_SYSTREE%"
+ )
+
+ :: Configures LuaRocks to instruct CMake the correct generator to use. Else, CMake will pick the highest
+ :: Visual Studio version installed
+ if "%Configuration%"=="MinGW" (
+ echo cmake_generator = "MinGW Makefiles" >> %LUAROCKS_INSTALL%\config-%LUA_SHORTV%.lua
+ ) else (
+ set MSVS_GENERATORS[2008]=Visual Studio 9 2008
+ set MSVS_GENERATORS[2010]=Visual Studio 10 2010
+ set MSVS_GENERATORS[2012]=Visual Studio 11 2012
+ set MSVS_GENERATORS[2013]=Visual Studio 12 2013
+ set MSVS_GENERATORS[2015]=Visual Studio 14 2015
+
+ set CMAKE_GENERATOR=!MSVS_GENERATORS[%Configuration%]!
+ if "%platform%" EQU "x64" (set CMAKE_GENERATOR=!CMAKE_GENERATOR! Win64)
+
+ echo cmake_generator = "!CMAKE_GENERATOR!" >> %LUAROCKS_INSTALL%\config-%LUA_SHORTV%.lua
+ )
+)
+
+if not exist "%LR_ROOT%" call :die "LuaRocks not found at %LR_ROOT%"
+
+set PATH=%LR_ROOT%;%LR_SYSTREE%\bin;%PATH%
+
+:: Lua will use just the system rocks
+set LUA_PATH=%LR_ROOT%\lua\?.lua;%LR_ROOT%\lua\?\init.lua
+set LUA_PATH=%LUA_PATH%;%LR_SYSTREE%\share\lua\%LUA_SHORTV%\?.lua
+set LUA_PATH=%LUA_PATH%;%LR_SYSTREE%\share\lua\%LUA_SHORTV%\?\init.lua
+set LUA_PATH=%LUA_PATH%;.\?.lua;.\?\init.lua
+set LUA_CPATH=%LR_SYSTREE%\lib\lua\%LUA_SHORTV%\?.dll;.\?.dll
+
+call luarocks --version || call :die "Error with LuaRocks installation"
+call luarocks list
+
+
+if not exist "%LR_EXTERNAL%" (
+ mkdir "%LR_EXTERNAL%"
+ mkdir "%LR_EXTERNAL%\lib"
+ mkdir "%LR_EXTERNAL%\include"
+)
+
+set PATH=%LR_EXTERNAL%;%PATH%
+
+:: Exports the following variables:
+:: (beware of whitespace between & and ^ below)
+endlocal & set PATH=%PATH%&^
+set LR_SYSTREE=%LR_SYSTREE%&^
+set LUA_PATH=%LUA_PATH%&^
+set LUA_CPATH=%LUA_CPATH%&^
+set LR_EXTERNAL=%LR_EXTERNAL%
+
+echo.
+echo ======================================================
+if "%LUA%"=="luajit" (
+ echo Installation of LuaJIT %LJ_VER% and LuaRocks %LUAROCKS_VER% done.
+) else (
+ echo Installation of Lua %LUA_VER% and LuaRocks %LUAROCKS_VER% done.
+ if defined NOCOMPAT echo Lua was built with compatibility flags disabled.
+)
+echo Platform - %platform%
+echo LUA - %LUA%
+echo LUA_SHORTV - %LUA_SHORTV%
+echo LJ_SHORTV - %LJ_SHORTV%
+echo LUA_PATH - %LUA_PATH%
+echo LUA_CPATH - %LUA_CPATH%
+echo.
+echo LR_EXTERNAL - %LR_EXTERNAL%
+echo ======================================================
+echo.
+
+goto :eof
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+:: This blank space is intentional. If you see errors like "The system cannot find the batch label specified 'foo'"
+:: then try adding or removing blank lines lines above.
+:: Yes, really.
+:: http://stackoverflow.com/questions/232651/why-the-system-cannot-find-the-batch-label-specified-is-thrown-even-if-label-e
+
+:: helper functions:
+
+:: for bailing out when an error occurred
+:die %1
+echo %1
+exit /B 1
+goto :eof
diff --git a/3rdparty/luv/.ci/platform.sh b/3rdparty/luv/.ci/platform.sh
new file mode 100644
index 00000000000..7259a7d6369
--- /dev/null
+++ b/3rdparty/luv/.ci/platform.sh
@@ -0,0 +1,15 @@
+if [ -z "${PLATFORM:-}" ]; then
+ PLATFORM=$TRAVIS_OS_NAME;
+fi
+
+if [ "$PLATFORM" == "osx" ]; then
+ PLATFORM="macosx";
+fi
+
+if [ -z "$PLATFORM" ]; then
+ if [ "$(uname)" == "Linux" ]; then
+ PLATFORM="linux";
+ else
+ PLATFORM="macosx";
+ fi;
+fi
diff --git a/3rdparty/luv/.ci/set_compiler_env.bat b/3rdparty/luv/.ci/set_compiler_env.bat
new file mode 100644
index 00000000000..7e8462ec57e
--- /dev/null
+++ b/3rdparty/luv/.ci/set_compiler_env.bat
@@ -0,0 +1,40 @@
+@echo off
+
+:: Now we declare a scope
+Setlocal EnableDelayedExpansion EnableExtensions
+
+if not defined Configuration set Configuration=2015
+
+if "%Configuration%"=="MinGW" ( goto :mingw )
+
+set arch=x86
+
+if "%platform%" EQU "x64" ( set arch=x86_amd64 )
+
+if "%Configuration%"=="2015" (
+ set SET_VS_ENV="C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
+)
+
+if "%Configuration%"=="2013" (
+ set SET_VS_ENV="C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"
+)
+
+if "%Configuration%"=="2012" (
+ set SET_VS_ENV="C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"
+)
+
+if "%Configuration%"=="2010" (
+ set SET_VS_ENV="C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"
+)
+
+if "%Configuration%"=="2008" (
+ set SET_VS_ENV="C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"
+)
+
+:: Visual Studio detected
+endlocal & call %SET_VS_ENV% %arch%
+goto :eof
+
+:: MinGW detected
+:mingw
+endlocal & set PATH=c:\mingw\bin;%PATH%
diff --git a/3rdparty/luv/.ci/setenv_lua.sh b/3rdparty/luv/.ci/setenv_lua.sh
new file mode 100644
index 00000000000..55454389398
--- /dev/null
+++ b/3rdparty/luv/.ci/setenv_lua.sh
@@ -0,0 +1,3 @@
+export PATH=${PATH}:$HOME/.lua:$HOME/.local/bin:${TRAVIS_BUILD_DIR}/install/luarocks/bin
+bash .ci/setup_lua.sh
+eval `$HOME/.lua/luarocks path`
diff --git a/3rdparty/luv/.ci/setup_lua.sh b/3rdparty/luv/.ci/setup_lua.sh
new file mode 100644
index 00000000000..f8963331767
--- /dev/null
+++ b/3rdparty/luv/.ci/setup_lua.sh
@@ -0,0 +1,122 @@
+#! /bin/bash
+
+# A script for setting up environment for travis-ci testing.
+# Sets up Lua and Luarocks.
+# LUA must be "lua5.1", "lua5.2" or "luajit".
+# luajit2.0 - master v2.0
+# luajit2.1 - master v2.1
+
+set -eufo pipefail
+
+LUAJIT_VERSION="2.0.4"
+LUAJIT_BASE="LuaJIT-$LUAJIT_VERSION"
+
+source .ci/platform.sh
+
+LUA_HOME_DIR=$TRAVIS_BUILD_DIR/install/lua
+
+LR_HOME_DIR=$TRAVIS_BUILD_DIR/install/luarocks
+
+mkdir $HOME/.lua
+
+LUAJIT="no"
+
+if [ "$PLATFORM" == "macosx" ]; then
+ if [ "$LUA" == "luajit" ]; then
+ LUAJIT="yes";
+ fi
+ if [ "$LUA" == "luajit2.0" ]; then
+ LUAJIT="yes";
+ fi
+ if [ "$LUA" == "luajit2.1" ]; then
+ LUAJIT="yes";
+ fi;
+elif [ "$(expr substr $LUA 1 6)" == "luajit" ]; then
+ LUAJIT="yes";
+fi
+
+mkdir -p "$LUA_HOME_DIR"
+
+if [ "$LUAJIT" == "yes" ]; then
+
+ if [ "$LUA" == "luajit" ]; then
+ curl --location https://github.com/LuaJIT/LuaJIT/archive/v$LUAJIT_VERSION.tar.gz | tar xz;
+ else
+ git clone https://github.com/LuaJIT/LuaJIT.git $LUAJIT_BASE;
+ fi
+
+ cd $LUAJIT_BASE
+
+ if [ "$LUA" == "luajit2.1" ]; then
+ git checkout v2.1;
+ # force the INSTALL_TNAME to be luajit
+ perl -i -pe 's/INSTALL_TNAME=.+/INSTALL_TNAME= luajit/' Makefile
+ fi
+
+ make && make install PREFIX="$LUA_HOME_DIR"
+
+ ln -s $LUA_HOME_DIR/bin/luajit $HOME/.lua/luajit
+ ln -s $LUA_HOME_DIR/bin/luajit $HOME/.lua/lua;
+
+else
+
+ if [ "$LUA" == "lua5.1" ]; then
+ curl http://www.lua.org/ftp/lua-5.1.5.tar.gz | tar xz
+ cd lua-5.1.5;
+ elif [ "$LUA" == "lua5.2" ]; then
+ curl http://www.lua.org/ftp/lua-5.2.4.tar.gz | tar xz
+ cd lua-5.2.4;
+ elif [ "$LUA" == "lua5.3" ]; then
+ curl http://www.lua.org/ftp/lua-5.3.2.tar.gz | tar xz
+ cd lua-5.3.2;
+ fi
+
+ # Build Lua without backwards compatibility for testing
+ perl -i -pe 's/-DLUA_COMPAT_(ALL|5_2)//' src/Makefile
+ make $PLATFORM
+ make INSTALL_TOP="$LUA_HOME_DIR" install;
+
+ ln -s $LUA_HOME_DIR/bin/lua $HOME/.lua/lua
+ ln -s $LUA_HOME_DIR/bin/luac $HOME/.lua/luac;
+
+fi
+
+cd $TRAVIS_BUILD_DIR
+
+lua -v
+
+LUAROCKS_BASE=luarocks-$LUAROCKS
+
+curl --location http://luarocks.org/releases/$LUAROCKS_BASE.tar.gz | tar xz
+
+cd $LUAROCKS_BASE
+
+if [ "$LUA" == "luajit" ]; then
+ ./configure --lua-suffix=jit --with-lua-include="$LUA_HOME_DIR/include/luajit-2.0" --prefix="$LR_HOME_DIR";
+elif [ "$LUA" == "luajit2.0" ]; then
+ ./configure --lua-suffix=jit --with-lua-include="$LUA_HOME_DIR/include/luajit-2.0" --prefix="$LR_HOME_DIR";
+elif [ "$LUA" == "luajit2.1" ]; then
+ ./configure --lua-suffix=jit --with-lua-include="$LUA_HOME_DIR/include/luajit-2.1" --prefix="$LR_HOME_DIR";
+else
+ ./configure --with-lua="$LUA_HOME_DIR" --prefix="$LR_HOME_DIR"
+fi
+
+make build && make install
+
+ln -s $LR_HOME_DIR/bin/luarocks $HOME/.lua/luarocks
+
+cd $TRAVIS_BUILD_DIR
+
+luarocks --version
+
+rm -rf $LUAROCKS_BASE
+
+if [ "$LUAJIT" == "yes" ]; then
+ rm -rf $LUAJIT_BASE;
+elif [ "$LUA" == "lua5.1" ]; then
+ rm -rf lua-5.1.5;
+elif [ "$LUA" == "lua5.2" ]; then
+ rm -rf lua-5.2.4;
+elif [ "$LUA" == "lua5.3" ]; then
+ rm -rf lua-5.3.2;
+fi
diff --git a/3rdparty/luv/.ci/winmake.bat b/3rdparty/luv/.ci/winmake.bat
new file mode 100644
index 00000000000..dcad55d36f7
--- /dev/null
+++ b/3rdparty/luv/.ci/winmake.bat
@@ -0,0 +1,457 @@
+@ECHO OFF
+SETLOCAL ENABLEDELAYEDEXPANSION
+
+REM *****************************
+REM * Customization section *
+REM *****************************
+
+REM use the /help option for generic usage information
+
+REM Where is the source code located (the unpacked Lua source archive, toplevel dir)
+SET SOURCETREE=.\
+
+REM set the toolchain to either MS or GCC (allcaps), leave blank to autodetect
+SET TOOLCHAIN=
+
+REM set the compatibility flags, defaults to empty for 5.1, -DLUA_COMPAT_ALL for 5.2,
+REM and -DLUA_COMPAT_5_2 for 5.3, which are the same as the unix make files
+REM This setting can be overridden with the --nocompat flag
+SET COMPATFLAG=
+
+
+
+
+
+
+
+
+
+REM **********************************
+REM * Nothing to customize below *
+REM **********************************
+
+SET BATCHNAME=%~n0
+SET SOURCE=%SOURCETREE%src\
+SET LUA_H=%SOURCE%lua.h
+SET CURDIR=%CD%
+
+REM the following line ends with a TAB. DO NOT REMOVE IT!
+SET TABCHAR=
+REM Define LF to contain a linefeed character
+set ^"LFCHAR=^
+
+^" The above empty line is critical. DO NOT REMOVE
+
+
+REM Supported toolchains (allcaps)
+SET TOOLCHAINS=MS GCC
+REM Commands which, if exiting without error, indicate presence of the toolchain
+SET CHECK_GCC=gcc --version
+SET CHECK_MS=cl
+
+REM **********************************
+REM * Check for help request *
+REM **********************************
+
+SET HELPCMDS=help -help --help /help ? -? /?
+for %%L in ("!LFCHAR!") do for /f %%a in ("!HELPCMDS: =%%~L!") do (
+ if "%%a"=="%~1" (
+ echo.
+ echo Builds a standalone Lua installation. Supports Lua version 5.1, 5.2 and 5.3.
+ echo Your compiler must be in the system path, and this "%BATCHNAME%.bat" file must be located
+ echo in ".\etc\" in the unpacked Lua source archive.
+ echo.
+ echo USAGE etc\%BATCHNAME% [FLAG] [COMMAND] [...]
+ echo ^(execute from the root of the unpacked archive^)
+ echo.
+ echo Commands;
+ echo clean : cleans the source tree of build ^(intermediate^) files
+ echo install [path] : installs the build results into "path"
+ echo local : installs into ".\local\" in the unpacked Lua source structure
+ echo [toolchain] : uses a specific toolchain to build. If not provided then supported
+ echo toolchains will be tested and the first available will be picked.
+ echo Supported toolchains are: "%TOOLCHAINS%" ^(must use ALLCAPS^)
+ echo.
+ echo Flags;
+ echo --nocompat : Specifies that no compatibility flags should be set when building.
+ echo If not specified, the default compatibility flags will be used.
+ echo.
+ echo Example use;
+ echo set PATH=C:\path\to\your\compiler\;%%PATH%%
+ echo etc\%BATCHNAME% clean
+ echo etc\%BATCHNAME%
+ echo etc\%BATCHNAME% --nocompat GCC
+ echo etc\%BATCHNAME% install "C:\Program Files\Lua"
+ echo.
+ goto :EXITOK
+ )
+)
+
+REM **********************************
+REM * Check commandline *
+REM **********************************
+
+SET CMDOK=FALSE
+if "%~1"=="" (
+ SET CMDOK=TRUE
+)
+for %%a in (local install clean) do (
+ if "%%a"=="%~1" (
+ SET CMDOK=TRUE
+ )
+)
+for %%a in (--nocompat) do (
+ if "%%a"=="%~1" (
+ SET NOCOMPAT=TRUE
+ if "%~2"=="" (
+ SET CMDOK=TRUE
+ )
+ SHIFT
+ )
+)
+for %%a in (%TOOLCHAINS%) do (
+ if "%%a"=="%~1" (
+ SET CMDOK=TRUE
+ SET TOOLCHAIN=%~1
+ )
+)
+if NOT %CMDOK%==TRUE (
+ echo.
+ echo Unknown command or toolchain specified.
+ goto :EXITERROR
+)
+
+REM **************************************
+REM * Check for cleaning *
+REM **************************************
+
+if "%1"=="clean" (
+ if NOT [%2]==[] (
+ echo.
+ echo ERROR: The clean command does not take extra parameters.
+ ) else (
+ echo Cleaning...
+ if exist "%SOURCE%*.exe" del "%SOURCE%*.exe"
+ if exist "%SOURCE%*.dll" del "%SOURCE%*.dll"
+ if exist "%SOURCE%*.o" del "%SOURCE%*.o"
+ if exist "%SOURCE%*.a" del "%SOURCE%*.a"
+ if exist "%SOURCE%*.obj" del "%SOURCE%*.obj"
+ if exist "%SOURCE%*.manifest" del "%SOURCE%*.manifest"
+ if exist "%SOURCE%*.lib" del "%SOURCE%*.lib"
+ echo Done.
+ )
+ goto :EXITOK
+)
+
+REM **************************************************
+REM * Fetch the Lua version from the source code *
+REM **************************************************
+
+Echo.
+Echo Checking source code to extract Lua version...
+IF NOT EXIST %LUA_H% (
+ Echo Cannot locate Lua header file; %LUA_H%
+ goto :EXITERROR
+)
+
+findstr /R /C:"#define[ %TABCHAR%][ %TABCHAR%]*LUA_VERSION_MAJOR" %LUA_H% > NUL
+if NOT %ERRORLEVEL%==0 (
+ rem ECHO We've got a Lua version 5.1
+ rem findstr /R /C:"#define[ %TABCHAR%][ %TABCHAR%]*LUA_VERSION[ %TABCHAR%]" %LUA_H%
+ SET LUA_VER=5.1
+) else (
+ rem ECHO We've got a Lua version 5.2+
+ rem findstr /R /C:"#define[ %TABCHAR%][ %TABCHAR%]*LUA_VERSION_MAJOR[ %TABCHAR%]" %LUA_H%
+ rem findstr /R /C:"#define[ %TABCHAR%][ %TABCHAR%]*LUA_VERSION_MINOR[ %TABCHAR%]" %LUA_H%
+
+ for /F "delims=" %%a in ('findstr /R /C:"#define[ %TABCHAR%][ %TABCHAR%]*LUA_VERSION_MAJOR[ %TABCHAR%]" %LUA_H%') do set LUA_MAJOR=%%a
+ SET LUA_MAJOR=!LUA_MAJOR:#define=!
+ SET LUA_MAJOR=!LUA_MAJOR:LUA_VERSION_MAJOR=!
+ SET LUA_MAJOR=!LUA_MAJOR: =!
+ SET LUA_MAJOR=!LUA_MAJOR:%TABCHAR%=!
+ SET LUA_MAJOR=!LUA_MAJOR:"=!
+ SET LUA_MAJOR=!LUA_MAJOR:~0,1!
+
+ for /F "delims=" %%a in ('findstr /R /C:"#define[ %TABCHAR%][ %TABCHAR%]*LUA_VERSION_MINOR[ %TABCHAR%]" %LUA_H%') do set LUA_MINOR=%%a
+ SET LUA_MINOR=!LUA_MINOR:#define=!
+ SET LUA_MINOR=!LUA_MINOR:LUA_VERSION_MINOR=!
+ SET LUA_MINOR=!LUA_MINOR: =!
+ SET LUA_MINOR=!LUA_MINOR:%TABCHAR%=!
+ SET LUA_MINOR=!LUA_MINOR:"=!
+ SET LUA_MINOR=!LUA_MINOR:~0,1!
+
+ SET LUA_VER=!LUA_MAJOR!.!LUA_MINOR!
+)
+SET LUA_SVER=!LUA_VER:.=!
+
+Echo Lua version found: %LUA_VER%
+Echo.
+
+REM **************************************
+REM * Set some Lua version specifics *
+REM **************************************
+
+REM FILES_CORE; files for Lua core (+lauxlib, needed for Luac)
+REM FILES_LIB; files for Lua standard libraries
+REM FILES_DLL; vm files to be build with dll option
+REM FILES_OTH; vm files to be build without dll, for static linking
+
+if %LUA_SVER%==51 (
+ set FILES_CORE=lapi lcode ldebug ldo ldump lfunc lgc llex lmem lobject lopcodes lparser lstate lstring ltable ltm lundump lvm lzio lauxlib
+ set FILES_LIB=lbaselib ldblib liolib lmathlib loslib ltablib lstrlib loadlib linit
+ set FILES_DLL=lua
+ set FILES_OTH=luac print
+ set INSTALL_H=lauxlib.h lua.h luaconf.h lualib.h ..\etc\lua.hpp
+)
+if %LUA_SVER%==52 (
+ set FILES_CORE=lapi lcode lctype ldebug ldo ldump lfunc lgc llex lmem lobject lopcodes lparser lstate lstring ltable ltm lundump lvm lzio lauxlib
+ set FILES_LIB=lbaselib lbitlib lcorolib ldblib liolib lmathlib loslib lstrlib ltablib loadlib linit
+ set FILES_DLL=lua
+ set FILES_OTH=luac
+ set INSTALL_H=lauxlib.h lua.h lua.hpp luaconf.h lualib.h
+ if "%COMPATFLAG%"=="" (
+ set COMPATFLAG=-DLUA_COMPAT_ALL
+ )
+)
+if %LUA_SVER%==53 (
+ set FILES_CORE=lapi lcode lctype ldebug ldo ldump lfunc lgc llex lmem lobject lopcodes lparser lstate lstring ltable ltm lundump lvm lzio lauxlib
+ set FILES_LIB=lbaselib lbitlib lcorolib ldblib liolib lmathlib loslib lstrlib ltablib lutf8lib loadlib linit
+ set FILES_DLL=lua
+ set FILES_OTH=luac
+ set INSTALL_H=lauxlib.h lua.h lua.hpp luaconf.h lualib.h
+ if "%COMPATFLAG%"=="" (
+ set COMPATFLAG=-DLUA_COMPAT_5_2
+ )
+)
+
+if "%NOCOMPAT%"=="TRUE" (
+ set COMPATFLAG=
+)
+
+SET FILES_BASE=%FILES_DLL% %FILES_CORE% %FILES_LIB%
+
+if "%FILES_BASE%"=="" (
+ Echo Unknown Lua version; %LUA_VER%
+ goto :EXITERROR
+)
+
+REM *********************************
+REM * Check available toolchain *
+REM *********************************
+
+if [%TOOLCHAIN%]==[] (
+ Echo Testing for MS...
+ %CHECK_MS%
+ IF !ERRORLEVEL!==0 SET TOOLCHAIN=MS
+)
+if [%TOOLCHAIN%]==[] (
+ Echo Testing for GCC...
+ %CHECK_GCC%
+ IF !ERRORLEVEL!==0 SET TOOLCHAIN=GCC
+)
+if [%TOOLCHAIN%]==[] (
+ Echo No supported toolchain found ^(please make sure it is in the system path^)
+ goto :EXITERROR
+)
+
+REM ***************************
+REM * Configure toolchain *
+REM ***************************
+
+if %TOOLCHAIN%==GCC (
+ echo Using GCC toolchain...
+ SET OBJEXT=o
+ SET LIBFILE=liblua%LUA_SVER%.a
+)
+if %TOOLCHAIN%==MS (
+ echo Using Microsoft toolchain...
+ SET OBJEXT=obj
+ SET LIBFILE=lua%LUA_SVER%.lib
+)
+echo.
+
+REM **************************************
+REM * Check for installing *
+REM **************************************
+
+if "%1"=="install" (
+ if "%~2"=="" (
+ echo.
+ echo ERROR: The install command requires a path where to install to.
+ goto :EXITERROR
+ )
+ SET TARGETPATH=%~2
+)
+if "%1"=="local" (
+ if NOT "%~2"=="" (
+ echo.
+ echo ERROR: The local command does not take extra parameters.
+ goto :EXITERROR
+ )
+ SET TARGETPATH=%SOURCETREE%local
+)
+if NOT "%TARGETPATH%"=="" (
+ mkdir "%TARGETPATH%\bin"
+ mkdir "%TARGETPATH%\include"
+ mkdir "%TARGETPATH%\lib\lua\%LUA_VER%"
+ mkdir "%TARGETPATH%\man\man1"
+ mkdir "%TARGETPATH%\share\lua\%LUA_VER%"
+ copy "%SOURCE%lua.exe" "%TARGETPATH%\bin"
+ copy "%SOURCE%luac.exe" "%TARGETPATH%\bin"
+ copy "%SOURCE%lua%LUA_SVER%.dll" "%TARGETPATH%\bin"
+ for %%a in (%INSTALL_H%) do ( copy "%SOURCE%%%a" "%TARGETPATH%\include" )
+ copy "%SOURCE%%LIBFILE%" "%TARGETPATH%\lib"
+ copy "%SOURCETREE%doc\lua.1" "%TARGETPATH%\man\man1"
+ copy "%SOURCETREE%doc\luac.1" "%TARGETPATH%\man\man1"
+
+ echo Installation completed in "%TARGETPATH%".
+ goto :EXITOK
+)
+
+REM ***********************
+REM * Compile sources *
+REM ***********************
+goto :after_compile_function
+:compile_function
+ REM Params: %1 is filelist (must be quoted)
+ REM Return: same list, with the object file extension included, will be stored in global OBJLIST
+
+ for %%a in (%~1) do (
+ SET FILENAME=%%a
+ if %TOOLCHAIN%==GCC (
+ SET COMPCMD=gcc -O2 -Wall !EXTRAFLAG! !COMPATFLAG! -c -o !FILENAME!.%OBJEXT% !FILENAME!.c
+ )
+ if %TOOLCHAIN%==MS (
+ SET COMPCMD=cl /nologo /MD /O2 /W3 /c /D_CRT_SECURE_NO_DEPRECATE !COMPATFLAG! !EXTRAFLAG! !FILENAME!.c
+ )
+ echo !COMPCMD!
+ !COMPCMD!
+ SET OBJLIST=!OBJLIST! !FILENAME!.%OBJEXT%
+ )
+
+goto :eof
+:after_compile_function
+
+CD %SOURCE%
+REM Traverse the 4 lists of source files
+
+for %%b in (CORE LIB DLL OTH) do (
+ SET LTYPE=%%b
+ SET OBJLIST=
+ if !LTYPE!==OTH (
+ REM OTH is the only list of files build without DLL option
+ SET EXTRAFLAG=
+ ) else (
+ SET EXTRAFLAG=-DLUA_BUILD_AS_DLL
+ )
+ if !LTYPE!==CORE SET FILELIST=%FILES_CORE%
+ if !LTYPE!==LIB SET FILELIST=%FILES_LIB%
+ if !LTYPE!==DLL SET FILELIST=%FILES_DLL%
+ if !LTYPE!==OTH SET FILELIST=%FILES_OTH%
+
+ echo Now compiling !LTYPE! file set...
+ call:compile_function "!FILELIST!"
+
+ if !LTYPE!==CORE SET FILES_CORE_O=!OBJLIST!
+ if !LTYPE!==LIB SET FILES_LIB_O=!OBJLIST!
+ if !LTYPE!==DLL SET FILES_DLL_O=!OBJLIST!
+ if !LTYPE!==OTH SET FILES_OTH_O=!OBJLIST!
+)
+
+
+REM ****************************
+REM * Link GCC based files *
+REM ****************************
+
+if %TOOLCHAIN%==GCC (
+ REM Link the LuaXX.dll file
+ SET LINKCMD=gcc -shared -o lua%LUA_SVER%.dll %FILES_CORE_O% %FILES_LIB_O%
+ echo !LINKCMD!
+ !LINKCMD!
+
+ REM strip from LuaXX.dll
+ SET RANCMD=strip --strip-unneeded lua%LUA_SVER%.dll
+ echo !RANCMD!
+ !RANCMD!
+
+ REM Link the Lua.exe file
+ SET LINKCMD=gcc -o lua.exe -s lua.%OBJEXT% lua%LUA_SVER%.dll -lm
+ echo !LINKCMD!
+ !LINKCMD!
+
+ REM create lib archive
+ SET LIBCMD=ar rcu liblua%LUA_SVER%.a %FILES_CORE_O% %FILES_LIB_O%
+ echo !LIBCMD!
+ !LIBCMD!
+
+ REM Speedup index using ranlib
+ SET RANCMD=ranlib liblua%LUA_SVER%.a
+ echo !RANCMD!
+ !RANCMD!
+
+ REM Link Luac.exe file
+ SET LINKCMD=gcc -o luac.exe %FILES_OTH_O% liblua%LUA_SVER%.a -lm
+ echo !LINKCMD!
+ !LINKCMD!
+
+)
+
+
+REM ****************************
+REM * Link MS based files *
+REM ****************************
+
+if %TOOLCHAIN%==MS (
+ REM Link the LuaXX.dll file, and LuaXX.obj
+ SET LINKCMD=link /nologo /DLL /out:lua%LUA_SVER%.dll %FILES_CORE_O% %FILES_LIB_O%
+ echo !LINKCMD!
+ !LINKCMD!
+
+ REM handle dll manifest
+ if exist lua%LUA_SVER%.dll.manifest (
+ SET MANICMD=mt /nologo -manifest lua%LUA_SVER%.dll.manifest -outputresource:lua%LUA_SVER%.dll;2
+ echo !MANICMD!
+ !MANICMD!
+ )
+
+ REM Link Lua.exe
+ SET LINKCMD=link /nologo /out:lua.exe lua.%OBJEXT% lua%LUA_SVER%.lib
+ echo !LINKCMD!
+ !LINKCMD!
+
+ REM handle manifest
+ if exist lua.exe.manifest (
+ SET MANICMD=mt /nologo -manifest lua.exe.manifest -outputresource:lua.exe
+ echo !MANICMD!
+ !MANICMD!
+ )
+
+ REM Link Luac.exe
+ SET LINKCMD=link /nologo /out:luac.exe %FILES_OTH_O% %FILES_CORE_O%
+ echo !LINKCMD!
+ !LINKCMD!
+
+ REM handle manifest
+ if exist luac.exe.manifest (
+ SET MANICMD=mt /nologo -manifest luac.exe.manifest -outputresource:luac.exe
+ echo !MANICMD!
+ !MANICMD!
+ )
+)
+
+CD %CURDIR%
+
+REM ****************************
+REM * Finished building *
+REM ****************************
+
+echo.
+echo Build completed.
+goto :EXITOK
+
+:EXITOK
+exit /B 0
+
+:EXITERROR
+echo For help try; etc\%BATCHNAME% /help
+exit /B 1
diff --git a/3rdparty/luv/.gitignore b/3rdparty/luv/.gitignore
new file mode 100644
index 00000000000..8bcf497a42c
--- /dev/null
+++ b/3rdparty/luv/.gitignore
@@ -0,0 +1,10 @@
+build
+libluv.a
+libluv.so
+luv.so
+luv.dll
+luajit.exe
+luv-*.tar.gz
+luv-*.src.rock
+luv-*/
+build.luarocks/
diff --git a/3rdparty/luv/.travis.yml b/3rdparty/luv/.travis.yml
new file mode 100644
index 00000000000..b6909b894cc
--- /dev/null
+++ b/3rdparty/luv/.travis.yml
@@ -0,0 +1,36 @@
+language: c
+sudo: false
+
+addons:
+ apt:
+ sources:
+ - kalakris-cmake
+ packages:
+ - cmake
+
+env:
+ global:
+ - LUAROCKS=2.3.0
+ matrix:
+ - WITH_LUA_ENGINE=Lua LUA=lua5.3
+ - WITH_LUA_ENGINE=LuaJIT LUA=luajit2.1
+ - PROCESS_CLEANUP_TEST=1 LUA=lua5.2
+
+os:
+ - linux
+ - osx
+
+before_install:
+ - git submodule update --init --recursive
+ - git submodule update --recursive
+
+script:
+ - if [ "x$PROCESS_CLEANUP_TEST" = "x" ]; then make && make test; else ./tests/test-sigchld-after-lua_close.sh; fi
+ # Test rock installation
+ - source .ci/setenv_lua.sh
+ - luarocks make
+ - test $PWD = `lua -e "print(require'luv'.cwd())"`
+
+notifications:
+ email: true
+ irc: "irc.freenode.org#luvit"
diff --git a/3rdparty/luv/CMakeLists.txt b/3rdparty/luv/CMakeLists.txt
new file mode 100644
index 00000000000..9f079670de2
--- /dev/null
+++ b/3rdparty/luv/CMakeLists.txt
@@ -0,0 +1,191 @@
+cmake_minimum_required(VERSION 2.8)
+
+if(POLICY CMP0053)
+ cmake_policy(SET CMP0053 NEW) # faster evaluation of variable references
+endif()
+
+project (luv C ASM)
+
+set(LUV_VERSION_MAJOR 1)
+set(LUV_VERSION_MINOR 8)
+set(LUV_VERSION_PATCH 0)
+set(LUV_VERSION ${LUV_VERSION_MAJOR}.${LUV_VERSION_MINOR}.${LUV_VERSION_PATCH})
+
+option(BUILD_MODULE "Build as module" ON)
+option(BUILD_SHARED_LIBS "Build shared library" OFF)
+option(WITH_SHARED_LIBUV "Link to a shared libuv library instead of static linking" OFF)
+
+if (NOT WITH_LUA_ENGINE)
+ set(WITH_LUA_ENGINE "LuaJIT"
+ CACHE STRING "Link to LuaJIT or PUC Lua" FORCE)
+ set_property(CACHE WITH_LUA_ENGINE
+ PROPERTY STRINGS "Lua;LuaJIT")
+endif (NOT WITH_LUA_ENGINE)
+
+if (NOT LUA_BUILD_TYPE)
+ set(LUA_BUILD_TYPE "Static"
+ CACHE STRING "Build Lua/LuaJIT as static, dynamic libary, or use system one" FORCE)
+ set_property(CACHE LUA_BUILD_TYPE
+ PROPERTY STRINGS "Static;Dynamic;System")
+endif (NOT LUA_BUILD_TYPE)
+
+if (WITH_LUA_ENGINE STREQUAL Lua)
+ add_definitions(-DLUA_USE_DLOPEN)
+ set(USE_LUAJIT OFF)
+else ()
+ set(USE_LUAJIT ON)
+endif ()
+
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
+
+if (WITH_SHARED_LIBUV)
+ find_package(Libuv)
+ if (LIBUV_FOUND)
+ include_directories(${LIBUV_INCLUDE_DIR})
+ endif (LIBUV_FOUND)
+else (WITH_SHARED_LIBUV)
+ include(deps/uv.cmake)
+ if (BUILD_MODULE)
+ add_definitions( -DBUILDING_UV_SHARED )
+ endif (BUILD_MODULE)
+endif (WITH_SHARED_LIBUV)
+
+if (LUA)
+ MESSAGE(STATUS "Lua: using information from luarocks")
+
+ MESSAGE(STATUS "LUA_LIBDIR: " ${LUA_LIBDIR})
+ MESSAGE(STATUS "LUA_INCDIR: " ${LUA_INCDIR})
+ MESSAGE(STATUS "LUA: " ${LUA})
+
+ SET(LUA_EXECUTABLE "${LUA}")
+ SET(LUA_INCLUDE_DIR "${LUA_INCDIR}")
+ SET(LUA_PACKAGE_PATH "${LUADIR}")
+ SET(LUA_PACKAGE_CPATH "${LIBDIR}")
+
+ SET(INSTALL_LIB_DIR ${LIBDIR})
+
+ GET_FILENAME_COMPONENT(LUA_EXEC_NAME ${LUA_EXECUTABLE} NAME_WE)
+ IF(LUA_EXEC_NAME STREQUAL "luajit")
+ FIND_LIBRARY(LUA_LIBRARIES
+ NAMES luajit libluajit
+ PATHS ${LUA_LIBDIR}
+ NO_DEFAULT_PATH)
+ ELSEIF(LUA_EXEC_NAME STREQUAL "lua")
+ FIND_LIBRARY(LUA_LIBRARIES
+ NAMES lua lua53 lua52 lua51 liblua liblua53 liblua52 liblua51
+ PATHS ${LUA_LIBDIR}
+ NO_DEFAULT_PATH)
+ ENDIF()
+ MESSAGE(STATUS "Lua library: ${LUA_LIBRARIES}")
+
+ include_directories(${LUA_INCLUDE_DIR})
+else (LUA)
+ if (LUA_BUILD_TYPE STREQUAL System)
+ if (USE_LUAJIT)
+ find_package(LuaJIT)
+ if (LUAJIT_FOUND)
+ include_directories(${LUAJIT_INCLUDE_DIR})
+ link_directories(${LUAJIT_LIBRARIES})
+ endif (LUAJIT_FOUND)
+ else (USE_LUAJIT)
+ find_package(Lua)
+ if (LUA_FOUND)
+ include_directories(${LUA_INCLUDE_DIR})
+ endif (LUA_FOUND)
+ endif (USE_LUAJIT)
+
+ else (LUA_BUILD_TYPE STREQUAL System)
+ if (LUA_BUILD_TYPE STREQUAL Static)
+ SET(WITH_SHARED_LUA OFF)
+ else (LUA_BUILD_TYPE STREQUAL Static)
+ SET(WITH_SHARED_LUA ON)
+ endif (LUA_BUILD_TYPE STREQUAL Static)
+ if (USE_LUAJIT)
+ include(deps/luajit.cmake)
+ include_directories(deps/luajit/src)
+ else(USE_LUAJIT)
+ include(deps/lua.cmake)
+ include_directories(deps/lua/src)
+ endif (USE_LUAJIT)
+ endif (LUA_BUILD_TYPE STREQUAL System)
+endif (LUA)
+
+if (BUILD_MODULE)
+ add_library(luv MODULE src/luv.c)
+ set_target_properties(luv PROPERTIES PREFIX "")
+else (BUILD_MODULE)
+ add_library(luv src/luv.c)
+ if (BUILD_SHARED_LIBS)
+ set_target_properties(luv
+ PROPERTIES VERSION ${LUV_VERSION} SOVERSION ${LUV_VERSION_MAJOR})
+ endif (BUILD_SHARED_LIBS)
+endif (BUILD_MODULE)
+
+if(APPLE)
+ set(CMAKE_SHARED_MODULE_CREATE_C_FLAGS
+ "${CMAKE_SHARED_MODULE_CREATE_C_FLAGS} -flat_namespace -undefined suppress"
+ )
+ # execute_process(COMMAND which luajit OUTPUT_VARIABLE LUAJIT)
+ # set(CMAKE_SHARED_MODULE_CREATE_C_FLAGS
+ # "${CMAKE_SHARED_MODULE_CREATE_C_FLAGS} -bundle_loader ${LUAJIT}"
+ # )
+endif()
+
+if(WIN32)
+ add_definitions(-DLUA_BUILD_AS_DLL -DLUA_LIB)
+ if (LUA)
+ target_link_libraries(luv uv ${LUA_LIBRARIES})
+ else (LUA)
+ if (USE_LUAJIT)
+ target_link_libraries(luv uv luajit-5.1)
+ else (USE_LUAJIT)
+ if (LUA_BUILD_TYPE STREQUAL System)
+ target_link_libraries(luv uv ${LUA_LIBRARIES})
+ else (LUA_BUILD_TYPE STREQUAL System)
+ target_link_libraries(luv uv lualib)
+ endif (LUA_BUILD_TYPE STREQUAL System)
+ endif (USE_LUAJIT)
+ endif (LUA)
+ # replace /MD to /MT to avoid link msvcr*.dll
+ set(CompilerFlags
+ CMAKE_C_FLAGS
+ CMAKE_C_FLAGS_DEBUG
+ CMAKE_C_FLAGS_MINSIZEREL
+ CMAKE_C_FLAGS_RELWITHDEBINFO
+ CMAKE_C_FLAGS_RELEASE)
+ foreach(CompilerFlag ${CompilerFlags})
+ string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}")
+ endforeach()
+elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
+ target_link_libraries(luv uv rt)
+else()
+ target_link_libraries(luv uv)
+endif()
+
+if (NOT LUA)
+ if (BUILD_MODULE)
+ if (WIN32)
+ set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
+ else (WIN32)
+ set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib/lua/${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}")
+ endif (WIN32)
+ else (BUILD_MODULE)
+ set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib"
+ CACHE PATH "Installation directory for libraries")
+ set(INSTALL_INC_DIR "${CMAKE_INSTALL_PREFIX}/include/luv"
+ CACHE PATH "Installation directory for headers")
+ endif (BUILD_MODULE)
+endif ()
+
+if (CMAKE_INSTALL_PREFIX)
+ install(TARGETS luv
+ ARCHIVE DESTINATION "${INSTALL_LIB_DIR}"
+ LIBRARY DESTINATION "${INSTALL_LIB_DIR}"
+ )
+ if (NOT BUILD_MODULE)
+ install(
+ FILES src/luv.h src/util.h src/lhandle.h src/lreq.h
+ DESTINATION "${INSTALL_INC_DIR}"
+ )
+ endif (NOT BUILD_MODULE)
+endif (CMAKE_INSTALL_PREFIX)
diff --git a/3rdparty/luv/LICENSE.txt b/3rdparty/luv/LICENSE.txt
new file mode 100644
index 00000000000..d6456956733
--- /dev/null
+++ b/3rdparty/luv/LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/3rdparty/luv/Makefile b/3rdparty/luv/Makefile
new file mode 100644
index 00000000000..1e7038c47ab
--- /dev/null
+++ b/3rdparty/luv/Makefile
@@ -0,0 +1,61 @@
+LUV_TAG=$(shell git describe --tags)
+
+ifdef WITHOUT_AMALG
+ CMAKE_OPTIONS+= -DWITH_AMALG=OFF
+endif
+
+BUILD_MODULE ?= ON
+BUILD_SHARED_LIBS ?= OFF
+WITH_SHARED_LIBUV ?= OFF
+WITH_LUA_ENGINE ?= LuaJIT
+LUA_BUILD_TYPE ?= Static
+
+
+ifeq ($(WITH_LUA_ENGINE), LuaJIT)
+ LUABIN=build/luajit
+else
+ LUABIN=build/lua
+endif
+
+CMAKE_OPTIONS += \
+ -DBUILD_MODULE=$(BUILD_MODULE) \
+ -DBUILD_SHARED_LIBS=$(BUILD_SHARED_LIBS) \
+ -DWITH_SHARED_LIBUV=$(WITH_SHARED_LIBUV) \
+ -DWITH_LUA_ENGINE=$(WITH_LUA_ENGINE) \
+ -DLUA_BUILD_TYPE=$(LUA_BUILD_TYPE) \
+
+all: luv
+
+deps/libuv/include:
+ git submodule update --init deps/libuv
+
+deps/luajit/src:
+ git submodule update --init deps/luajit
+
+build/Makefile: deps/libuv/include deps/luajit/src
+ cmake -H. -Bbuild ${CMAKE_OPTIONS} -DWITH_AMALG=OFF
+
+luv: build/Makefile
+ cmake --build build --config Debug
+ ln -sf build/luv.so
+
+clean:
+ rm -rf build luv.so
+
+test: luv
+ ${LUABIN} tests/run.lua
+
+reset:
+ git submodule update --init --recursive && \
+ git clean -f -d && \
+ git checkout .
+
+publish-luarocks:
+ rm -rf luv-${LUV_TAG}
+ mkdir -p luv-${LUV_TAG}/deps
+ cp -r src cmake CMakeLists.txt LICENSE.txt README.md docs.md luv-${LUV_TAG}/
+ cp -r deps/libuv deps/*.cmake deps/lua_one.c luv-${LUV_TAG}/deps/
+ tar -czvf luv-${LUV_TAG}.tar.gz luv-${LUV_TAG}
+ github-release upload --user luvit --repo luv --tag ${LUV_TAG} \
+ --file luv-${LUV_TAG}.tar.gz --name luv-${LUV_TAG}.tar.gz
+ luarocks upload luv-${LUV_TAG}.rockspec --api-key=${LUAROCKS_TOKEN}
diff --git a/3rdparty/luv/README.md b/3rdparty/luv/README.md
new file mode 100644
index 00000000000..47059d01ee7
--- /dev/null
+++ b/3rdparty/luv/README.md
@@ -0,0 +1,213 @@
+luv
+===
+
+[![Linux Build Status](https://travis-ci.org/luvit/luv.svg?branch=master)](https://travis-ci.org/luvit/luv)
+
+[![Windows Build status](https://ci.appveyor.com/api/projects/status/uo1qhdcc0vcqsiok/branch/master?svg=true)](https://ci.appveyor.com/project/racker-buildbot/luv/branch/master)
+
+[libuv](https://github.com/joyent/libuv) bindings for
+[luajit](http://luajit.org/) and [lua](http://www.lua.org/)
+[5.1](http://www.lua.org/manual/5.1/manual.html)/
+[5.2](http://www.lua.org/manual/5.2/manual.html)/
+[5.3](http://www.lua.org/manual/5.3/manual.html).
+
+This library makes libuv available to lua scripts. It was made for the [luvit](http://luvit.io/) project but should usable from nearly any lua project.
+
+The library can be used by multiple threads at once. Each thread is assumed to load the library from a different `lua_State`. Luv will create a unique `uv_loop_t` for each state. You can't share uv handles between states/loops.
+
+The best docs currently are the [libuv docs](http://docs.libuv.org/) themselves. Hopfully soon we'll have a copy locally tailored for lua.
+
+```lua
+local uv = require('luv')
+
+-- Create a handle to a uv_timer_t
+local timer = uv.new_timer()
+
+-- This will wait 1000ms and then continue inside the callback
+timer:start(1000, 0, function ()
+ -- timer here is the value we passed in before from new_timer.
+
+ print ("Awake!")
+
+ -- You must always close your uv handles or you'll leak memory
+ -- We can't depend on the GC since it doesn't know enough about libuv.
+ timer:close()
+end)
+
+print("Sleeping");
+
+-- uv.run will block and wait for all events to run.
+-- When there are no longer any active handles, it will return
+uv.run()
+```
+
+
+Here is an example of an TCP echo server
+```lua
+local uv = require('luv')
+
+local function create_server(host, port, on_connection)
+
+ local server = uv.new_tcp()
+ server:bind(host, port)
+
+ server:listen(128, function(err)
+ -- Make sure there was no problem setting up listen
+ assert(not err, err)
+
+ -- Accept the client
+ local client = uv.new_tcp()
+ server:accept(client)
+
+ on_connection(client)
+ end)
+
+ return server
+end
+
+local server = create_server("0.0.0.0", 0, function (client)
+
+ client:read_start(function (err, chunk)
+
+ -- Crash on errors
+ assert(not err, err)
+
+ if chunk then
+ -- Echo anything heard
+ client:write(chunk)
+ else
+ -- When the stream ends, close the socket
+ client:close()
+ end
+ end)
+end)
+
+print("TCP Echo serverr listening on port " .. server:getsockname().port)
+
+uv.run()
+```
+
+More examples can be found in the [examples](examples) and [tests](tests) folders.
+
+## Building From Source
+
+To build, first install your compiler tools.
+
+### Get a Compiler
+
+On linux this probably means `gcc` and `make`. On Ubuntu, the `build-essential`
+package is good for this.
+
+On OSX, you probably want XCode which comes with `clang` and `make` and friends.
+
+For windows the free Visual Studio Express works. If you get the 2013 edition,
+make sure to get the `Windows Deskop` edition. The `Windows` version doesn't
+include a working C compiler. Make sure to run all of setup including getting a
+free license.
+
+### Install CMake
+
+Now install Cmake. The version in `brew` on OSX or most Linux package managers
+is good. The version on Travis CI is too old and so I use a PPA there. On
+windows use the installer and make sure to add cmake to your command prompt
+path.
+
+### Install Git
+
+If you haven't already, install git and make sure it's in your path. This comes
+with XCode on OSX. On Linux it's in your package manager. For windows, use the
+installer at <http://git-scm.com>. Make sure it's available to your windows
+command prompt.
+
+### Clone the Code
+
+Now open a terminal and clone the code. For windows I recommend the special
+developer command prompt that came with Visual Studio.
+
+```
+git clone https://github.com/luvit/luv.git --recursive
+cd luv
+```
+
+### Build the Code and Test
+
+On windows I wrote a small batch file that runs the correct cmake commands and
+copies the output files for easy access.
+
+```
+C:\Code\luv> msvcbuild.bat
+C:\Code\luv> luajit tests\run.lua
+```
+
+On unix systems, use the Makefile.
+
+```
+~/Code/luv> make test
+```
+
+This will build luv as a module library. Module libraries are plugins that are
+not linked into other targets.
+
+#### Build with PUC Lua 5.3
+By default luv is linked with LuaJIT 2.0.4. If you rather like to link luv
+with PUC Lua 5.3 you can run make with:
+
+```
+~/Code/luv> WITH_LUA_ENGINE=Lua make
+```
+
+#### Build as static library
+
+If you want to build luv as a static library run make with:
+
+```
+~/Code/luv> BUILD_MODULE=OFF make
+```
+
+This will create a static library `libluv.a`.
+
+#### Build as shared library
+
+If you want to build luv as a shared library run make with:
+
+```
+~/Code/luv> BUILD_MODULE=OFF BUILD_SHARED_LIBS=ON make
+```
+
+This will create a shared library `libluv.so`.
+
+#### Build with shared libraries
+
+By default the build system will build luv with the supplied dependencies.
+These are:
+ * libuv
+ * LuaJIT or Lua
+
+However, if your target system has already one or more of these dependencies
+installed you can link `luv` against them.
+
+##### Linking with shared libuv
+
+The default shared library name for libuv is `libuv`. To link against it use:
+
+```
+~/Code/luv> WITH_SHARED_LIBUV=ON make
+```
+
+##### Linking with shared LuaJIT
+
+The default shared library name for LuaJIT is `libluajit-5.1`. To link against
+it use:
+
+```
+~/Code/luv> LUA_BUILD_TYPE=System make
+```
+
+##### Linking with shared Lua 5.x
+
+The default shared library name for Lua 5.x is `liblua5.x`. To link against
+it use:
+
+```
+~/Code/luv> LUA_BUILD_TYPE=System WITH_LUA_ENGINE=Lua make
+```
diff --git a/3rdparty/luv/appveyor.yml b/3rdparty/luv/appveyor.yml
new file mode 100644
index 00000000000..b8d01898573
--- /dev/null
+++ b/3rdparty/luv/appveyor.yml
@@ -0,0 +1,42 @@
+os: Visual Studio 2015
+
+# Test with the latest two releases of MSVC
+configuration:
+ - 2015
+ - 2013
+
+# Test with the latest Lua and LuaJIT versions
+environment:
+ LUAROCKS_VER: 2.3.0
+ matrix:
+ - LUA_VER: 5.3.2
+ NOCOMPAT: true # with compatibility flags disabled.
+ - LJ_VER: 2.1
+
+platform:
+ - x86
+ - x64
+
+matrix:
+ fast_finish: true
+
+cache:
+ - c:\lua -> appveyor.yml
+ - c:\external -> appveyor.yml
+
+install:
+ - git submodule update --init
+
+build_script:
+ - msvcbuild.bat
+ - luajit.exe tests\run.lua
+ # Test rock installation
+ - call .ci\set_compiler_env.bat
+ - call .ci\install.bat
+ - luarocks make
+ - ps: if("$(Get-Location)" -eq $(lua -e "print(require'luv'.cwd())")) { "LuaRocks test OK" } else { "LuaRocks test failed"; exit 1 }
+ - luarocks remove luv
+
+artifacts:
+ - path: luv.dll
+ - path: luajit.exe
diff --git a/3rdparty/luv/cmake/Modules/FindLibuv.cmake b/3rdparty/luv/cmake/Modules/FindLibuv.cmake
new file mode 100644
index 00000000000..045362ae5db
--- /dev/null
+++ b/3rdparty/luv/cmake/Modules/FindLibuv.cmake
@@ -0,0 +1,11 @@
+# Locate libuv library
+# This module defines
+# LIBUV_FOUND, if false, do not try to link to libuv
+# LIBUV_LIBRARIES
+# LIBUV_INCLUDE_DIR, where to find uv.h
+
+FIND_PATH(LIBUV_INCLUDE_DIR NAMES uv.h)
+FIND_LIBRARY(LIBUV_LIBRARIES NAMES uv libuv)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBUV DEFAULT_MSG LIBUV_LIBRARIES LIBUV_INCLUDE_DIR)
diff --git a/3rdparty/luv/cmake/Modules/FindLuaJIT.cmake b/3rdparty/luv/cmake/Modules/FindLuaJIT.cmake
new file mode 100644
index 00000000000..b9c2c3ee41a
--- /dev/null
+++ b/3rdparty/luv/cmake/Modules/FindLuaJIT.cmake
@@ -0,0 +1,55 @@
+#=============================================================================
+# Copyright 2007-2009 Kitware, Inc.
+# Copyright 2013 Rolf Eike Beer <eike@sf-mail.de>
+#
+# 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.
+#=============================================================================
+# We use code from the CMake project to detect the Lua version.
+
+# Locate LuaJIT library
+# This module defines
+# LUAJIT_FOUND, if false, do not try to link to Lua JIT
+# LUAJIT_LIBRARIES
+# LUAJIT_INCLUDE_DIR, where to find lua.h
+#
+# Additionally it defines the Lua API/ABI version:
+# LUA_VERSION_STRING - the version of Lua found
+# LUA_VERSION_MAJOR - the major version of Lua
+# LUA_VERSION_MINOR - the minor version of Lua
+# LUA_VERSION_PATCH - the patch version of Lua
+
+FIND_PATH(LUAJIT_INCLUDE_DIR NAMES lua.h PATH_SUFFIXES luajit-2.0)
+FIND_LIBRARY(LUAJIT_LIBRARIES NAMES luajit-5.1)
+
+if (LUAJIT_INCLUDE_DIR AND EXISTS "${LUAJIT_INCLUDE_DIR}/lua.h")
+ # At least 5.[012] have different ways to express the version
+ # so all of them need to be tested. Lua 5.2 defines LUA_VERSION
+ # and LUA_RELEASE as joined by the C preprocessor, so avoid those.
+ file(STRINGS "${LUAJIT_INCLUDE_DIR}/lua.h" lua_version_strings
+ REGEX "^#define[ \t]+LUA_(RELEASE[ \t]+\"Lua [0-9]|VERSION([ \t]+\"Lua [0-9]|_[MR])).*")
+
+ string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MAJOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_MAJOR ";${lua_version_strings};")
+ if (LUA_VERSION_MAJOR MATCHES "^[0-9]+$")
+ string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_MINOR[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_MINOR ";${lua_version_strings};")
+ string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION_RELEASE[ \t]+\"([0-9])\"[ \t]*;.*" "\\1" LUA_VERSION_PATCH ";${lua_version_strings};")
+ set(LUA_VERSION_STRING "${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}.${LUA_VERSION_PATCH}")
+ else ()
+ string(REGEX REPLACE ".*;#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" LUA_VERSION_STRING ";${lua_version_strings};")
+ if (NOT LUA_VERSION_STRING MATCHES "^[0-9.]+$")
+ string(REGEX REPLACE ".*;#define[ \t]+LUA_VERSION[ \t]+\"Lua ([0-9.]+)\"[ \t]*;.*" "\\1" LUA_VERSION_STRING ";${lua_version_strings};")
+ endif ()
+ string(REGEX REPLACE "^([0-9]+)\\.[0-9.]*$" "\\1" LUA_VERSION_MAJOR "${LUA_VERSION_STRING}")
+ string(REGEX REPLACE "^[0-9]+\\.([0-9]+)[0-9.]*$" "\\1" LUA_VERSION_MINOR "${LUA_VERSION_STRING}")
+ string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]).*" "\\1" LUA_VERSION_PATCH "${LUA_VERSION_STRING}")
+ endif ()
+
+ unset(lua_version_strings)
+endif()
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LUAJIT DEFAULT_MSG LUAJIT_LIBRARIES LUAJIT_INCLUDE_DIR)
diff --git a/3rdparty/luv/deps/lua.cmake b/3rdparty/luv/deps/lua.cmake
new file mode 100644
index 00000000000..393e67a107a
--- /dev/null
+++ b/3rdparty/luv/deps/lua.cmake
@@ -0,0 +1,128 @@
+# Modfied from luajit.cmake
+# Added LUAJIT_ADD_EXECUTABLE Ryan Phillips <ryan at trolocsis.com>
+# This CMakeLists.txt has been first taken from LuaDist
+# Copyright (C) 2007-2011 LuaDist.
+# Created by Peter Drahoš
+# Redistribution and use of this file is allowed according to the terms of the MIT license.
+# Debugged and (now seriously) modified by Ronan Collobert, for Torch7
+
+#project(Lua53 C)
+
+SET(LUA_DIR ${CMAKE_CURRENT_LIST_DIR}/lua)
+
+SET(CMAKE_REQUIRED_INCLUDES
+ ${LUA_DIR}
+ ${LUA_DIR}/src
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+OPTION(WITH_AMALG "Build eveything in one shot (needs memory)" ON)
+
+# Ugly warnings
+IF(MSVC)
+ ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
+ENDIF()
+
+# Various includes
+INCLUDE(CheckLibraryExists)
+INCLUDE(CheckFunctionExists)
+INCLUDE(CheckCSourceCompiles)
+INCLUDE(CheckTypeSize)
+
+CHECK_TYPE_SIZE("void*" SIZEOF_VOID_P)
+IF(SIZEOF_VOID_P EQUAL 8)
+ ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE)
+ENDIF()
+
+IF(NOT WIN32)
+ FIND_LIBRARY(DL_LIBRARY "dl")
+ IF(DL_LIBRARY)
+ SET(CMAKE_REQUIRED_LIBRARIES ${DL_LIBRARY})
+ LIST(APPEND LIBS ${DL_LIBRARY})
+ ENDIF(DL_LIBRARY)
+ CHECK_FUNCTION_EXISTS(dlopen LUA_USE_DLOPEN)
+ IF(NOT LUA_USE_DLOPEN)
+ MESSAGE(FATAL_ERROR "Cannot compile a useful lua.
+Function dlopen() seems not to be supported on your platform.
+Apparently you are not on a Windows platform as well.
+So lua has no way to deal with shared libraries!")
+ ENDIF(NOT LUA_USE_DLOPEN)
+ENDIF(NOT WIN32)
+
+check_library_exists(m sin "" LUA_USE_LIBM)
+if ( LUA_USE_LIBM )
+ list ( APPEND LIBS m )
+endif ()
+
+## SOURCES
+SET(SRC_LUALIB
+ ${LUA_DIR}/src/lbaselib.c
+ ${LUA_DIR}/src/lcorolib.c
+ ${LUA_DIR}/src/ldblib.c
+ ${LUA_DIR}/src/liolib.c
+ ${LUA_DIR}/src/lmathlib.c
+ ${LUA_DIR}/src/loadlib.c
+ ${LUA_DIR}/src/loslib.c
+ ${LUA_DIR}/src/lstrlib.c
+ ${LUA_DIR}/src/ltablib.c
+ ${LUA_DIR}/src/lutf8lib.c)
+
+SET(SRC_LUACORE
+ ${LUA_DIR}/src/lauxlib.c
+ ${LUA_DIR}/src/lapi.c
+ ${LUA_DIR}/src/lcode.c
+ ${LUA_DIR}/src/lctype.c
+ ${LUA_DIR}/src/ldebug.c
+ ${LUA_DIR}/src/ldo.c
+ ${LUA_DIR}/src/ldump.c
+ ${LUA_DIR}/src/lfunc.c
+ ${LUA_DIR}/src/lgc.c
+ ${LUA_DIR}/src/linit.c
+ ${LUA_DIR}/src/llex.c
+ ${LUA_DIR}/src/lmem.c
+ ${LUA_DIR}/src/lobject.c
+ ${LUA_DIR}/src/lopcodes.c
+ ${LUA_DIR}/src/lparser.c
+ ${LUA_DIR}/src/lstate.c
+ ${LUA_DIR}/src/lstring.c
+ ${LUA_DIR}/src/ltable.c
+ ${LUA_DIR}/src/ltm.c
+ ${LUA_DIR}/src/lundump.c
+ ${LUA_DIR}/src/lvm.c
+ ${LUA_DIR}/src/lzio.c
+ ${SRC_LUALIB})
+
+## GENERATE
+
+IF(WITH_SHARED_LUA)
+ IF(WITH_AMALG)
+ add_library(lualib SHARED ${LUA_DIR}/../lua_one.c ${DEPS})
+ ELSE()
+ add_library(lualib SHARED ${SRC_LUACORE} ${DEPS} )
+ ENDIF()
+ELSE()
+ IF(WITH_AMALG)
+ add_library(lualib STATIC ${LUA_DIR}/../lua_one.c ${DEPS} )
+ ELSE()
+ add_library(lualib STATIC ${SRC_LUACORE} ${DEPS} )
+ ENDIF()
+ set_target_properties(lualib PROPERTIES
+ PREFIX "lib" IMPORT_PREFIX "lib")
+ENDIF()
+
+target_link_libraries (lualib ${LIBS} )
+set_target_properties (lualib PROPERTIES OUTPUT_NAME "lua53")
+
+IF(WIN32)
+ add_executable(lua ${LUA_DIR}/src/lua.c)
+ target_link_libraries(lua lualib)
+ELSE()
+ IF(WITH_AMALG)
+ add_executable(lua ${LUA_DIR}/src/lua.c ${LUA_DIR}/lua_one.c ${DEPS})
+ ELSE()
+ add_executable(lua ${LUA_DIR}/src/lua.c ${SRC_LUACORE} ${DEPS})
+ ENDIF()
+ target_link_libraries(lua ${LIBS})
+ SET_TARGET_PROPERTIES(lua PROPERTIES ENABLE_EXPORTS ON)
+ENDIF(WIN32)
+
diff --git a/3rdparty/luv/deps/lua_one.c b/3rdparty/luv/deps/lua_one.c
new file mode 100644
index 00000000000..2531883cc67
--- /dev/null
+++ b/3rdparty/luv/deps/lua_one.c
@@ -0,0 +1,97 @@
+/*
+* one.c -- Lua core, libraries, and interpreter in a single file
+*/
+
+/* default is to build the full interpreter */
+#ifndef MAKE_LIB
+#ifndef MAKE_LUAC
+#ifndef MAKE_LUA
+#define MAKE_LIB
+#endif
+#endif
+#endif
+
+/* choose suitable platform-specific features */
+/* some of these may need extra libraries such as -ldl -lreadline -lncurses */
+#if 0
+#define LUA_USE_LINUX
+#define LUA_USE_MACOSX
+#define LUA_USE_POSIX
+#define LUA_ANSI
+#endif
+
+/* no need to change anything below this line ----------------------------- */
+
+/* setup for luaconf.h */
+#if HAVE_LPREFIX
+# include "lprefix.h"
+#endif
+
+#define LUA_CORE
+#define LUA_LIB
+#define ltable_c
+#define lvm_c
+#include "luaconf.h"
+
+/* do not export internal symbols */
+#undef LUAI_FUNC
+#undef LUAI_DDEC
+#undef LUAI_DDEF
+#define LUAI_FUNC static
+#define LUAI_DDEC static
+#define LUAI_DDEF static
+
+/* core -- used by all */
+#include "lapi.c"
+#include "lcode.c"
+#include "lctype.c"
+#include "ldebug.c"
+#include "ldo.c"
+#include "ldump.c"
+#include "lfunc.c"
+#include "lgc.c"
+#include "llex.c"
+#include "lmem.c"
+#include "lobject.c"
+#include "lopcodes.c"
+#include "lparser.c"
+#include "lstate.c"
+#include "lstring.c"
+#include "ltable.c"
+#include "ltm.c"
+#include "lundump.c"
+#include "lvm.c"
+#include "lzio.c"
+
+/* auxiliary library -- used by all */
+#include "lauxlib.c"
+
+/* standard library -- not used by luac */
+#ifndef MAKE_LUAC
+#include "lbaselib.c"
+#if LUA_VERSION_NUM == 502
+# include "lbitlib.c"
+#endif
+#include "lcorolib.c"
+#include "ldblib.c"
+#include "liolib.c"
+#include "lmathlib.c"
+#include "loadlib.c"
+#include "loslib.c"
+#include "lstrlib.c"
+#include "ltablib.c"
+#if LUA_VERSION_NUM >= 503
+# include "lutf8lib.c"
+#endif
+#include "linit.c"
+#endif
+
+/* lua */
+#ifdef MAKE_LUA
+#include "lua.c"
+#endif
+
+/* luac */
+#ifdef MAKE_LUAC
+#include "luac.c"
+#endif
diff --git a/3rdparty/luv/deps/luajit.cmake b/3rdparty/luv/deps/luajit.cmake
new file mode 100644
index 00000000000..e9d5b3582e1
--- /dev/null
+++ b/3rdparty/luv/deps/luajit.cmake
@@ -0,0 +1,407 @@
+# Added LUAJIT_ADD_EXECUTABLE Ryan Phillips <ryan at trolocsis.com>
+# This CMakeLists.txt has been first taken from LuaDist
+# Copyright (C) 2007-2011 LuaDist.
+# Created by Peter Drahoš
+# Redistribution and use of this file is allowed according to the terms of the MIT license.
+# Debugged and (now seriously) modified by Ronan Collobert, for Torch7
+
+#project(LuaJIT C ASM)
+
+SET(LUAJIT_DIR ${CMAKE_CURRENT_LIST_DIR}/luajit)
+
+SET(CMAKE_REQUIRED_INCLUDES
+ ${LUAJIT_DIR}
+ ${LUAJIT_DIR}/src
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+OPTION(WITH_AMALG "Build eveything in one shot (needs memory)" ON)
+
+# Ugly warnings
+IF(MSVC)
+ ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
+ENDIF()
+
+# Various includes
+INCLUDE(CheckLibraryExists)
+INCLUDE(CheckFunctionExists)
+INCLUDE(CheckCSourceCompiles)
+INCLUDE(CheckTypeSize)
+
+# LuaJIT specific
+option(LUAJIT_DISABLE_FFI "Disable FFI." OFF)
+option(LUAJIT_ENABLE_LUA52COMPAT "Enable Lua 5.2 compatibility." ON)
+option(LUAJIT_DISABLE_JIT "Disable JIT." OFF)
+option(LUAJIT_CPU_SSE2 "Use SSE2 instead of x87 instructions." ON)
+option(LUAJIT_CPU_NOCMOV "Disable NOCMOV." OFF)
+MARK_AS_ADVANCED(LUAJIT_DISABLE_FFI LUAJIT_ENABLE_LUA52COMPAT LUAJIT_DISABLE_JIT LUAJIT_CPU_SSE2 LUAJIT_CPU_NOCMOV)
+
+IF(LUAJIT_DISABLE_FFI)
+ ADD_DEFINITIONS(-DLUAJIT_DISABLE_FFI)
+ENDIF()
+
+IF(LUAJIT_ENABLE_LUA52COMPAT)
+ ADD_DEFINITIONS(-DLUAJIT_ENABLE_LUA52COMPAT)
+ENDIF()
+
+IF(LUAJIT_DISABLE_JIT)
+ ADD_DEFINITIONS(-DLUAJIT_DISABLE_JIT)
+ENDIF()
+
+IF(LUAJIT_CPU_SSE2)
+ ADD_DEFINITIONS(-DLUAJIT_CPU_SSE2)
+ENDIF()
+
+IF(LUAJIT_CPU_NOCMOV)
+ ADD_DEFINITIONS(-DLUAJIT_CPU_NOCMOV)
+ENDIF()
+######
+
+
+CHECK_TYPE_SIZE("void*" SIZEOF_VOID_P)
+IF(SIZEOF_VOID_P EQUAL 8)
+ ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE)
+ENDIF()
+
+if ( WIN32 AND NOT CYGWIN )
+ add_definitions ( -DLUAJIT_OS=LUAJIT_OS_WINDOWS)
+ set ( LJVM_MODE coffasm )
+elseif ( APPLE )
+ set ( CMAKE_EXE_LINKER_FLAGS "-pagezero_size 10000 -image_base 100000000 ${CMAKE_EXE_LINKER_FLAGS}" )
+ set ( LJVM_MODE machasm )
+else ()
+ set ( LJVM_MODE elfasm )
+endif ()
+
+IF(NOT WIN32)
+ FIND_LIBRARY(DL_LIBRARY "dl")
+ IF(DL_LIBRARY)
+ SET(CMAKE_REQUIRED_LIBRARIES ${DL_LIBRARY})
+ LIST(APPEND LIBS ${DL_LIBRARY})
+ ENDIF(DL_LIBRARY)
+ CHECK_FUNCTION_EXISTS(dlopen LUA_USE_DLOPEN)
+ IF(NOT LUA_USE_DLOPEN)
+ MESSAGE(FATAL_ERROR "Cannot compile a useful lua.
+Function dlopen() seems not to be supported on your platform.
+Apparently you are not on a Windows platform as well.
+So lua has no way to deal with shared libraries!")
+ ENDIF(NOT LUA_USE_DLOPEN)
+ENDIF(NOT WIN32)
+
+check_library_exists(m sin "" LUA_USE_LIBM)
+if ( LUA_USE_LIBM )
+ list ( APPEND LIBS m )
+endif ()
+
+## SOURCES
+MACRO(LJ_TEST_ARCH stuff)
+ CHECK_C_SOURCE_COMPILES("
+#undef ${stuff}
+#include \"lj_arch.h\"
+#if ${stuff}
+int main() { return 0; }
+#else
+#error \"not defined\"
+#endif
+" ${stuff})
+ENDMACRO()
+
+MACRO(LJ_TEST_ARCH_VALUE stuff value)
+ CHECK_C_SOURCE_COMPILES("
+#undef ${stuff}
+#include \"lj_arch.h\"
+#if ${stuff} == ${value}
+int main() { return 0; }
+#else
+#error \"not defined\"
+#endif
+" ${stuff}_${value})
+ENDMACRO()
+
+
+FOREACH(arch X64 X86 ARM PPC PPCSPE MIPS)
+ LJ_TEST_ARCH(LJ_TARGET_${arch})
+ if(LJ_TARGET_${arch})
+ STRING(TOLOWER ${arch} TARGET_LJARCH)
+ MESSAGE(STATUS "LuaJIT Target: ${TARGET_LJARCH}")
+ BREAK()
+ ENDIF()
+ENDFOREACH()
+
+IF(NOT TARGET_LJARCH)
+ MESSAGE(FATAL_ERROR "architecture not supported")
+ELSE()
+ MESSAGE(STATUS "LuaJIT target ${TARGET_LJARCH}")
+ENDIF()
+
+FILE(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/jit)
+FILE(GLOB jit_files ${LUAJIT_DIR}/src/jit/*.lua)
+FILE(COPY ${jit_files} DESTINATION ${CMAKE_BINARY_DIR}/jit)
+
+SET(DASM_ARCH ${TARGET_LJARCH})
+SET(DASM_FLAGS)
+SET(TARGET_ARCH)
+LIST(APPEND TARGET_ARCH "LUAJIT_TARGET=LUAJIT_ARCH_${TARGET_LJARCH}")
+LJ_TEST_ARCH_VALUE(LJ_ARCH_BITS 64)
+IF(LJ_ARCH_BITS_64)
+ SET(DASM_FLAGS ${DASM_FLAGS} -D P64)
+ENDIF()
+LJ_TEST_ARCH_VALUE(LJ_HASJIT 1)
+IF(LJ_HASJIT_1)
+ SET(DASM_FLAGS ${DASM_FLAGS} -D JIT)
+ENDIF()
+LJ_TEST_ARCH_VALUE(LJ_HASFFI 1)
+IF(LJ_HASFFI_1)
+ SET(DASM_FLAGS ${DASM_FLAGS} -D FFI)
+ENDIF()
+LJ_TEST_ARCH_VALUE(LJ_DUALNUM 1)
+IF(LJ_DUALNUM_1)
+ SET(DASM_FLAGS ${DASM_FLAGS} -D DUALNUM)
+ENDIF()
+LJ_TEST_ARCH_VALUE(LJ_ARCH_HASFPU 1)
+IF(LJ_ARCH_HASFPU_1)
+ SET(DASM_FLAGS ${DASM_FLAGS} -D FPU)
+ LIST(APPEND TARGET_ARCH "LJ_ARCH_HASFPU=1")
+ELSE()
+ LIST(APPEND TARGET_ARCH "LJ_ARCH_HASFPU=0")
+ENDIF()
+LJ_TEST_ARCH_VALUE(LJ_ABI_SOFTFP 1)
+IF(NOT LJ_ABI_SOFTFP_1)
+ SET(DASM_FLAGS ${DASM_FLAGS} -D HFABI)
+ LIST(APPEND TARGET_ARCH "LJ_ABI_SOFTFP=0")
+ELSE()
+ LIST(APPEND TARGET_ARCH "LJ_ABI_SOFTFP=1")
+ENDIF()
+IF(WIN32)
+ SET(DASM_FLAGS ${DASM_FLAGS} -LN -D WIN)
+ENDIF()
+IF(TARGET_LJARCH STREQUAL "x86")
+ LJ_TEST_ARCH_VALUE(__SSE2__ 1)
+ IF(__SSE2__1)
+ SET(DASM_FLAGS ${DASM_FLAGS} -D SSE)
+ ENDIF()
+ENDIF()
+IF(TARGET_LJARCH STREQUAL "x64")
+ SET(DASM_ARCH "x86")
+ENDIF()
+IF(TARGET_LJARCH STREQUAL "ppc")
+ LJ_TEST_ARCH_VALUE(LJ_ARCH_SQRT 1)
+ IF(NOT LJ_ARCH_SQRT_1)
+ SET(DASM_FLAGS ${DASM_FLAGS} -D SQRT)
+ ENDIF()
+ LJ_TEST_ARCH_VALUE(LJ_ARCH_PPC64 1)
+ IF(NOT LJ_ARCH_PPC64_1)
+ SET(DASM_FLAGS ${DASM_FLAGS} -D GPR64)
+ ENDIF()
+ENDIF()
+
+add_executable(minilua ${LUAJIT_DIR}/src/host/minilua.c)
+SET_TARGET_PROPERTIES(minilua PROPERTIES COMPILE_DEFINITIONS "${TARGET_ARCH}")
+CHECK_LIBRARY_EXISTS(m sin "" MINILUA_USE_LIBM)
+if(MINILUA_USE_LIBM)
+ TARGET_LINK_LIBRARIES(minilua m)
+endif()
+
+add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/buildvm_arch.h
+ COMMAND minilua ${LUAJIT_DIR}/dynasm/dynasm.lua ${DASM_FLAGS} -o ${CMAKE_CURRENT_BINARY_DIR}/buildvm_arch.h ${LUAJIT_DIR}/src/vm_${DASM_ARCH}.dasc
+ DEPENDS ${LUAJIT_DIR}/dynasm/dynasm.lua minilua
+)
+
+SET(SRC_LJLIB
+ ${LUAJIT_DIR}/src/lib_base.c
+ ${LUAJIT_DIR}/src/lib_math.c
+ ${LUAJIT_DIR}/src/lib_bit.c
+ ${LUAJIT_DIR}/src/lib_string.c
+ ${LUAJIT_DIR}/src/lib_table.c
+ ${LUAJIT_DIR}/src/lib_io.c
+ ${LUAJIT_DIR}/src/lib_os.c
+ ${LUAJIT_DIR}/src/lib_package.c
+ ${LUAJIT_DIR}/src/lib_debug.c
+ ${LUAJIT_DIR}/src/lib_jit.c
+ ${LUAJIT_DIR}/src/lib_ffi.c)
+
+SET(SRC_LJCORE
+ ${LUAJIT_DIR}/src/lj_gc.c
+ ${LUAJIT_DIR}/src/lj_err.c
+ ${LUAJIT_DIR}/src/lj_char.c
+ ${LUAJIT_DIR}/src/lj_buf.c
+ ${LUAJIT_DIR}/src/lj_profile.c
+ ${LUAJIT_DIR}/src/lj_strfmt.c
+ ${LUAJIT_DIR}/src/lj_bc.c
+ ${LUAJIT_DIR}/src/lj_obj.c
+ ${LUAJIT_DIR}/src/lj_str.c
+ ${LUAJIT_DIR}/src/lj_tab.c
+ ${LUAJIT_DIR}/src/lj_func.c
+ ${LUAJIT_DIR}/src/lj_udata.c
+ ${LUAJIT_DIR}/src/lj_meta.c
+ ${LUAJIT_DIR}/src/lj_debug.c
+ ${LUAJIT_DIR}/src/lj_state.c
+ ${LUAJIT_DIR}/src/lj_dispatch.c
+ ${LUAJIT_DIR}/src/lj_vmevent.c
+ ${LUAJIT_DIR}/src/lj_vmmath.c
+ ${LUAJIT_DIR}/src/lj_strscan.c
+ ${LUAJIT_DIR}/src/lj_api.c
+ ${LUAJIT_DIR}/src/lj_lex.c
+ ${LUAJIT_DIR}/src/lj_parse.c
+ ${LUAJIT_DIR}/src/lj_bcread.c
+ ${LUAJIT_DIR}/src/lj_bcwrite.c
+ ${LUAJIT_DIR}/src/lj_load.c
+ ${LUAJIT_DIR}/src/lj_ir.c
+ ${LUAJIT_DIR}/src/lj_opt_mem.c
+ ${LUAJIT_DIR}/src/lj_opt_fold.c
+ ${LUAJIT_DIR}/src/lj_opt_narrow.c
+ ${LUAJIT_DIR}/src/lj_opt_dce.c
+ ${LUAJIT_DIR}/src/lj_opt_loop.c
+ ${LUAJIT_DIR}/src/lj_opt_split.c
+ ${LUAJIT_DIR}/src/lj_opt_sink.c
+ ${LUAJIT_DIR}/src/lj_mcode.c
+ ${LUAJIT_DIR}/src/lj_snap.c
+ ${LUAJIT_DIR}/src/lj_record.c
+ ${LUAJIT_DIR}/src/lj_crecord.c
+ ${LUAJIT_DIR}/src/lj_ffrecord.c
+ ${LUAJIT_DIR}/src/lj_asm.c
+ ${LUAJIT_DIR}/src/lj_trace.c
+ ${LUAJIT_DIR}/src/lj_gdbjit.c
+ ${LUAJIT_DIR}/src/lj_ctype.c
+ ${LUAJIT_DIR}/src/lj_cdata.c
+ ${LUAJIT_DIR}/src/lj_cconv.c
+ ${LUAJIT_DIR}/src/lj_ccall.c
+ ${LUAJIT_DIR}/src/lj_ccallback.c
+ ${LUAJIT_DIR}/src/lj_carith.c
+ ${LUAJIT_DIR}/src/lj_clib.c
+ ${LUAJIT_DIR}/src/lj_cparse.c
+ ${LUAJIT_DIR}/src/lj_lib.c
+ ${LUAJIT_DIR}/src/lj_alloc.c
+ ${LUAJIT_DIR}/src/lj_vmmath.c
+ ${LUAJIT_DIR}/src/lib_aux.c
+ ${LUAJIT_DIR}/src/lib_init.c
+ ${SRC_LJLIB})
+
+SET(SRC_BUILDVM
+ ${LUAJIT_DIR}/src/host/buildvm.c
+ ${LUAJIT_DIR}/src/host/buildvm_asm.c
+ ${LUAJIT_DIR}/src/host/buildvm_peobj.c
+ ${LUAJIT_DIR}/src/host/buildvm_lib.c
+ ${LUAJIT_DIR}/src/host/buildvm_fold.c
+ ${CMAKE_CURRENT_BINARY_DIR}/buildvm_arch.h)
+
+## GENERATE
+ADD_EXECUTABLE(buildvm ${SRC_BUILDVM})
+SET_TARGET_PROPERTIES(buildvm PROPERTIES COMPILE_DEFINITIONS "${TARGET_ARCH}")
+
+macro(add_buildvm_target _target _mode)
+ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_target}
+ COMMAND buildvm ARGS -m ${_mode} -o ${CMAKE_CURRENT_BINARY_DIR}/${_target} ${ARGN}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ DEPENDS buildvm ${ARGN}
+ )
+endmacro(add_buildvm_target)
+
+if (MSVC)
+ add_buildvm_target ( lj_vm.obj peobj )
+ set (LJ_VM_SRC ${CMAKE_CURRENT_BINARY_DIR}/lj_vm.obj)
+else ()
+ add_buildvm_target ( lj_vm.S ${LJVM_MODE} )
+ set (LJ_VM_SRC ${CMAKE_CURRENT_BINARY_DIR}/lj_vm.S)
+endif ()
+add_buildvm_target ( lj_ffdef.h ffdef ${SRC_LJLIB} )
+add_buildvm_target ( lj_bcdef.h bcdef ${SRC_LJLIB} )
+add_buildvm_target ( lj_folddef.h folddef ${LUAJIT_DIR}/src/lj_opt_fold.c )
+add_buildvm_target ( lj_recdef.h recdef ${SRC_LJLIB} )
+add_buildvm_target ( lj_libdef.h libdef ${SRC_LJLIB} )
+add_buildvm_target ( vmdef.lua vmdef ${SRC_LJLIB} )
+
+SET(DEPS
+ ${LJ_VM_SRC}
+ ${CMAKE_CURRENT_BINARY_DIR}/lj_ffdef.h
+ ${CMAKE_CURRENT_BINARY_DIR}/lj_bcdef.h
+ ${CMAKE_CURRENT_BINARY_DIR}/lj_libdef.h
+ ${CMAKE_CURRENT_BINARY_DIR}/lj_recdef.h
+ ${CMAKE_CURRENT_BINARY_DIR}/lj_folddef.h
+ ${CMAKE_CURRENT_BINARY_DIR}/vmdef.lua
+ )
+
+## COMPILE
+include_directories(
+ ${LUAJIT_DIR}/dynasm
+ ${LUAJIT_DIR}/src
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+IF(WITH_SHARED_LUA)
+ IF(WITH_AMALG)
+ add_library(luajit-5.1 SHARED ${LUAJIT_DIR}/src/ljamalg.c ${DEPS} )
+ ELSE()
+ add_library(luajit-5.1 SHARED ${SRC_LJCORE} ${DEPS} )
+ ENDIF()
+ SET_TARGET_PROPERTIES(luajit-5.1 PROPERTIES OUTPUT_NAME "lua51")
+ELSE()
+ IF(WITH_AMALG)
+ add_library(luajit-5.1 STATIC ${LUAJIT_DIR}/src/ljamalg.c ${DEPS} )
+ ELSE()
+ add_library(luajit-5.1 STATIC ${SRC_LJCORE} ${DEPS} )
+ ENDIF()
+ SET_TARGET_PROPERTIES(luajit-5.1 PROPERTIES
+ PREFIX "lib" IMPORT_PREFIX "lib" OUTPUT_NAME "luajit")
+ENDIF()
+
+target_link_libraries (luajit-5.1 ${LIBS} )
+
+IF(WIN32)
+ add_executable(luajit ${LUAJIT_DIR}/src/luajit.c)
+ target_link_libraries(luajit luajit-5.1)
+ELSE()
+ IF(WITH_AMALG)
+ add_executable(luajit ${LUAJIT_DIR}/src/luajit.c ${LUAJIT_DIR}/src/ljamalg.c ${DEPS})
+ ELSE()
+ add_executable(luajit ${LUAJIT_DIR}/src/luajit.c ${SRC_LJCORE} ${DEPS})
+ ENDIF()
+ target_link_libraries(luajit ${LIBS})
+ SET_TARGET_PROPERTIES(luajit PROPERTIES ENABLE_EXPORTS ON)
+ENDIF()
+
+MACRO(LUAJIT_add_custom_commands luajit_target)
+ SET(target_srcs "")
+ FOREACH(file ${ARGN})
+ IF(${file} MATCHES ".*\\.lua$")
+ set(file "${CMAKE_CURRENT_SOURCE_DIR}/${file}")
+ set(source_file ${file})
+ string(LENGTH ${CMAKE_SOURCE_DIR} _luajit_source_dir_length)
+ string(LENGTH ${file} _luajit_file_length)
+ math(EXPR _begin "${_luajit_source_dir_length} + 1")
+ math(EXPR _stripped_file_length "${_luajit_file_length} - ${_luajit_source_dir_length} - 1")
+ string(SUBSTRING ${file} ${_begin} ${_stripped_file_length} stripped_file)
+
+ set(generated_file "${CMAKE_BINARY_DIR}/jitted_tmp/${stripped_file}_${luajit_target}_generated${CMAKE_C_OUTPUT_EXTENSION}")
+
+ add_custom_command(
+ OUTPUT ${generated_file}
+ MAIN_DEPENDENCY ${source_file}
+ DEPENDS luajit
+ COMMAND luajit
+ ARGS -bg
+ ${source_file}
+ ${generated_file}
+ COMMENT "Building Luajitted ${source_file}: ${generated_file}"
+ )
+
+ get_filename_component(basedir ${generated_file} PATH)
+ file(MAKE_DIRECTORY ${basedir})
+
+ set(target_srcs ${target_srcs} ${generated_file})
+ set_source_files_properties(
+ ${generated_file}
+ properties
+ external_object true # this is an object file
+ generated true # to say that "it is OK that the obj-files do not exist before build time"
+ )
+ ELSE()
+ set(target_srcs ${target_srcs} ${file})
+ ENDIF(${file} MATCHES ".*\\.lua$")
+ ENDFOREACH(file)
+ENDMACRO()
+
+MACRO(LUAJIT_ADD_EXECUTABLE luajit_target)
+ LUAJIT_add_custom_commands(${luajit_target} ${ARGN})
+ add_executable(${luajit_target} ${target_srcs})
+ENDMACRO(LUAJIT_ADD_EXECUTABLE luajit_target)
diff --git a/3rdparty/luv/deps/uv.cmake b/3rdparty/luv/deps/uv.cmake
new file mode 100644
index 00000000000..b6570b26b60
--- /dev/null
+++ b/3rdparty/luv/deps/uv.cmake
@@ -0,0 +1,224 @@
+## Modifications
+## Copyright 2014 The Luvit Authors. All Rights Reserved.
+
+## Original Copyright
+# Copyright (c) 2014 David Capello
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# 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 AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+include(CheckTypeSize)
+
+cmake_minimum_required(VERSION 2.8.9)
+
+set(LIBUVDIR ${CMAKE_CURRENT_LIST_DIR}/libuv)
+
+include_directories(
+ ${LIBUVDIR}/src
+ ${LIBUVDIR}/include
+)
+
+set(SOURCES
+ ${LIBUVDIR}/include/uv.h
+ ${LIBUVDIR}/include/tree.h
+ ${LIBUVDIR}/include/uv-errno.h
+ ${LIBUVDIR}/include/uv-threadpool.h
+ ${LIBUVDIR}/include/uv-version.h
+ ${LIBUVDIR}/src/fs-poll.c
+ ${LIBUVDIR}/src/heap-inl.h
+ ${LIBUVDIR}/src/inet.c
+ ${LIBUVDIR}/src/queue.h
+ ${LIBUVDIR}/src/threadpool.c
+ ${LIBUVDIR}/src/uv-common.c
+ ${LIBUVDIR}/src/uv-common.h
+ ${LIBUVDIR}/src/version.c
+)
+
+if(WIN32)
+ add_definitions(
+ -D_WIN32_WINNT=0x0600
+ -D_CRT_SECURE_NO_WARNINGS
+ -D_GNU_SOURCE
+ )
+ set(SOURCES ${SOURCES}
+ ${LIBUVDIR}/include/uv-win.h
+ ${LIBUVDIR}/src/win/async.c
+ ${LIBUVDIR}/src/win/atomicops-inl.h
+ ${LIBUVDIR}/src/win/core.c
+ ${LIBUVDIR}/src/win/dl.c
+ ${LIBUVDIR}/src/win/error.c
+ ${LIBUVDIR}/src/win/fs.c
+ ${LIBUVDIR}/src/win/fs-event.c
+ ${LIBUVDIR}/src/win/getaddrinfo.c
+ ${LIBUVDIR}/src/win/getnameinfo.c
+ ${LIBUVDIR}/src/win/handle.c
+ ${LIBUVDIR}/src/win/handle-inl.h
+ ${LIBUVDIR}/src/win/internal.h
+ ${LIBUVDIR}/src/win/loop-watcher.c
+ ${LIBUVDIR}/src/win/pipe.c
+ ${LIBUVDIR}/src/win/thread.c
+ ${LIBUVDIR}/src/win/poll.c
+ ${LIBUVDIR}/src/win/process.c
+ ${LIBUVDIR}/src/win/process-stdio.c
+ ${LIBUVDIR}/src/win/req.c
+ ${LIBUVDIR}/src/win/req-inl.h
+ ${LIBUVDIR}/src/win/signal.c
+ ${LIBUVDIR}/src/win/snprintf.c
+ ${LIBUVDIR}/src/win/stream.c
+ ${LIBUVDIR}/src/win/stream-inl.h
+ ${LIBUVDIR}/src/win/tcp.c
+ ${LIBUVDIR}/src/win/tty.c
+ ${LIBUVDIR}/src/win/timer.c
+ ${LIBUVDIR}/src/win/udp.c
+ ${LIBUVDIR}/src/win/util.c
+ ${LIBUVDIR}/src/win/winapi.c
+ ${LIBUVDIR}/src/win/winapi.h
+ ${LIBUVDIR}/src/win/winsock.c
+ ${LIBUVDIR}/src/win/winsock.h
+ )
+else()
+ include_directories(${LIBUVDIR}/src/unix)
+ set(SOURCES ${SOURCES}
+ ${LIBUVDIR}/include/uv-unix.h
+ ${LIBUVDIR}/include/uv-linux.h
+ ${LIBUVDIR}/include/uv-sunos.h
+ ${LIBUVDIR}/include/uv-darwin.h
+ ${LIBUVDIR}/include/uv-bsd.h
+ ${LIBUVDIR}/include/uv-aix.h
+ ${LIBUVDIR}/src/unix/async.c
+ ${LIBUVDIR}/src/unix/atomic-ops.h
+ ${LIBUVDIR}/src/unix/core.c
+ ${LIBUVDIR}/src/unix/dl.c
+ ${LIBUVDIR}/src/unix/fs.c
+ ${LIBUVDIR}/src/unix/getaddrinfo.c
+ ${LIBUVDIR}/src/unix/getnameinfo.c
+ ${LIBUVDIR}/src/unix/internal.h
+ ${LIBUVDIR}/src/unix/loop.c
+ ${LIBUVDIR}/src/unix/loop-watcher.c
+ ${LIBUVDIR}/src/unix/pipe.c
+ ${LIBUVDIR}/src/unix/poll.c
+ ${LIBUVDIR}/src/unix/process.c
+ ${LIBUVDIR}/src/unix/signal.c
+ ${LIBUVDIR}/src/unix/spinlock.h
+ ${LIBUVDIR}/src/unix/stream.c
+ ${LIBUVDIR}/src/unix/tcp.c
+ ${LIBUVDIR}/src/unix/thread.c
+ ${LIBUVDIR}/src/unix/timer.c
+ ${LIBUVDIR}/src/unix/tty.c
+ ${LIBUVDIR}/src/unix/udp.c
+ )
+endif()
+
+check_type_size("void*" SIZEOF_VOID_P)
+if(SIZEOF_VOID_P EQUAL 8)
+ add_definitions(-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE)
+endif()
+
+## Freebsd
+if("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD")
+ set(SOURCES ${SOURCES}
+ ${LIBUVDIR}/src/unix/kqueue.c
+ ${LIBUVDIR}/src/unix/freebsd.c
+ )
+endif()
+
+## Linux
+if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
+ add_definitions(
+ -D_GNU_SOURCE
+ )
+ set(SOURCES ${SOURCES}
+ ${LIBUVDIR}/src/unix/proctitle.c
+ ${LIBUVDIR}/src/unix/linux-core.c
+ ${LIBUVDIR}/src/unix/linux-inotify.c
+ ${LIBUVDIR}/src/unix/linux-syscalls.c
+ ${LIBUVDIR}/src/unix/linux-syscalls.h
+ )
+endif()
+
+## SunOS
+if("${CMAKE_SYSTEM_NAME}" MATCHES "SunOS")
+ add_definitions(
+ -D__EXTENSIONS__
+ -D_XOPEN_SOURCE=500
+ )
+ set(SOURCES ${SOURCES}
+ ${LIBUVDIR}/src/unix/sunos.c
+ )
+endif()
+
+## Darwin
+if(APPLE)
+ add_definitions(
+ -D=_DARWIN_USE_64_BIT_INODE
+ )
+ set(SOURCES ${SOURCES}
+ ${LIBUVDIR}/src/unix/proctitle.c
+ ${LIBUVDIR}/src/unix/darwin.c
+ ${LIBUVDIR}/src/unix/fsevents.c
+ ${LIBUVDIR}/src/unix/darwin-proctitle.c
+ ${LIBUVDIR}/src/unix/kqueue.c
+ )
+endif()
+
+add_library(uv STATIC ${SOURCES})
+set_property(TARGET uv PROPERTY POSITION_INDEPENDENT_CODE ON)
+
+if("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD")
+ target_link_libraries(uv
+ pthread
+ kvm
+ )
+endif()
+
+if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
+ target_link_libraries(uv
+ pthread
+ )
+endif()
+
+if(WIN32)
+ target_link_libraries(uv
+ ws2_32.lib
+ shell32.lib
+ psapi.lib
+ iphlpapi.lib
+ advapi32.lib
+ Userenv.lib
+ )
+endif()
+
+if("${CMAKE_SYSTEM_NAME}" MATCHES "SunOS")
+ target_link_libraries(uv
+ kstat
+ socket
+ sendfile
+ )
+endif()
+
+if(APPLE)
+ find_library(FOUNDATION_LIBRARY Foundation)
+ find_library(CORESERVICES_LIBRARY CoreServices)
+ find_library(APPLICATION_SERVICES_LIBRARY ApplicationServices)
+ target_link_libraries(uv
+ ${FOUNDATION_LIBRARY}
+ ${CORESERVICES_LIBRARY}
+ ${APPLICATION_SERVICES_LIBRARY}
+ )
+endif()
diff --git a/3rdparty/luv/docs.md b/3rdparty/luv/docs.md
new file mode 100644
index 00000000000..187dec24ff1
--- /dev/null
+++ b/3rdparty/luv/docs.md
@@ -0,0 +1,1309 @@
+# LibUV in Lua
+
+The [luv][] project provides access to the multi-platform support library
+[libuv][] to lua code. It was primariliy developed for the [luvit][] project as
+the `uv` builtin module, but can be used in other lua environments.
+
+### TCP Echo Server Example
+
+Here is a small example showing a TCP echo server:
+
+```lua
+local uv = require('uv')
+
+local server = uv.new_tcp()
+server:bind("127.0.0.1", 1337)
+server:listen(128, function (err)
+ assert(not err, err)
+ local client = uv.new_tcp()
+ server:accept(client)
+ client:read_start(function (err, chunk)
+ assert(not err, err)
+ if chunk then
+ client:write(chunk)
+ else
+ client:shutdown()
+ client:close()
+ end
+ end)
+end)
+print("TCP server listening at 127.0.0.1 port 1337")
+uv.run()
+```
+
+### Methods vs Functions
+
+As a quick note, [libuv][] is a C library and as such, there are no such things
+as methods. The [luv][] bindings allow calling the libuv functions as either
+functions or methods. For example, calling `server:bind(host, port)` is
+equivalent to calling `uv.tcp_bind(server, host, port)`. All wrapped uv types
+in lua have method shortcuts where is makes sense. Some are even renamed
+shorter like the `tcp_` prefix that removed in method form. Under the hood it's
+the exact same C function.
+
+## Table Of Contents
+
+The rest of the docs are organized by libuv type. There is some hierarchy as
+most types are considered handles and some are considered streams.
+
+ - [`uv_loop_t`][] — Event loop
+ - [`uv_handle_t`][] — Base handle
+ - [`uv_timer_t`][] — Timer handle
+ - [`uv_prepare_t`][] — Prepare handle
+ - [`uv_check_t`][] — Check handle
+ - [`uv_idle_t`][] — Idle handle
+ - [`uv_async_t`][] — Async handle
+ - [`uv_poll_t`][] — Poll handle
+ - [`uv_signal_t`][] — Signal handle
+ - [`uv_process_t`][] — Process handle
+ - [`uv_stream_t`][] — Stream handle
+ - [`uv_tcp_t`][] — TCP handle
+ - [`uv_pipe_t`][] — Pipe handle
+ - [`uv_tty_t`][] — TTY handle
+ - [`uv_udp_t`][] — UDP handle
+ - [`uv_fs_event_t`][] — FS Event handle
+ - [`uv_fs_poll_t`][] — FS Poll handle
+ - [Filesystem operations][]
+ - [DNS utility functions][]
+ - [Miscellaneous utilities][]
+
+## `uv_loop_t` — Event loop
+
+[`uv_loop_t`]: #uv_loop_t--event-loop
+
+The event loop is the central part of libuv’s functionality. It takes care of
+polling for i/o and scheduling callbacks to be run based on different sources of
+events.
+
+In [luv][], there is an implicit uv loop for every lua state that loads the
+library. You can use this library in an multithreaded environment as long as
+each thread has it's own lua state with corresponsding own uv loop.
+
+### `uv.loop_close()`
+
+Closes all internal loop resources. This function must only be called once the
+loop has finished its execution or it will raise a UV_EBUSY error.
+
+### `uv.run([mode])`
+
+> optional `mode` defaults to `"default"`
+
+This function runs the event loop. It will act differently depending on the
+specified mode:
+
+ - `"default"`: Runs the event loop until there are no more active and
+ referenced handles or requests. Always returns `false`.
+
+ - `"once"`: Poll for i/o once. Note that this function blocks if there are no
+ pending callbacks. Returns `false` when done (no active handles or requests
+ left), or `true` if more callbacks are expected (meaning you should run
+ the event loop again sometime in the future).
+
+ - `"nowait"`: Poll for i/o once but don’t block if there are no
+ pending callbacks. Returns `false` if done (no active handles or requests
+ left), or `true` if more callbacks are expected (meaning you should run
+ the event loop again sometime in the future).
+
+Luvit will implicitly call `uv.run()` after loading user code, but if you use
+the `luv` bindings directly, you need to call this after registering your
+initial set of event callbacks to start the event loop.
+
+### `uv.loop_alive()`
+
+Returns true if there are active handles or request in the loop.
+
+### `uv.stop()`
+
+Stop the event loop, causing `uv_run()` to end as soon as possible. This
+will happen not sooner than the next loop iteration. If this function was called
+before blocking for i/o, the loop won’t block for i/o on this iteration.
+
+### `uv.backend_fd()`
+
+Get backend file descriptor. Only kqueue, epoll and event ports are supported.
+
+This can be used in conjunction with `uv_run("nowait")` to poll in one thread
+and run the event loop’s callbacks in another.
+
+**Note**: Embedding a kqueue fd in another kqueue pollset doesn’t work on all
+platforms. It’s not an error to add the fd but it never generates events.
+
+### `uv.backend_timeout()`
+
+Get the poll timeout. The return value is in milliseconds, or -1 for no timeout.
+
+### `uv.now()`
+
+Return the current timestamp in milliseconds. The timestamp is cached at the
+start of the event loop tick, see `uv.update_time()` for details and rationale.
+
+The timestamp increases monotonically from some arbitrary point in time. Don’t
+make assumptions about the starting point, you will only get disappointed.
+
+**Note**: Use `uv.hrtime()` if you need sub-millisecond granularity.
+
+### `uv.update_time()`
+
+Update the event loop’s concept of “nowâ€. Libuv caches the current time at the
+start of the event loop tick in order to reduce the number of time-related
+system calls.
+
+You won’t normally need to call this function unless you have callbacks that
+block the event loop for longer periods of time, where “longer†is somewhat
+subjective but probably on the order of a millisecond or more.
+
+### `uv.walk(callback)`
+
+Walk the list of handles: `callback` will be executed with the handle.
+
+```lua
+-- Example usage of uv.walk to close all handles that aren't already closing.
+uv.walk(function (handle)
+ if not handle:is_closing() then
+ handle:close()
+ end
+end)
+```
+
+## `uv_handle_t` — Base handle
+
+[`uv_handle_t`]: #uv_handle_t--base-handle
+
+`uv_handle_t` is the base type for all libuv handle types.
+
+Structures are aligned so that any libuv handle can be cast to `uv_handle_t`.
+All API functions defined here work with any handle type.
+
+### `uv.is_active(handle)`
+
+> method form `handle:is_active()`
+
+Returns `true` if the handle is active, `false` if it’s inactive. What “activeâ€
+means depends on the type of handle:
+
+ - A [`uv_async_t`][] handle is always active and cannot be deactivated, except
+ by closing it with uv_close().
+
+ - A [`uv_pipe_t`][], [`uv_tcp_t`][], [`uv_udp_t`][], etc. handlebasically any
+ handle that deals with i/ois active when it is doing something that
+ involves i/o, like reading, writing, connecting, accepting new connections,
+ etc.
+
+ - A [`uv_check_t`][], [`uv_idle_t`][], [`uv_timer_t`][], etc. handle is active
+ when it has been started with a call to `uv.check_start()`,
+ `uv.idle_start()`, etc.
+
+Rule of thumb: if a handle of type `uv_foo_t` has a `uv.foo_start()` function,
+then it’s active from the moment that function is called. Likewise,
+`uv.foo_stop()` deactivates the handle again.
+
+### `uv.is_closing(handle)`
+
+> method form `handle:is_closing()`
+
+Returns `true` if the handle is closing or closed, `false` otherwise.
+
+**Note**: This function should only be used between the initialization of the
+handle and the arrival of the close callback.
+
+### `uv.close(handle, callback)`
+
+> method form `handle:close(callback)`
+
+Request handle to be closed. `callback` will be called asynchronously after this
+call. This MUST be called on each handle before memory is released.
+
+Handles that wrap file descriptors are closed immediately but `callback` will
+still be deferred to the next iteration of the event loop. It gives you a chance
+to free up any resources associated with the handle.
+
+In-progress requests, like `uv_connect_t` or `uv_write_t`, are cancelled and
+have their callbacks called asynchronously with `status=UV_ECANCELED`.
+
+### `uv.ref(handle)`
+
+> method form `handle:ref()`
+
+Reference the given handle. References are idempotent, that is, if a handle is
+already referenced calling this function again will have no effect.
+
+See [Reference counting][].
+
+### `uv.unref(handle)`
+
+> method form `handle:unref()`
+
+Un-reference the given handle. References are idempotent, that is, if a handle
+is not referenced calling this function again will have no effect.
+
+See [Reference counting][].
+
+### `uv.has_ref(handle)`
+
+> method form `handle:has_ref()`
+
+Returns `true` if the handle referenced, `false` otherwise.
+
+See [Reference counting][].
+
+### `uv.send_buffer_size(handle, [size]) -> size`
+
+> method form `handle:send_buffer_size(size)`
+
+Gets or sets the size of the send buffer that the operating system uses for the
+socket.
+
+If `size` is omitted, it will return the current send buffer size, otherwise it
+will use `size` to set the new send buffer size.
+
+This function works for TCP, pipe and UDP handles on Unix and for TCP and UDP
+handles on Windows.
+
+**Note**: Linux will set double the size and return double the size of the
+original set value.
+
+### `uv.recv_buffer_size(handle, [size])`
+
+> method form `handle:recv_buffer_size(size)`
+
+Gets or sets the size of the receive buffer that the operating system uses for
+the socket.
+
+If `size` is omitted, it will return the current receive buffer size, otherwise
+it will use `size` to set the new receive buffer size.
+
+This function works for TCP, pipe and UDP handles on Unix and for TCP and UDP
+handles on Windows.
+
+**Note**: Linux will set double the size and return double the size of the
+original set value.
+
+### `uv.fileno(handle)`
+
+> method form `handle:fileno()`
+
+Gets the platform dependent file descriptor equivalent.
+
+The following handles are supported: TCP, pipes, TTY, UDP and poll. Passing any
+other handle type will fail with UV_EINVAL.
+
+If a handle doesn’t have an attached file descriptor yet or the handle itself
+has been closed, this function will return UV_EBADF.
+
+**Warning**: Be very careful when using this function. libuv assumes it’s in
+control of the file descriptor so any change to it may lead to malfunction.
+
+## Reference counting
+
+[reference counting]: #reference-counting
+
+The libuv event loop (if run in the default mode) will run until there are no
+active and referenced handles left. The user can force the loop to exit early by
+unreferencing handles which are active, for example by calling `uv.unref()`
+after calling `uv.timer_start()`.
+
+A handle can be referenced or unreferenced, the refcounting scheme doesn’t use a
+counter, so both operations are idempotent.
+
+All handles are referenced when active by default, see `uv.is_active()` for a
+more detailed explanation on what being active involves.
+
+## `uv_timer_t` — Timer handle
+
+[`uv_timer_t`]: #uv_timer_t--timer-handle
+
+Timer handles are used to schedule callbacks to be called in the future.
+
+### `uv.new_timer() -> timer`
+
+Creates and initializes a new `uv_timer_t`. Returns the lua userdata wrapping
+it.
+
+```lua
+-- Creating a simple setTimeout wrapper
+local function setTimeout(timeout, callback)
+ local timer = uv.new_timer()
+ timer:start(timeout, 0, function ()
+ timer:stop()
+ timer:close()
+ callback()
+ end)
+ return timer
+end
+
+-- Creating a simple setInterval wrapper
+local function setInterval(interval, callback)
+ local timer = uv.new_timer()
+ timer:start(interval, interval, function ()
+ timer:stop()
+ timer:close()
+ callback()
+ end)
+ return timer
+end
+
+-- And clearInterval
+local function clearInterval(timer)
+ timer:stop()
+ timer:close()
+end
+```
+
+### `uv.timer_start(timer, timeout, repeat, callback)`
+
+> method form `timer:start(timeout, repeat, callback)`
+
+Start the timer. `timeout` and `repeat` are in milliseconds.
+
+If `timeout` is zero, the callback fires on the next event loop iteration. If
+`repeat` is non-zero, the callback fires first after timeout milliseconds and
+then repeatedly after repeat milliseconds.
+
+### `uv.timer_stop(timer)`
+
+> method form `timer:stop()`
+
+Stop the timer, the callback will not be called anymore.
+
+### `uv.timer_again(timer)`
+
+> method form `timer:again()`
+
+Stop the timer, and if it is repeating restart it using the repeat value as the
+timeout. If the timer has never been started before it raises `EINVAL`.
+
+### `uv.timer_set_repeat(timer, repeat)`
+
+> method form `timer:set_repeat(repeat)`
+
+Set the repeat value in milliseconds.
+
+**Note**: If the repeat value is set from a timer callback it does not
+immediately take effect. If the timer was non-repeating before, it will have
+been stopped. If it was repeating, then the old repeat value will have been
+used to schedule the next timeout.
+
+### `uv.timer_get_repeat(timer) -> repeat`
+
+> method form `timer:get_repeat() -> repeat`
+
+Get the timer repeat value.
+
+## `uv_prepare_t` — Prepare handle
+
+[`uv_prepare_t`]: #uv_prepare_t--prepare-handle
+
+Prepare handles will run the given callback once per loop iteration, right before polling for i/o.
+
+```lua
+local prepare = uv.new_prepare()
+prepare:start(function()
+ print("Before I/O polling")
+end)
+```
+
+### `uv.new_prepare() -> prepare`
+
+Creates and initializes a new `uv_prepare_t`. Returns the lua userdata wrapping
+it.
+
+### `uv.prepare_start(prepare, callback)`
+
+> method form `prepare:start(callback)`
+
+Start the handle with the given callback.
+
+### `uv.prepare_stop(prepare)`
+
+> method form `prepare:stop()`
+
+Stop the handle, the callback will no longer be called.
+
+## `uv_check_t` — Check handle
+
+[`uv_check_t`]: #uv_check_t--check-handle
+
+Check handles will run the given callback once per loop iteration, right after
+polling for i/o.
+
+```lua
+local check = uv.new_check()
+check:start(function()
+ print("After I/O polling")
+end)
+```
+
+### `uv.new_check() -> check`
+
+Creates and initializes a new `uv_check_t`. Returns the lua userdata wrapping
+it.
+
+### `uv.check_start(check, callback)`
+
+> method form `check:start(callback)`
+
+Start the handle with the given callback.
+
+### `uv.check_stop(check)`
+
+> method form `check:stop()`
+
+Stop the handle, the callback will no longer be called.
+
+## `uv_idle_t` — Idle handle
+
+[`uv_idle_t`]: #uv_idle_t--idle-handle
+
+Idle handles will run the given callback once per loop iteration, right before
+the [`uv_prepare_t`][] handles.
+
+**Note**: The notable difference with prepare handles is that when there are
+active idle handles, the loop will perform a zero timeout poll instead of
+blocking for i/o.
+
+**Warning**: Despite the name, idle handles will get their callbacks called on
+every loop iteration, not when the loop is actually “idleâ€.
+
+```lua
+local idle = uv.new_idle()
+idle:start(function()
+ print("Before I/O polling, no blocking")
+end)
+```
+### `uv.new_idle() -> idle`
+
+Creates and initializes a new `uv_idle_t`. Returns the lua userdata wrapping
+it.
+
+### `uv.idle_start(idle, callback)`
+
+> method form `idle:start(callback)`
+
+Start the handle with the given callback.
+
+### `uv.idle_stop(check)`
+
+> method form `idle:stop()`
+
+Stop the handle, the callback will no longer be called.
+
+## `uv_async_t` — Async handle
+
+[`uv_async_t`]: #uv_async_t--async-handle
+
+Async handles allow the user to “wakeup†the event loop and get a callback
+called from another thread.
+
+```lua
+local async
+async = uv.new_async(function()
+ print("async operation ran")
+ async:close()
+end)
+
+async:send()
+```
+
+### `uv.new_async(callback) -> async`
+
+Creates and initializes a new `uv_async_t`. Returns the lua userdata wrapping
+it. A NULL callback is allowed.
+
+**Note**: Unlike other handle initialization functions, it immediately starts
+the handle.
+
+### `uv.async_send(async)`
+
+> method form `async:send()`
+
+Wakeup the event loop and call the async handle’s callback.
+
+**Note**: It’s safe to call this function from any thread. The callback will be
+called on the loop thread.
+
+**Warning**: libuv will coalesce calls to `uv.async_send(async)`, that is, not
+every call to it will yield an execution of the callback, the only guarantee is
+that it will be called at least once. Thus, calling this function may not
+wakeup the event loop if it was already called previously within a short period
+of time.
+
+## `uv_poll_t` — Poll handle
+
+[`uv_poll_t`]: #uv_poll_t--poll-handle
+
+Poll handles are used to watch file descriptors for readability and writability,
+similar to the purpose of [poll(2)](http://linux.die.net/man/2/poll).
+
+The purpose of poll handles is to enable integrating external libraries that
+rely on the event loop to signal it about the socket status changes, like c-ares
+or libssh2. Using `uv_poll_t` for any other purpose is not recommended;
+`uv_tcp_t`, `uv_udp_t`, etc. provide an implementation that is faster and more
+scalable than what can be achieved with `uv_poll_t`, especially on Windows.
+
+It is possible that poll handles occasionally signal that a file descriptor is
+readable or writable even when it isn’t. The user should therefore always be
+prepared to handle EAGAIN or equivalent when it attempts to read from or write
+to the fd.
+
+It is not okay to have multiple active poll handles for the same socket, this
+can cause libuv to busyloop or otherwise malfunction.
+
+The user should not close a file descriptor while it is being polled by an
+active poll handle. This can cause the handle to report an error, but it might
+also start polling another socket. However the fd can be safely closed
+immediately after a call to `uv.poll_stop()` or `uv.close()`.
+
+**Note** On windows only sockets can be polled with poll handles. On Unix any
+file descriptor that would be accepted by poll(2) can be used.
+
+
+### `uv.new_poll(fd) -> poll`
+
+Initialize the handle using a file descriptor.
+
+The file descriptor is set to non-blocking mode.
+
+### `uv.new_socket_poll(fd) -> poll`
+
+Initialize the handle using a socket descriptor. On Unix this is identical to
+`uv.poll_init()`. On windows it takes a SOCKET handle.
+
+The socket is set to non-blocking mode.
+
+### `uv.poll_start(poll, events, callback)`
+
+> method form `poll:start()`
+
+Starts polling the file descriptor. `events` is `"r"`, `"w"`, or `"rw"` and
+translates to a bitmask made up of UV_READABLE and UV_WRITABLE. As soon as an
+event is detected the callback will be called with status set to 0, and the
+detected events set on the events field.
+
+The user should not close the socket while the handle is active. If the user
+does that anyway, the callback may be called reporting an error status, but this
+is not guaranteed.
+
+**Note** Calling `uv.poll_start()`` on a handle that is already active is fine.
+Doing so will update the events mask that is being watched for.
+
+## `uv.poll_stop(poll)`
+
+> method form `poll:stop()`
+
+Stop polling the file descriptor, the callback will no longer be called.
+
+## `uv_signal_t` — Signal handle
+
+[`uv_signal_t`]: #uv_signal_t--signal-handle
+
+Signal handles implement Unix style signal handling on a per-event loop bases.
+
+Reception of some signals is emulated on Windows:
+* SIGINT is normally delivered when the user presses CTRL+C. However, like on
+Unix, it is not generated when terminal raw mode is enabled.
+* SIGBREAK is delivered when the user pressed CTRL + BREAK.
+* SIGHUP is generated when the user closes the console window. On SIGHUP the
+program is given approximately 10 seconds to perform cleanup. After that
+Windows will unconditionally terminate it.
+* SIGWINCH is raised whenever libuv detects that the console has been resized.
+SIGWINCH is emulated by libuv when the program uses a uv_tty_t handle to write
+to the console. SIGWINCH may not always be delivered in a timely manner; libuv
+will only detect size changes when the cursor is being moved. When a readable
+[`uv_tty_t`][] handle is used in raw mode, resizing the console buffer will
+also trigger a SIGWINCH signal.
+
+Watchers for other signals can be successfully created, but these signals are
+never received. These signals are: SIGILL, SIGABRT, SIGFPE, SIGSEGV, SIGTERM
+and SIGKILL.
+
+Calls to raise() or abort() to programmatically raise a signal are not detected
+by libuv; these will not trigger a signal watcher.
+
+**Note**: On Linux SIGRT0 and SIGRT1 (signals 32 and 33) are used by the NPTL
+pthreads library to manage threads. Installing watchers for those signals will
+lead to unpredictable behavior and is strongly discouraged. Future versions of
+libuv may simply reject them.
+
+```lua
+-- Create a new signal handler
+local sigint = uv.new_signal()
+-- Define a handler function
+uv.signal_start(sigint, "sigint", function(signal)
+print("got " .. signal .. ", shutting down")
+os.exit(1)
+end)
+```
+
+### `uv.new_signal() -> signal`
+
+Creates and initializes a new `uv_signal_t`. Returns the lua userdata wrapping
+it.
+
+### `uv.signal_start(signal, signum, callback)`
+
+> method form `signal:start(signum, callback)`
+
+Start the handle with the given callback, watching for the given signal.
+
+### `uv.signal_stop(signal)`
+
+> method form `signal:stop()`
+
+Stop the handle, the callback will no longer be called.
+
+## `uv_process_t` — Process handle
+
+[`uv_process_t`]: #uv_process_t--process-handle
+
+Process handles will spawn a new process and allow the user to control it and
+establish communication channels with it using streams.
+
+### `uv.disable_stdio_inheritance()`
+
+Disables inheritance for file descriptors / handles that this process inherited
+from its parent. The effect is that child processes spawned by this process
+don’t accidentally inherit these handles.
+
+It is recommended to call this function as early in your program as possible,
+before the inherited file descriptors can be closed or duplicated.
+
+**Note** This function works on a best-effort basis: there is no guarantee that
+libuv can discover all file descriptors that were inherited. In general it does
+a better job on Windows than it does on Unix.
+
+### `uv.spawn(file, options, onexit) -> process, pid`
+
+Initializes the process handle and starts the process. If the process is
+successfully spawned, this function will return the handle and pid of the child
+process.
+
+Possible reasons for failing to spawn would include (but not be limited to) the
+file to execute not existing, not having permissions to use the setuid or setgid
+specified, or not having enough memory to allocate for the new process.
+
+
+```lua
+local stdout = uv.new_pipe(false)
+local stderr = uv.new_pipe(false)
+local stdin = uv.new_pipe(false)
+
+local handle, pid
+
+local function onexit(code, signal)
+ p("exit", {code=code,signal=signal})
+end
+
+local function onclose()
+ p("close")
+end
+
+local function onread(err, chunk)
+ assert(not err, err)
+ if (chunk) then
+ p("data", {data=chunk})
+ else
+ p("end")
+ end
+end
+
+local function onshutdown()
+ uv.close(handle, onclose)
+end
+
+handle, pid = uv.spawn("cat", {
+ stdio = {stdin, stdout, stderr}
+}, onexit)
+
+p{
+ handle=handle,
+ pid=pid
+}
+
+uv.read_start(stdout, onread)
+uv.read_start(stderr, onread)
+uv.write(stdin, "Hello World")
+uv.shutdown(stdin, onshutdown)
+```
+
+ - `options.args` - Command line arguments as a list of string. The first string
+ should be the path to the program. On Windows this uses CreateProcess which
+ concatenates the arguments into a string this can cause some strange errors.
+ (See `options.verbatim` below for Windows.)
+ - `options.stdio` - Set the file descriptors that will be made available to the
+ child process. The convention is that the first entries are stdin, stdout,
+ and stderr. (**Note** On Windows file descriptors after the third are
+ available to the child process only if the child processes uses the MSVCRT
+ runtime.)
+ - `options.env` - Set environment variables for the new process.
+ - `options.cwd` - Set current working directory for the subprocess.
+ - `options.uid` - Set the child process' user id.
+ - `options.gid` - Set the child process' group id.
+ - `options.verbatim` - If true, do not wrap any arguments in quotes, or perform
+ any other escaping, when converting the argument list into a command line
+ string. This option is only meaningful on Windows systems. On Unix it is
+ silently ignored.
+ - `options.detached` - If true, spawn the child process in a detached state -
+ this will make it a process group leader, and will effectively enable the
+ child to keep running after the parent exits. Note that the child process
+ will still keep the parent's event loop alive unless the parent process calls
+ `uv.unref()` on the child's process handle.
+ - `options.hide` - If true, hide the subprocess console window that would
+ normally be created. This option is only meaningful on Windows systems. On
+ Unix it is silently ignored.
+
+The `options.stdio` entries can take many shapes.
+
+- If they are numbers, then the child process inherits that same zero-indexed fd
+ from the parent process.
+- If `uv_stream_h` handles are passed in, those are used as a read-write pipe or
+ inherited stream depending if the stream has a valid fd.
+- Including `nil` placeholders means to ignore that fd in the child.
+
+When the child process exits, the `onexit` callback will be called with exit
+code and signal.
+
+### `uv.process_kill(process, sigmun)`
+
+> method form `process:kill(sigmun)`
+
+Sends the specified signal to the given process handle.
+
+### `uv.kill(pid, sigmun)`
+
+Sends the specified signal to the given PID.
+
+## `uv_stream_t` — Stream handle
+
+[`uv_stream_t`]: #uv_stream_t--stream-handle
+
+Stream handles provide an abstraction of a duplex communication channel.
+[`uv_stream_t`][] is an abstract type, libuv provides 3 stream implementations in
+the form of [`uv_tcp_t`][], [`uv_pipe_t`][] and [`uv_tty_t`][].
+
+### `uv.shutdown(stream, [callback]) -> req`
+
+> (method form `stream:shutdown([callback]) -> req`)
+
+Shutdown the outgoing (write) side of a duplex stream. It waits for pending
+write requests to complete. The callback is called after
+shutdown is complete.
+
+### `uv.listen(stream, backlog, callback)`
+
+> (method form `stream:listen(backlog, callback)`)
+
+Start listening for incoming connections. `backlog` indicates the number of
+connections the kernel might queue, same as `listen(2)`. When a new incoming
+connection is received the callback is called.
+
+### `uv.accept(stream, client_stream)`
+
+> (method form `stream:accept(client_stream)`)
+
+This call is used in conjunction with `uv.listen()` to accept incoming
+connections. Call this function after receiving a callback to accept the
+connection.
+
+When the connection callback is called it is guaranteed that this function
+will complete successfully the first time. If you attempt to use it more than
+once, it may fail. It is suggested to only call this function once per
+connection call.
+
+```lua
+server:listen(128, function (err)
+ local client = uv.new_tcp()
+ server:accept(client)
+end)
+```
+
+### `uv.read_start(stream, callback)`
+
+> (method form `stream:read_start(callback)`)
+
+Callback is of the form `(err, data)`.
+
+Read data from an incoming stream. The callback will be made several times until
+there is no more data to read or `uv.read_stop()` is called. When we’ve reached
+EOF, `data` will be `nil`.
+
+```lua
+stream:read_start(function (err, chunk)
+ if err then
+ -- handle read error
+ elseif chunk then
+ -- handle data
+ else
+ -- handle disconnect
+ end
+end)
+```
+
+### `uv.read_stop(stream)`
+
+> (method form `stream:read_stop()`)
+
+Stop reading data from the stream. The read callback will no longer be called.
+
+### `uv.write(stream, data, [callback])`
+
+> (method form `stream:write(data, [callback])`)
+
+Write data to stream.
+
+`data` can either be a lua string or a table of strings. If a table is passed
+in, the C backend will use writev to send all strings in a single system call.
+
+The optional `callback` is for knowing when the write is
+complete.
+
+### `uv.write2(stream, data, send_handle, callback)`
+
+> (method form `stream:write2(data, send_handle, callback)`)
+
+Extended write function for sending handles over a pipe. The pipe must be
+initialized with ip option to `true`.
+
+**Note: `send_handle` must be a TCP socket or pipe, which is a server or a
+connection (listening or connected state). Bound sockets or pipes will be
+assumed to be servers.
+
+### `uv.try_write(stream, data)`
+
+> (method form `stream:try_write(data)`)
+
+Same as `uv.write()`, but won’t queue a write request if it can’t be completed
+immediately.
+
+Will return number of bytes written (can be less than the supplied buffer size).
+
+### `uv.is_readable(stream)`
+
+> (method form `stream:is_readable()`)
+
+Returns `true` if the stream is readable, `false` otherwise.
+
+### `uv.is_writable(stream)`
+
+> (method form `stream:is_writable()`)
+
+Returns `true` if the stream is writable, `false` otherwise.
+
+### `uv.stream_set_blocking(stream, blocking)`
+
+> (method form `stream:set_blocking(blocking)`)
+
+Enable or disable blocking mode for a stream.
+
+When blocking mode is enabled all writes complete synchronously. The interface
+remains unchanged otherwise, e.g. completion or failure of the operation will
+still be reported through a callback which is made asynchronously.
+
+**Warning**: Relying too much on this API is not recommended. It is likely to
+change significantly in the future. Currently this only works on Windows and
+only for uv_pipe_t handles. Also libuv currently makes no ordering guarantee
+when the blocking mode is changed after write requests have already been
+submitted. Therefore it is recommended to set the blocking mode immediately
+after opening or creating the stream.
+
+## `uv_tcp_t` — TCP handle
+
+[`uv_tcp_t`]: #uv_tcp_t--tcp-handle
+
+TCP handles are used to represent both TCP streams and servers.
+
+`uv_tcp_t` is a ‘subclass’ of [`uv_stream_t`][](#uv_stream_t--stream-handle).
+
+### `uv.new_tcp() -> tcp`
+
+Creates and initializes a new `uv_tcp_t`. Returns the lua userdata wrapping it.
+
+### `uv.tcp_open(tcp, sock)`
+
+> (method form `tcp:open(sock)`)
+
+Open an existing file descriptor or SOCKET as a TCP handle.
+
+**Note: The user is responsible for setting the file descriptor in non-blocking
+mode.
+
+### `uv.tcp_nodelay(tcp, enable)`
+
+> (method form `tcp:nodelay(enable)`)
+
+Enable / disable Nagle’s algorithm.
+
+### `uv.tcp_keepalive(tcp, enable, [delay])`
+
+> (method form `tcp:keepalive(enable, [delay])`)
+
+Enable / disable TCP keep-alive. `delay` is the initial delay in seconds, ignored
+when enable is `false`.
+
+### `uv.tcp_simultaneous_accepts(tcp, enable)`
+
+> (method form `tcp:simultaneous_accepts(enable)`)
+
+Enable / disable simultaneous asynchronous accept requests that are queued by
+the operating system when listening for new TCP connections.
+
+This setting is used to tune a TCP server for the desired performance. Having
+simultaneous accepts can significantly improve the rate of accepting connections
+(which is why it is enabled by default) but may lead to uneven load distribution
+in multi-process setups.
+
+### `uv.tcp_bind(tcp, address, port)`
+
+> (method form `tcp:bind(address, port)`)
+
+Bind the handle to an address and port. `address` should be an IP address and
+not a domain name.
+
+When the port is already taken, you can expect to see an UV_EADDRINUSE error
+from either `uv.tcp_bind()`, `uv.listen()` or `uv.tcp_connect()`. That is, a
+successful call to this function does not guarantee that the call to `uv.listen()`
+or `uv.tcp_connect()` will succeed as well.
+
+Use a port of `0` to let the OS assign an ephemeral port. You can look it up
+later using `uv.tcp_getsockname()`.
+
+### `uv.tcp_getsockname(tcp)`
+
+> (method form `tcp:getsockname()`)
+
+Get the current address to which the handle is bound.
+
+### `uv.tcp_getpeername(tcp)`
+
+> (method form `tcp:getpeername()`)
+
+Get the address of the peer connected to the handle.
+
+### `uv.tcp_connect(tcp, address, port, callback) -> req`
+
+> (method form `tcp:connect(host, port, callback) -> req`)
+
+### `uv.tcp_write_queue_size(tcp) -> size`
+
+> (method form `tcp:write_queue_size() -> size`)
+
+Establish an IPv4 or IPv6 TCP connection.
+
+The callback is made when the connection has been established or when a
+connection error happened.
+
+```lua
+local client = uv.new_tcp()
+client:connect("127.0.0.1", 8080, function (err)
+ -- check error and carry on.
+end)
+```
+
+## `uv_pipe_t` — Pipe handle
+
+[`uv_pipe_t`]: #uv_pipe_t--pipe-handle
+
+Pipe handles provide an abstraction over local domain sockets on Unix and named
+pipes on Windows.
+
+```lua
+local pipe = uv.new_pipe(false)
+
+pipe:bind('/tmp/sock.test')
+
+pipe:listen(128, function()
+ local client = uv.new_pipe(false)
+ pipe:accept(client)
+ client:write("hello!\n")
+ client:close()
+end)
+```
+
+### `uv.new_pipe(ipc) -> pipe`
+
+Creates and initializes a new `uv_pipe_t`. Returns the lua userdata wrapping
+it. The `ipc` argument is a boolean to indicate if this pipe will be used for
+handle passing between processes.
+
+### `uv.pipe_open(file) -> pipe`
+
+Open an existing file descriptor or [`uv_handle_t`][] as a pipe.
+
+**Note**: The file descriptor is set to non-blocking mode.
+
+### `uv.pipe_bind(pipe, name)`
+
+> (method form `pipe:bind(name)`)
+
+Bind the pipe to a file path (Unix) or a name (Windows).
+
+**Note**: Paths on Unix get truncated to sizeof(sockaddr_un.sun_path) bytes,
+typically between 92 and 108 bytes.
+
+### `uv.pipe_connect(pipe, name, callback)`
+
+> (method form `pipe:connect(name, callback)`)
+
+Connect to the Unix domain socket or the named pipe.
+
+**Note**: Paths on Unix get truncated to sizeof(sockaddr_un.sun_path) bytes,
+typically between 92 and 108 bytes.
+
+### `uv.pipe_getsockname(pipe)`
+
+> (method form `pipe:getsockname()`)
+
+Returns the name of the Unix domain socket or the named pipe.
+
+### `uv.pipe_pending_instances(pipe, count)`
+
+> (method form `pipe:pending_instances(count)`)
+
+Set the number of pending pipe instance handles when the pipe server is waiting for connections.
+
+**Note**: This setting applies to Windows only.
+
+### `uv.pipe_pending_count(pipe)`
+
+> (method form `pipe:pending_count()`)
+
+Returns the pending pipe count for the named pipe.
+
+### `uv.pipe_pending_type(pipe)`
+
+> (method form `pipe:pending_type()`)
+
+Used to receive handles over IPC pipes.
+
+First - call [`uv.pipe_pending_count`][], if it’s > 0 then initialize a handle
+of the given type, returned by [`uv.pipe_pending_type`][] and call
+[`uv.accept(pipe, handle)`][].
+
+## `uv_tty_t` — TTY handle
+
+[`uv_tty_t`]: #uv_tty_t--tty-handle
+
+TTY handles represent a stream for the console.
+
+```lua
+-- Simple echo program
+local stdin = uv.new_tty(0, true)
+local stdout = uv.new_tty(1, false)
+
+stdin:read_start(function (err, data)
+ assert(not err, err)
+ if data then
+ stdout:write(data)
+ else
+ stdin:close()
+ stdout:close()
+ end
+end)
+```
+
+### uv.new_tty(fd, readable) -> tty
+
+Initialize a new TTY stream with the given file descriptor. Usually the file
+descriptor will be:
+
+ - 0 - stdin
+ - 1 - stdout
+ - 2 - stderr
+
+`readable, specifies if you plan on calling uv_read_start() with this stream.
+`stdin is readable, stdout is not.
+
+On Unix this function will try to open /dev/tty and use it if the passed file
+descriptor refers to a TTY. This lets libuv put the tty in non-blocking mode
+without affecting other processes that share the tty.
+
+Note: If opening `/dev/tty` fails, libuv falls back to blocking writes for
+non-readable TTY streams.
+
+### uv.tty_set_mode(mode)
+
+> (method form `tty:set_mode(mode)`)
+
+Set the TTY using the specified terminal mode.
+
+Parameter `mode` is a C enum with the following values:
+
+- 0 - UV_TTY_MODE_NORMAL: Initial/normal terminal mode
+
+- 1 - UV_TTY_MODE_RAW: Raw input mode (On Windows, ENABLE_WINDOW_INPUT is
+ also enabled)
+
+- 2 - UV_TTY_MODE_IO: Binary-safe I/O mode for IPC (Unix-only)
+
+## uv.tty_reset_mode()
+
+To be called when the program exits. Resets TTY settings to default values for
+the next process to take over.
+
+This function is async signal-safe on Unix platforms but can fail with error
+code UV_EBUSY if you call it when execution is inside uv_tty_set_mode().
+
+## uv.tty_get_winsize() -> w, h
+
+> (method form `tty:get_winsize() -> w, h`)
+
+Gets the current Window size.
+
+## `uv_udp_t` — UDP handle
+
+[`uv_udp_t`]: #uv_udp_t--udp-handle
+
+UDP handles encapsulate UDP communication for both clients and servers.
+
+### uv.new_udp() -> udp
+
+Initialize a new UDP handle. The actual socket is created lazily.
+
+### uv.udp_open(udp, fd)
+
+> (method form `udp:open(fd)`)
+
+Opens an existing file descriptor or Windows SOCKET as a UDP handle.
+
+Unix only: The only requirement of the sock argument is that it follows the
+datagram contract (works in unconnected mode, supports sendmsg()/recvmsg(),
+etc). In other words, other datagram-type sockets like raw sockets or netlink
+sockets can also be passed to this function.
+
+The file descriptor is set to non-blocking mode.
+
+Note: The passed file descriptor or SOCKET is not checked for its type, but
+it’s required that it represents a valid datagram socket.
+
+### uv.udp_bind(udp, host, port)
+
+> (method form `udp:bind(host, port)`)
+
+Bind the UDP handle to an IP address and port.
+
+### uv.udp_getsockname(udp)
+
+> (method form `udp:getsockname()`)
+
+Get the local IP and port of the UDP handle.
+
+### uv.udp_set_membership(udp, multicast_addr, interface_addr, membership)
+
+> (method form `udp:set_membership(multicast_addr, interface_addr, membership)`)
+
+Set membership for a multicast address.
+
+`multicast_addr` is multicast address to set membership for.
+
+`interface_addr` is interface address.
+
+`membership` can be the string `"leave"` or `"join"`.
+
+### uv.udp_set_multicast_loop(udp, on)
+
+> (method form `udp:set_multicast_loop(on)`)
+
+Set IP multicast loop flag. Makes multicast packets loop back to local
+sockets.
+
+`on` is a boolean.
+
+### uv.udp_set_multicast_ttl(udp, tty)
+
+> (method form `udp:set_multicast_ttl(tty)`)
+
+Set the multicast ttl.
+
+`ttl` is an integer 1 through 255.
+
+### uv.udp_set_multicast_interface(udp, interface_addr)
+
+> (method form `udp:set_multicast_interface(interface_addr)`)
+
+Set the multicast interface to send or receive data on.
+
+### uv.udp_set_broadcast(udp, on)
+
+Set broadcast on or off.
+
+> (method form `udp:set_broadcast(, on)`)
+
+### uv.udp_set_ttl(udp, ttl)
+
+> (method form `udp:set_ttl(ttl)`)
+
+Set the time to live.
+
+`ttl` is an integer 1 through 255.
+
+### uv.udp_send(udp, data, host, port, callback)
+
+> (method form `udp:send(data, host, port, callback)`)
+
+Send data over the UDP socket. If the socket has not previously been bound
+with `uv_udp_bind()` it will be bound to `0.0.0.0` (the “all interfaces†IPv4
+address) and a random port number.
+
+### uv.udp_try_send(udp, data, host, port)
+
+> (method form `udp:try_send(data, host, port)`)
+
+Same as `uv_udp_send()`, but won’t queue a send request if it can’t be
+completed immediately.
+
+### uv.udp_recv_start(udp, callback)
+
+> (method form `udp:recv_start(callback)`)
+
+Prepare for receiving data. If the socket has not previously been bound with
+`uv_udp_bind()` it is bound to `0.0.0.0` (the “all interfaces†IPv4 address)
+and a random port number.
+
+### uv.udp_recv_stop(udp)
+
+> (method form `udp:recv_stop()`)
+
+## `uv_fs_event_t` — FS Event handle
+
+[`uv_fs_event_t`]: #uv_fs_event_t--fs-event-handle
+
+**TODO**: port docs from [docs.libuv.org](http://docs.libuv.org/en/v1.x/fs_event.html)
+using [functions](https://github.com/luvit/luv/blob/25278a3871962cab29763692fdc3b270a7e96fe9/src/luv.c#L174-L177)
+and [methods](https://github.com/luvit/luv/blob/25278a3871962cab29763692fdc3b270a7e96fe9/src/luv.c#L265-L270)
+from [fs_event.c](https://github.com/luvit/luv/blob/master/src/fs_event.c)
+
+## `uv_fs_poll_t` — FS Poll handle
+
+[`uv_fs_poll_t`]: #uv_fs_poll_t--fs-poll-handle
+
+**TODO**: port docs from [docs.libuv.org](http://docs.libuv.org/en/v1.x/fs_poll.html)
+using [functions](https://github.com/luvit/luv/blob/25278a3871962cab29763692fdc3b270a7e96fe9/src/luv.c#L180-L183)
+and [methods](https://github.com/luvit/luv/blob/25278a3871962cab29763692fdc3b270a7e96fe9/src/luv.c#L272-L277)
+from [fs_poll.c](https://github.com/luvit/luv/blob/master/src/fs_poll.c)
+
+## Filesystem operations
+
+[Filesystem operations]:#filesystem-operations
+
+**TODO**: port docs from [docs.libuv.org](http://docs.libuv.org/en/v1.x/fs.html)
+using [functions](https://github.com/luvit/luv/blob/25278a3871962cab29763692fdc3b270a7e96fe9/src/luv.c#L186-L213)
+from [fs.c](https://github.com/luvit/luv/blob/master/src/fs.c)
+
+## DNS utility functions
+
+[DNS utility functions]: #dns-utility-functions
+
+**TODO**: port docs from [docs.libuv.org](http://docs.libuv.org/en/v1.x/dns.html)
+using [functions](https://github.com/luvit/luv/blob/25278a3871962cab29763692fdc3b270a7e96fe9/src/luv.c#L216-L217)
+from [dns.c](https://github.com/luvit/luv/blob/master/src/dns.c)
+
+## Miscellaneous utilities
+
+[Miscellaneous utilities]: #miscellaneous-utilities
+
+**TODO**: port docs from [docs.libuv.org](http://docs.libuv.org/en/v1.x/misc.html)
+using [functions](https://github.com/luvit/luv/blob/25278a3871962cab29763692fdc3b270a7e96fe9/src/luv.c#L220-L235)
+from [misc.c](https://github.com/luvit/luv/blob/master/src/misc.c)
+
+[luv]: https://github.com/luvit/luv
+[luvit]: https://github.com/luvit/luvit
+[libuv]: https://github.com/libuv/libuv
diff --git a/3rdparty/luv/examples/cqueues-main.lua b/3rdparty/luv/examples/cqueues-main.lua
new file mode 100644
index 00000000000..ff60ec2b1c9
--- /dev/null
+++ b/3rdparty/luv/examples/cqueues-main.lua
@@ -0,0 +1,31 @@
+--[[
+Demonstrates using luv with a cqueues mainloop
+]]
+
+local cqueues = require "cqueues"
+local uv = require "luv"
+
+local cq = cqueues.new()
+
+cq:wrap(function()
+ while cqueues.poll({
+ pollfd = uv.backend_fd();
+ timeout = uv.backend_timeout() / 1000;
+ events = "r";
+ }) do
+ uv.run("nowait")
+ end
+end)
+
+cq:wrap(function()
+ while true do
+ cqueues.sleep(1)
+ print("HELLO FROM CQUEUES")
+ end
+end)
+
+uv.new_timer():start(1000, 1000, function()
+ print("HELLO FROM LUV")
+end)
+
+assert(cq:loop())
diff --git a/3rdparty/luv/examples/cqueues-slave.lua b/3rdparty/luv/examples/cqueues-slave.lua
new file mode 100644
index 00000000000..599e7c6ded7
--- /dev/null
+++ b/3rdparty/luv/examples/cqueues-slave.lua
@@ -0,0 +1,55 @@
+--[[
+Demonstrates using cqueues with a luv mainloop
+
+Starts a simple sleep+print loop using each library's native form.
+They should print intertwined.
+]]
+
+local cqueues = require "cqueues"
+local uv = require "luv"
+
+local cq = cqueues.new()
+
+do
+ local timer = uv.new_timer()
+ local function reset_timer()
+ local timeout = cq:timeout()
+ if timeout then
+ -- libuv takes milliseconds as an integer,
+ -- while cqueues gives timeouts as a floating point number
+ -- use `math.ceil` as we'd rather wake up late than early
+ timer:set_repeat(math.ceil(timeout * 1000))
+ timer:again()
+ else
+ -- stop timer for now; it may be restarted later.
+ timer:stop()
+ end
+ end
+ local function onready()
+ -- Step the cqueues loop once (sleeping for max 0 seconds)
+ assert(cq:step(0))
+ reset_timer()
+ end
+ -- Need to call `start` on libuv timer now
+ -- to provide callback and so that `again` works
+ timer:start(0, 0, onready)
+ -- Ask libuv to watch the cqueue pollfd
+ uv.new_poll(cq:pollfd()):start(cq:events(), onready)
+end
+
+-- Adds a new function to the scheduler `cq`
+-- The functions is an infinite loop that sleeps for 1 second and prints
+cq:wrap(function()
+ while true do
+ cqueues.sleep(1)
+ print("HELLO FROM CQUEUES")
+ end
+end)
+
+-- Start a luv timer that fires every 1 second
+uv.new_timer():start(1000, 1000, function()
+ print("HELLO FROM LUV")
+end)
+
+-- Run luv mainloop
+uv.run()
diff --git a/3rdparty/luv/examples/echo-server-client.lua b/3rdparty/luv/examples/echo-server-client.lua
new file mode 100644
index 00000000000..ea4e6d2132d
--- /dev/null
+++ b/3rdparty/luv/examples/echo-server-client.lua
@@ -0,0 +1,68 @@
+local p = require('lib/utils').prettyPrint
+local uv = require('luv')
+
+local function create_server(host, port, on_connection)
+
+ local server = uv.new_tcp()
+ p(1, server)
+ uv.tcp_bind(server, host, port)
+
+ uv.listen(server, 128, function(err)
+ assert(not err, err)
+ local client = uv.new_tcp()
+ uv.accept(server, client)
+ on_connection(client)
+ end)
+
+ return server
+end
+
+local server = create_server("0.0.0.0", 0, function (client)
+ p("new client", client, uv.tcp_getsockname(client), uv.tcp_getpeername(client))
+ uv.read_start(client, function (err, chunk)
+ p("onread", {err=err,chunk=chunk})
+
+ -- Crash on errors
+ assert(not err, err)
+
+ if chunk then
+ -- Echo anything heard
+ uv.write(client, chunk)
+ else
+ -- When the stream ends, close the socket
+ uv.close(client)
+ end
+ end)
+end)
+
+local address = uv.tcp_getsockname(server)
+p("server", server, address)
+
+local client = uv.new_tcp()
+uv.tcp_connect(client, "127.0.0.1", address.port, function (err)
+ assert(not err, err)
+
+ uv.read_start(client, function (err, chunk)
+ p("received at client", {err=err,chunk=chunk})
+ assert(not err, err)
+ if chunk then
+ uv.shutdown(client)
+ p("client done shutting down")
+ else
+ uv.close(client)
+ uv.close(server)
+ end
+ end)
+
+ p("writing from client")
+ uv.write(client, "Hello")
+ uv.write(client, "World")
+
+end)
+
+-- Start the main event loop
+uv.run()
+-- Close any stray handles when done
+uv.walk(uv.close)
+uv.run()
+uv.loop_close()
diff --git a/3rdparty/luv/examples/killing-children.lua b/3rdparty/luv/examples/killing-children.lua
new file mode 100644
index 00000000000..6aab693d0c1
--- /dev/null
+++ b/3rdparty/luv/examples/killing-children.lua
@@ -0,0 +1,24 @@
+local p = require('lib/utils').prettyPrint
+local uv = require('luv')
+
+
+
+local child, pid
+child, pid = uv.spawn("sleep", {
+ args = {"100"}
+}, function (code, signal)
+ p("EXIT", {code=code,signal=signal})
+ uv.close(child)
+end)
+
+p{child=child, pid=pid}
+
+-- uv.kill(pid, "SIGTERM")
+uv.process_kill(child, "SIGTERM")
+
+repeat
+ print("\ntick.")
+until uv.run('once') == 0
+
+print("done")
+
diff --git a/3rdparty/luv/examples/lots-o-dns.lua b/3rdparty/luv/examples/lots-o-dns.lua
new file mode 100644
index 00000000000..59a1b0fe534
--- /dev/null
+++ b/3rdparty/luv/examples/lots-o-dns.lua
@@ -0,0 +1,49 @@
+local p = require('lib/utils').prettyPrint
+local uv = require('luv')
+
+uv.getaddrinfo(nil, 80, nil, p)
+
+local domains = {
+ "facebook.com",
+ "google.com",
+ "mail.google.com",
+ "maps.google.com",
+ "plus.google.com",
+ "play.google.com",
+ "apple.com",
+ "hp.com",
+ "yahoo.com",
+ "mozilla.com",
+ "developer.mozilla.com",
+ "luvit.io",
+ "creationix.com",
+ "howtonode.org",
+ "github.com",
+ "gist.github.com"
+}
+
+local i = 1
+local function next()
+ uv.getaddrinfo(domains[i], nil, {
+ v4mapped = true,
+ all = true,
+ addrconfig = true,
+ canonname = true,
+ numericserv = true,
+ socktype = "STREAM"
+ }, function (err, data)
+ assert(not err, err)
+ p(data)
+ i = i + 1
+ if i <= #domains then
+ next()
+ end
+ end)
+end
+next();
+
+repeat
+ print("\nTick..")
+until uv.run('once') == 0
+
+print("done")
diff --git a/3rdparty/luv/examples/repl.lua b/3rdparty/luv/examples/repl.lua
new file mode 100644
index 00000000000..92be0f17d87
--- /dev/null
+++ b/3rdparty/luv/examples/repl.lua
@@ -0,0 +1,89 @@
+local uv = require('luv')
+local utils = require('lib/utils')
+
+if uv.guess_handle(0) ~= "tty" or
+ uv.guess_handle(1) ~= "tty" then
+ error "stdio must be a tty"
+end
+local stdin = uv.new_tty(0, true)
+local stdout = require('lib/utils').stdout
+
+local debug = require('debug')
+local c = utils.color
+
+local function gatherResults(success, ...)
+ local n = select('#', ...)
+ return success, { n = n, ... }
+end
+
+local function printResults(results)
+ for i = 1, results.n do
+ results[i] = utils.dump(results[i])
+ end
+ print(table.concat(results, '\t'))
+end
+
+local buffer = ''
+
+local function evaluateLine(line)
+ if line == "<3\n" then
+ print("I " .. c("Bred") .. "♥" .. c() .. " you too!")
+ return '>'
+ end
+ local chunk = buffer .. line
+ local f, err = loadstring('return ' .. chunk, 'REPL') -- first we prefix return
+
+ if not f then
+ f, err = loadstring(chunk, 'REPL') -- try again without return
+ end
+
+ if f then
+ buffer = ''
+ local success, results = gatherResults(xpcall(f, debug.traceback))
+
+ if success then
+ -- successful call
+ if results.n > 0 then
+ printResults(results)
+ end
+ else
+ -- error
+ print(results[1])
+ end
+ else
+
+ if err:match "'<eof>'$" then
+ -- Lua expects some more input; stow it away for next time
+ buffer = chunk .. '\n'
+ return '>>'
+ else
+ print(err)
+ buffer = ''
+ end
+ end
+
+ return '>'
+end
+
+local function displayPrompt(prompt)
+ uv.write(stdout, prompt .. ' ')
+end
+
+local function onread(err, line)
+ if err then error(err) end
+ if line then
+ local prompt = evaluateLine(line)
+ displayPrompt(prompt)
+ else
+ uv.close(stdin)
+ end
+end
+
+coroutine.wrap(function()
+ displayPrompt '>'
+ uv.read_start(stdin, onread)
+end)()
+
+uv.run()
+
+print("")
diff --git a/3rdparty/luv/examples/talking-to-children.lua b/3rdparty/luv/examples/talking-to-children.lua
new file mode 100644
index 00000000000..10a53ef8c88
--- /dev/null
+++ b/3rdparty/luv/examples/talking-to-children.lua
@@ -0,0 +1,47 @@
+local p = require('lib/utils').prettyPrint
+local uv = require('luv')
+
+local stdout = uv.new_pipe(false)
+local stderr = uv.new_pipe( false)
+local stdin = uv.new_pipe(false)
+
+local handle, pid
+
+local function onexit(code, signal)
+ p("exit", {code=code,signal=signal})
+end
+
+local function onclose()
+ p("close")
+end
+
+local function onread(err, chunk)
+ assert(not err, err)
+ if (chunk) then
+ p("data", {data=chunk})
+ else
+ p("end")
+ end
+end
+
+local function onshutdown()
+ uv.close(handle, onclose)
+end
+
+handle, pid = uv.spawn("cat", {
+ stdio = {stdin, stdout, stderr}
+}, onexit)
+
+p{
+ handle=handle,
+ pid=pid
+}
+
+uv.read_start(stdout, onread)
+uv.read_start(stderr, onread)
+uv.write(stdin, "Hello World")
+uv.shutdown(stdin, onshutdown)
+
+uv.run()
+uv.walk(uv.close)
+uv.run()
diff --git a/3rdparty/luv/examples/tcp-cluster.lua b/3rdparty/luv/examples/tcp-cluster.lua
new file mode 100644
index 00000000000..e69ceffc62d
--- /dev/null
+++ b/3rdparty/luv/examples/tcp-cluster.lua
@@ -0,0 +1,84 @@
+
+-- This function will be run in a child process
+local child_code = string.dump(function ()
+ local p = require('lib/utils').prettyPrint
+ local uv = require('luv')
+
+ -- The parent is going to pass us the server handle over a pipe
+ -- This will be our local file descriptor at PIPE_FD
+ local pipe = uv.new_pipe(true)
+ local pipe_fd = tonumber(os.getenv("PIPE_FD"))
+ assert(uv.pipe_open(pipe, pipe_fd))
+
+ -- Configure the server handle
+ local server = uv.new_tcp()
+ local function onconnection()
+ local client = uv.new_tcp()
+ uv.accept(server, client)
+ p("New TCP", client, "on", server)
+ p{client=client}
+ uv.write(client, "BYE!\n");
+ uv.shutdown(client, function ()
+ uv.close(client)
+ uv.close(server)
+ end)
+ end
+
+ -- Read the server handle from the parent
+ local function onread(err, data)
+ p("onread", {err=err,data=data})
+ assert(not err, err)
+ if uv.pipe_pending_count(pipe) > 0 then
+ local pending_type = uv.pipe_pending_type(pipe)
+ p("pending_type", pending_type)
+ assert(pending_type == "tcp")
+ assert(uv.accept(pipe, server))
+ assert(uv.listen(server, 128, onconnection))
+ p("Received server handle from parent process", server)
+ elseif data then
+ p("ondata", data)
+ else
+ p("onend", data)
+ end
+ end
+ uv.read_start(pipe, onread)
+
+ -- Start the event loop!
+ uv.run()
+end)
+
+local p = require('lib/utils').prettyPrint
+local uv = require('luv')
+
+local exepath = assert(uv.exepath())
+local cpu_count = # assert(uv.cpu_info())
+
+local server = uv.new_tcp()
+assert(uv.tcp_bind(server, "::1", 1337))
+print("Master process bound to TCP port 1337 on ::1")
+
+
+local function onexit(status, signal)
+ p("Child exited", {status=status,signal=signal})
+end
+
+local function spawnChild()
+ local pipe = uv.new_pipe(true)
+ local input = uv.new_pipe(false)
+ local _, pid = assert(uv.spawn(exepath, {
+ stdio = {input,1,2,pipe},
+ env= {"PIPE_FD=3"}
+ }, onexit))
+ uv.write(input, child_code)
+ uv.shutdown(input)
+ p("Spawned child", pid, "and sending handle", server)
+ assert(uv.write2(pipe, "123", server))
+ assert(uv.shutdown(pipe))
+end
+
+-- Spawn a child process for each CPU core
+for _ = 1, cpu_count do
+ spawnChild()
+end
+
+uv.run()
diff --git a/3rdparty/luv/examples/timers.lua b/3rdparty/luv/examples/timers.lua
new file mode 100644
index 00000000000..049235e6fb1
--- /dev/null
+++ b/3rdparty/luv/examples/timers.lua
@@ -0,0 +1,68 @@
+local p = require('lib/utils').prettyPrint
+local uv = require('luv')
+
+local function set_timeout(timeout, callback)
+ local timer = uv.new_timer()
+ local function ontimeout()
+ p("ontimeout", timer)
+ uv.timer_stop(timer)
+ uv.close(timer)
+ callback(timer)
+ end
+ uv.timer_start(timer, timeout, 0, ontimeout)
+ return timer
+end
+
+local function clear_timeout(timer)
+ uv.timer_stop(timer)
+ uv.close(timer)
+end
+
+local function set_interval(interval, callback)
+ local timer = uv.new_timer()
+ local function ontimeout()
+ p("interval", timer)
+ callback(timer)
+ end
+ uv.timer_start(timer, interval, interval, ontimeout)
+ return timer
+end
+
+local clear_interval = clear_timeout
+
+local i = set_interval(300, function()
+ print("interval...")
+end)
+
+set_timeout(1000, function()
+ clear_interval(i)
+end)
+
+
+local handle = uv.new_timer()
+local delay = 1024
+local function ontimeout()
+ p("tick", delay)
+ delay = delay / 2
+ if delay >= 1 then
+ uv.timer_set_repeat(handle, delay)
+ uv.timer_again(handle)
+ else
+ uv.timer_stop(handle)
+ uv.close(handle)
+ p("done")
+ end
+end
+uv.timer_start(handle, delay, 0, ontimeout)
+
+
+repeat
+ print("\ntick.")
+until uv.run('once') == 0
+
+print("done")
+
+uv.walk(uv.close)
+uv.run()
+uv.loop_close()
+
diff --git a/3rdparty/luv/examples/uvbook/helloworld.lua b/3rdparty/luv/examples/uvbook/helloworld.lua
new file mode 100644
index 00000000000..2c77d0c51bc
--- /dev/null
+++ b/3rdparty/luv/examples/uvbook/helloworld.lua
@@ -0,0 +1,5 @@
+local uv = require('luv')
+
+print('Now quitting.')
+uv.run('default')
+uv.loop_close()
diff --git a/3rdparty/luv/examples/uvbook/idle-basic.lua b/3rdparty/luv/examples/uvbook/idle-basic.lua
new file mode 100644
index 00000000000..dc2a47b3c30
--- /dev/null
+++ b/3rdparty/luv/examples/uvbook/idle-basic.lua
@@ -0,0 +1,14 @@
+local uv = require('luv')
+
+local counter = 0
+local idle = uv.new_idle()
+idle:start(function()
+ counter = counter + 1
+ if counter >= 10e6 then
+ idle:stop()
+ end
+end)
+
+print("Idling...")
+uv.run('default')
+uv.loop_close() \ No newline at end of file
diff --git a/3rdparty/luv/examples/uvbook/onchange.lua b/3rdparty/luv/examples/uvbook/onchange.lua
new file mode 100644
index 00000000000..07b3f9b1d78
--- /dev/null
+++ b/3rdparty/luv/examples/uvbook/onchange.lua
@@ -0,0 +1,30 @@
+local uv = require('luv')
+
+if #arg==0 then
+ print(string.format("Usage: %s <command> <file1> [file2 ...]",arg[0]));
+ return
+end
+
+for i=1,#arg do
+ local fse = uv.new_fs_event()
+ assert(uv.fs_event_start(fse,arg[i],{
+ --"watch_entry"=true,"stat"=true,
+ recursive=true
+ },function (err,fname,status)
+ if(err) then
+ print("Error "..err)
+ else
+ print(string.format('Change detected in %s',
+ uv.fs_event_getpath(fse)))
+ for k,v in pairs(status) do
+ print(k,v)
+ end
+ print('file changed:'..(fname and fname or ''))
+ end
+ end))
+
+end
+
+uv.run('default')
+uv.loop_close()
+
diff --git a/3rdparty/luv/examples/uvbook/queue-work.lua b/3rdparty/luv/examples/uvbook/queue-work.lua
new file mode 100644
index 00000000000..cf52abfb216
--- /dev/null
+++ b/3rdparty/luv/examples/uvbook/queue-work.lua
@@ -0,0 +1,19 @@
+local uv = require('luv')
+
+local ctx = uv.new_work(
+ function(n) --work,in threadpool
+ local uv = require('luv')
+ local t = uv.thread_self()
+ uv.sleep(100)
+ return n*n,n
+ end,
+ function(r,n) print(string.format('%d => %d',n,r)) end --after work, in loop thread
+)
+uv.queue_work(ctx,2)
+uv.queue_work(ctx,4)
+uv.queue_work(ctx,6)
+uv.queue_work(ctx,8)
+uv.queue_work(ctx,10)
+
+uv.run('default')
+uv.loop_close()
diff --git a/3rdparty/luv/examples/uvbook/tcp-echo-client.lua b/3rdparty/luv/examples/uvbook/tcp-echo-client.lua
new file mode 100644
index 00000000000..40dd22a311f
--- /dev/null
+++ b/3rdparty/luv/examples/uvbook/tcp-echo-client.lua
@@ -0,0 +1,21 @@
+local uv = require('luv')
+
+
+local client = uv.new_tcp()
+uv.tcp_connect(client, "127.0.0.1", 1337, function (err)
+ assert(not err, err)
+ uv.read_start(client, function (err, chunk)
+ assert(not err, err)
+ if chunk then
+ print(chunk)
+ else
+ uv.close(client)
+ end
+ end)
+
+ uv.write(client, "Hello")
+ uv.write(client, "World")
+end)
+print('CTRL-C to break')
+uv.run('default')
+uv.loop_close()
diff --git a/3rdparty/luv/examples/uvbook/tcp-echo-server.lua b/3rdparty/luv/examples/uvbook/tcp-echo-server.lua
new file mode 100644
index 00000000000..269c49114cf
--- /dev/null
+++ b/3rdparty/luv/examples/uvbook/tcp-echo-server.lua
@@ -0,0 +1,22 @@
+local uv = require('luv')
+
+
+local server = uv.new_tcp()
+server:bind("127.0.0.1", 1337)
+server:listen(128, function (err)
+ assert(not err, err)
+ local client = uv.new_tcp()
+ server:accept(client)
+ client:read_start(function (err, chunk)
+ assert(not err, err)
+ if chunk then
+ client:write(chunk)
+ else
+ client:shutdown()
+ client:close()
+ end
+ end)
+end)
+
+uv.run('default')
+uv.loop_close()
diff --git a/3rdparty/luv/examples/uvbook/thread-create.lua b/3rdparty/luv/examples/uvbook/thread-create.lua
new file mode 100644
index 00000000000..4b42587adbf
--- /dev/null
+++ b/3rdparty/luv/examples/uvbook/thread-create.lua
@@ -0,0 +1,38 @@
+local uv = require('luv')
+
+local step = 10
+
+local hare_id = uv.new_thread(function(step,...)
+ local ffi = require'ffi'
+ local uv = require('luv')
+ local sleep
+ if ffi.os=='Windows' then
+ ffi.cdef "void Sleep(int ms);"
+ sleep = ffi.C.Sleep
+ else
+ ffi.cdef "unsigned int usleep(unsigned int seconds);"
+ sleep = ffi.C.usleep
+ end
+ while (step>0) do
+ step = step - 1
+ uv.sleep(math.random(1000))
+ print("Hare ran another step")
+ end
+ print("Hare done running!")
+end, step,true,'abcd','false')
+
+local tortoise_id = uv.new_thread(function(step,...)
+ local uv = require('luv')
+ while (step>0) do
+ step = step - 1
+ uv.sleep(math.random(100))
+ print("Tortoise ran another step")
+ end
+ print("Tortoise done running!")
+end,step,'abcd','false')
+
+print(hare_id==hare_id,uv.thread_equal(hare_id,hare_id))
+print(tortoise_id==hare_id,uv.thread_equal(tortoise_id,hare_id))
+
+uv.thread_join(hare_id)
+uv.thread_join(tortoise_id)
diff --git a/3rdparty/luv/examples/uvbook/uvcat.lua b/3rdparty/luv/examples/uvbook/uvcat.lua
new file mode 100644
index 00000000000..99fdd68000b
--- /dev/null
+++ b/3rdparty/luv/examples/uvbook/uvcat.lua
@@ -0,0 +1,37 @@
+local uv = require('luv')
+
+
+local fname = arg[1] and arg[1] or arg[0]
+
+uv.fs_open(fname, 'r', tonumber('644', 8), function(err,fd)
+ if err then
+ print("error opening file:"..err)
+ else
+ local stat = uv.fs_fstat(fd)
+ local off = 0
+ local block = 10
+
+ local function on_read(err,chunk)
+ if(err) then
+ print("Read error: "..err);
+ elseif #chunk==0 then
+ uv.fs_close(fd)
+ else
+ off = block + off
+ uv.fs_write(1,chunk,-1,function(err,chunk)
+ if err then
+ print("Write error: "..err)
+ else
+ uv.fs_read(fd, block, off, on_read)
+ end
+ end)
+ end
+ end
+ uv.fs_read(fd, block, off, on_read)
+ end
+end)
+
+
+
+uv.run('default')
+uv.loop_close()
diff --git a/3rdparty/luv/examples/uvbook/uvtee.lua b/3rdparty/luv/examples/uvbook/uvtee.lua
new file mode 100644
index 00000000000..c91b066ae21
--- /dev/null
+++ b/3rdparty/luv/examples/uvbook/uvtee.lua
@@ -0,0 +1,35 @@
+local uv = require('luv')
+
+if not arg[1] then
+ print(string.format("please run %s filename",arg[0]))
+ return
+end
+
+
+local stdin = uv.new_tty(0, true)
+local stdout = uv.new_tty(1, true)
+--local stdin_pipe = uv.new_pipe(false)
+--uv.pipe_open(stdin_pipe,0)
+
+local fname = arg[1]
+
+uv.fs_open(fname, 'w+', tonumber('644', 8), function(err,fd)
+ if err then
+ print("error opening file:"..err)
+ else
+ local fpipe = uv.new_pipe(false)
+ uv.pipe_open(fpipe, fd)
+
+ uv.read_start(stdin, function(err,chunk)
+ if err then
+ print('Read error: '..err)
+ else
+ uv.write(stdout,chunk)
+ uv.write(fpipe,chunk)
+ end
+ end);
+ end
+end)
+
+uv.run('default')
+uv.loop_close()
diff --git a/3rdparty/luv/lib/tap.lua b/3rdparty/luv/lib/tap.lua
new file mode 100644
index 00000000000..d1cfb59c249
--- /dev/null
+++ b/3rdparty/luv/lib/tap.lua
@@ -0,0 +1,165 @@
+local uv = require('luv')
+local dump = require('lib/utils').dump
+local stdout = require('lib/utils').stdout
+
+local function protect(...)
+ local n = select('#', ...)
+ local arguments = {...}
+ for i = 1, n do
+ arguments[i] = tostring(arguments[i])
+ end
+
+ local text = table.concat(arguments, "\t")
+ text = " " .. string.gsub(text, "\n", "\n ")
+ print(text)
+end
+
+local function pprotect(...)
+ local n = select('#', ...)
+ local arguments = { ... }
+
+ for i = 1, n do
+ arguments[i] = dump(arguments[i])
+ end
+
+ protect(table.concat(arguments, "\t"))
+end
+
+
+local tests = {};
+
+local function run()
+ local passed = 0
+
+ if #tests < 1 then
+ error("No tests specified!")
+ end
+
+ print("1.." .. #tests)
+ for i = 1, #tests do
+ local test = tests[i]
+ local cwd = uv.cwd()
+ local pass, err = xpcall(function ()
+ local expected = 0
+ local function expect(fn, count)
+ expected = expected + (count or 1)
+ return function (...)
+ expected = expected - 1
+ local ret = fn(...)
+ collectgarbage()
+ return ret
+ end
+ end
+ test.fn(protect, pprotect, expect, uv)
+ collectgarbage()
+ uv.run()
+ collectgarbage()
+ if expected > 0 then
+ error("Missing " .. expected .. " expected call" .. (expected == 1 and "" or "s"))
+ elseif expected < 0 then
+ error("Found " .. -expected .. " unexpected call" .. (expected == -1 and "" or "s"))
+ end
+ collectgarbage()
+ local unclosed = 0
+ uv.walk(function (handle)
+ if handle == stdout then return end
+ unclosed = unclosed + 1
+ print("UNCLOSED", handle)
+ end)
+ if unclosed > 0 then
+ error(unclosed .. " unclosed handle" .. (unclosed == 1 and "" or "s"))
+ end
+ if uv.cwd() ~= cwd then
+ error("Test moved cwd from " .. cwd .. " to " .. uv.cwd())
+ end
+ collectgarbage()
+ end, debug.traceback)
+
+ -- Flush out any more opened handles
+ uv.stop()
+ uv.walk(function (handle)
+ if handle == stdout then return end
+ if not uv.is_closing(handle) then uv.close(handle) end
+ end)
+ uv.run()
+ uv.chdir(cwd)
+
+ if pass then
+ print("ok " .. i .. " " .. test.name)
+ passed = passed + 1
+ else
+ protect(err)
+ print("not ok " .. i .. " " .. test.name)
+ end
+ end
+
+ local failed = #tests - passed
+ if failed == 0 then
+ print("# All tests passed")
+ else
+ print("#" .. failed .. " failed test" .. (failed == 1 and "" or "s"))
+ end
+
+ -- Close all then handles, including stdout
+ uv.walk(uv.close)
+ uv.run()
+
+ os.exit(-failed)
+end
+
+local single = true
+local prefix
+
+local function tap(suite)
+
+ if type(suite) == "function" then
+ -- Pass in suite directly for single mode
+ suite(function (name, fn)
+ if prefix then
+ name = prefix .. ' - ' .. name
+ end
+ tests[#tests + 1] = {
+ name = name,
+ fn = fn
+ }
+ end)
+ prefix = nil
+ elseif type(suite) == "string" then
+ prefix = suite
+ single = false
+ else
+ -- Or pass in false to collect several runs of tests
+ -- And then pass in true in a later call to flush tests queue.
+ single = suite
+ end
+
+ if single then run() end
+
+end
+
+
+--[[
+-- Sample Usage
+
+local passed, failed, total = tap(function (test)
+
+ test("add 1 to 2", function(print)
+ print("Adding 1 to 2")
+ assert(1 + 2 == 3)
+ end)
+
+ test("close handle", function (print, p, expect, uv)
+ local handle = uv.new_timer()
+ uv.close(handle, expect(function (self)
+ assert(self == handle)
+ end))
+ end)
+
+ test("simulate failure", function ()
+ error("Oopsie!")
+ end)
+
+end)
+]]
+
+return tap
diff --git a/3rdparty/luv/lib/utils.lua b/3rdparty/luv/lib/utils.lua
new file mode 100644
index 00000000000..777879ec28c
--- /dev/null
+++ b/3rdparty/luv/lib/utils.lua
@@ -0,0 +1,165 @@
+
+local uv = require('luv')
+local utils = {}
+local usecolors
+
+if uv.guess_handle(1) == "tty" then
+ utils.stdout = uv.new_tty(1, false)
+ usecolors = true
+else
+ utils.stdout = uv.new_pipe(false)
+ uv.pipe_open(utils.stdout, 1)
+ usecolors = false
+end
+
+local colors = {
+ black = "0;30",
+ red = "0;31",
+ green = "0;32",
+ yellow = "0;33",
+ blue = "0;34",
+ magenta = "0;35",
+ cyan = "0;36",
+ white = "0;37",
+ B = "1;",
+ Bblack = "1;30",
+ Bred = "1;31",
+ Bgreen = "1;32",
+ Byellow = "1;33",
+ Bblue = "1;34",
+ Bmagenta = "1;35",
+ Bcyan = "1;36",
+ Bwhite = "1;37"
+}
+
+function utils.color(color_name)
+ if usecolors then
+ return "\27[" .. (colors[color_name] or "0") .. "m"
+ else
+ return ""
+ end
+end
+
+function utils.colorize(color_name, string, reset_name)
+ return utils.color(color_name) .. tostring(string) .. utils.color(reset_name)
+end
+
+local backslash, null, newline, carriage, tab, quote, quote2, obracket, cbracket
+
+function utils.loadColors(n)
+ if n ~= nil then usecolors = n end
+ backslash = utils.colorize("Bgreen", "\\\\", "green")
+ null = utils.colorize("Bgreen", "\\0", "green")
+ newline = utils.colorize("Bgreen", "\\n", "green")
+ carriage = utils.colorize("Bgreen", "\\r", "green")
+ tab = utils.colorize("Bgreen", "\\t", "green")
+ quote = utils.colorize("Bgreen", '"', "green")
+ quote2 = utils.colorize("Bgreen", '"')
+ obracket = utils.colorize("B", '[')
+ cbracket = utils.colorize("B", ']')
+end
+
+utils.loadColors()
+
+function utils.dump(o, depth)
+ local t = type(o)
+ if t == 'string' then
+ return quote .. o:gsub("\\", backslash):gsub("%z", null):gsub("\n", newline):gsub("\r", carriage):gsub("\t", tab) .. quote2
+ end
+ if t == 'nil' then
+ return utils.colorize("Bblack", "nil")
+ end
+ if t == 'boolean' then
+ return utils.colorize("yellow", tostring(o))
+ end
+ if t == 'number' then
+ return utils.colorize("blue", tostring(o))
+ end
+ if t == 'userdata' then
+ return utils.colorize("magenta", tostring(o))
+ end
+ if t == 'thread' then
+ return utils.colorize("Bred", tostring(o))
+ end
+ if t == 'function' then
+ return utils.colorize("cyan", tostring(o))
+ end
+ if t == 'cdata' then
+ return utils.colorize("Bmagenta", tostring(o))
+ end
+ if t == 'table' then
+ if type(depth) == 'nil' then
+ depth = 0
+ end
+ if depth > 1 then
+ return utils.colorize("yellow", tostring(o))
+ end
+ local indent = (" "):rep(depth)
+
+ -- Check to see if this is an array
+ local is_array = true
+ local i = 1
+ for k,v in pairs(o) do
+ if not (k == i) then
+ is_array = false
+ end
+ i = i + 1
+ end
+
+ local first = true
+ local lines = {}
+ i = 1
+ local estimated = 0
+ for k,v in (is_array and ipairs or pairs)(o) do
+ local s
+ if is_array then
+ s = ""
+ else
+ if type(k) == "string" and k:find("^[%a_][%a%d_]*$") then
+ s = k .. ' = '
+ else
+ s = '[' .. utils.dump(k, 100) .. '] = '
+ end
+ end
+ s = s .. utils.dump(v, depth + 1)
+ lines[i] = s
+ estimated = estimated + #s
+ i = i + 1
+ end
+ if estimated > 200 then
+ return "{\n " .. indent .. table.concat(lines, ",\n " .. indent) .. "\n" .. indent .. "}"
+ else
+ return "{ " .. table.concat(lines, ", ") .. " }"
+ end
+ end
+ -- This doesn't happen right?
+ return tostring(o)
+end
+
+
+
+-- Print replacement that goes through libuv. This is useful on windows
+-- to use libuv's code to translate ansi escape codes to windows API calls.
+function print(...)
+ local n = select('#', ...)
+ local arguments = {...}
+ for i = 1, n do
+ arguments[i] = tostring(arguments[i])
+ end
+ uv.write(utils.stdout, table.concat(arguments, "\t") .. "\n")
+end
+
+-- A nice global data dumper
+function utils.prettyPrint(...)
+ local n = select('#', ...)
+ local arguments = { ... }
+
+ for i = 1, n do
+ arguments[i] = utils.dump(arguments[i])
+ end
+
+ print(table.concat(arguments, "\t"))
+end
+
+return utils
+
diff --git a/3rdparty/luv/luv-1.8.0-4.rockspec b/3rdparty/luv/luv-1.8.0-4.rockspec
new file mode 100644
index 00000000000..23855203e0d
--- /dev/null
+++ b/3rdparty/luv/luv-1.8.0-4.rockspec
@@ -0,0 +1,34 @@
+package = "luv"
+version = "1.8.0-4"
+source = {
+ url = 'https://github.com/luvit/luv/releases/download/1.8.0-4/luv-1.8.0-4.tar.gz',
+}
+
+description = {
+ summary = "Bare libuv bindings for lua",
+ detailed = [[
+libuv bindings for luajit and lua 5.1/5.2/5.3.
+
+This library makes libuv available to lua scripts. It was made for the luvit
+project but should usable from nearly any lua project.
+ ]],
+ homepage = "https://github.com/luvit/luv",
+ license = "Apache 2.0"
+}
+
+dependencies = {
+ "lua >= 5.1"
+}
+
+build = {
+ type = 'cmake',
+ variables = {
+ CMAKE_C_FLAGS="$(CFLAGS)",
+ CMAKE_MODULE_LINKER_FLAGS="$(LIBFLAG)",
+ LUA_LIBDIR="$(LUA_LIBDIR)",
+ LUA_INCDIR="$(LUA_INCDIR)",
+ LUA="$(LUA)",
+ LIBDIR="$(LIBDIR)",
+ LUADIR="$(LUADIR)",
+ },
+}
diff --git a/3rdparty/luv/msvcbuild.bat b/3rdparty/luv/msvcbuild.bat
new file mode 100644
index 00000000000..7a5c7bd4c31
--- /dev/null
+++ b/3rdparty/luv/msvcbuild.bat
@@ -0,0 +1,13 @@
+@echo off
+
+set VS=12
+if "%configuration%"=="2015" (set VS=14)
+if "%configuration%"=="2013" (set VS=12)
+
+if not defined platform set platform=x64
+if "%platform%" EQU "x64" (set VS=%VS% Win64)
+
+cmake -H. -Bbuild -G"Visual Studio %VS%"
+cmake --build build --config Release
+copy build\Release\luv.dll .
+copy build\Release\luajit.exe .
diff --git a/3rdparty/luv/src/async.c b/3rdparty/luv/src/async.c
new file mode 100644
index 00000000000..87ae0cc0460
--- /dev/null
+++ b/3rdparty/luv/src/async.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "luv.h"
+#include "lthreadpool.h"
+
+static uv_async_t* luv_check_async(lua_State* L, int index) {
+ uv_async_t* handle = luv_checkudata(L, index, "uv_async");
+ luaL_argcheck(L, handle->type == UV_ASYNC && handle->data, index, "Expected uv_async_t");
+ return handle;
+}
+
+static void luv_async_cb(uv_async_t* handle) {
+ lua_State* L = luv_state(handle->loop);
+ luv_handle_t* data = handle->data;
+ int n = luv_thread_arg_push(L, data->extra);
+ luv_call_callback(L, data, LUV_ASYNC, n);
+ luv_thread_arg_clear(data->extra);
+}
+
+static int luv_new_async(lua_State* L) {
+ uv_async_t* handle;
+ luv_handle_t* data;
+ int ret;
+ luaL_checktype(L, 1, LUA_TFUNCTION);
+ handle = luv_newuserdata(L, sizeof(*handle));
+ ret = uv_async_init(luv_loop(L), handle, luv_async_cb);
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ data = luv_setup_handle(L);
+ data->extra = malloc(sizeof(luv_thread_arg_t));
+ memset(data->extra, 0, sizeof(luv_thread_arg_t));
+ handle->data = data;
+ luv_check_callback(L, handle->data, LUV_ASYNC, 1);
+ return 1;
+}
+
+static int luv_async_send(lua_State* L) {
+ int ret;
+ uv_async_t* handle = luv_check_async(L, 1);
+ luv_thread_arg_t* arg = ((luv_handle_t*) handle->data)->extra;
+
+ luv_thread_arg_set(L, arg, 2, lua_gettop(L), 0);
+ ret = uv_async_send(handle);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
diff --git a/3rdparty/luv/src/check.c b/3rdparty/luv/src/check.c
new file mode 100644
index 00000000000..dbd330ae255
--- /dev/null
+++ b/3rdparty/luv/src/check.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "luv.h"
+
+static uv_check_t* luv_check_check(lua_State* L, int index) {
+ uv_check_t* handle = luv_checkudata(L, index, "uv_check");
+ luaL_argcheck(L, handle->type == UV_CHECK && handle->data, index, "Expected uv_check_t");
+ return handle;
+}
+
+static int luv_new_check(lua_State* L) {
+ uv_check_t* handle = luv_newuserdata(L, sizeof(*handle));
+ int ret = uv_check_init(luv_loop(L), handle);
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ handle->data = luv_setup_handle(L);
+ return 1;
+}
+
+static void luv_check_cb(uv_check_t* handle) {
+ lua_State* L = luv_state(handle->loop);
+ luv_handle_t* data = handle->data;
+ luv_call_callback(L, data, LUV_CHECK, 0);
+}
+
+static int luv_check_start(lua_State* L) {
+ uv_check_t* handle = luv_check_check(L, 1);
+ int ret;
+ luv_check_callback(L, handle->data, LUV_CHECK, 2);
+ ret = uv_check_start(handle, luv_check_cb);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_check_stop(lua_State* L) {
+ uv_check_t* handle = luv_check_check(L, 1);
+ int ret = uv_check_stop(handle);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
diff --git a/3rdparty/luv/src/constants.c b/3rdparty/luv/src/constants.c
new file mode 100644
index 00000000000..3417028c438
--- /dev/null
+++ b/3rdparty/luv/src/constants.c
@@ -0,0 +1,649 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "luv.h"
+
+static int luv_constants(lua_State* L) {
+ lua_newtable(L);
+
+ // File open bitwise flags O_*
+#ifdef O_RDONLY
+ lua_pushinteger(L, O_RDONLY);
+ lua_setfield(L, -2, "O_RDONLY");
+#endif
+#ifdef O_WRONLY
+ lua_pushinteger(L, O_WRONLY);
+ lua_setfield(L, -2, "O_WRONLY");
+#endif
+#ifdef O_RDWR
+ lua_pushinteger(L, O_RDWR);
+ lua_setfield(L, -2, "O_RDWR");
+#endif
+#ifdef O_APPEND
+ lua_pushinteger(L, O_APPEND);
+ lua_setfield(L, -2, "O_APPEND");
+#endif
+#ifdef O_CREAT
+ lua_pushinteger(L, O_CREAT);
+ lua_setfield(L, -2, "O_CREAT");
+#endif
+#ifdef O_DSYNC
+ lua_pushinteger(L, O_DSYNC);
+ lua_setfield(L, -2, "O_DSYNC");
+#endif
+#ifdef O_EXCL
+ lua_pushinteger(L, O_EXCL);
+ lua_setfield(L, -2, "O_EXCL");
+#endif
+#ifdef O_EXLOCK
+ lua_pushinteger(L, O_EXLOCK);
+ lua_setfield(L, -2, "O_EXLOCK");
+#endif
+#ifdef O_NOCTTY
+ lua_pushinteger(L, O_NOCTTY);
+ lua_setfield(L, -2, "O_NOCTTY");
+#endif
+#ifdef O_NONBLOCK
+ lua_pushinteger(L, O_NONBLOCK);
+ lua_setfield(L, -2, "O_NONBLOCK");
+#endif
+#ifdef O_RSYNC
+ lua_pushinteger(L, O_RSYNC);
+ lua_setfield(L, -2, "O_RSYNC");
+#endif
+#ifdef O_SYNC
+ lua_pushinteger(L, O_SYNC);
+ lua_setfield(L, -2, "O_SYNC");
+#endif
+#ifdef O_TRUNC
+ lua_pushinteger(L, O_TRUNC);
+ lua_setfield(L, -2, "O_TRUNC");
+#endif
+
+ // Socket types SOCK_*
+#ifdef SOCK_STREAM
+ lua_pushinteger(L, SOCK_STREAM);
+ lua_setfield(L, -2, "SOCK_STREAM");
+#endif
+#ifdef SOCK_DGRAM
+ lua_pushinteger(L, SOCK_DGRAM);
+ lua_setfield(L, -2, "SOCK_DGRAM");
+#endif
+#ifdef SOCK_SEQPACKET
+ lua_pushinteger(L, SOCK_SEQPACKET);
+ lua_setfield(L, -2, "SOCK_SEQPACKET");
+#endif
+#ifdef SOCK_RAW
+ lua_pushinteger(L, SOCK_RAW);
+ lua_setfield(L, -2, "SOCK_RAW");
+#endif
+#ifdef SOCK_RDM
+ lua_pushinteger(L, SOCK_RDM);
+ lua_setfield(L, -2, "SOCK_RDM");
+#endif
+
+ // AF_*
+#ifdef AF_UNIX
+ lua_pushinteger(L, AF_UNIX);
+ lua_setfield(L, -2, "AF_UNIX");
+#endif
+#ifdef AF_INET
+ lua_pushinteger(L, AF_INET);
+ lua_setfield(L, -2, "AF_INET");
+#endif
+#ifdef AF_INET6
+ lua_pushinteger(L, AF_INET6);
+ lua_setfield(L, -2, "AF_INET6");
+#endif
+#ifdef AF_IPX
+ lua_pushinteger(L, AF_IPX);
+ lua_setfield(L, -2, "AF_IPX");
+#endif
+#ifdef AF_NETLINK
+ lua_pushinteger(L, AF_NETLINK);
+ lua_setfield(L, -2, "AF_NETLINK");
+#endif
+#ifdef AF_X25
+ lua_pushinteger(L, AF_X25);
+ lua_setfield(L, -2, "AF_X25");
+#endif
+#ifdef AF_AX25
+ lua_pushinteger(L, AF_AX25);
+ lua_setfield(L, -2, "AF_AX25");
+#endif
+#ifdef AF_ATMPVC
+ lua_pushinteger(L, AF_ATMPVC);
+ lua_setfield(L, -2, "AF_ATMPVC");
+#endif
+#ifdef AF_APPLETALK
+ lua_pushinteger(L, AF_APPLETALK);
+ lua_setfield(L, -2, "AF_APPLETALK");
+#endif
+#ifdef AF_PACKET
+ lua_pushinteger(L, AF_PACKET);
+ lua_setfield(L, -2, "AF_PACKET");
+#endif
+
+ // AI_*
+#ifdef AI_ADDRCONFIG
+ lua_pushinteger(L, AI_ADDRCONFIG);
+ lua_setfield(L, -2, "AI_ADDRCONFIG");
+#endif
+#ifdef AI_V4MAPPED
+ lua_pushinteger(L, AI_V4MAPPED);
+ lua_setfield(L, -2, "AI_V4MAPPED");
+#endif
+#ifdef AI_ALL
+ lua_pushinteger(L, AI_ALL);
+ lua_setfield(L, -2, "AI_ALL");
+#endif
+#ifdef AI_NUMERICHOST
+ lua_pushinteger(L, AI_NUMERICHOST);
+ lua_setfield(L, -2, "AI_NUMERICHOST");
+#endif
+#ifdef AI_PASSIVE
+ lua_pushinteger(L, AI_PASSIVE);
+ lua_setfield(L, -2, "AI_PASSIVE");
+#endif
+#ifdef AI_NUMERICSERV
+ lua_pushinteger(L, AI_NUMERICSERV);
+ lua_setfield(L, -2, "AI_NUMERICSERV");
+#endif
+
+ // Signals
+#ifdef SIGHUP
+ lua_pushinteger(L, SIGHUP);
+ lua_setfield(L, -2, "SIGHUP");
+#endif
+#ifdef SIGINT
+ lua_pushinteger(L, SIGINT);
+ lua_setfield(L, -2, "SIGINT");
+#endif
+#ifdef SIGQUIT
+ lua_pushinteger(L, SIGQUIT);
+ lua_setfield(L, -2, "SIGQUIT");
+#endif
+#ifdef SIGILL
+ lua_pushinteger(L, SIGILL);
+ lua_setfield(L, -2, "SIGILL");
+#endif
+#ifdef SIGTRAP
+ lua_pushinteger(L, SIGTRAP);
+ lua_setfield(L, -2, "SIGTRAP");
+#endif
+#ifdef SIGABRT
+ lua_pushinteger(L, SIGABRT);
+ lua_setfield(L, -2, "SIGABRT");
+#endif
+#ifdef SIGIOT
+ lua_pushinteger(L, SIGIOT);
+ lua_setfield(L, -2, "SIGIOT");
+#endif
+#ifdef SIGBUS
+ lua_pushinteger(L, SIGBUS);
+ lua_setfield(L, -2, "SIGBUS");
+#endif
+#ifdef SIGFPE
+ lua_pushinteger(L, SIGFPE);
+ lua_setfield(L, -2, "SIGFPE");
+#endif
+#ifdef SIGKILL
+ lua_pushinteger(L, SIGKILL);
+ lua_setfield(L, -2, "SIGKILL");
+#endif
+#ifdef SIGUSR1
+ lua_pushinteger(L, SIGUSR1);
+ lua_setfield(L, -2, "SIGUSR1");
+#endif
+#ifdef SIGSEGV
+ lua_pushinteger(L, SIGSEGV);
+ lua_setfield(L, -2, "SIGSEGV");
+#endif
+#ifdef SIGUSR2
+ lua_pushinteger(L, SIGUSR2);
+ lua_setfield(L, -2, "SIGUSR2");
+#endif
+#ifdef SIGPIPE
+ lua_pushinteger(L, SIGPIPE);
+ lua_setfield(L, -2, "SIGPIPE");
+#endif
+#ifdef SIGALRM
+ lua_pushinteger(L, SIGALRM);
+ lua_setfield(L, -2, "SIGALRM");
+#endif
+#ifdef SIGTERM
+ lua_pushinteger(L, SIGTERM);
+ lua_setfield(L, -2, "SIGTERM");
+#endif
+#ifdef SIGCHLD
+ lua_pushinteger(L, SIGCHLD);
+ lua_setfield(L, -2, "SIGCHLD");
+#endif
+#ifdef SIGSTKFLT
+ lua_pushinteger(L, SIGSTKFLT);
+ lua_setfield(L, -2, "SIGSTKFLT");
+#endif
+#ifdef SIGCONT
+ lua_pushinteger(L, SIGCONT);
+ lua_setfield(L, -2, "SIGCONT");
+#endif
+#ifdef SIGSTOP
+ lua_pushinteger(L, SIGSTOP);
+ lua_setfield(L, -2, "SIGSTOP");
+#endif
+#ifdef SIGTSTP
+ lua_pushinteger(L, SIGTSTP);
+ lua_setfield(L, -2, "SIGTSTP");
+#endif
+#ifdef SIGBREAK
+ lua_pushinteger(L, SIGBREAK);
+ lua_setfield(L, -2, "SIGBREAK");
+#endif
+#ifdef SIGTTIN
+ lua_pushinteger(L, SIGTTIN);
+ lua_setfield(L, -2, "SIGTTIN");
+#endif
+#ifdef SIGTTOU
+ lua_pushinteger(L, SIGTTOU);
+ lua_setfield(L, -2, "SIGTTOU");
+#endif
+#ifdef SIGURG
+ lua_pushinteger(L, SIGURG);
+ lua_setfield(L, -2, "SIGURG");
+#endif
+#ifdef SIGXCPU
+ lua_pushinteger(L, SIGXCPU);
+ lua_setfield(L, -2, "SIGXCPU");
+#endif
+#ifdef SIGXFSZ
+ lua_pushinteger(L, SIGXFSZ);
+ lua_setfield(L, -2, "SIGXFSZ");
+#endif
+#ifdef SIGVTALRM
+ lua_pushinteger(L, SIGVTALRM);
+ lua_setfield(L, -2, "SIGVTALRM");
+#endif
+#ifdef SIGPROF
+ lua_pushinteger(L, SIGPROF);
+ lua_setfield(L, -2, "SIGPROF");
+#endif
+#ifdef SIGWINCH
+ lua_pushinteger(L, SIGWINCH);
+ lua_setfield(L, -2, "SIGWINCH");
+#endif
+#ifdef SIGIO
+ lua_pushinteger(L, SIGIO);
+ lua_setfield(L, -2, "SIGIO");
+#endif
+#ifdef SIGPOLL
+ lua_pushinteger(L, SIGPOLL);
+ lua_setfield(L, -2, "SIGPOLL");
+#endif
+#ifdef SIGLOST
+ lua_pushinteger(L, SIGLOST);
+ lua_setfield(L, -2, "SIGLOST");
+#endif
+#ifdef SIGPWR
+ lua_pushinteger(L, SIGPWR);
+ lua_setfield(L, -2, "SIGPWR");
+#endif
+#ifdef SIGSYS
+ lua_pushinteger(L, SIGSYS);
+ lua_setfield(L, -2, "SIGSYS");
+#endif
+ return 1;
+}
+
+static int luv_af_string_to_num(const char* string) {
+ if (!string) return AF_UNSPEC;
+#ifdef AF_UNIX
+ if (strcmp(string, "unix") == 0) return AF_UNIX;
+#endif
+#ifdef AF_INET
+ if (strcmp(string, "inet") == 0) return AF_INET;
+#endif
+#ifdef AF_INET6
+ if (strcmp(string, "inet6") == 0) return AF_INET6;
+#endif
+#ifdef AF_IPX
+ if (strcmp(string, "ipx") == 0) return AF_IPX;
+#endif
+#ifdef AF_NETLINK
+ if (strcmp(string, "netlink") == 0) return AF_NETLINK;
+#endif
+#ifdef AF_X25
+ if (strcmp(string, "x25") == 0) return AF_X25;
+#endif
+#ifdef AF_AX25
+ if (strcmp(string, "ax25") == 0) return AF_AX25;
+#endif
+#ifdef AF_ATMPVC
+ if (strcmp(string, "atmpvc") == 0) return AF_ATMPVC;
+#endif
+#ifdef AF_APPLETALK
+ if (strcmp(string, "appletalk") == 0) return AF_APPLETALK;
+#endif
+#ifdef AF_PACKET
+ if (strcmp(string, "packet") == 0) return AF_PACKET;
+#endif
+ return 0;
+}
+
+static const char* luv_af_num_to_string(const int num) {
+ switch (num) {
+#ifdef AF_UNIX
+ case AF_UNIX: return "unix";
+#endif
+#ifdef AF_INET
+ case AF_INET: return "inet";
+#endif
+#ifdef AF_INET6
+ case AF_INET6: return "inet6";
+#endif
+#ifdef AF_IPX
+ case AF_IPX: return "ipx";
+#endif
+#ifdef AF_NETLINK
+ case AF_NETLINK: return "netlink";
+#endif
+#ifdef AF_X25
+ case AF_X25: return "x25";
+#endif
+#ifdef AF_AX25
+ case AF_AX25: return "ax25";
+#endif
+#ifdef AF_ATMPVC
+ case AF_ATMPVC: return "atmpvc";
+#endif
+#ifdef AF_APPLETALK
+ case AF_APPLETALK: return "appletalk";
+#endif
+#ifdef AF_PACKET
+ case AF_PACKET: return "packet";
+#endif
+ }
+ return NULL;
+}
+
+
+static int luv_sock_string_to_num(const char* string) {
+ if (!string) return 0;
+#ifdef SOCK_STREAM
+ if (strcmp(string, "stream") == 0) return SOCK_STREAM;
+#endif
+#ifdef SOCK_DGRAM
+ if (strcmp(string, "dgram") == 0) return SOCK_DGRAM;
+#endif
+#ifdef SOCK_SEQPACKET
+ if (strcmp(string, "seqpacket") == 0) return SOCK_SEQPACKET;
+#endif
+#ifdef SOCK_RAW
+ if (strcmp(string, "raw") == 0) return SOCK_RAW;
+#endif
+#ifdef SOCK_RDM
+ if (strcmp(string, "rdm") == 0) return SOCK_RDM;
+#endif
+ return 0;
+}
+
+static const char* luv_sock_num_to_string(const int num) {
+ switch (num) {
+#ifdef SOCK_STREAM
+ case SOCK_STREAM: return "stream";
+#endif
+#ifdef SOCK_DGRAM
+ case SOCK_DGRAM: return "dgram";
+#endif
+#ifdef SOCK_SEQPACKET
+ case SOCK_SEQPACKET: return "seqpacket";
+#endif
+#ifdef SOCK_RAW
+ case SOCK_RAW: return "raw";
+#endif
+#ifdef SOCK_RDM
+ case SOCK_RDM: return "rdm";
+#endif
+ }
+ return NULL;
+}
+
+static int luv_sig_string_to_num(const char* string) {
+ if (!string) return 0;
+#ifdef SIGHUP
+ if (strcmp(string, "sighup") == 0) return SIGHUP;
+#endif
+#ifdef SIGINT
+ if (strcmp(string, "sigint") == 0) return SIGINT;
+#endif
+#ifdef SIGQUIT
+ if (strcmp(string, "sigquit") == 0) return SIGQUIT;
+#endif
+#ifdef SIGILL
+ if (strcmp(string, "sigill") == 0) return SIGILL;
+#endif
+#ifdef SIGTRAP
+ if (strcmp(string, "sigtrap") == 0) return SIGTRAP;
+#endif
+#ifdef SIGABRT
+ if (strcmp(string, "sigabrt") == 0) return SIGABRT;
+#endif
+#ifdef SIGIOT
+ if (strcmp(string, "sigiot") == 0) return SIGIOT;
+#endif
+#ifdef SIGBUS
+ if (strcmp(string, "sigbus") == 0) return SIGBUS;
+#endif
+#ifdef SIGFPE
+ if (strcmp(string, "sigfpe") == 0) return SIGFPE;
+#endif
+#ifdef SIGKILL
+ if (strcmp(string, "sigkill") == 0) return SIGKILL;
+#endif
+#ifdef SIGUSR1
+ if (strcmp(string, "sigusr1") == 0) return SIGUSR1;
+#endif
+#ifdef SIGSEGV
+ if (strcmp(string, "sigsegv") == 0) return SIGSEGV;
+#endif
+#ifdef SIGUSR2
+ if (strcmp(string, "sigusr2") == 0) return SIGUSR2;
+#endif
+#ifdef SIGPIPE
+ if (strcmp(string, "sigpipe") == 0) return SIGPIPE;
+#endif
+#ifdef SIGALRM
+ if (strcmp(string, "sigalrm") == 0) return SIGALRM;
+#endif
+#ifdef SIGTERM
+ if (strcmp(string, "sigterm") == 0) return SIGTERM;
+#endif
+#ifdef SIGCHLD
+ if (strcmp(string, "sigchld") == 0) return SIGCHLD;
+#endif
+#ifdef SIGSTKFLT
+ if (strcmp(string, "sigstkflt") == 0) return SIGSTKFLT;
+#endif
+#ifdef SIGCONT
+ if (strcmp(string, "sigcont") == 0) return SIGCONT;
+#endif
+#ifdef SIGSTOP
+ if (strcmp(string, "sigstop") == 0) return SIGSTOP;
+#endif
+#ifdef SIGTSTP
+ if (strcmp(string, "sigtstp") == 0) return SIGTSTP;
+#endif
+#ifdef SIGBREAK
+ if (strcmp(string, "sigbreak") == 0) return SIGBREAK;
+#endif
+#ifdef SIGTTIN
+ if (strcmp(string, "sigttin") == 0) return SIGTTIN;
+#endif
+#ifdef SIGTTOU
+ if (strcmp(string, "sigttou") == 0) return SIGTTOU;
+#endif
+#ifdef SIGURG
+ if (strcmp(string, "sigurg") == 0) return SIGURG;
+#endif
+#ifdef SIGXCPU
+ if (strcmp(string, "sigxcpu") == 0) return SIGXCPU;
+#endif
+#ifdef SIGXFSZ
+ if (strcmp(string, "sigxfsz") == 0) return SIGXFSZ;
+#endif
+#ifdef SIGVTALRM
+ if (strcmp(string, "sigvtalrm") == 0) return SIGVTALRM;
+#endif
+#ifdef SIGPROF
+ if (strcmp(string, "sigprof") == 0) return SIGPROF;
+#endif
+#ifdef SIGWINCH
+ if (strcmp(string, "sigwinch") == 0) return SIGWINCH;
+#endif
+#ifdef SIGIO
+ if (strcmp(string, "sigio") == 0) return SIGIO;
+#endif
+#ifdef SIGPOLL
+ if (strcmp(string, "sigpoll") == 0) return SIGPOLL;
+#endif
+#ifdef SIGLOST
+ if (strcmp(string, "siglost") == 0) return SIGLOST;
+#endif
+#ifdef SIGPWR
+ if (strcmp(string, "sigpwr") == 0) return SIGPWR;
+#endif
+#ifdef SIGSYS
+ if (strcmp(string, "sigsys") == 0) return SIGSYS;
+#endif
+ return 0;
+}
+
+static const char* luv_sig_num_to_string(const int num) {
+ switch (num) {
+#ifdef SIGHUP
+ case SIGHUP: return "sighup";
+#endif
+#ifdef SIGINT
+ case SIGINT: return "sigint";
+#endif
+#ifdef SIGQUIT
+ case SIGQUIT: return "sigquit";
+#endif
+#ifdef SIGILL
+ case SIGILL: return "sigill";
+#endif
+#ifdef SIGTRAP
+ case SIGTRAP: return "sigtrap";
+#endif
+#ifdef SIGABRT
+ case SIGABRT: return "sigabrt";
+#endif
+#ifdef SIGIOT
+# if SIGIOT != SIGABRT
+ case SIGIOT: return "sigiot";
+# endif
+#endif
+#ifdef SIGBUS
+ case SIGBUS: return "sigbus";
+#endif
+#ifdef SIGFPE
+ case SIGFPE: return "sigfpe";
+#endif
+#ifdef SIGKILL
+ case SIGKILL: return "sigkill";
+#endif
+#ifdef SIGUSR1
+ case SIGUSR1: return "sigusr1";
+#endif
+#ifdef SIGSEGV
+ case SIGSEGV: return "sigsegv";
+#endif
+#ifdef SIGUSR2
+ case SIGUSR2: return "sigusr2";
+#endif
+#ifdef SIGPIPE
+ case SIGPIPE: return "sigpipe";
+#endif
+#ifdef SIGALRM
+ case SIGALRM: return "sigalrm";
+#endif
+#ifdef SIGTERM
+ case SIGTERM: return "sigterm";
+#endif
+#ifdef SIGCHLD
+ case SIGCHLD: return "sigchld";
+#endif
+#ifdef SIGSTKFLT
+ case SIGSTKFLT: return "sigstkflt";
+#endif
+#ifdef SIGCONT
+ case SIGCONT: return "sigcont";
+#endif
+#ifdef SIGSTOP
+ case SIGSTOP: return "sigstop";
+#endif
+#ifdef SIGTSTP
+ case SIGTSTP: return "sigtstp";
+#endif
+#ifdef SIGBREAK
+ case SIGBREAK: return "sigbreak";
+#endif
+#ifdef SIGTTIN
+ case SIGTTIN: return "sigttin";
+#endif
+#ifdef SIGTTOU
+ case SIGTTOU: return "sigttou";
+#endif
+#ifdef SIGURG
+ case SIGURG: return "sigurg";
+#endif
+#ifdef SIGXCPU
+ case SIGXCPU: return "sigxcpu";
+#endif
+#ifdef SIGXFSZ
+ case SIGXFSZ: return "sigxfsz";
+#endif
+#ifdef SIGVTALRM
+ case SIGVTALRM: return "sigvtalrm";
+#endif
+#ifdef SIGPROF
+ case SIGPROF: return "sigprof";
+#endif
+#ifdef SIGWINCH
+ case SIGWINCH: return "sigwinch";
+#endif
+#ifdef SIGIO
+ case SIGIO: return "sigio";
+#endif
+#ifdef SIGPOLL
+# if SIGPOLL != SIGIO
+ case SIGPOLL: return "sigpoll";
+# endif
+#endif
+#ifdef SIGLOST
+ case SIGLOST: return "siglost";
+#endif
+#ifdef SIGPWR
+# if SIGPWR != SIGLOST
+ case SIGPWR: return "sigpwr";
+# endif
+#endif
+#ifdef SIGSYS
+ case SIGSYS: return "sigsys";
+#endif
+ }
+ return NULL;
+}
diff --git a/3rdparty/luv/src/dns.c b/3rdparty/luv/src/dns.c
new file mode 100644
index 00000000000..f3446f30985
--- /dev/null
+++ b/3rdparty/luv/src/dns.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "luv.h"
+#ifndef WIN32
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#endif
+
+static void luv_pushaddrinfo(lua_State* L, struct addrinfo* res) {
+ char ip[INET6_ADDRSTRLEN];
+ int port, i = 0;
+ const char *addr;
+ struct addrinfo* curr = res;
+ lua_newtable(L);
+ for (curr = res; curr; curr = curr->ai_next) {
+ if (curr->ai_family == AF_INET || curr->ai_family == AF_INET6) {
+ lua_newtable(L);
+ if (curr->ai_family == AF_INET) {
+ addr = (char*) &((struct sockaddr_in*) curr->ai_addr)->sin_addr;
+ port = ((struct sockaddr_in*) curr->ai_addr)->sin_port;
+ } else {
+ addr = (char*) &((struct sockaddr_in6*) curr->ai_addr)->sin6_addr;
+ port = ((struct sockaddr_in6*) curr->ai_addr)->sin6_port;
+ }
+ lua_pushstring(L, luv_af_num_to_string(curr->ai_family));
+ lua_setfield(L, -2, "family");
+ uv_inet_ntop(curr->ai_family, addr, ip, INET6_ADDRSTRLEN);
+ lua_pushstring(L, ip);
+ lua_setfield(L, -2, "addr");
+ if (ntohs(port)) {
+ lua_pushinteger(L, ntohs(port));
+ lua_setfield(L, -2, "port");
+ }
+ lua_pushstring(L, luv_sock_num_to_string(curr->ai_socktype));
+ lua_setfield(L, -2, "socktype");
+ lua_pushstring(L, luv_af_num_to_string(curr->ai_protocol));
+ lua_setfield(L, -2, "protocol");
+ if (curr->ai_canonname) {
+ lua_pushstring(L, curr->ai_canonname);
+ lua_setfield(L, -2, "canonname");
+ }
+ lua_rawseti(L, -2, ++i);
+ }
+ }
+}
+
+static void luv_getaddrinfo_cb(uv_getaddrinfo_t* req, int status, struct addrinfo* res) {
+ lua_State* L = luv_state(req->loop);
+ int nargs;
+
+ if (status < 0) {
+ luv_status(L, status);
+ nargs = 1;
+ }
+ else {
+ lua_pushnil(L);
+ luv_pushaddrinfo(L, res);
+ nargs = 2;
+ }
+ luv_fulfill_req(L, req->data, nargs);
+ luv_cleanup_req(L, req->data);
+ req->data = NULL;
+ if (res) uv_freeaddrinfo(res);
+}
+
+
+static int luv_getaddrinfo(lua_State* L) {
+ uv_getaddrinfo_t* req;
+ const char* node;
+ const char* service;
+ struct addrinfo hints_s;
+ struct addrinfo* hints = &hints_s;
+ int ret, ref;
+ if (lua_isnoneornil(L, 1)) node = NULL;
+ else node = luaL_checkstring(L, 1);
+ if (lua_isnoneornil(L, 2)) service = NULL;
+ else service = luaL_checkstring(L, 2);
+ if (!lua_isnoneornil(L, 3)) luaL_checktype(L, 3, LUA_TTABLE);
+ else hints = NULL;
+ ref = lua_isnoneornil(L, 4) ? LUA_NOREF : luv_check_continuation(L, 4);
+ if (hints) {
+ // Initialize the hints
+ memset(hints, 0, sizeof(*hints));
+
+ // Process the `family` hint.
+ lua_getfield(L, 3, "family");
+ if (lua_isnumber(L, -1)) {
+ hints->ai_family = lua_tointeger(L, -1);
+ }
+ else if (lua_isstring(L, -1)) {
+ hints->ai_family = luv_af_string_to_num(lua_tostring(L, -1));
+ }
+ else if (lua_isnil(L, -1)) {
+ hints->ai_family = AF_UNSPEC;
+ }
+ else {
+ luaL_argerror(L, 3, "family hint must be string if set");
+ }
+ lua_pop(L, 1);
+
+ // Process `socktype` hint
+ lua_getfield(L, 3, "socktype");
+ if (lua_isnumber(L, -1)) {
+ hints->ai_socktype = lua_tointeger(L, -1);
+ }
+ else if (lua_isstring(L, -1)) {
+ hints->ai_socktype = luv_sock_string_to_num(lua_tostring(L, -1));
+ }
+ else if (!lua_isnil(L, -1)) {
+ return luaL_argerror(L, 3, "socktype hint must be string if set");
+ }
+ lua_pop(L, 1);
+
+ // Process the `protocol` hint
+ lua_getfield(L, 3, "protocol");
+ if (lua_isnumber(L, -1)) {
+ hints->ai_protocol = lua_tointeger(L, -1);
+ }
+ else if (lua_isstring(L, -1)) {
+ int protocol = luv_af_string_to_num(lua_tostring(L, -1));
+ if (protocol) {
+ hints->ai_protocol = protocol;
+ }
+ else {
+ return luaL_argerror(L, 3, "Invalid protocol hint");
+ }
+ }
+ else if (!lua_isnil(L, -1)) {
+ return luaL_argerror(L, 3, "protocol hint must be string if set");
+ }
+ lua_pop(L, 1);
+
+ lua_getfield(L, 3, "addrconfig");
+ if (lua_toboolean(L, -1)) hints->ai_flags |= AI_ADDRCONFIG;
+ lua_pop(L, 1);
+
+ lua_getfield(L, 3, "v4mapped");
+ if (lua_toboolean(L, -1)) hints->ai_flags |= AI_V4MAPPED;
+ lua_pop(L, 1);
+
+ lua_getfield(L, 3, "all");
+ if (lua_toboolean(L, -1)) hints->ai_flags |= AI_ALL;
+ lua_pop(L, 1);
+
+ lua_getfield(L, 3, "numerichost");
+ if (lua_toboolean(L, -1)) hints->ai_flags |= AI_NUMERICHOST;
+ lua_pop(L, 1);
+
+ lua_getfield(L, 3, "passive");
+ if (lua_toboolean(L, -1)) hints->ai_flags |= AI_PASSIVE;
+ lua_pop(L, 1);
+
+ lua_getfield(L, 3, "numericserv");
+ if (lua_toboolean(L, -1)) {
+ hints->ai_flags |= AI_NUMERICSERV;
+ /* On OS X upto at least OSX 10.9, getaddrinfo crashes
+ * if AI_NUMERICSERV is set and the servname is NULL or "0".
+ * This workaround avoids a segfault in libsystem.
+ */
+ if (NULL == service) service = "00";
+ }
+ lua_pop(L, 1);
+
+ lua_getfield(L, 3, "canonname");
+ if (lua_toboolean(L, -1)) hints->ai_flags |= AI_CANONNAME;
+ lua_pop(L, 1);
+ }
+
+ req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+
+ ret = uv_getaddrinfo(luv_loop(L), req, ref == LUA_NOREF ? NULL : luv_getaddrinfo_cb, node, service, hints);
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ if (ref == LUA_NOREF) {
+
+ lua_pop(L, 1);
+ luv_pushaddrinfo(L, req->addrinfo);
+ uv_freeaddrinfo(req->addrinfo);
+ luv_cleanup_req(L, req->data);
+ }
+ return 1;
+}
+
+static void luv_getnameinfo_cb(uv_getnameinfo_t* req, int status, const char* hostname, const char* service) {
+ lua_State* L = luv_state(req->loop);
+
+ int nargs;
+
+ if (status < 0) {
+ luv_status(L, status);
+ nargs = 1;
+ }
+ else {
+ lua_pushnil(L);
+ lua_pushstring(L, hostname);
+ lua_pushstring(L, service);
+ nargs = 3;
+ }
+
+ luv_fulfill_req(L, req->data, nargs);
+ luv_cleanup_req(L, req->data);
+ req->data = NULL;
+}
+
+static int luv_getnameinfo(lua_State* L) {
+ uv_getnameinfo_t* req;
+ struct sockaddr_storage addr;
+ const char* ip = NULL;
+ int flags = 0;
+ int ret, ref, port = 0;
+
+ luaL_checktype(L, 1, LUA_TTABLE);
+ memset(&addr, 0, sizeof(addr));
+
+ lua_getfield(L, 1, "ip");
+ if (lua_isstring(L, -1)) {
+ ip = lua_tostring(L, -1);
+ }
+ else if (!lua_isnil(L, -1)) {
+ luaL_argerror(L, 1, "ip property must be string if set");
+ }
+ lua_pop(L, 1);
+
+ lua_getfield(L, 1, "port");
+ if (lua_isnumber(L, -1)) {
+ port = lua_tointeger(L, -1);
+ }
+ else if (!lua_isnil(L, -1)) {
+ luaL_argerror(L, 1, "port property must be integer if set");
+ }
+ lua_pop(L, 1);
+
+ if (ip || port) {
+ if (!ip) ip = "0.0.0.0";
+ if (!uv_ip4_addr(ip, port, (struct sockaddr_in*)&addr)) {
+ addr.ss_family = AF_INET;
+ }
+ else if (!uv_ip6_addr(ip, port, (struct sockaddr_in6*)&addr)) {
+ addr.ss_family = AF_INET6;
+ }
+ else {
+ return luaL_argerror(L, 1, "Invalid ip address or port");
+ }
+ }
+
+ lua_getfield(L, 1, "family");
+ if (lua_isnumber(L, -1)) {
+ addr.ss_family = lua_tointeger(L, -1);
+ }
+ else if (lua_isstring(L, -1)) {
+ addr.ss_family = luv_af_string_to_num(lua_tostring(L, -1));
+ }
+ else if (!lua_isnil(L, -1)) {
+ luaL_argerror(L, 1, "family must be string if set");
+ }
+ lua_pop(L, 1);
+
+ ref = lua_isnoneornil(L, 2) ? LUA_NOREF : luv_check_continuation(L, 2);
+
+ req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+
+ ret = uv_getnameinfo(luv_loop(L), req, ref == LUA_NOREF ? NULL : luv_getnameinfo_cb, (struct sockaddr*)&addr, flags);
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ if (ref == LUA_NOREF) {
+ lua_pop(L, 1);
+ lua_pushstring(L, req->host);
+ lua_pushstring(L, req->service);
+ luv_cleanup_req(L, req->data);
+ return 2;
+ }
+ return 1;
+}
+
diff --git a/3rdparty/luv/src/fs.c b/3rdparty/luv/src/fs.c
new file mode 100644
index 00000000000..bacf11ea647
--- /dev/null
+++ b/3rdparty/luv/src/fs.c
@@ -0,0 +1,614 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "luv.h"
+
+static uv_fs_t* luv_check_fs(lua_State* L, int index) {
+ uv_fs_t* req = luaL_checkudata(L, index, "uv_req");
+ luaL_argcheck(L, req->type = UV_FS && req->data, index, "Expected uv_fs_t");
+ return req;
+}
+
+static void luv_push_timespec_table(lua_State* L, const uv_timespec_t* t) {
+ lua_createtable(L, 0, 2);
+ lua_pushinteger(L, t->tv_sec);
+ lua_setfield(L, -2, "sec");
+ lua_pushinteger(L, t->tv_nsec);
+ lua_setfield(L, -2, "nsec");
+}
+
+static void luv_push_stats_table(lua_State* L, const uv_stat_t* s) {
+ const char* type = NULL;
+ lua_createtable(L, 0, 23);
+ lua_pushinteger(L, s->st_dev);
+ lua_setfield(L, -2, "dev");
+ lua_pushinteger(L, s->st_mode);
+ lua_setfield(L, -2, "mode");
+ lua_pushinteger(L, s->st_nlink);
+ lua_setfield(L, -2, "nlink");
+ lua_pushinteger(L, s->st_uid);
+ lua_setfield(L, -2, "uid");
+ lua_pushinteger(L, s->st_gid);
+ lua_setfield(L, -2, "gid");
+ lua_pushinteger(L, s->st_rdev);
+ lua_setfield(L, -2, "rdev");
+ lua_pushinteger(L, s->st_ino);
+ lua_setfield(L, -2, "ino");
+ lua_pushinteger(L, s->st_size);
+ lua_setfield(L, -2, "size");
+ lua_pushinteger(L, s->st_blksize);
+ lua_setfield(L, -2, "blksize");
+ lua_pushinteger(L, s->st_blocks);
+ lua_setfield(L, -2, "blocks");
+ lua_pushinteger(L, s->st_flags);
+ lua_setfield(L, -2, "flags");
+ lua_pushinteger(L, s->st_gen);
+ lua_setfield(L, -2, "gen");
+ luv_push_timespec_table(L, &s->st_atim);
+ lua_setfield(L, -2, "atime");
+ luv_push_timespec_table(L, &s->st_mtim);
+ lua_setfield(L, -2, "mtime");
+ luv_push_timespec_table(L, &s->st_ctim);
+ lua_setfield(L, -2, "ctime");
+ luv_push_timespec_table(L, &s->st_birthtim);
+ lua_setfield(L, -2, "birthtime");
+ if (S_ISREG(s->st_mode)) {
+ type = "file";
+ }
+ else if (S_ISDIR(s->st_mode)) {
+ type = "directory";
+ }
+ else if (S_ISLNK(s->st_mode)) {
+ type = "link";
+ }
+ else if (S_ISFIFO(s->st_mode)) {
+ type = "fifo";
+ }
+#ifdef S_ISSOCK
+ else if (S_ISSOCK(s->st_mode)) {
+ type = "socket";
+ }
+#endif
+ else if (S_ISCHR(s->st_mode)) {
+ type = "char";
+ }
+ else if (S_ISBLK(s->st_mode)) {
+ type = "block";
+ }
+ if (type) {
+ lua_pushstring(L, type);
+ lua_setfield(L, -2, "type");
+ }
+}
+
+static int luv_check_flags(lua_State* L, int index) {
+ const char* string;
+ if (lua_isnumber(L, index)) {
+ return lua_tointeger(L, index);
+ }
+ else if (!lua_isstring(L, index)) {
+ return luaL_argerror(L, index, "Expected string or integer for file open mode");
+ }
+ string = lua_tostring(L, index);
+
+ if (strcmp(string, "r") == 0) return O_RDONLY;
+#ifdef O_SYNC
+ if (strcmp(string, "rs") == 0 ||
+ strcmp(string, "sr") == 0) return O_RDONLY | O_SYNC;
+#endif
+ if (strcmp(string, "r+") == 0) return O_RDWR;
+#ifdef O_SYNC
+ if (strcmp(string, "rs+") == 0 ||
+ strcmp(string, "sr+") == 0) return O_RDWR | O_SYNC;
+#endif
+ if (strcmp(string, "w") == 0) return O_TRUNC | O_CREAT | O_WRONLY;
+ if (strcmp(string, "wx") == 0 ||
+ strcmp(string, "xw") == 0) return O_TRUNC | O_CREAT | O_WRONLY | O_EXCL;
+ if (strcmp(string, "w+") == 0) return O_TRUNC | O_CREAT | O_RDWR;
+ if (strcmp(string, "wx+") == 0 ||
+ strcmp(string, "xw+") == 0) return O_TRUNC | O_CREAT | O_RDWR | O_EXCL;
+ if (strcmp(string, "a") == 0) return O_APPEND | O_CREAT | O_WRONLY;
+ if (strcmp(string, "ax") == 0 ||
+ strcmp(string, "xa") == 0) return O_APPEND | O_CREAT | O_WRONLY | O_EXCL;
+ if (strcmp(string, "a+") == 0) return O_APPEND | O_CREAT | O_RDWR;
+ if (strcmp(string, "ax+") == 0 ||
+ strcmp(string, "xa+") == 0) return O_APPEND | O_CREAT | O_RDWR | O_EXCL;
+
+ return luaL_error(L, "Unknown file open flag '%s'", string);
+}
+
+static int luv_check_amode(lua_State* L, int index) {
+ size_t i;
+ int mode;
+ const char* string;
+ if (lua_isnumber(L, index)) {
+ return lua_tointeger(L, index);
+ }
+ else if (!lua_isstring(L, index)) {
+ return luaL_argerror(L, index, "Expected string or integer for file access mode check");
+ }
+ string = lua_tostring(L, index);
+ mode = 0;
+ for (i = 0; i < strlen(string); ++i) {
+ switch (string[i]) {
+ case 'r': case 'R':
+ mode |= R_OK;
+ break;
+ case 'w': case 'W':
+ mode |= W_OK;
+ break;
+ case 'x': case 'X':
+ mode |= X_OK;
+ break;
+ default:
+ return luaL_argerror(L, index, "Unknown character in access mode string");
+ }
+ }
+ return mode;
+}
+
+/* Processes a result and pushes the data onto the stack
+ returns the number of items pushed */
+static int push_fs_result(lua_State* L, uv_fs_t* req) {
+ luv_req_t* data = req->data;
+
+ if (req->fs_type == UV_FS_ACCESS) {
+ lua_pushboolean(L, req->result >= 0);
+ return 1;
+ }
+
+ if (req->result < 0) {
+ lua_pushnil(L);
+ if (req->path) {
+ lua_pushfstring(L, "%s: %s: %s", uv_err_name(req->result), uv_strerror(req->result), req->path);
+ }
+ else {
+ lua_pushfstring(L, "%s: %s", uv_err_name(req->result), uv_strerror(req->result));
+ }
+ return 2;
+ }
+
+ switch (req->fs_type) {
+ case UV_FS_CLOSE:
+ case UV_FS_RENAME:
+ case UV_FS_UNLINK:
+ case UV_FS_RMDIR:
+ case UV_FS_MKDIR:
+ case UV_FS_FTRUNCATE:
+ case UV_FS_FSYNC:
+ case UV_FS_FDATASYNC:
+ case UV_FS_LINK:
+ case UV_FS_SYMLINK:
+ case UV_FS_CHMOD:
+ case UV_FS_FCHMOD:
+ case UV_FS_CHOWN:
+ case UV_FS_FCHOWN:
+ case UV_FS_UTIME:
+ case UV_FS_FUTIME:
+ lua_pushboolean(L, 1);
+ return 1;
+
+ case UV_FS_OPEN:
+ case UV_FS_SENDFILE:
+ case UV_FS_WRITE:
+ lua_pushinteger(L, req->result);
+ return 1;
+
+ case UV_FS_STAT:
+ case UV_FS_LSTAT:
+ case UV_FS_FSTAT:
+ luv_push_stats_table(L, &req->statbuf);
+ return 1;
+
+ case UV_FS_MKDTEMP:
+ lua_pushstring(L, req->path);
+ return 1;
+
+ case UV_FS_READLINK:
+ case UV_FS_REALPATH:
+ lua_pushstring(L, (char*)req->ptr);
+ return 1;
+
+ case UV_FS_READ:
+ lua_pushlstring(L, data->data, req->result);
+ return 1;
+
+ case UV_FS_SCANDIR:
+ // Expose the userdata for the request.
+ lua_rawgeti(L, LUA_REGISTRYINDEX, data->req_ref);
+ return 1;
+
+ default:
+ lua_pushnil(L);
+ lua_pushfstring(L, "UNKNOWN FS TYPE %d\n", req->fs_type);
+ return 2;
+ }
+
+}
+
+static void luv_fs_cb(uv_fs_t* req) {
+ lua_State* L = luv_state(req->loop);
+
+ int nargs = push_fs_result(L, req);
+ if (nargs == 2 && lua_isnil(L, -nargs)) {
+ // If it was an error, convert to (err, value) format.
+ lua_remove(L, -nargs);
+ nargs--;
+ }
+ else {
+ // Otherwise insert a nil in front to convert to (err, value) format.
+ lua_pushnil(L);
+ lua_insert(L, -nargs - 1);
+ nargs++;
+ }
+ luv_fulfill_req(L, req->data, nargs);
+ if (req->fs_type != UV_FS_SCANDIR) {
+ luv_cleanup_req(L, req->data);
+ req->data = NULL;
+ uv_fs_req_cleanup(req);
+ }
+}
+
+#define FS_CALL(func, req, ...) { \
+ int ret, sync; \
+ luv_req_t* data = req->data; \
+ sync = data->callback_ref == LUA_NOREF; \
+ ret = uv_fs_##func(luv_loop(L), req, __VA_ARGS__, \
+ sync ? NULL : luv_fs_cb); \
+ if (req->fs_type != UV_FS_ACCESS && ret < 0) { \
+ lua_pushnil(L); \
+ if (req->path) { \
+ lua_pushfstring(L, "%s: %s: %s", uv_err_name(req->result), uv_strerror(req->result), req->path); \
+ } \
+ else { \
+ lua_pushfstring(L, "%s: %s", uv_err_name(req->result), uv_strerror(req->result)); \
+ } \
+ lua_pushstring(L, uv_err_name(req->result)); \
+ luv_cleanup_req(L, req->data); \
+ req->data = NULL; \
+ uv_fs_req_cleanup(req); \
+ return 3; \
+ } \
+ if (sync) { \
+ int nargs = push_fs_result(L, req); \
+ if (req->fs_type != UV_FS_SCANDIR) { \
+ luv_cleanup_req(L, req->data); \
+ req->data = NULL; \
+ uv_fs_req_cleanup(req); \
+ } \
+ return nargs; \
+ } \
+ lua_rawgeti(L, LUA_REGISTRYINDEX, data->req_ref); \
+ return 1; \
+}
+
+static int luv_fs_close(lua_State* L) {
+ uv_file file = luaL_checkinteger(L, 1);
+ int ref = luv_check_continuation(L, 2);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(close, req, file);
+}
+
+static int luv_fs_open(lua_State* L) {
+ const char* path = luaL_checkstring(L, 1);
+ int flags = luv_check_flags(L, 2);
+ int mode = luaL_checkinteger(L, 3);
+ int ref = luv_check_continuation(L, 4);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(open, req, path, flags, mode);
+}
+
+static int luv_fs_read(lua_State* L) {
+ uv_file file = luaL_checkinteger(L, 1);
+ int64_t len = luaL_checkinteger(L, 2);
+ int64_t offset = luaL_checkinteger(L, 3);
+ uv_buf_t buf;
+ int ref;
+ uv_fs_t* req;
+ char* data = malloc(len);
+ if (!data) return luaL_error(L, "Failure to allocate buffer");
+ buf = uv_buf_init(data, len);
+ ref = luv_check_continuation(L, 4);
+ req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ // TODO: find out why we can't just use req->ptr for the base
+ ((luv_req_t*)req->data)->data = buf.base;
+ FS_CALL(read, req, file, &buf, 1, offset);
+}
+
+static int luv_fs_unlink(lua_State* L) {
+ const char* path = luaL_checkstring(L, 1);
+ int ref = luv_check_continuation(L, 2);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(unlink, req, path);
+}
+
+static int luv_fs_write(lua_State* L) {
+ uv_file file = luaL_checkinteger(L, 1);
+ uv_buf_t buf;
+ int64_t offset;
+ int ref;
+ uv_fs_t* req;
+ size_t count;
+ uv_buf_t *bufs = NULL;
+
+ if (lua_istable(L, 2)) {
+ bufs = luv_prep_bufs(L, 2, &count);
+ buf.base = NULL;
+ }
+ else if (lua_isstring(L, 2)) {
+ luv_check_buf(L, 2, &buf);
+ count = 1;
+ }
+ else {
+ return luaL_argerror(L, 2, "data must be string or table of strings");
+ }
+
+ offset = luaL_checkinteger(L, 3);
+ ref = luv_check_continuation(L, 4);
+ req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ req->ptr = buf.base;
+ ((luv_req_t*)req->data)->data = bufs;
+ FS_CALL(write, req, file, bufs ? bufs : &buf, count, offset);
+}
+
+static int luv_fs_mkdir(lua_State* L) {
+ const char* path = luaL_checkstring(L, 1);
+ int mode = luaL_checkinteger(L, 2);
+ int ref = luv_check_continuation(L, 3);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(mkdir, req, path, mode);
+}
+
+static int luv_fs_mkdtemp(lua_State* L) {
+ const char* tpl = luaL_checkstring(L, 1);
+ int ref = luv_check_continuation(L, 2);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(mkdtemp, req, tpl);
+}
+
+static int luv_fs_rmdir(lua_State* L) {
+ const char* path = luaL_checkstring(L, 1);
+ int ref = luv_check_continuation(L, 2);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(rmdir, req, path);
+}
+
+static int luv_fs_scandir(lua_State* L) {
+ const char* path = luaL_checkstring(L, 1);
+ int flags = 0; // TODO: find out what these flags are.
+ int ref = luv_check_continuation(L, 2);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(scandir, req, path, flags);
+}
+
+static int luv_fs_scandir_next(lua_State* L) {
+ uv_fs_t* req = luv_check_fs(L, 1);
+ uv_dirent_t ent;
+ int ret = uv_fs_scandir_next(req, &ent);
+ const char* type;
+ if (ret == UV_EOF) {
+ luv_cleanup_req(L, req->data);
+ req->data = NULL;
+ uv_fs_req_cleanup(req);
+ return 0;
+ }
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushstring(L, ent.name);
+ switch (ent.type) {
+ case UV_DIRENT_UNKNOWN: return 1;
+ case UV_DIRENT_FILE: type = "file"; break;
+ case UV_DIRENT_DIR: type = "directory"; break;
+ case UV_DIRENT_LINK: type = "link"; break;
+ case UV_DIRENT_FIFO: type = "fifo"; break;
+ case UV_DIRENT_SOCKET: type = "socket"; break;
+ case UV_DIRENT_CHAR: type = "char"; break;
+ case UV_DIRENT_BLOCK: type = "block"; break;
+ default: assert(0);
+ }
+ lua_pushstring(L, type);
+ return 2;
+}
+
+static int luv_fs_stat(lua_State* L) {
+ const char* path = luaL_checkstring(L, 1);
+ int ref = luv_check_continuation(L, 2);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(stat, req, path);
+}
+
+static int luv_fs_fstat(lua_State* L) {
+ uv_file file = luaL_checkinteger(L, 1);
+ int ref = luv_check_continuation(L, 2);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(fstat, req, file);
+}
+
+static int luv_fs_lstat(lua_State* L) {
+ const char* path = luaL_checkstring(L, 1);
+ int ref = luv_check_continuation(L, 2);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(lstat, req, path);
+}
+
+static int luv_fs_rename(lua_State* L) {
+ const char* path = luaL_checkstring(L, 1);
+ const char* new_path = luaL_checkstring(L, 2);
+ int ref = luv_check_continuation(L, 3);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(rename, req, path, new_path);
+}
+
+static int luv_fs_fsync(lua_State* L) {
+ uv_file file = luaL_checkinteger(L, 1);
+ int ref = luv_check_continuation(L, 2);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(fsync, req, file);
+}
+
+static int luv_fs_fdatasync(lua_State* L) {
+ uv_file file = luaL_checkinteger(L, 1);
+ int ref = luv_check_continuation(L, 2);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(fdatasync, req, file);
+}
+
+static int luv_fs_ftruncate(lua_State* L) {
+ uv_file file = luaL_checkinteger(L, 1);
+ int64_t offset = luaL_checkinteger(L, 2);
+ int ref = luv_check_continuation(L, 3);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(ftruncate, req, file, offset);
+}
+
+static int luv_fs_sendfile(lua_State* L) {
+ uv_file out_fd = luaL_checkinteger(L, 1);
+ uv_file in_fd = luaL_checkinteger(L, 2);
+ int64_t in_offset = luaL_checkinteger(L, 3);
+ size_t length = luaL_checkinteger(L, 4);
+ int ref = luv_check_continuation(L, 5);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(sendfile, req, out_fd, in_fd, in_offset, length);
+}
+
+static int luv_fs_access(lua_State* L) {
+ const char* path = luaL_checkstring(L, 1);
+ int amode = luv_check_amode(L, 2);
+ int ref = luv_check_continuation(L, 3);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(access, req, path, amode);
+}
+
+static int luv_fs_chmod(lua_State* L) {
+ const char* path = luaL_checkstring(L, 1);
+ int mode = luaL_checkinteger(L, 2);
+ int ref = luv_check_continuation(L, 3);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(chmod, req, path, mode);
+}
+
+static int luv_fs_fchmod(lua_State* L) {
+ uv_file file = luaL_checkinteger(L, 1);
+ int mode = luaL_checkinteger(L, 2);
+ int ref = luv_check_continuation(L, 3);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(fchmod, req, file, mode);
+}
+
+static int luv_fs_utime(lua_State* L) {
+ const char* path = luaL_checkstring(L, 1);
+ double atime = luaL_checknumber(L, 2);
+ double mtime = luaL_checknumber(L, 3);
+ int ref = luv_check_continuation(L, 4);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(utime, req, path, atime, mtime);
+}
+
+static int luv_fs_futime(lua_State* L) {
+ uv_file file = luaL_checkinteger(L, 1);
+ double atime = luaL_checknumber(L, 2);
+ double mtime = luaL_checknumber(L, 3);
+ int ref = luv_check_continuation(L, 4);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(futime, req, file, atime, mtime);
+}
+
+static int luv_fs_link(lua_State* L) {
+ const char* path = luaL_checkstring(L, 1);
+ const char* new_path = luaL_checkstring(L, 2);
+ int ref = luv_check_continuation(L, 3);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(link, req, path, new_path);
+}
+
+static int luv_fs_symlink(lua_State* L) {
+ const char* path = luaL_checkstring(L, 1);
+ const char* new_path = luaL_checkstring(L, 2);
+ int flags = 0, ref;
+ uv_fs_t* req;
+ if (lua_type(L, 3) == LUA_TTABLE) {
+ lua_getfield(L, 3, "dir");
+ if (lua_toboolean(L, -1)) flags |= UV_FS_SYMLINK_DIR;
+ lua_pop(L, 1);
+ lua_getfield(L, 3, "junction");
+ if (lua_toboolean(L, -1)) flags |= UV_FS_SYMLINK_JUNCTION;
+ lua_pop(L, 1);
+ }
+ ref = luv_check_continuation(L, 4);
+ req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+
+ FS_CALL(symlink, req, path, new_path, flags);
+}
+
+static int luv_fs_readlink(lua_State* L) {
+ const char* path = luaL_checkstring(L, 1);
+ int ref = luv_check_continuation(L, 2);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(readlink, req, path);
+}
+
+static int luv_fs_realpath(lua_State* L) {
+ const char* path = luaL_checkstring(L, 1);
+ int ref = luv_check_continuation(L, 2);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(realpath, req, path);
+}
+
+static int luv_fs_chown(lua_State* L) {
+ const char* path = luaL_checkstring(L, 1);
+ uv_uid_t uid = luaL_checkinteger(L, 2);
+ uv_uid_t gid = luaL_checkinteger(L, 3);
+ int ref = luv_check_continuation(L, 4);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(chown, req, path, uid, gid);
+}
+
+static int luv_fs_fchown(lua_State* L) {
+ uv_file file = luaL_checkinteger(L, 1);
+ uv_uid_t uid = luaL_checkinteger(L, 2);
+ uv_uid_t gid = luaL_checkinteger(L, 3);
+ int ref = luv_check_continuation(L, 4);
+ uv_fs_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ FS_CALL(fchown, req, file, uid, gid);
+}
diff --git a/3rdparty/luv/src/fs_event.c b/3rdparty/luv/src/fs_event.c
new file mode 100644
index 00000000000..52bda788421
--- /dev/null
+++ b/3rdparty/luv/src/fs_event.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "luv.h"
+
+static uv_fs_event_t* luv_check_fs_event(lua_State* L, int index) {
+ uv_fs_event_t* handle = luv_checkudata(L, index, "uv_fs_event");
+ luaL_argcheck(L, handle->type == UV_FS_EVENT && handle->data, index, "Expected uv_fs_event_t");
+ return handle;
+}
+
+static int luv_new_fs_event(lua_State* L) {
+ uv_fs_event_t* handle = luv_newuserdata(L, sizeof(*handle));
+ int ret = uv_fs_event_init(luv_loop(L), handle);
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ handle->data = luv_setup_handle(L);
+ return 1;
+}
+
+static void luv_fs_event_cb(uv_fs_event_t* handle, const char* filename, int events, int status) {
+ lua_State* L = luv_state(handle->loop);
+
+ // err
+ luv_status(L, status);
+
+ // filename
+ lua_pushstring(L, filename);
+
+ // events
+ lua_newtable(L);
+ if (events & UV_RENAME) {
+ lua_pushboolean(L, 1);
+ lua_setfield(L, -2, "rename");
+ }
+ if (events & UV_CHANGE) {
+ lua_pushboolean(L, 1);
+ lua_setfield(L, -2, "change");
+ }
+
+ luv_call_callback(L, handle->data, LUV_FS_EVENT, 3);
+}
+
+static int luv_fs_event_start(lua_State* L) {
+ uv_fs_event_t* handle = luv_check_fs_event(L, 1);
+ const char* path = luaL_checkstring(L, 2);
+ int flags = 0, ret;
+ luaL_checktype(L, 3, LUA_TTABLE);
+ lua_getfield(L, 3, "watch_entry");
+ if (lua_toboolean(L, -1)) flags |= UV_FS_EVENT_WATCH_ENTRY;
+ lua_pop(L, 1);
+ lua_getfield(L, 3, "stat");
+ if (lua_toboolean(L, -1)) flags |= UV_FS_EVENT_STAT;
+ lua_pop(L, 1);
+ lua_getfield(L, 3, "recursive");
+ if (lua_toboolean(L, -1)) flags |= UV_FS_EVENT_RECURSIVE;
+ lua_pop(L, 1);
+ luv_check_callback(L, handle->data, LUV_FS_EVENT, 4);
+ ret = uv_fs_event_start(handle, luv_fs_event_cb, path, flags);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_fs_event_stop(lua_State* L) {
+ uv_fs_event_t* handle = luv_check_fs_event(L, 1);
+ int ret = uv_fs_event_stop(handle);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_fs_event_getpath(lua_State* L) {
+ uv_fs_event_t* handle = luv_check_fs_event(L, 1);
+ size_t len = 2*PATH_MAX;
+ char buf[2*PATH_MAX];
+ int ret = uv_fs_event_getpath(handle, buf, &len);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushlstring(L, buf, len);
+ return 1;
+}
diff --git a/3rdparty/luv/src/fs_poll.c b/3rdparty/luv/src/fs_poll.c
new file mode 100644
index 00000000000..7ead32f322c
--- /dev/null
+++ b/3rdparty/luv/src/fs_poll.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "luv.h"
+
+static uv_fs_poll_t* luv_check_fs_poll(lua_State* L, int index) {
+ uv_fs_poll_t* handle = luv_checkudata(L, index, "uv_fs_poll");
+ luaL_argcheck(L, handle->type == UV_FS_POLL && handle->data, index, "Expected uv_fs_poll_t");
+ return handle;
+}
+
+static int luv_new_fs_poll(lua_State* L) {
+ uv_fs_poll_t* handle = luv_newuserdata(L, sizeof(*handle));
+ int ret = uv_fs_poll_init(luv_loop(L), handle);
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ handle->data = luv_setup_handle(L);
+ return 1;
+}
+
+static void luv_fs_poll_cb(uv_fs_poll_t* handle, int status, const uv_stat_t* prev, const uv_stat_t* curr) {
+ lua_State* L = luv_state(handle->loop);
+
+ // err
+ luv_status(L, status);
+
+ // prev
+ if (prev) {
+ luv_push_stats_table(L, prev);
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ // curr
+ if (curr) {
+ luv_push_stats_table(L, curr);
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ luv_call_callback(L, handle->data, LUV_FS_POLL, 3);
+}
+
+static int luv_fs_poll_start(lua_State* L) {
+ uv_fs_poll_t* handle = luv_check_fs_poll(L, 1);
+ const char* path = luaL_checkstring(L, 2);
+ unsigned int interval = luaL_checkinteger(L, 3);
+ int ret;
+ luv_check_callback(L, handle->data, LUV_FS_POLL, 4);
+ ret = uv_fs_poll_start(handle, luv_fs_poll_cb, path, interval);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_fs_poll_stop(lua_State* L) {
+ uv_fs_poll_t* handle = luv_check_fs_poll(L, 1);
+ int ret = uv_fs_poll_stop(handle);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_fs_poll_getpath(lua_State* L) {
+ uv_fs_poll_t* handle = luv_check_fs_poll(L, 1);
+ size_t len = 2*PATH_MAX;
+ char buf[2*PATH_MAX];
+ int ret = uv_fs_poll_getpath(handle, buf, &len);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushlstring(L, buf, len);
+ return 1;
+}
diff --git a/3rdparty/luv/src/handle.c b/3rdparty/luv/src/handle.c
new file mode 100644
index 00000000000..3efd2982641
--- /dev/null
+++ b/3rdparty/luv/src/handle.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "luv.h"
+
+static void* luv_newuserdata(lua_State* L, size_t sz) {
+ void* handle = malloc(sz);
+ if (handle) {
+ *(void**)lua_newuserdata(L, sizeof(void*)) = handle;
+ }
+ return handle;
+}
+
+static void* luv_checkudata(lua_State* L, int ud, const char* tname) {
+ return *(void**) luaL_checkudata(L, ud, tname);
+}
+
+static uv_handle_t* luv_check_handle(lua_State* L, int index) {
+ int isHandle;
+ uv_handle_t* handle;
+ if (!(handle = *(void**)lua_touserdata(L, index))) { goto fail; }
+ lua_getfield(L, LUA_REGISTRYINDEX, "uv_handle");
+ lua_getmetatable(L, index < 0 ? index - 1 : index);
+ lua_rawget(L, -2);
+ isHandle = lua_toboolean(L, -1);
+ lua_pop(L, 2);
+ if (isHandle) { return handle; }
+ fail: luaL_argerror(L, index, "Expected uv_handle userdata");
+ return NULL;
+}
+
+// Show the libuv type instead of generic "userdata"
+static int luv_handle_tostring(lua_State* L) {
+ uv_handle_t* handle = luv_check_handle(L, 1);
+ switch (handle->type) {
+#define XX(uc, lc) case UV_##uc: lua_pushfstring(L, "uv_"#lc"_t: %p", handle); break;
+ UV_HANDLE_TYPE_MAP(XX)
+#undef XX
+ default: lua_pushfstring(L, "uv_handle_t: %p", handle); break;
+ }
+ return 1;
+}
+
+static int luv_is_active(lua_State* L) {
+ uv_handle_t* handle = luv_check_handle(L, 1);
+ int ret = uv_is_active(handle);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushboolean(L, ret);
+ return 1;
+}
+
+static int luv_is_closing(lua_State* L) {
+ uv_handle_t* handle = luv_check_handle(L, 1);
+ int ret = uv_is_closing(handle);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushboolean(L, ret);
+ return 1;
+}
+
+static void luv_close_cb(uv_handle_t* handle) {
+ lua_State* L = luv_state(handle->loop);
+ luv_handle_t* data = handle->data;
+ if (!data) return;
+ luv_call_callback(L, data, LUV_CLOSED, 0);
+ luv_cleanup_handle(L, data);
+ handle->data = NULL;
+}
+
+static int luv_close(lua_State* L) {
+ uv_handle_t* handle = luv_check_handle(L, 1);
+ if (uv_is_closing(handle)) {
+ luaL_error(L, "handle %p is already closing", handle);
+ }
+ if (!lua_isnoneornil(L, 2)) {
+ luv_check_callback(L, handle->data, LUV_CLOSED, 2);
+ }
+ uv_close(handle, luv_close_cb);
+ return 0;
+}
+
+static void luv_gc_cb(uv_handle_t* handle) {
+ luv_close_cb(handle);
+ free(handle);
+}
+
+static int luv_handle_gc(lua_State* L) {
+ void** udata = lua_touserdata(L, 1);
+ uv_handle_t* handle = *udata;
+ if (handle != NULL) {
+ if (!uv_is_closing(handle))
+ uv_close(handle, luv_gc_cb);
+ else
+ free(*udata);
+
+ *udata = NULL;
+ }
+
+ return 0;
+}
+
+static int luv_ref(lua_State* L) {
+ uv_handle_t* handle = luv_check_handle(L, 1);
+ uv_ref(handle);
+ return 0;
+}
+
+static int luv_unref(lua_State* L) {
+ uv_handle_t* handle = luv_check_handle(L, 1);
+ uv_unref(handle);
+ return 0;
+}
+
+static int luv_has_ref(lua_State* L) {
+ uv_handle_t* handle = luv_check_handle(L, 1);
+ int ret = uv_has_ref(handle);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushboolean(L, ret);
+ return 1;
+}
+
+static int luv_send_buffer_size(lua_State* L) {
+ uv_handle_t* handle = luv_check_handle(L, 1);
+ int value;
+ int ret;
+ if (lua_isnoneornil(L, 2)) {
+ value = 0;
+ }
+ else {
+ value = luaL_checkinteger(L, 2);
+ }
+ ret = uv_send_buffer_size(handle, &value);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_recv_buffer_size(lua_State* L) {
+ uv_handle_t* handle = luv_check_handle(L, 1);
+ int value;
+ int ret;
+ if (lua_isnoneornil(L, 2)) {
+ value = 0;
+ }
+ else {
+ value = luaL_checkinteger(L, 2);
+ }
+ ret = uv_recv_buffer_size(handle, &value);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_fileno(lua_State* L) {
+ uv_handle_t* handle = luv_check_handle(L, 1);
+ uv_os_fd_t fd;
+ int ret = uv_fileno(handle, &fd);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, (LUA_INTEGER)(ptrdiff_t)fd);
+ return 1;
+}
diff --git a/3rdparty/luv/src/idle.c b/3rdparty/luv/src/idle.c
new file mode 100644
index 00000000000..132cbe43c33
--- /dev/null
+++ b/3rdparty/luv/src/idle.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "luv.h"
+
+static uv_idle_t* luv_check_idle(lua_State* L, int index) {
+ uv_idle_t* handle = luv_checkudata(L, index, "uv_idle");
+ luaL_argcheck(L, handle->type == UV_IDLE && handle->data, index, "Expected uv_idle_t");
+ return handle;
+}
+
+static int luv_new_idle(lua_State* L) {
+ uv_idle_t* handle = luv_newuserdata(L, sizeof(*handle));
+ int ret = uv_idle_init(luv_loop(L), handle);
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ handle->data = luv_setup_handle(L);
+ return 1;
+}
+
+static void luv_idle_cb(uv_idle_t* handle) {
+ lua_State* L = luv_state(handle->loop);
+ luv_handle_t* data = handle->data;
+ luv_call_callback(L, data, LUV_IDLE, 0);
+}
+
+static int luv_idle_start(lua_State* L) {
+ uv_idle_t* handle = luv_check_idle(L, 1);
+ int ret;
+ luv_check_callback(L, handle->data, LUV_IDLE, 2);
+ ret = uv_idle_start(handle, luv_idle_cb);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_idle_stop(lua_State* L) {
+ uv_idle_t* handle = luv_check_idle(L, 1);
+ int ret = uv_idle_stop(handle);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
diff --git a/3rdparty/luv/src/lhandle.c b/3rdparty/luv/src/lhandle.c
new file mode 100644
index 00000000000..c8cf294504e
--- /dev/null
+++ b/3rdparty/luv/src/lhandle.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "lhandle.h"
+
+static luv_handle_t* luv_setup_handle(lua_State* L) {
+ luv_handle_t* data;
+ const uv_handle_t* handle = *(void**)lua_touserdata(L, -1);
+ luaL_checktype(L, -1, LUA_TUSERDATA);
+
+ data = malloc(sizeof(*data));
+ if (!data) luaL_error(L, "Can't allocate luv handle");
+
+ #define XX(uc, lc) case UV_##uc: \
+ luaL_getmetatable(L, "uv_"#lc); \
+ break;
+ switch (handle->type) {
+ UV_HANDLE_TYPE_MAP(XX)
+ default:
+ luaL_error(L, "Unknown handle type");
+ return NULL;
+ }
+ #undef XX
+
+ lua_setmetatable(L, -2);
+
+ lua_pushvalue(L, -1);
+
+ data->ref = luaL_ref(L, LUA_REGISTRYINDEX);
+ data->callbacks[0] = LUA_NOREF;
+ data->callbacks[1] = LUA_NOREF;
+ data->extra = NULL;
+ return data;
+}
+
+static void luv_check_callback(lua_State* L, luv_handle_t* data, luv_callback_id id, int index) {
+ luaL_checktype(L, index, LUA_TFUNCTION);
+ luaL_unref(L, LUA_REGISTRYINDEX, data->callbacks[id]);
+ lua_pushvalue(L, index);
+ data->callbacks[id] = luaL_ref(L, LUA_REGISTRYINDEX);
+}
+
+static int traceback (lua_State *L) {
+ if (!lua_isstring(L, 1)) /* 'message' not a string? */
+ return 1; /* keep it intact */
+ lua_pushglobaltable(L);
+ lua_getfield(L, -1, "debug");
+ lua_remove(L, -2);
+ if (!lua_istable(L, -1)) {
+ lua_pop(L, 1);
+ return 1;
+ }
+ lua_getfield(L, -1, "traceback");
+ if (!lua_isfunction(L, -1)) {
+ lua_pop(L, 2);
+ return 1;
+ }
+ lua_pushvalue(L, 1); /* pass error message */
+ lua_pushinteger(L, 2); /* skip this function and traceback */
+ lua_call(L, 2, 1); /* call debug.traceback */
+ return 1;
+}
+
+static void luv_call_callback(lua_State* L, luv_handle_t* data, luv_callback_id id, int nargs) {
+ int ref = data->callbacks[id];
+ if (ref == LUA_NOREF) {
+ lua_pop(L, nargs);
+ }
+ else {
+ // Get the traceback function in case of error
+ lua_pushcfunction(L, traceback);
+ // And insert it before the args if there are any.
+ if (nargs) {
+ lua_insert(L, -1 - nargs);
+ }
+ // Get the callback
+ lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
+ // And insert it before the args if there are any.
+ if (nargs) {
+ lua_insert(L, -1 - nargs);
+ }
+
+ if (lua_pcall(L, nargs, 0, -2 - nargs)) {
+ fprintf(stderr, "Uncaught Error: %s\n", lua_tostring(L, -1));
+ exit(-1);
+ }
+ // Remove the traceback function
+ lua_pop(L, 1);
+ }
+}
+
+static void luv_cleanup_handle(lua_State* L, luv_handle_t* data) {
+ luaL_unref(L, LUA_REGISTRYINDEX, data->ref);
+ luaL_unref(L, LUA_REGISTRYINDEX, data->callbacks[0]);
+ luaL_unref(L, LUA_REGISTRYINDEX, data->callbacks[1]);
+ if (data->extra)
+ free(data->extra);
+ free(data);
+}
+
+static void luv_find_handle(lua_State* L, luv_handle_t* data) {
+ lua_rawgeti(L, LUA_REGISTRYINDEX, data->ref);
+}
diff --git a/3rdparty/luv/src/lhandle.h b/3rdparty/luv/src/lhandle.h
new file mode 100644
index 00000000000..f6c0733719b
--- /dev/null
+++ b/3rdparty/luv/src/lhandle.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef LUV_LHANDLE_H
+#define LUV_LHANDLE_H
+
+#include "luv.h"
+
+/* There are two slots for holding callbacks. One is for the CLOSED event.
+ The other slot is for all others since they never conflict in practice.
+*/
+#define luv_callback_id int
+#define LUV_CLOSED 0
+#define LUV_TIMEOUT 1
+#define LUV_PREPARE 1
+#define LUV_IDLE 1
+#define LUV_CHECK 1
+#define LUV_ASYNC 1
+#define LUV_POLL 1
+#define LUV_SIGNAL 1
+#define LUV_EXIT 1
+#define LUV_CONNECTION 1
+#define LUV_READ 1
+#define LUV_RECV 1
+#define LUV_FS_EVENT 1
+#define LUV_FS_POLL 1
+
+/* Ref for userdata and event callbacks */
+typedef struct {
+ int ref;
+ int callbacks[2];
+ void* extra;
+} luv_handle_t;
+
+/* Setup the handle at the top of the stack */
+static luv_handle_t* luv_setup_handle(lua_State* L);
+
+/* Store a lua callback in a luv_handle for future callbacks.
+ Either replace an existing callback by id or append a new one at the end.
+*/
+static void luv_check_callback(lua_State* L, luv_handle_t* data, luv_callback_id id, int index);
+
+/* Lookup a function and call it with nargs
+ If there is no such function, pop the args.
+*/
+static void luv_call_callback(lua_State* L, luv_handle_t* data, luv_callback_id id, int nargs);
+
+/* Push a userdata on the stack from a handle */
+static void luv_find_handle(lua_State* L, luv_handle_t* data);
+
+/* Recursivly free the luv_handle and all event handlers */
+static void luv_cleanup_handle(lua_State* L, luv_handle_t* data);
+
+#endif
diff --git a/3rdparty/luv/src/loop.c b/3rdparty/luv/src/loop.c
new file mode 100644
index 00000000000..33c49d3f64c
--- /dev/null
+++ b/3rdparty/luv/src/loop.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "luv.h"
+
+static int luv_loop_close(lua_State* L) {
+ int ret = uv_loop_close(luv_loop(L));
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+// These are the same order as uv_run_mode which also starts at 0
+static const char *const luv_runmodes[] = {
+ "default", "once", "nowait", NULL
+};
+
+static int luv_run(lua_State* L) {
+ int mode = luaL_checkoption(L, 1, "default", luv_runmodes);
+ int ret = uv_run(luv_loop(L), mode);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushboolean(L, ret);
+ return 1;
+}
+
+static int luv_loop_alive(lua_State* L) {
+ int ret = uv_loop_alive(luv_loop(L));
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushboolean(L, ret);
+ return 1;
+}
+
+static int luv_stop(lua_State* L) {
+ uv_stop(luv_loop(L));
+ return 0;
+}
+
+static int luv_backend_fd(lua_State* L) {
+ int ret = uv_backend_fd(luv_loop(L));
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_backend_timeout(lua_State* L) {
+ int ret = uv_backend_timeout(luv_loop(L));
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_now(lua_State* L) {
+ uint64_t now = uv_now(luv_loop(L));
+ lua_pushinteger(L, now);
+ return 1;
+}
+
+static int luv_update_time(lua_State* L) {
+ uv_update_time(luv_loop(L));
+ return 0;
+}
+
+static void luv_walk_cb(uv_handle_t* handle, void* arg) {
+ lua_State* L = arg;
+ luv_handle_t* data = handle->data;
+
+ // Sanity check
+ // Most invalid values are large and refs are small, 0x1000000 is arbitrary.
+ assert(data && data->ref < 0x1000000);
+
+ lua_pushvalue(L, 1); // Copy the function
+ luv_find_handle(L, data); // Get the userdata
+ lua_call(L, 1, 0); // Call the function
+}
+
+static int luv_walk(lua_State* L) {
+ luaL_checktype(L, 1, LUA_TFUNCTION);
+ uv_walk(luv_loop(L), luv_walk_cb, L);
+ return 0;
+}
diff --git a/3rdparty/luv/src/lreq.c b/3rdparty/luv/src/lreq.c
new file mode 100644
index 00000000000..38ed6a77eb0
--- /dev/null
+++ b/3rdparty/luv/src/lreq.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "lreq.h"
+
+
+static int luv_check_continuation(lua_State* L, int index) {
+ if (lua_isnoneornil(L, index)) return LUA_NOREF;
+ luaL_checktype(L, index, LUA_TFUNCTION);
+ lua_pushvalue(L, index);
+ return luaL_ref(L, LUA_REGISTRYINDEX);
+}
+
+// Store a lua callback in a luv_req for the continuation.
+// The uv_req_t is assumed to be at the top of the stack
+static luv_req_t* luv_setup_req(lua_State* L, int callback_ref) {
+ luv_req_t* data;
+
+ luaL_checktype(L, -1, LUA_TUSERDATA);
+
+ data = malloc(sizeof(*data));
+ if (!data) luaL_error(L, "Problem allocating luv request");
+
+ luaL_getmetatable(L, "uv_req");
+ lua_setmetatable(L, -2);
+
+ lua_pushvalue(L, -1);
+ data->req_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+ data->callback_ref = callback_ref;
+ data->data_ref = LUA_NOREF;
+ data->data = NULL;
+
+ return data;
+}
+
+
+static void luv_fulfill_req(lua_State* L, luv_req_t* data, int nargs) {
+ if (data->callback_ref == LUA_NOREF) {
+ lua_pop(L, nargs);
+ }
+ else {
+ // Get the callback
+ lua_rawgeti(L, LUA_REGISTRYINDEX, data->callback_ref);
+ // And insert it before the args if there are any.
+ if (nargs) {
+ lua_insert(L, -1 - nargs);
+ }
+ lua_call(L, nargs, 0);
+ }
+}
+
+static void luv_cleanup_req(lua_State* L, luv_req_t* data) {
+ luaL_unref(L, LUA_REGISTRYINDEX, data->req_ref);
+ luaL_unref(L, LUA_REGISTRYINDEX, data->callback_ref);
+ luaL_unref(L, LUA_REGISTRYINDEX, data->data_ref);
+ free(data->data);
+ free(data);
+}
diff --git a/3rdparty/luv/src/lreq.h b/3rdparty/luv/src/lreq.h
new file mode 100644
index 00000000000..a8b147e057b
--- /dev/null
+++ b/3rdparty/luv/src/lreq.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef LUV_LREQ_H
+#define LUV_LREQ_H
+
+#include "luv.h"
+
+typedef struct {
+ int req_ref; /* ref for uv_req_t's userdata */
+ int callback_ref; /* ref for callback */
+ int data_ref; /* ref for write data */
+ void* data; /* extra data */
+} luv_req_t;
+
+/* Used in the top of a setup function to check the arg
+ and ref the callback to an integer.
+*/
+static int luv_check_continuation(lua_State* L, int index);
+
+/* setup a luv_req_t. The userdata is assumed to be at the
+ top of the stack.
+*/
+static luv_req_t* luv_setup_req(lua_State* L, int ref);
+
+static void luv_fulfill_req(lua_State* L, luv_req_t* data, int nargs);
+
+static void luv_cleanup_req(lua_State* L, luv_req_t* data);
+
+#endif
diff --git a/3rdparty/luv/src/lthreadpool.h b/3rdparty/luv/src/lthreadpool.h
new file mode 100644
index 00000000000..0994746bc52
--- /dev/null
+++ b/3rdparty/luv/src/lthreadpool.h
@@ -0,0 +1,48 @@
+/*
+* Copyright 2014 The Luvit Authors. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+#ifndef LUV_LTHREADPOOL_H
+#define LUV_LTHREADPOOL_H
+
+#include "luv.h"
+
+#define LUV_THREAD_MAXNUM_ARG 9
+
+typedef struct {
+ /* only support LUA_TNIL, LUA_TBOOLEAN, LUA_TLIGHTUSERDATA, LUA_TNUMBER, LUA_TSTRING*/
+ int type;
+ union
+ {
+ lua_Number num;
+ int boolean;
+ void* userdata;
+ struct {
+ const char* base;
+ size_t len;
+ } str;
+ } val;
+} luv_val_t;
+
+typedef struct {
+ int argc;
+ luv_val_t argv[LUV_THREAD_MAXNUM_ARG];
+} luv_thread_arg_t;
+
+static int luv_thread_arg_set(lua_State* L, luv_thread_arg_t* args, int idx, int top, int flag);
+static int luv_thread_arg_push(lua_State* L, const luv_thread_arg_t* args);
+static void luv_thread_arg_clear(luv_thread_arg_t* args);
+
+#endif //LUV_LTHREADPOOL_H
diff --git a/3rdparty/luv/src/luv.c b/3rdparty/luv/src/luv.c
new file mode 100644
index 00000000000..7b552d68d53
--- /dev/null
+++ b/3rdparty/luv/src/luv.c
@@ -0,0 +1,519 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "luv.h"
+#include "util.c"
+#include "lhandle.c"
+#include "lreq.c"
+#include "loop.c"
+#include "req.c"
+#include "handle.c"
+#include "timer.c"
+#include "prepare.c"
+#include "check.c"
+#include "idle.c"
+#include "async.c"
+#include "poll.c"
+#include "signal.c"
+#include "process.c"
+#include "stream.c"
+#include "tcp.c"
+#include "pipe.c"
+#include "tty.c"
+#include "udp.c"
+#include "fs_event.c"
+#include "fs_poll.c"
+#include "fs.c"
+#include "dns.c"
+#include "thread.c"
+#include "work.c"
+#include "misc.c"
+#include "constants.c"
+
+static const luaL_Reg luv_functions[] = {
+ // loop.c
+ {"loop_close", luv_loop_close},
+ {"run", luv_run},
+ {"loop_alive", luv_loop_alive},
+ {"stop", luv_stop},
+ {"backend_fd", luv_backend_fd},
+ {"backend_timeout", luv_backend_timeout},
+ {"now", luv_now},
+ {"update_time", luv_update_time},
+ {"walk", luv_walk},
+
+ // req.c
+ {"cancel", luv_cancel},
+
+ // handle.c
+ {"is_active", luv_is_active},
+ {"is_closing", luv_is_closing},
+ {"close", luv_close},
+ {"ref", luv_ref},
+ {"unref", luv_unref},
+ {"has_ref", luv_has_ref},
+ {"send_buffer_size", luv_send_buffer_size},
+ {"recv_buffer_size", luv_recv_buffer_size},
+ {"fileno", luv_fileno},
+
+ // timer.c
+ {"new_timer", luv_new_timer},
+ {"timer_start", luv_timer_start},
+ {"timer_stop", luv_timer_stop},
+ {"timer_again", luv_timer_again},
+ {"timer_set_repeat", luv_timer_set_repeat},
+ {"timer_get_repeat", luv_timer_get_repeat},
+
+ // prepare.c
+ {"new_prepare", luv_new_prepare},
+ {"prepare_start", luv_prepare_start},
+ {"prepare_stop", luv_prepare_stop},
+
+ // check.c
+ {"new_check", luv_new_check},
+ {"check_start", luv_check_start},
+ {"check_stop", luv_check_stop},
+
+ // idle.c
+ {"new_idle", luv_new_idle},
+ {"idle_start", luv_idle_start},
+ {"idle_stop", luv_idle_stop},
+
+ // async.c
+ {"new_async", luv_new_async},
+ {"async_send", luv_async_send},
+
+ // poll.c
+ {"new_poll", luv_new_poll},
+ {"new_socket_poll", luv_new_socket_poll},
+ {"poll_start", luv_poll_start},
+ {"poll_stop", luv_poll_stop},
+
+ // signal.c
+ {"new_signal", luv_new_signal},
+ {"signal_start", luv_signal_start},
+ {"signal_stop", luv_signal_stop},
+
+ // process.c
+ {"disable_stdio_inheritance", luv_disable_stdio_inheritance},
+ {"spawn", luv_spawn},
+ {"process_kill", luv_process_kill},
+ {"kill", luv_kill},
+
+ // stream.c
+ {"shutdown", luv_shutdown},
+ {"listen", luv_listen},
+ {"accept", luv_accept},
+ {"read_start", luv_read_start},
+ {"read_stop", luv_read_stop},
+ {"write", luv_write},
+ {"write2", luv_write2},
+ {"try_write", luv_try_write},
+ {"is_readable", luv_is_readable},
+ {"is_writable", luv_is_writable},
+ {"stream_set_blocking", luv_stream_set_blocking},
+
+ // tcp.c
+ {"new_tcp", luv_new_tcp},
+ {"tcp_open", luv_tcp_open},
+ {"tcp_nodelay", luv_tcp_nodelay},
+ {"tcp_keepalive", luv_tcp_keepalive},
+ {"tcp_simultaneous_accepts", luv_tcp_simultaneous_accepts},
+ {"tcp_bind", luv_tcp_bind},
+ {"tcp_getpeername", luv_tcp_getpeername},
+ {"tcp_getsockname", luv_tcp_getsockname},
+ {"tcp_connect", luv_tcp_connect},
+ {"tcp_write_queue_size", luv_write_queue_size},
+
+ // pipe.c
+ {"new_pipe", luv_new_pipe},
+ {"pipe_open", luv_pipe_open},
+ {"pipe_bind", luv_pipe_bind},
+ {"pipe_connect", luv_pipe_connect},
+ {"pipe_getsockname", luv_pipe_getsockname},
+ {"pipe_getpeername", luv_pipe_getpeername},
+ {"pipe_pending_instances", luv_pipe_pending_instances},
+ {"pipe_pending_count", luv_pipe_pending_count},
+ {"pipe_pending_type", luv_pipe_pending_type},
+
+ // tty.c
+ {"new_tty", luv_new_tty},
+ {"tty_set_mode", luv_tty_set_mode},
+ {"tty_reset_mode", luv_tty_reset_mode},
+ {"tty_get_winsize", luv_tty_get_winsize},
+
+ // udp.c
+ {"new_udp", luv_new_udp},
+ {"udp_open", luv_udp_open},
+ {"udp_bind", luv_udp_bind},
+ {"udp_getsockname", luv_udp_getsockname},
+ {"udp_set_membership", luv_udp_set_membership},
+ {"udp_set_multicast_loop", luv_udp_set_multicast_loop},
+ {"udp_set_multicast_ttl", luv_udp_set_multicast_ttl},
+ {"udp_set_multicast_interface", luv_udp_set_multicast_interface},
+ {"udp_set_broadcast", luv_udp_set_broadcast},
+ {"udp_set_ttl", luv_udp_set_ttl},
+ {"udp_send", luv_udp_send},
+ {"udp_try_send", luv_udp_try_send},
+ {"udp_recv_start", luv_udp_recv_start},
+ {"udp_recv_stop", luv_udp_recv_stop},
+
+ // fs_event.c
+ {"new_fs_event", luv_new_fs_event},
+ {"fs_event_start", luv_fs_event_start},
+ {"fs_event_stop", luv_fs_event_stop},
+ {"fs_event_getpath", luv_fs_event_getpath},
+
+ // fs_poll.c
+ {"new_fs_poll", luv_new_fs_poll},
+ {"fs_poll_start", luv_fs_poll_start},
+ {"fs_poll_stop", luv_fs_poll_stop},
+ {"fs_poll_getpath", luv_fs_poll_getpath},
+
+ // fs.c
+ {"fs_close", luv_fs_close},
+ {"fs_open", luv_fs_open},
+ {"fs_read", luv_fs_read},
+ {"fs_unlink", luv_fs_unlink},
+ {"fs_write", luv_fs_write},
+ {"fs_mkdir", luv_fs_mkdir},
+ {"fs_mkdtemp", luv_fs_mkdtemp},
+ {"fs_rmdir", luv_fs_rmdir},
+ {"fs_scandir", luv_fs_scandir},
+ {"fs_scandir_next", luv_fs_scandir_next},
+ {"fs_stat", luv_fs_stat},
+ {"fs_fstat", luv_fs_fstat},
+ {"fs_lstat", luv_fs_lstat},
+ {"fs_rename", luv_fs_rename},
+ {"fs_fsync", luv_fs_fsync},
+ {"fs_fdatasync", luv_fs_fdatasync},
+ {"fs_ftruncate", luv_fs_ftruncate},
+ {"fs_sendfile", luv_fs_sendfile},
+ {"fs_access", luv_fs_access},
+ {"fs_chmod", luv_fs_chmod},
+ {"fs_fchmod", luv_fs_fchmod},
+ {"fs_utime", luv_fs_utime},
+ {"fs_futime", luv_fs_futime},
+ {"fs_link", luv_fs_link},
+ {"fs_symlink", luv_fs_symlink},
+ {"fs_readlink", luv_fs_readlink},
+ {"fs_realpath", luv_fs_realpath},
+ {"fs_chown", luv_fs_chown},
+ {"fs_fchown", luv_fs_fchown},
+
+ // dns.c
+ {"getaddrinfo", luv_getaddrinfo},
+ {"getnameinfo", luv_getnameinfo},
+
+ // misc.c
+ {"chdir", luv_chdir},
+ {"os_homedir", luv_os_homedir},
+ {"cpu_info", luv_cpu_info},
+ {"cwd", luv_cwd},
+ {"exepath", luv_exepath},
+ {"get_process_title", luv_get_process_title},
+ {"get_total_memory", luv_get_total_memory},
+ {"get_free_memory", luv_get_free_memory},
+ {"getpid", luv_getpid},
+#ifndef _WIN32
+ {"getuid", luv_getuid},
+ {"setuid", luv_setuid},
+ {"getgid", luv_getgid},
+ {"setgid", luv_setgid},
+#endif
+ {"getrusage", luv_getrusage},
+ {"guess_handle", luv_guess_handle},
+ {"hrtime", luv_hrtime},
+ {"interface_addresses", luv_interface_addresses},
+ {"loadavg", luv_loadavg},
+ {"resident_set_memory", luv_resident_set_memory},
+ {"set_process_title", luv_set_process_title},
+ {"uptime", luv_uptime},
+ {"version", luv_version},
+ {"version_string", luv_version_string},
+
+ // thread.c
+ {"new_thread", luv_new_thread},
+ {"thread_equal", luv_thread_equal},
+ {"thread_self", luv_thread_self},
+ {"thread_join", luv_thread_join},
+ {"sleep", luv_thread_sleep},
+
+ // work.c
+ {"new_work", luv_new_work},
+ {"queue_work", luv_queue_work},
+
+ {NULL, NULL}
+};
+
+static const luaL_Reg luv_handle_methods[] = {
+ // handle.c
+ {"is_active", luv_is_active},
+ {"is_closing", luv_is_closing},
+ {"close", luv_close},
+ {"ref", luv_ref},
+ {"unref", luv_unref},
+ {"has_ref", luv_has_ref},
+ {"send_buffer_size", luv_send_buffer_size},
+ {"recv_buffer_size", luv_recv_buffer_size},
+ {"fileno", luv_fileno},
+ {NULL, NULL}
+};
+
+static const luaL_Reg luv_async_methods[] = {
+ {"send", luv_async_send},
+ {NULL, NULL}
+};
+
+static const luaL_Reg luv_check_methods[] = {
+ {"start", luv_check_start},
+ {"stop", luv_check_stop},
+ {NULL, NULL}
+};
+
+static const luaL_Reg luv_fs_event_methods[] = {
+ {"start", luv_fs_event_start},
+ {"stop", luv_fs_event_stop},
+ {"getpath", luv_fs_event_getpath},
+ {NULL, NULL}
+};
+
+static const luaL_Reg luv_fs_poll_methods[] = {
+ {"start", luv_fs_poll_start},
+ {"stop", luv_fs_poll_stop},
+ {"getpath", luv_fs_poll_getpath},
+ {NULL, NULL}
+};
+
+static const luaL_Reg luv_idle_methods[] = {
+ {"start", luv_idle_start},
+ {"stop", luv_idle_stop},
+ {NULL, NULL}
+};
+
+static const luaL_Reg luv_stream_methods[] = {
+ {"shutdown", luv_shutdown},
+ {"listen", luv_listen},
+ {"accept", luv_accept},
+ {"read_start", luv_read_start},
+ {"read_stop", luv_read_stop},
+ {"write", luv_write},
+ {"write2", luv_write2},
+ {"try_write", luv_try_write},
+ {"is_readable", luv_is_readable},
+ {"is_writable", luv_is_writable},
+ {"set_blocking", luv_stream_set_blocking},
+ {NULL, NULL}
+};
+
+static const luaL_Reg luv_pipe_methods[] = {
+ {"open", luv_pipe_open},
+ {"bind", luv_pipe_bind},
+ {"connect", luv_pipe_connect},
+ {"getsockname", luv_pipe_getsockname},
+ {"getpeername", luv_pipe_getpeername},
+ {"pending_instances", luv_pipe_pending_instances},
+ {"pending_count", luv_pipe_pending_count},
+ {"pending_type", luv_pipe_pending_type},
+ {NULL, NULL}
+};
+
+static const luaL_Reg luv_poll_methods[] = {
+ {"start", luv_poll_start},
+ {"stop", luv_poll_stop},
+ {NULL, NULL}
+};
+
+static const luaL_Reg luv_prepare_methods[] = {
+ {"start", luv_prepare_start},
+ {"stop", luv_prepare_stop},
+ {NULL, NULL}
+};
+
+static const luaL_Reg luv_process_methods[] = {
+ {"kill", luv_process_kill},
+ {NULL, NULL}
+};
+
+static const luaL_Reg luv_tcp_methods[] = {
+ {"open", luv_tcp_open},
+ {"nodelay", luv_tcp_nodelay},
+ {"keepalive", luv_tcp_keepalive},
+ {"simultaneous_accepts", luv_tcp_simultaneous_accepts},
+ {"bind", luv_tcp_bind},
+ {"getpeername", luv_tcp_getpeername},
+ {"getsockname", luv_tcp_getsockname},
+ {"connect", luv_tcp_connect},
+ {"write_queue_size", luv_write_queue_size},
+ {NULL, NULL}
+};
+
+static const luaL_Reg luv_timer_methods[] = {
+ {"start", luv_timer_start},
+ {"stop", luv_timer_stop},
+ {"again", luv_timer_again},
+ {"set_repeat", luv_timer_set_repeat},
+ {"get_repeat", luv_timer_get_repeat},
+ {NULL, NULL}
+};
+
+static const luaL_Reg luv_tty_methods[] = {
+ {"set_mode", luv_tty_set_mode},
+ {"get_winsize", luv_tty_get_winsize},
+ {NULL, NULL}
+};
+
+static const luaL_Reg luv_udp_methods[] = {
+ {"open", luv_udp_open},
+ {"bind", luv_udp_bind},
+ {"bindgetsockname", luv_udp_getsockname},
+ {"set_membership", luv_udp_set_membership},
+ {"set_multicast_loop", luv_udp_set_multicast_loop},
+ {"set_multicast_ttl", luv_udp_set_multicast_ttl},
+ {"set_multicast_interface", luv_udp_set_multicast_interface},
+ {"set_broadcast", luv_udp_set_broadcast},
+ {"set_ttl", luv_udp_set_ttl},
+ {"send", luv_udp_send},
+ {"try_send", luv_udp_try_send},
+ {"recv_start", luv_udp_recv_start},
+ {"recv_stop", luv_udp_recv_stop},
+ {NULL, NULL}
+};
+
+static const luaL_Reg luv_signal_methods[] = {
+ {"start", luv_signal_start},
+ {"stop", luv_signal_stop},
+ {NULL, NULL}
+};
+
+static void luv_handle_init(lua_State* L) {
+
+ lua_newtable(L);
+#define XX(uc, lc) \
+ luaL_newmetatable (L, "uv_"#lc); \
+ lua_pushcfunction(L, luv_handle_tostring); \
+ lua_setfield(L, -2, "__tostring"); \
+ lua_pushcfunction(L, luv_handle_gc); \
+ lua_setfield(L, -2, "__gc"); \
+ luaL_newlib(L, luv_##lc##_methods); \
+ luaL_setfuncs(L, luv_handle_methods, 0); \
+ lua_setfield(L, -2, "__index"); \
+ lua_pushboolean(L, 1); \
+ lua_rawset(L, -3);
+
+ UV_HANDLE_TYPE_MAP(XX)
+#undef XX
+ lua_setfield(L, LUA_REGISTRYINDEX, "uv_handle");
+
+ lua_newtable(L);
+
+ luaL_getmetatable(L, "uv_pipe");
+ lua_getfield(L, -1, "__index");
+ luaL_setfuncs(L, luv_stream_methods, 0);
+ lua_pop(L, 1);
+ lua_pushboolean(L, 1);
+ lua_rawset(L, -3);
+
+ luaL_getmetatable(L, "uv_tcp");
+ lua_getfield(L, -1, "__index");
+ luaL_setfuncs(L, luv_stream_methods, 0);
+ lua_pop(L, 1);
+ lua_pushboolean(L, 1);
+ lua_rawset(L, -3);
+
+ luaL_getmetatable(L, "uv_tty");
+ lua_getfield(L, -1, "__index");
+ luaL_setfuncs(L, luv_stream_methods, 0);
+ lua_pop(L, 1);
+ lua_pushboolean(L, 1);
+ lua_rawset(L, -3);
+
+ lua_setfield(L, LUA_REGISTRYINDEX, "uv_stream");
+}
+
+LUALIB_API lua_State* luv_state(uv_loop_t* loop) {
+ return loop->data;
+}
+
+// TODO: find out if storing this somehow in an upvalue is faster
+LUALIB_API uv_loop_t* luv_loop(lua_State* L) {
+ uv_loop_t* loop;
+ lua_pushstring(L, "uv_loop");
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ loop = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+ return loop;
+}
+
+static void walk_cb(uv_handle_t *handle, void *arg)
+{
+ (void)arg;
+ if (!uv_is_closing(handle)) {
+ uv_close(handle, luv_close_cb);
+ }
+}
+
+static int loop_gc(lua_State *L) {
+ uv_loop_t* loop = luv_loop(L);
+ // Call uv_close on every active handle
+ uv_walk(loop, walk_cb, NULL);
+ // Run the event loop until all handles are successfully closed
+ while (uv_loop_close(loop)) {
+ uv_run(loop, UV_RUN_DEFAULT);
+ }
+ return 0;
+}
+
+LUALIB_API int luaopen_luv (lua_State *L) {
+
+ uv_loop_t* loop;
+ int ret;
+
+ // Setup the uv_loop meta table for a proper __gc
+ luaL_newmetatable(L, "uv_loop.meta");
+ lua_pushstring(L, "__gc");
+ lua_pushcfunction(L, loop_gc);
+ lua_settable(L, -3);
+
+ loop = lua_newuserdata(L, sizeof(*loop));
+ ret = uv_loop_init(loop);
+ if (ret < 0) {
+ return luaL_error(L, "%s: %s\n", uv_err_name(ret), uv_strerror(ret));
+ }
+ // setup the metatable for __gc
+ luaL_getmetatable(L, "uv_loop.meta");
+ lua_setmetatable(L, -2);
+ // Tell the state how to find the loop.
+ lua_pushstring(L, "uv_loop");
+ lua_insert(L, -2);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+ lua_pop(L, 1);
+
+ // Tell the loop how to find the state.
+ loop->data = L;
+
+ luv_req_init(L);
+ luv_handle_init(L);
+ luv_thread_init(L);
+ luv_work_init(L);
+
+ luaL_newlib(L, luv_functions);
+ luv_constants(L);
+ lua_setfield(L, -2, "constants");
+
+ return 1;
+}
diff --git a/3rdparty/luv/src/luv.h b/3rdparty/luv/src/luv.h
new file mode 100644
index 00000000000..681384da363
--- /dev/null
+++ b/3rdparty/luv/src/luv.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef LUV_H
+#define LUV_H
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+#include "uv.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#if defined(_WIN32)
+# include <fcntl.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# ifndef __MINGW32__
+# define S_ISREG(x) (((x) & _S_IFMT) == _S_IFREG)
+# define S_ISDIR(x) (((x) & _S_IFMT) == _S_IFDIR)
+# define S_ISFIFO(x) (((x) & _S_IFMT) == _S_IFIFO)
+# define S_ISCHR(x) (((x) & _S_IFMT) == _S_IFCHR)
+# define S_ISBLK(x) 0
+# endif
+# define S_ISLNK(x) (((x) & S_IFLNK) == S_IFLNK)
+# define S_ISSOCK(x) 0
+#else
+# include <unistd.h>
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX (8096)
+#endif
+
+#ifndef MAX_TITLE_LENGTH
+#define MAX_TITLE_LENGTH (8192)
+#endif
+
+#if LUA_VERSION_NUM < 502
+# define lua_rawlen lua_objlen
+/* lua_...uservalue: Something very different, but it should get the job done */
+# define lua_getuservalue lua_getfenv
+# define lua_setuservalue lua_setfenv
+# define luaL_newlib(L,l) (lua_newtable(L), luaL_register(L,NULL,l))
+# define luaL_setfuncs(L,l,n) (assert(n==0), luaL_register(L,NULL,l))
+# define lua_resume(L,F,n) lua_resume(L,n)
+# define lua_pushglobaltable(L) lua_pushvalue(L, LUA_GLOBALSINDEX)
+#endif
+
+/* There is a 1-1 relation between a lua_State and a uv_loop_t
+ These helpers will give you one if you have the other
+ These are exposed for extensions built with luv
+ This allows luv to be used in multithreaded applications.
+*/
+LUALIB_API lua_State* luv_state(uv_loop_t* loop);
+/* All libuv callbacks will lua_call directly from this root-per-thread state
+*/
+LUALIB_API uv_loop_t* luv_loop(lua_State* L);
+
+/* This is the main hook to load the library.
+ This can be called multiple times in a process as long
+ as you use a different lua_State and thread for each.
+*/
+LUALIB_API int luaopen_luv (lua_State *L);
+
+#include "util.h"
+#include "lhandle.h"
+#include "lreq.h"
+
+/* From stream.c */
+static uv_stream_t* luv_check_stream(lua_State* L, int index);
+static void luv_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf);
+static void luv_check_buf(lua_State *L, int idx, uv_buf_t *pbuf);
+static uv_buf_t* luv_prep_bufs(lua_State* L, int index, size_t *count);
+
+/* from tcp.c */
+static void parse_sockaddr(lua_State* L, struct sockaddr_storage* address, int addrlen);
+static void luv_connect_cb(uv_connect_t* req, int status);
+
+/* From fs.c */
+static void luv_push_stats_table(lua_State* L, const uv_stat_t* s);
+
+/* from constants.c */
+static int luv_af_string_to_num(const char* string);
+static const char* luv_af_num_to_string(const int num);
+static int luv_sock_string_to_num(const char* string);
+static const char* luv_sock_num_to_string(const int num);
+static int luv_sig_string_to_num(const char* string);
+static const char* luv_sig_num_to_string(const int num);
+
+typedef lua_State* (*luv_acquire_vm)();
+typedef void (*luv_release_vm)(lua_State* L);
+LUALIB_API void luv_set_thread_cb(luv_acquire_vm acquire, luv_release_vm release);
+
+#endif
diff --git a/3rdparty/luv/src/misc.c b/3rdparty/luv/src/misc.c
new file mode 100644
index 00000000000..64c9e3d5822
--- /dev/null
+++ b/3rdparty/luv/src/misc.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "luv.h"
+#ifdef _WIN32
+#include <process.h>
+#endif
+
+static int luv_guess_handle(lua_State* L) {
+ uv_file file = luaL_checkinteger(L, 1);
+ switch (uv_guess_handle(file)) {
+#define XX(uc, lc) case UV_##uc: lua_pushstring(L, #lc); break;
+ UV_HANDLE_TYPE_MAP(XX)
+#undef XX
+ case UV_FILE: lua_pushstring(L, "file"); break;
+ default: return 0;
+ }
+ return 1;
+}
+
+static int luv_version(lua_State* L) {
+ lua_pushinteger(L, uv_version());
+ return 1;
+}
+
+static int luv_version_string(lua_State* L) {
+ lua_pushstring(L, uv_version_string());
+ return 1;
+}
+
+static int luv_get_process_title(lua_State* L) {
+ char title[MAX_TITLE_LENGTH];
+ int ret = uv_get_process_title(title, MAX_TITLE_LENGTH);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushstring(L, title);
+ return 1;
+}
+
+static int luv_set_process_title(lua_State* L) {
+ const char* title = luaL_checkstring(L, 1);
+ int ret = uv_set_process_title(title);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_resident_set_memory(lua_State* L) {
+ size_t rss;
+ int ret = uv_resident_set_memory(&rss);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, rss);
+ return 1;
+}
+
+static int luv_uptime(lua_State* L) {
+ double uptime;
+ int ret = uv_uptime(&uptime);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushnumber(L, uptime);
+ return 1;
+}
+
+static void luv_push_timeval_table(lua_State* L, const uv_timeval_t* t) {
+ lua_createtable(L, 0, 2);
+ lua_pushinteger(L, t->tv_sec);
+ lua_setfield(L, -2, "sec");
+ lua_pushinteger(L, t->tv_usec);
+ lua_setfield(L, -2, "usec");
+}
+
+static int luv_getrusage(lua_State* L) {
+ uv_rusage_t rusage;
+ int ret = uv_getrusage(&rusage);
+ if (ret < 0) return luv_error(L, ret);
+ lua_createtable(L, 0, 16);
+ // user CPU time used
+ luv_push_timeval_table(L, &rusage.ru_utime);
+ lua_setfield(L, -2, "utime");
+ // system CPU time used
+ luv_push_timeval_table(L, &rusage.ru_stime);
+ lua_setfield(L, -2, "stime");
+ // maximum resident set size
+ lua_pushinteger(L, rusage.ru_maxrss);
+ lua_setfield(L, -2, "maxrss");
+ // integral shared memory size
+ lua_pushinteger(L, rusage.ru_ixrss);
+ lua_setfield(L, -2, "ixrss");
+ // integral unshared data size
+ lua_pushinteger(L, rusage.ru_idrss);
+ lua_setfield(L, -2, "idrss");
+ // integral unshared stack size
+ lua_pushinteger(L, rusage.ru_isrss);
+ lua_setfield(L, -2, "isrss");
+ // page reclaims (soft page faults)
+ lua_pushinteger(L, rusage.ru_minflt);
+ lua_setfield(L, -2, "minflt");
+ // page faults (hard page faults)
+ lua_pushinteger(L, rusage.ru_majflt);
+ lua_setfield(L, -2, "majflt");
+ // swaps
+ lua_pushinteger(L, rusage.ru_nswap);
+ lua_setfield(L, -2, "nswap");
+ // block input operations
+ lua_pushinteger(L, rusage.ru_inblock);
+ lua_setfield(L, -2, "inblock");
+ // block output operations
+ lua_pushinteger(L, rusage.ru_oublock);
+ lua_setfield(L, -2, "oublock");
+ // IPC messages sent
+ lua_pushinteger(L, rusage.ru_msgsnd);
+ lua_setfield(L, -2, "msgsnd");
+ // IPC messages received
+ lua_pushinteger(L, rusage.ru_msgrcv);
+ lua_setfield(L, -2, "msgrcv");
+ // signals received
+ lua_pushinteger(L, rusage.ru_nsignals);
+ lua_setfield(L, -2, "nsignals");
+ // voluntary context switches
+ lua_pushinteger(L, rusage.ru_nvcsw);
+ lua_setfield(L, -2, "nvcsw");
+ // involuntary context switches
+ lua_pushinteger(L, rusage.ru_nivcsw);
+ lua_setfield(L, -2, "nivcsw");
+ return 1;
+}
+
+static int luv_cpu_info(lua_State* L) {
+ uv_cpu_info_t* cpu_infos;
+ int count, i;
+ int ret = uv_cpu_info(&cpu_infos, &count);
+ if (ret < 0) return luv_error(L, ret);
+ lua_newtable(L);
+
+ for (i = 0; i < count; i++) {
+ lua_newtable(L);
+ lua_pushstring(L, cpu_infos[i].model);
+ lua_setfield(L, -2, "model");
+ lua_pushnumber(L, cpu_infos[i].speed);
+ lua_setfield(L, -2, "speed");
+ lua_newtable(L);
+ lua_pushnumber(L, cpu_infos[i].cpu_times.user);
+ lua_setfield(L, -2, "user");
+ lua_pushnumber(L, cpu_infos[i].cpu_times.nice);
+ lua_setfield(L, -2, "nice");
+ lua_pushnumber(L, cpu_infos[i].cpu_times.sys);
+ lua_setfield(L, -2, "sys");
+ lua_pushnumber(L, cpu_infos[i].cpu_times.idle);
+ lua_setfield(L, -2, "idle");
+ lua_pushnumber(L, cpu_infos[i].cpu_times.irq);
+ lua_setfield(L, -2, "irq");
+ lua_setfield(L, -2, "times");
+ lua_rawseti(L, -2, i + 1);
+ }
+
+ uv_free_cpu_info(cpu_infos, count);
+ return 1;
+}
+
+static int luv_interface_addresses(lua_State* L) {
+ uv_interface_address_t* interfaces;
+ int count, i;
+ char ip[INET6_ADDRSTRLEN];
+ char netmask[INET6_ADDRSTRLEN];
+
+ uv_interface_addresses(&interfaces, &count);
+
+ lua_newtable(L);
+
+ for (i = 0; i < count; i++) {
+ lua_getfield(L, -1, interfaces[i].name);
+ if (!lua_istable(L, -1)) {
+ lua_pop(L, 1);
+ lua_newtable(L);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -3, interfaces[i].name);
+ }
+ lua_newtable(L);
+ lua_pushboolean(L, interfaces[i].is_internal);
+ lua_setfield(L, -2, "internal");
+
+ lua_pushlstring(L, interfaces[i].phys_addr, sizeof(interfaces[i].phys_addr));
+ lua_setfield(L, -2, "mac");
+
+ if (interfaces[i].address.address4.sin_family == AF_INET) {
+ uv_ip4_name(&interfaces[i].address.address4, ip, sizeof(ip));
+ uv_ip4_name(&interfaces[i].netmask.netmask4, netmask, sizeof(netmask));
+ } else if (interfaces[i].address.address4.sin_family == AF_INET6) {
+ uv_ip6_name(&interfaces[i].address.address6, ip, sizeof(ip));
+ uv_ip6_name(&interfaces[i].netmask.netmask6, netmask, sizeof(netmask));
+ } else {
+ strncpy(ip, "<unknown sa family>", INET6_ADDRSTRLEN);
+ strncpy(netmask, "<unknown sa family>", INET6_ADDRSTRLEN);
+ }
+ lua_pushstring(L, ip);
+ lua_setfield(L, -2, "ip");
+ lua_pushstring(L, netmask);
+ lua_setfield(L, -2, "netmask");
+
+ lua_pushstring(L, luv_af_num_to_string(interfaces[i].address.address4.sin_family));
+ lua_setfield(L, -2, "family");
+ lua_rawseti(L, -2, lua_rawlen (L, -2) + 1);
+ lua_pop(L, 1);
+ }
+ uv_free_interface_addresses(interfaces, count);
+ return 1;
+}
+
+static int luv_loadavg(lua_State* L) {
+ double avg[3];
+ uv_loadavg(avg);
+ lua_pushnumber(L, avg[0]);
+ lua_pushnumber(L, avg[1]);
+ lua_pushnumber(L, avg[2]);
+ return 3;
+}
+
+static int luv_exepath(lua_State* L) {
+ size_t size = 2*PATH_MAX;
+ char exe_path[2*PATH_MAX];
+ int ret = uv_exepath(exe_path, &size);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushlstring(L, exe_path, size);
+ return 1;
+}
+
+static int luv_cwd(lua_State* L) {
+ size_t size = 2*PATH_MAX;
+ char path[2*PATH_MAX];
+ int ret = uv_cwd(path, &size);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushlstring(L, path, size);
+ return 1;
+}
+
+static int luv_chdir(lua_State* L) {
+ int ret = uv_chdir(luaL_checkstring(L, 1));
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_os_homedir(lua_State* L) {
+ size_t size = 2*PATH_MAX;
+ char homedir[2*PATH_MAX];
+ int ret = uv_os_homedir(homedir, &size);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushlstring(L, homedir, size);
+ return 1;
+}
+
+static int luv_get_total_memory(lua_State* L) {
+ lua_pushnumber(L, uv_get_total_memory());
+ return 1;
+}
+
+static int luv_get_free_memory(lua_State* L) {
+ lua_pushnumber(L, uv_get_free_memory());
+ return 1;
+}
+
+static int luv_hrtime(lua_State* L) {
+ lua_pushnumber(L, uv_hrtime());
+ return 1;
+}
+
+static int luv_getpid(lua_State* L){
+ int pid = getpid();
+ lua_pushinteger(L, pid);
+ return 1;
+}
+
+#ifndef _WIN32
+static int luv_getuid(lua_State* L){
+ int uid = getuid();
+ lua_pushinteger(L, uid);
+ return 1;
+}
+
+static int luv_getgid(lua_State* L){
+ int gid = getgid();
+ lua_pushinteger(L, gid);
+ return 1;
+}
+
+static int luv_setuid(lua_State* L){
+ int uid = luaL_checkinteger(L, 1);
+ int r = setuid(uid);
+ if (-1 == r) {
+ luaL_error(L, "Error setting UID");
+ }
+ return 0;
+}
+
+static int luv_setgid(lua_State* L){
+ int gid = luaL_checkinteger(L, 1);
+ int r = setgid(gid);
+ if (-1 == r) {
+ luaL_error(L, "Error setting GID");
+ }
+ return 0;
+}
+#endif
diff --git a/3rdparty/luv/src/pipe.c b/3rdparty/luv/src/pipe.c
new file mode 100644
index 00000000000..b490c1597b3
--- /dev/null
+++ b/3rdparty/luv/src/pipe.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "luv.h"
+
+static uv_pipe_t* luv_check_pipe(lua_State* L, int index) {
+ uv_pipe_t* handle = luv_checkudata(L, index, "uv_pipe");
+ luaL_argcheck(L, handle->type == UV_NAMED_PIPE && handle->data, index, "Expected uv_pipe_t");
+ return handle;
+}
+
+static int luv_new_pipe(lua_State* L) {
+ uv_pipe_t* handle;
+ int ipc, ret;
+ luaL_checktype(L, 1, LUA_TBOOLEAN);
+ ipc = lua_toboolean(L, 1);
+ handle = luv_newuserdata(L, sizeof(*handle));
+ ret = uv_pipe_init(luv_loop(L), handle, ipc);
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ handle->data = luv_setup_handle(L);
+ return 1;
+}
+
+static int luv_pipe_open(lua_State* L) {
+ uv_pipe_t* handle = luv_check_pipe(L, 1);
+ uv_file file = luaL_checkinteger(L, 2);
+ int ret = uv_pipe_open(handle, file);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_pipe_bind(lua_State* L) {
+ uv_pipe_t* handle = luv_check_pipe(L, 1);
+ const char* name = luaL_checkstring(L, 2);
+ int ret = uv_pipe_bind(handle, name);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_pipe_connect(lua_State* L) {
+ uv_pipe_t* handle = luv_check_pipe(L, 1);
+ const char* name = luaL_checkstring(L, 2);
+ int ref = luv_check_continuation(L, 3);
+ uv_connect_t* req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ uv_pipe_connect(req, handle, name, luv_connect_cb);
+ return 1;
+}
+
+static int luv_pipe_getsockname(lua_State* L) {
+ uv_pipe_t* handle = luv_check_pipe(L, 1);
+ size_t len = 2*PATH_MAX;
+ char buf[2*PATH_MAX];
+ int ret = uv_pipe_getsockname(handle, buf, &len);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushlstring(L, buf, len);
+ return 1;
+}
+
+static int luv_pipe_getpeername(lua_State* L) {
+ uv_pipe_t* handle = luv_check_pipe(L, 1);
+ size_t len = 2*PATH_MAX;
+ char buf[2*PATH_MAX];
+ int ret = uv_pipe_getpeername(handle, buf, &len);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushlstring(L, buf, len);
+ return 1;
+}
+
+static int luv_pipe_pending_instances(lua_State* L) {
+ uv_pipe_t* handle = luv_check_pipe(L, 1);
+ int count = luaL_checkinteger(L, 2);
+ uv_pipe_pending_instances(handle, count);
+ return 0;
+}
+
+static int luv_pipe_pending_count(lua_State* L) {
+ uv_pipe_t* handle = luv_check_pipe(L, 1);
+ lua_pushinteger(L, uv_pipe_pending_count(handle));
+ return 1;
+}
+
+static int luv_pipe_pending_type(lua_State* L) {
+ uv_pipe_t* handle = luv_check_pipe(L, 1);
+ uv_handle_type type = uv_pipe_pending_type(handle);
+ const char* type_name;
+ switch (type) {
+#define XX(uc, lc) \
+ case UV_##uc: type_name = #lc; break;
+ UV_HANDLE_TYPE_MAP(XX)
+#undef XX
+ default: return 0;
+ }
+ lua_pushstring(L, type_name);
+ return 1;
+}
diff --git a/3rdparty/luv/src/poll.c b/3rdparty/luv/src/poll.c
new file mode 100644
index 00000000000..e007c9f9634
--- /dev/null
+++ b/3rdparty/luv/src/poll.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "luv.h"
+
+static uv_poll_t* luv_check_poll(lua_State* L, int index) {
+ uv_poll_t* handle = luv_checkudata(L, index, "uv_poll");
+ luaL_argcheck(L, handle->type == UV_POLL && handle->data, index, "Expected uv_poll_t");
+ return handle;
+}
+
+static int luv_new_poll(lua_State* L) {
+ int fd = luaL_checkinteger(L, 1);
+ uv_poll_t* handle = luv_newuserdata(L, sizeof(*handle));
+ int ret = uv_poll_init(luv_loop(L), handle, fd);
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ handle->data = luv_setup_handle(L);
+ return 1;
+}
+
+static int luv_new_socket_poll(lua_State* L) {
+ int fd = luaL_checkinteger(L, 1);
+ uv_poll_t* handle = luv_newuserdata(L, sizeof(*handle));
+ int ret = uv_poll_init_socket(luv_loop(L), handle, fd);
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ handle->data = luv_setup_handle(L);
+ return 1;
+}
+
+// These are the same order as uv_run_mode which also starts at 0
+static const char *const luv_pollevents[] = {
+ "r", "w", "rw", NULL
+};
+
+static void luv_poll_cb(uv_poll_t* handle, int status, int events) {
+ lua_State* L = luv_state(handle->loop);
+ luv_handle_t* data = handle->data;
+ const char* evtstr;
+
+ if (status < 0) {
+ fprintf(stderr, "%s: %s\n", uv_err_name(status), uv_strerror(status));
+ lua_pushstring(L, uv_err_name(status));
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ switch (events) {
+ case UV_READABLE: evtstr = "r"; break;
+ case UV_WRITABLE: evtstr = "w"; break;
+ case UV_READABLE|UV_WRITABLE: evtstr = "rw"; break;
+ default: evtstr = ""; break;
+ }
+ lua_pushstring(L, evtstr);
+
+ luv_call_callback(L, data, LUV_POLL, 2);
+}
+
+static int luv_poll_start(lua_State* L) {
+ uv_poll_t* handle = luv_check_poll(L, 1);
+ int events, ret;
+ switch (luaL_checkoption(L, 2, "rw", luv_pollevents)) {
+ case 0: events = UV_READABLE; break;
+ case 1: events = UV_WRITABLE; break;
+ case 2: events = UV_READABLE | UV_WRITABLE; break;
+ default: events = 0; /* unreachable */
+ }
+ luv_check_callback(L, handle->data, LUV_POLL, 3);
+ ret = uv_poll_start(handle, events, luv_poll_cb);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_poll_stop(lua_State* L) {
+ uv_poll_t* handle = luv_check_poll(L, 1);
+ int ret = uv_poll_stop(handle);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
diff --git a/3rdparty/luv/src/prepare.c b/3rdparty/luv/src/prepare.c
new file mode 100644
index 00000000000..6577439a466
--- /dev/null
+++ b/3rdparty/luv/src/prepare.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "luv.h"
+
+static uv_prepare_t* luv_check_prepare(lua_State* L, int index) {
+ uv_prepare_t* handle = luv_checkudata(L, index, "uv_prepare");
+ luaL_argcheck(L, handle->type == UV_PREPARE && handle->data, index, "Expected uv_prepare_t");
+ return handle;
+}
+
+static int luv_new_prepare(lua_State* L) {
+ uv_prepare_t* handle = luv_newuserdata(L, sizeof(*handle));
+ int ret = uv_prepare_init(luv_loop(L), handle);
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ handle->data = luv_setup_handle(L);
+ return 1;
+}
+
+static void luv_prepare_cb(uv_prepare_t* handle) {
+ lua_State* L = luv_state(handle->loop);
+ luv_handle_t* data = handle->data;
+ luv_call_callback(L, data, LUV_PREPARE, 0);
+}
+
+static int luv_prepare_start(lua_State* L) {
+ uv_prepare_t* handle = luv_check_prepare(L, 1);
+ int ret;
+ luv_check_callback(L, handle->data, LUV_PREPARE, 2);
+ ret = uv_prepare_start(handle, luv_prepare_cb);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_prepare_stop(lua_State* L) {
+ uv_prepare_t* handle = luv_check_prepare(L, 1);
+ int ret = uv_prepare_stop(handle);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
diff --git a/3rdparty/luv/src/process.c b/3rdparty/luv/src/process.c
new file mode 100644
index 00000000000..d939503868b
--- /dev/null
+++ b/3rdparty/luv/src/process.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "luv.h"
+
+static int luv_disable_stdio_inheritance(lua_State* L) {
+ (void)L;
+ uv_disable_stdio_inheritance();
+ return 0;
+}
+
+static uv_process_t* luv_check_process(lua_State* L, int index) {
+ uv_process_t* handle = luv_checkudata(L, index, "uv_process");
+ luaL_argcheck(L, handle->type == UV_PROCESS && handle->data, index, "Expected uv_process_t");
+ return handle;
+}
+
+static void exit_cb(uv_process_t* handle, int64_t exit_status, int term_signal) {
+ lua_State* L = luv_state(handle->loop);
+ luv_handle_t* data = handle->data;
+ lua_pushinteger(L, exit_status);
+ lua_pushinteger(L, term_signal);
+ luv_call_callback(L, data, LUV_EXIT, 2);
+}
+
+static void luv_spawn_close_cb(uv_handle_t* handle) {
+ lua_State *L = luv_state(handle->loop);
+ luv_cleanup_handle(L, handle->data);
+}
+
+static void luv_clean_options(uv_process_options_t* options) {
+ free(options->args);
+ free(options->stdio);
+ free(options->env);
+}
+
+static int luv_spawn(lua_State* L) {
+ uv_process_t* handle;
+ uv_process_options_t options;
+ size_t i, len = 0;
+ int ret;
+
+ memset(&options, 0, sizeof(options));
+ options.exit_cb = exit_cb;
+ options.file = luaL_checkstring(L, 1);
+ options.flags = 0;
+
+ // Make sure the 2nd argument is a table
+ luaL_checktype(L, 2, LUA_TTABLE);
+
+ // get the args list
+ lua_getfield(L, 2, "args");
+ // +1 for inserted command at front
+ if (lua_type(L, -1) == LUA_TTABLE) {
+ len = 1 + lua_rawlen(L, -1);
+ }
+ else if (lua_type(L, -1) != LUA_TNIL) {
+ luv_clean_options(&options);
+ return luaL_argerror(L, 3, "args option must be table");
+ }
+ else {
+ len = 1;
+ }
+ // +1 for null terminator at end
+ options.args = malloc((len + 1) * sizeof(*options.args));
+ if (!options.args) {
+ luv_clean_options(&options);
+ return luaL_error(L, "Problem allocating args");
+ }
+ options.args[0] = (char*)options.file;
+ for (i = 1; i < len; ++i) {
+ lua_rawgeti(L, -1, i);
+ options.args[i] = (char*)lua_tostring(L, -1);
+ lua_pop(L, 1);
+ }
+ options.args[len] = NULL;
+ lua_pop(L, 1);
+
+ // get the stdio list
+ lua_getfield(L, 2, "stdio");
+ if (lua_type(L, -1) == LUA_TTABLE) {
+ options.stdio_count = len = lua_rawlen(L, -1);
+ options.stdio = malloc(len * sizeof(*options.stdio));
+ if (!options.stdio) {
+ luv_clean_options(&options);
+ return luaL_error(L, "Problem allocating stdio");
+ }
+ for (i = 0; i < len; ++i) {
+ lua_rawgeti(L, -1, i + 1);
+ // integers are assumed to be file descripters
+ if (lua_type(L, -1) == LUA_TNUMBER) {
+ options.stdio[i].flags = UV_INHERIT_FD;
+ options.stdio[i].data.fd = lua_tointeger(L, -1);
+ }
+ // userdata is assumed to be a uv_stream_t instance
+ else if (lua_type(L, -1) == LUA_TUSERDATA) {
+ uv_os_fd_t fd;
+ uv_stream_t* stream = luv_check_stream(L, -1);
+ int err = uv_fileno((uv_handle_t*)stream, &fd);
+ if (err == UV_EINVAL || err == UV_EBADF) {
+ // stdin (fd 0) is read-only, stdout and stderr (fds 1 & 2) are
+ // write-only, and all fds > 2 are read-write
+ int flags = UV_CREATE_PIPE;
+ if (i == 0 || i > 2)
+ flags |= UV_READABLE_PIPE;
+ if (i != 0)
+ flags |= UV_WRITABLE_PIPE;
+ options.stdio[i].flags = flags;
+ }
+ else {
+ options.stdio[i].flags = UV_INHERIT_STREAM;
+ }
+ options.stdio[i].data.stream = stream;
+ }
+ else if (lua_type(L, -1) == LUA_TNIL) {
+ options.stdio[i].flags = UV_IGNORE;
+ }
+ else {
+ luv_clean_options(&options);
+ return luaL_argerror(L, 2, "stdio table entries must be nil, uv_stream_t, or integer");
+ }
+ lua_pop(L, 1);
+ }
+ }
+ else if (lua_type(L, -1) != LUA_TNIL) {
+ luv_clean_options(&options);
+ return luaL_argerror(L, 2, "stdio option must be table");
+ }
+ lua_pop(L, 1);
+
+ // Get the env
+ lua_getfield(L, 2, "env");
+ if (lua_type(L, -1) == LUA_TTABLE) {
+ len = lua_rawlen(L, -1);
+ options.env = malloc((len + 1) * sizeof(*options.env));
+ if (!options.env) {
+ luv_clean_options(&options);
+ return luaL_error(L, "Problem allocating env");
+ }
+ for (i = 0; i < len; ++i) {
+ lua_rawgeti(L, -1, i + 1);
+ options.env[i] = (char*)lua_tostring(L, -1);
+ lua_pop(L, 1);
+ }
+ options.env[len] = NULL;
+ }
+ else if (lua_type(L, -1) != LUA_TNIL) {
+ luv_clean_options(&options);
+ return luaL_argerror(L, 2, "env option must be table");
+ }
+ lua_pop(L, 1);
+
+ // Get the cwd
+ lua_getfield(L, 2, "cwd");
+ if (lua_type(L, -1) == LUA_TSTRING) {
+ options.cwd = (char*)lua_tostring(L, -1);
+ }
+ else if (lua_type(L, -1) != LUA_TNIL) {
+ luv_clean_options(&options);
+ return luaL_argerror(L, 2, "cwd option must be string");
+ }
+ lua_pop(L, 1);
+
+ // Check for uid
+ lua_getfield(L, 2, "uid");
+ if (lua_type(L, -1) == LUA_TNUMBER) {
+ options.uid = lua_tointeger(L, -1);
+ options.flags |= UV_PROCESS_SETUID;
+ }
+ else if (lua_type(L, -1) != LUA_TNIL) {
+ luv_clean_options(&options);
+ return luaL_argerror(L, 2, "uid option must be number");
+ }
+ lua_pop(L, 1);
+
+ // Check for gid
+ lua_getfield(L, 2, "gid");
+ if (lua_type(L, -1) == LUA_TNUMBER) {
+ options.gid = lua_tointeger(L, -1);
+ options.flags |= UV_PROCESS_SETGID;
+ }
+ else if (lua_type(L, -1) != LUA_TNIL) {
+ luv_clean_options(&options);
+ return luaL_argerror(L, 2, "gid option must be number");
+ }
+ lua_pop(L, 1);
+
+ // Check for the boolean flags
+ lua_getfield(L, 2, "verbatim");
+ if (lua_toboolean(L, -1)) {
+ options.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
+ }
+ lua_pop(L, 1);
+ lua_getfield(L, 2, "detached");
+ if (lua_toboolean(L, -1)) {
+ options.flags |= UV_PROCESS_DETACHED;
+ }
+ lua_pop(L, 1);
+ lua_getfield(L, 2, "hide");
+ if (lua_toboolean(L, -1)) {
+ options.flags |= UV_PROCESS_WINDOWS_HIDE;
+ }
+ lua_pop(L, 1);
+
+ handle = luv_newuserdata(L, sizeof(*handle));
+ handle->type = UV_PROCESS;
+ handle->data = luv_setup_handle(L);
+
+ if (!lua_isnoneornil(L, 3)) {
+ luv_check_callback(L, handle->data, LUV_EXIT, 3);
+ }
+
+ ret = uv_spawn(luv_loop(L), handle, &options);
+
+ luv_clean_options(&options);
+ if (ret < 0) {
+ /* The async callback is required here because luajit GC may reclaim the
+ * luv handle before libuv is done closing it down.
+ */
+ uv_close((uv_handle_t*)handle, luv_spawn_close_cb);
+ return luv_error(L, ret);
+ }
+ lua_pushinteger(L, handle->pid);
+ return 2;
+}
+
+static int luv_parse_signal(lua_State* L, int slot) {
+ if (lua_isnumber(L, slot)) {
+ return lua_tonumber(L, slot);
+ }
+ if (lua_isstring(L, slot)) {
+ return luv_sig_string_to_num(lua_tostring(L, slot));
+ }
+ return SIGTERM;
+}
+
+static int luv_process_kill(lua_State* L) {
+ uv_process_t* handle = luv_check_process(L, 1);
+ int signum = luv_parse_signal(L, 2);
+ int ret = uv_process_kill(handle, signum);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_kill(lua_State* L) {
+ int pid = luaL_checkinteger(L, 1);
+ int signum = luv_parse_signal(L, 2);
+ int ret = uv_kill(pid, signum);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
diff --git a/3rdparty/luv/src/req.c b/3rdparty/luv/src/req.c
new file mode 100644
index 00000000000..6d7b7e4a30b
--- /dev/null
+++ b/3rdparty/luv/src/req.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "luv.h"
+
+static uv_req_t* luv_check_req(lua_State* L, int index) {
+ uv_req_t* req = luaL_checkudata(L, index, "uv_req");
+ luaL_argcheck(L, req->data, index, "Expected uv_req_t");
+ return req;
+}
+
+static int luv_req_tostring(lua_State* L) {
+ uv_req_t* req = luaL_checkudata(L, 1, "uv_req");
+ switch (req->type) {
+#define XX(uc, lc) case UV_##uc: lua_pushfstring(L, "uv_"#lc"_t: %p", req); break;
+ UV_REQ_TYPE_MAP(XX)
+#undef XX
+ default: lua_pushfstring(L, "uv_req_t: %p", req); break;
+ }
+ return 1;
+}
+
+static void luv_req_init(lua_State* L) {
+ luaL_newmetatable (L, "uv_req");
+ lua_pushcfunction(L, luv_req_tostring);
+ lua_setfield(L, -2, "__tostring");
+ lua_pop(L, 1);
+}
+
+// Metamethod to allow storing anything in the userdata's environment
+static int luv_cancel(lua_State* L) {
+ uv_req_t* req = luv_check_req(L, 1);
+ int ret = uv_cancel(req);
+ if (ret < 0) return luv_error(L, ret);
+ luv_cleanup_req(L, req->data);
+ req->data = NULL;
+ lua_pushinteger(L, ret);
+ return 1;
+}
diff --git a/3rdparty/luv/src/schema.c b/3rdparty/luv/src/schema.c
new file mode 100644
index 00000000000..e7b82e11d66
--- /dev/null
+++ b/3rdparty/luv/src/schema.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
diff --git a/3rdparty/luv/src/signal.c b/3rdparty/luv/src/signal.c
new file mode 100644
index 00000000000..48ace2bf601
--- /dev/null
+++ b/3rdparty/luv/src/signal.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "luv.h"
+
+static uv_signal_t* luv_check_signal(lua_State* L, int index) {
+ uv_signal_t* handle = luv_checkudata(L, index, "uv_signal");
+ luaL_argcheck(L, handle->type == UV_SIGNAL && handle->data, index, "Expected uv_signal_t");
+ return handle;
+}
+
+static int luv_new_signal(lua_State* L) {
+ uv_signal_t* handle = luv_newuserdata(L, sizeof(*handle));
+ int ret = uv_signal_init(luv_loop(L), handle);
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ handle->data = luv_setup_handle(L);
+ return 1;
+}
+
+static void luv_signal_cb(uv_signal_t* handle, int signum) {
+ lua_State* L = luv_state(handle->loop);
+ luv_handle_t* data = handle->data;
+ lua_pushstring(L, luv_sig_num_to_string(signum));
+ luv_call_callback(L, data, LUV_SIGNAL, 1);
+}
+
+static int luv_signal_start(lua_State* L) {
+ uv_signal_t* handle = luv_check_signal(L, 1);
+ int signum, ret;
+ if (lua_isnumber(L, 2)) {
+ signum = lua_tointeger(L, 2);
+ }
+ else if (lua_isstring(L, 2)) {
+ signum = luv_sig_string_to_num(luaL_checkstring(L, 2));
+ luaL_argcheck(L, signum, 2, "Invalid Signal name");
+ }
+ else {
+ return luaL_argerror(L, 2, "Missing Signal name");
+ }
+
+ if (!lua_isnoneornil(L, 3)) {
+ luv_check_callback(L, handle->data, LUV_SIGNAL, 3);
+ }
+ ret = uv_signal_start(handle, luv_signal_cb, signum);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_signal_stop(lua_State* L) {
+ uv_signal_t* handle = luv_check_signal(L, 1);
+ int ret = uv_signal_stop(handle);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
diff --git a/3rdparty/luv/src/stream.c b/3rdparty/luv/src/stream.c
new file mode 100644
index 00000000000..5009e04f097
--- /dev/null
+++ b/3rdparty/luv/src/stream.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "luv.h"
+
+static void luv_check_buf(lua_State *L, int idx, uv_buf_t *pbuf) {
+ size_t len;
+ pbuf->base = (char*)luaL_checklstring(L, idx, &len);
+ pbuf->len = len;
+}
+
+static uv_stream_t* luv_check_stream(lua_State* L, int index) {
+ int isStream;
+ uv_stream_t* handle;
+ if (!(handle = *(void**) lua_touserdata(L, index))) { goto fail; }
+ lua_getfield(L, LUA_REGISTRYINDEX, "uv_stream");
+ lua_getmetatable(L, index < 0 ? index - 1 : index);
+ lua_rawget(L, -2);
+ isStream = lua_toboolean(L, -1);
+ lua_pop(L, 2);
+ if (isStream) { return handle; }
+ fail: luaL_argerror(L, index, "Expected uv_stream userdata");
+ return NULL;
+}
+
+static void luv_shutdown_cb(uv_shutdown_t* req, int status) {
+ lua_State* L = luv_state(req->handle->loop);
+ luv_status(L, status);
+ luv_fulfill_req(L, req->data, 1);
+ luv_cleanup_req(L, req->data);
+ req->data = NULL;
+}
+
+static int luv_shutdown(lua_State* L) {
+ uv_stream_t* handle = luv_check_stream(L, 1);
+ int ref = luv_check_continuation(L, 2);
+ uv_shutdown_t* req = lua_newuserdata(L, sizeof(*req));
+ int ret;
+ req->data = luv_setup_req(L, ref);
+ ret = uv_shutdown(req, handle, luv_shutdown_cb);
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ return 1;
+}
+
+static void luv_connection_cb(uv_stream_t* handle, int status) {
+ lua_State* L = luv_state(handle->loop);
+ luv_status(L, status);
+ luv_call_callback(L, handle->data, LUV_CONNECTION, 1);
+}
+
+static int luv_listen(lua_State* L) {
+ uv_stream_t* handle = luv_check_stream(L, 1);
+ int backlog = luaL_checkinteger(L, 2);
+ int ret;
+ luv_check_callback(L, handle->data, LUV_CONNECTION, 3);
+ ret = uv_listen(handle, backlog, luv_connection_cb);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_accept(lua_State* L) {
+ uv_stream_t* server = luv_check_stream(L, 1);
+ uv_stream_t* client = luv_check_stream(L, 2);
+ int ret = uv_accept(server, client);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static void luv_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
+ (void)handle;
+ buf->base = malloc(suggested_size);
+ assert(buf->base);
+ buf->len = suggested_size;
+}
+
+static void luv_read_cb(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) {
+ lua_State* L = luv_state(handle->loop);
+ int nargs;
+
+ if (nread > 0) {
+ lua_pushnil(L);
+ lua_pushlstring(L, buf->base, nread);
+ nargs = 2;
+ }
+
+ free(buf->base);
+ if (nread == 0) return;
+
+ if (nread == UV_EOF) {
+ nargs = 0;
+ }
+ else if (nread < 0) {
+ luv_status(L, nread);
+ nargs = 1;
+ }
+
+ luv_call_callback(L, handle->data, LUV_READ, nargs);
+}
+
+static int luv_read_start(lua_State* L) {
+ uv_stream_t* handle = luv_check_stream(L, 1);
+ int ret;
+ luv_check_callback(L, handle->data, LUV_READ, 2);
+ ret = uv_read_start(handle, luv_alloc_cb, luv_read_cb);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_read_stop(lua_State* L) {
+ uv_stream_t* handle = luv_check_stream(L, 1);
+ int ret = uv_read_stop(handle);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static void luv_write_cb(uv_write_t* req, int status) {
+ lua_State* L = luv_state(req->handle->loop);
+ luv_status(L, status);
+ luv_fulfill_req(L, req->data, 1);
+ luv_cleanup_req(L, req->data);
+ req->data = NULL;
+}
+
+static uv_buf_t* luv_prep_bufs(lua_State* L, int index, size_t *count) {
+ uv_buf_t *bufs;
+ size_t i;
+ *count = lua_rawlen(L, index);
+ bufs = malloc(sizeof(uv_buf_t) * *count);
+ for (i = 0; i < *count; ++i) {
+ lua_rawgeti(L, index, i + 1);
+ luv_check_buf(L, -1, &bufs[i]);
+ lua_pop(L, 1);
+ }
+ return bufs;
+}
+
+static int luv_write(lua_State* L) {
+ uv_stream_t* handle = luv_check_stream(L, 1);
+ uv_write_t* req;
+ int ret, ref;
+ ref = luv_check_continuation(L, 3);
+ req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ if (lua_istable(L, 2)) {
+ size_t count;
+ uv_buf_t *bufs = luv_prep_bufs(L, 2, &count);
+ ret = uv_write(req, handle, bufs, count, luv_write_cb);
+ free(bufs);
+ }
+ else if (lua_isstring(L, 2)) {
+ uv_buf_t buf;
+ luv_check_buf(L, 2, &buf);
+ ret = uv_write(req, handle, &buf, 1, luv_write_cb);
+ }
+ else {
+ return luaL_argerror(L, 2, "data must be string or table of strings");
+ }
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ lua_pushvalue(L, 2);
+ ((luv_req_t*)req->data)->data_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+ return 1;
+}
+
+static int luv_write2(lua_State* L) {
+ uv_stream_t* handle = luv_check_stream(L, 1);
+ uv_write_t* req;
+ int ret, ref;
+ uv_stream_t* send_handle;
+ send_handle = luv_check_stream(L, 3);
+ ref = luv_check_continuation(L, 4);
+ req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ if (lua_istable(L, 2)) {
+ size_t count;
+ uv_buf_t *bufs = luv_prep_bufs(L, 2, &count);
+ ret = uv_write2(req, handle, bufs, count, send_handle, luv_write_cb);
+ free(bufs);
+ }
+ else if (lua_isstring(L, 2)) {
+ uv_buf_t buf;
+ luv_check_buf(L, 2, &buf);
+ ret = uv_write2(req, handle, &buf, 1, send_handle, luv_write_cb);
+ }
+ else {
+ return luaL_argerror(L, 2, "data must be string or table of strings");
+ }
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ lua_pushvalue(L, 2);
+ ((luv_req_t*)req->data)->data_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+ return 1;
+}
+
+static int luv_try_write(lua_State* L) {
+ uv_stream_t* handle = luv_check_stream(L, 1);
+ int ret;
+ if (lua_istable(L, 2)) {
+ size_t count;
+ uv_buf_t *bufs = luv_prep_bufs(L, 2, &count);
+ ret = uv_try_write(handle, bufs, count);
+ free(bufs);
+ }
+ else if (lua_isstring(L, 2)) {
+ uv_buf_t buf;
+ luv_check_buf(L, 2, &buf);
+ ret = uv_try_write(handle, &buf, 1);
+ }
+ else {
+ return luaL_argerror(L, 2, "data must be string or table of strings");
+ }
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_is_readable(lua_State* L) {
+ uv_stream_t* handle = luv_check_stream(L, 1);
+ lua_pushboolean(L, uv_is_readable(handle));
+ return 1;
+}
+
+static int luv_is_writable(lua_State* L) {
+ uv_stream_t* handle = luv_check_stream(L, 1);
+ lua_pushboolean(L, uv_is_writable(handle));
+ return 1;
+}
+
+static int luv_stream_set_blocking(lua_State* L) {
+ uv_stream_t* handle = luv_check_stream(L, 1);
+ int blocking, ret;
+ luaL_checktype(L, 2, LUA_TBOOLEAN);
+ blocking = lua_toboolean(L, 2);
+ ret = uv_stream_set_blocking(handle, blocking);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
diff --git a/3rdparty/luv/src/tcp.c b/3rdparty/luv/src/tcp.c
new file mode 100644
index 00000000000..7ffef5ae763
--- /dev/null
+++ b/3rdparty/luv/src/tcp.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "luv.h"
+
+static uv_tcp_t* luv_check_tcp(lua_State* L, int index) {
+ uv_tcp_t* handle = luv_checkudata(L, index, "uv_tcp");
+ luaL_argcheck(L, handle->type == UV_TCP && handle->data, index, "Expected uv_tcp_t");
+ return handle;
+}
+
+static int luv_new_tcp(lua_State* L) {
+ uv_tcp_t* handle = luv_newuserdata(L, sizeof(*handle));
+ int ret = uv_tcp_init(luv_loop(L), handle);
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ handle->data = luv_setup_handle(L);
+ return 1;
+}
+
+static int luv_tcp_open(lua_State* L) {
+ uv_tcp_t* handle = luv_check_tcp(L, 1);
+ uv_os_sock_t sock = luaL_checkinteger(L, 2);
+ int ret = uv_tcp_open(handle, sock);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_tcp_nodelay(lua_State* L) {
+ uv_tcp_t* handle = luv_check_tcp(L, 1);
+ int ret, enable;
+ luaL_checktype(L, 2, LUA_TBOOLEAN);
+ enable = lua_toboolean(L, 2);
+ ret = uv_tcp_nodelay(handle, enable);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_tcp_keepalive(lua_State* L) {
+ uv_tcp_t* handle = luv_check_tcp(L, 1);
+ int ret, enable;
+ unsigned int delay = 0;
+ luaL_checktype(L, 2, LUA_TBOOLEAN);
+ enable = lua_toboolean(L, 2);
+ if (enable) {
+ delay = luaL_checkinteger(L, 3);
+ }
+ ret = uv_tcp_keepalive(handle, enable, delay);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_tcp_simultaneous_accepts(lua_State* L) {
+ uv_tcp_t* handle = luv_check_tcp(L, 1);
+ int ret, enable;
+ luaL_checktype(L, 2, LUA_TBOOLEAN);
+ enable = lua_toboolean(L, 2);
+ ret = uv_tcp_simultaneous_accepts(handle, enable);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_tcp_bind(lua_State* L) {
+ uv_tcp_t* handle = luv_check_tcp(L, 1);
+ const char* host = luaL_checkstring(L, 2);
+ int port = luaL_checkinteger(L, 3);
+ unsigned int flags = 0;
+ struct sockaddr_storage addr;
+ int ret;
+ if (uv_ip4_addr(host, port, (struct sockaddr_in*)&addr) &&
+ uv_ip6_addr(host, port, (struct sockaddr_in6*)&addr)) {
+ return luaL_error(L, "Invalid IP address or port [%s:%d]", host, port);
+ }
+ if (lua_type(L, 4) == LUA_TTABLE) {
+ lua_getfield(L, 4, "ipv6only");
+ if (lua_toboolean(L, -1)) flags |= UV_TCP_IPV6ONLY;
+ lua_pop(L, 1);
+ }
+ ret = uv_tcp_bind(handle, (struct sockaddr*)&addr, flags);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static void parse_sockaddr(lua_State* L, struct sockaddr_storage* address, int addrlen) {
+ char ip[INET6_ADDRSTRLEN];
+ int port = 0;
+ lua_newtable(L);
+ if (address->ss_family == AF_INET) {
+ struct sockaddr_in* addrin = (struct sockaddr_in*)address;
+ uv_inet_ntop(AF_INET, &(addrin->sin_addr), ip, addrlen);
+ port = ntohs(addrin->sin_port);
+ } else if (address->ss_family == AF_INET6) {
+ struct sockaddr_in6* addrin6 = (struct sockaddr_in6*)address;
+ uv_inet_ntop(AF_INET6, &(addrin6->sin6_addr), ip, addrlen);
+ port = ntohs(addrin6->sin6_port);
+ }
+
+ lua_pushstring(L, luv_af_num_to_string(address->ss_family));
+ lua_setfield(L, -2, "family");
+ lua_pushinteger(L, port);
+ lua_setfield(L, -2, "port");
+ lua_pushstring(L, ip);
+ lua_setfield(L, -2, "ip");
+}
+
+static int luv_tcp_getsockname(lua_State* L) {
+ uv_tcp_t* handle = luv_check_tcp(L, 1);
+ struct sockaddr_storage address;
+ int addrlen = sizeof(address);
+ int ret = uv_tcp_getsockname(handle, (struct sockaddr*)&address, &addrlen);
+ if (ret < 0) return luv_error(L, ret);
+ parse_sockaddr(L, &address, addrlen);
+ return 1;
+}
+
+static int luv_tcp_getpeername(lua_State* L) {
+ uv_tcp_t* handle = luv_check_tcp(L, 1);
+ struct sockaddr_storage address;
+ int addrlen = sizeof(address);
+ int ret = uv_tcp_getpeername(handle, (struct sockaddr*)&address, &addrlen);
+ if (ret < 0) return luv_error(L, ret);
+ parse_sockaddr(L, &address, addrlen);
+ return 1;
+}
+
+
+static void luv_connect_cb(uv_connect_t* req, int status) {
+ lua_State* L = luv_state(req->handle->loop);
+ luv_status(L, status);
+ luv_fulfill_req(L, req->data, 1);
+ luv_cleanup_req(L, req->data);
+ req->data = NULL;
+}
+
+static int luv_write_queue_size(lua_State* L) {
+ uv_tcp_t* handle = luv_check_tcp(L, 1);
+ lua_pushinteger(L, handle->write_queue_size);
+ return 1;
+}
+
+static int luv_tcp_connect(lua_State* L) {
+ uv_tcp_t* handle = luv_check_tcp(L, 1);
+ const char* host = luaL_checkstring(L, 2);
+ int port = luaL_checkinteger(L, 3);
+ struct sockaddr_storage addr;
+ uv_connect_t* req;
+ int ret, ref;
+ if (uv_ip4_addr(host, port, (struct sockaddr_in*)&addr) &&
+ uv_ip6_addr(host, port, (struct sockaddr_in6*)&addr)) {
+ return luaL_error(L, "Invalid IP address or port [%s:%d]", host, port);
+ }
+ ref = luv_check_continuation(L, 4);
+
+ req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ ret = uv_tcp_connect(req, handle, (struct sockaddr*)&addr, luv_connect_cb);
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ return 1;
+}
diff --git a/3rdparty/luv/src/thread.c b/3rdparty/luv/src/thread.c
new file mode 100644
index 00000000000..cc53011e6ed
--- /dev/null
+++ b/3rdparty/luv/src/thread.c
@@ -0,0 +1,353 @@
+/*
+* Copyright 2014 The Luvit Authors. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+#include "luv.h"
+#include "lthreadpool.h"
+
+typedef struct {
+ uv_thread_t handle;
+ char* code;
+ int len;
+ int argc;
+ luv_thread_arg_t arg;
+} luv_thread_t;
+
+static luv_acquire_vm acquire_vm_cb = NULL;
+static luv_release_vm release_vm_cb = NULL;
+
+static lua_State* luv_thread_acquire_vm() {
+ lua_State* L = luaL_newstate();
+
+ // Add in the lua standard libraries
+ luaL_openlibs(L);
+
+ // Get package.loaded, so we can store uv in it.
+ lua_getglobal(L, "package");
+ lua_getfield(L, -1, "loaded");
+ lua_remove(L, -2); // Remove package
+
+ // Store uv module definition at loaded.uv
+ luaopen_luv(L);
+ lua_setfield(L, -2, "luv");
+ lua_pop(L, 1);
+
+ return L;
+}
+
+static void luv_thread_release_vm(lua_State* L) {
+ lua_close(L);
+}
+
+static int luv_thread_arg_set(lua_State* L, luv_thread_arg_t* args, int idx, int top, int flag)
+{
+ int i;
+ idx = idx > 0 ? idx : 1;
+ i = idx;
+ while (i <= top && i <= LUV_THREAD_MAXNUM_ARG + idx)
+ {
+ luv_val_t *arg = args->argv + i - idx;
+ arg->type = lua_type(L, i);
+ switch (arg->type)
+ {
+ case LUA_TNIL:
+ break;
+ case LUA_TBOOLEAN:
+ arg->val.boolean = lua_toboolean(L, i);
+ break;
+ case LUA_TNUMBER:
+ arg->val.num = lua_tonumber(L, i);
+ break;
+ case LUA_TLIGHTUSERDATA:
+ arg->val.userdata = lua_touserdata(L, i);
+ break;
+ case LUA_TSTRING:
+ {
+ const char* p = lua_tolstring(L, i, &arg->val.str.len);
+ arg->val.str.base = malloc(arg->val.str.len);
+ if (arg->val.str.base == NULL)
+ {
+ perror("out of memory");
+ return 0;
+ }
+ memcpy((void*)arg->val.str.base, p, arg->val.str.len);
+ break;
+ }
+ case LUA_TUSERDATA:
+ if (flag == 1) {
+ arg->val.userdata = luv_check_handle(L, i);
+ break;
+ }
+ default:
+ fprintf(stderr, "Error: thread arg not support type '%s' at %d",
+ luaL_typename(L, arg->type), i);
+ exit(-1);
+ break;
+ }
+ i++;
+ }
+ args->argc = i - idx;
+ return args->argc;
+}
+
+static void luv_thread_arg_clear(luv_thread_arg_t* args) {
+ int i;
+ for (i = 0; i < args->argc; i++)
+ {
+ if (args->argv[i].type == LUA_TSTRING)
+ {
+ free((void*)args->argv[i].val.str.base);
+ }
+ }
+ memset(args, 0, sizeof(*args));
+ args->argc = 0;
+}
+
+static void luv_thread_setup_handle(lua_State* L, uv_handle_t* handle) {
+ *(void**) lua_newuserdata(L, sizeof(void*)) = handle;
+
+#define XX(uc, lc) case UV_##uc: \
+ luaL_getmetatable(L, "uv_"#lc); \
+ break;
+ switch (handle->type) {
+ UV_HANDLE_TYPE_MAP(XX)
+ default:
+ luaL_error(L, "Unknown handle type");
+ }
+#undef XX
+
+ lua_setmetatable(L, -2);
+}
+
+static int luv_thread_arg_push(lua_State* L, const luv_thread_arg_t* args) {
+ int i = 0;
+ while (i < args->argc)
+ {
+ const luv_val_t* arg = args->argv + i;
+ switch (arg->type)
+ {
+ case LUA_TNIL:
+ lua_pushnil(L);
+ break;
+ case LUA_TBOOLEAN:
+ lua_pushboolean(L, arg->val.boolean);
+ break;
+ case LUA_TLIGHTUSERDATA:
+ lua_pushlightuserdata(L, arg->val.userdata);
+ break;
+ case LUA_TNUMBER:
+ lua_pushnumber(L, arg->val.num);
+ break;
+ case LUA_TSTRING:
+ lua_pushlstring(L, arg->val.str.base, arg->val.str.len);
+ break;
+ case LUA_TUSERDATA:
+ luv_thread_setup_handle(L, arg->val.userdata);
+ break;
+ default:
+ fprintf(stderr, "Error: thread arg not support type %s at %d",
+ luaL_typename(L, arg->type), i + 1);
+ }
+ i++;
+ };
+ return i;
+}
+
+int thread_dump(lua_State* L, const void* p, size_t sz, void* B)
+{
+ (void)L;
+ luaL_addlstring((luaL_Buffer*) B, (const char*) p, sz);
+ return 0;
+}
+
+static const char* luv_thread_dumped(lua_State* L, int idx, size_t* l) {
+ if (lua_isstring(L, idx)) {
+ return lua_tolstring(L, idx, l);
+ } else {
+ const char* buff = NULL;
+ int top = lua_gettop(L);
+ luaL_Buffer b;
+ luaL_checktype(L, idx, LUA_TFUNCTION);
+ lua_pushvalue(L, idx);
+ luaL_buffinit(L, &b);
+#if LUA_VERSION_NUM>=503
+ int test_lua_dump = (lua_dump(L, thread_dump, &b, 1) == 0);
+#else
+ int test_lua_dump = (lua_dump(L, thread_dump, &b) == 0);
+#endif
+ if (test_lua_dump) {
+ luaL_pushresult(&b);
+ buff = lua_tolstring(L, -1, l);
+ } else
+ luaL_error(L, "Error: unable to dump given function");
+ lua_settop(L, top);
+
+ return buff;
+ }
+}
+
+static luv_thread_t* luv_check_thread(lua_State* L, int index)
+{
+ luv_thread_t* thread = luaL_checkudata(L, index, "uv_thread");
+ return thread;
+}
+
+static int luv_thread_gc(lua_State* L) {
+ luv_thread_t* tid = luv_check_thread(L, 1);
+ free(tid->code);
+ tid->code = NULL;
+ tid->len = 0;
+ luv_thread_arg_clear(&tid->arg);
+ return 0;
+}
+
+static int luv_thread_tostring(lua_State* L)
+{
+ luv_thread_t* thd = luv_check_thread(L, 1);
+ lua_pushfstring(L, "uv_thread_t: %p", thd->handle);
+ return 1;
+}
+
+static void luv_thread_cb(void* varg) {
+ luv_thread_t* thd = (luv_thread_t*)varg;
+ lua_State* L = acquire_vm_cb();
+ if (luaL_loadbuffer(L, thd->code, thd->len, "=thread") == 0)
+ {
+ int top = lua_gettop(L);
+ int i = luv_thread_arg_push(L, &thd->arg);
+
+ for (i = 0; i < thd->arg.argc; i++) {
+ if (thd->arg.argv[i].type == LUA_TUSERDATA) {
+ lua_pushlightuserdata(L, thd->arg.argv[i].val.userdata);
+ lua_pushvalue(L, top + i + 1);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+ }
+ }
+
+ if (lua_pcall(L, i, 0, 0)) {
+ fprintf(stderr, "Uncaught Error in thread: %s\n", lua_tostring(L, -1));
+ }
+
+ for (i = 0; i < thd->arg.argc; i++) {
+ if (thd->arg.argv[i].type == LUA_TUSERDATA) {
+ lua_pushlightuserdata(L, thd->arg.argv[i].val.userdata);
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ lua_pushnil(L);
+ lua_setmetatable(L, -2);
+ lua_pop(L, 1);
+
+ lua_pushlightuserdata(L, thd->arg.argv[i].val.userdata);
+ lua_pushnil(L);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+ }
+ }
+
+ } else {
+ fprintf(stderr, "Uncaught Error: %s\n", lua_tostring(L, -1));
+ }
+ release_vm_cb(L);
+}
+
+static int luv_new_thread(lua_State* L) {
+ int ret;
+ size_t len;
+ const char* buff;
+ luv_thread_t* thread;
+ thread = lua_newuserdata(L, sizeof(*thread));
+ memset(thread, 0, sizeof(*thread));
+ luaL_getmetatable(L, "uv_thread");
+ lua_setmetatable(L, -2);
+
+ buff = luv_thread_dumped(L, 1, &len);
+
+ thread->argc = luv_thread_arg_set(L, &thread->arg, 2, lua_gettop(L) - 1, 1);
+ thread->len = len;
+ thread->code = malloc(thread->len);
+ memcpy(thread->code, buff, len);
+
+ ret = uv_thread_create(&thread->handle, luv_thread_cb, thread);
+ if (ret < 0) return luv_error(L, ret);
+
+ return 1;
+}
+
+static int luv_thread_join(lua_State* L) {
+ luv_thread_t* tid = luv_check_thread(L, 1);
+ int ret = uv_thread_join(&tid->handle);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushboolean(L, 1);
+ return 1;
+}
+
+static int luv_thread_self(lua_State* L)
+{
+ luv_thread_t* thread;
+ uv_thread_t t = uv_thread_self();
+ thread = lua_newuserdata(L, sizeof(*thread));
+ memset(thread, 0, sizeof(*thread));
+ memcpy(&thread->handle, &t, sizeof(t));
+ luaL_getmetatable(L, "uv_thread");
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int luv_thread_equal(lua_State* L) {
+ luv_thread_t* t1 = luv_check_thread(L, 1);
+ luv_thread_t* t2 = luv_check_thread(L, 2);
+ int ret = uv_thread_equal(&t1->handle, &t2->handle);
+ lua_pushboolean(L, ret);
+ return 1;
+}
+
+/* Pause the calling thread for a number of milliseconds. */
+static int luv_thread_sleep(lua_State* L) {
+#ifdef _WIN32
+ DWORD msec = luaL_checkinteger(L, 1);
+ Sleep(msec);
+#else
+ lua_Integer msec = luaL_checkinteger(L, 1);
+ usleep(msec * 1000);
+#endif
+ return 0;
+}
+
+static const luaL_Reg luv_thread_methods[] = {
+ {"equal", luv_thread_equal},
+ {"join", luv_thread_join},
+ {NULL, NULL}
+};
+
+static void luv_thread_init(lua_State* L) {
+ luaL_newmetatable(L, "uv_thread");
+ lua_pushcfunction(L, luv_thread_tostring);
+ lua_setfield(L, -2, "__tostring");
+ lua_pushcfunction(L, luv_thread_equal);
+ lua_setfield(L, -2, "__eq");
+ lua_pushcfunction(L, luv_thread_gc);
+ lua_setfield(L, -2, "__gc");
+ lua_newtable(L);
+ luaL_setfuncs(L, luv_thread_methods, 0);
+ lua_setfield(L, -2, "__index");
+ lua_pop(L, 1);
+
+ if (acquire_vm_cb == NULL) acquire_vm_cb = luv_thread_acquire_vm;
+ if (release_vm_cb == NULL) release_vm_cb = luv_thread_release_vm;
+}
+
+LUALIB_API void luv_set_thread_cb(luv_acquire_vm acquire, luv_release_vm release)
+{
+ acquire_vm_cb = acquire;
+ release_vm_cb = release;
+}
diff --git a/3rdparty/luv/src/timer.c b/3rdparty/luv/src/timer.c
new file mode 100644
index 00000000000..b283f1fc8b2
--- /dev/null
+++ b/3rdparty/luv/src/timer.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "luv.h"
+
+static uv_timer_t* luv_check_timer(lua_State* L, int index) {
+ uv_timer_t* handle = luv_checkudata(L, index, "uv_timer");
+ luaL_argcheck(L, handle->type == UV_TIMER && handle->data, index, "Expected uv_timer_t");
+ return handle;
+}
+
+static int luv_new_timer(lua_State* L) {
+ uv_timer_t* handle = luv_newuserdata(L, sizeof(*handle));
+ int ret = uv_timer_init(luv_loop(L), handle);
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ handle->data = luv_setup_handle(L);
+ return 1;
+}
+
+static void luv_timer_cb(uv_timer_t* handle) {
+ lua_State* L = luv_state(handle->loop);
+ luv_handle_t* data = handle->data;
+ luv_call_callback(L, data, LUV_TIMEOUT, 0);
+}
+
+static int luv_timer_start(lua_State* L) {
+ uv_timer_t* handle = luv_check_timer(L, 1);
+ uint64_t timeout;
+ uint64_t repeat;
+ int ret;
+ timeout = luaL_checkinteger(L, 2);
+ repeat = luaL_checkinteger(L, 3);
+ luv_check_callback(L, handle->data, LUV_TIMEOUT, 4);
+ ret = uv_timer_start(handle, luv_timer_cb, timeout, repeat);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_timer_stop(lua_State* L) {
+ uv_timer_t* handle = luv_check_timer(L, 1);
+ int ret = uv_timer_stop(handle);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_timer_again(lua_State* L) {
+ uv_timer_t* handle = luv_check_timer(L, 1);
+ int ret = uv_timer_again(handle);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_timer_set_repeat(lua_State* L) {
+ uv_timer_t* handle = luv_check_timer(L, 1);
+ uint64_t repeat = luaL_checkinteger(L, 2);
+ uv_timer_set_repeat(handle, repeat);
+ return 0;
+}
+
+static int luv_timer_get_repeat(lua_State* L) {
+ uv_timer_t* handle = luv_check_timer(L, 1);
+ uint64_t repeat = uv_timer_get_repeat(handle);
+ lua_pushinteger(L, repeat);
+ return 1;
+}
diff --git a/3rdparty/luv/src/tty.c b/3rdparty/luv/src/tty.c
new file mode 100644
index 00000000000..9232dc07603
--- /dev/null
+++ b/3rdparty/luv/src/tty.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "luv.h"
+
+static uv_tty_t* luv_check_tty(lua_State* L, int index) {
+ uv_tty_t* handle = luv_checkudata(L, index, "uv_tty");
+ luaL_argcheck(L, handle->type == UV_TTY && handle->data, index, "Expected uv_tty_t");
+ return handle;
+}
+
+static int luv_new_tty(lua_State* L) {
+ int readable, ret;
+ uv_tty_t* handle;
+ uv_file fd = luaL_checkinteger(L, 1);
+ luaL_checktype(L, 2, LUA_TBOOLEAN);
+ readable = lua_toboolean(L, 2);
+ handle = luv_newuserdata(L, sizeof(*handle));
+ ret = uv_tty_init(luv_loop(L), handle, fd, readable);
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ handle->data = luv_setup_handle(L);
+ return 1;
+}
+
+static int luv_tty_set_mode(lua_State* L) {
+ uv_tty_t* handle = luv_check_tty(L, 1);
+ int mode = luaL_checkinteger(L, 2);
+ int ret = uv_tty_set_mode(handle, mode);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_tty_reset_mode(lua_State* L) {
+ int ret = uv_tty_reset_mode();
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_tty_get_winsize(lua_State* L) {
+ uv_tty_t* handle = luv_check_tty(L, 1);
+ int width, height;
+ int ret = uv_tty_get_winsize(handle, &width, &height);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, width);
+ lua_pushinteger(L, height);
+ return 2;
+}
diff --git a/3rdparty/luv/src/udp.c b/3rdparty/luv/src/udp.c
new file mode 100644
index 00000000000..9cc25555559
--- /dev/null
+++ b/3rdparty/luv/src/udp.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "luv.h"
+
+static uv_udp_t* luv_check_udp(lua_State* L, int index) {
+ uv_udp_t* handle = luv_checkudata(L, index, "uv_udp");
+ luaL_argcheck(L, handle->type == UV_UDP && handle->data, index, "Expected uv_udp_t");
+ return handle;
+}
+
+static int luv_new_udp(lua_State* L) {
+ uv_udp_t* handle = luv_newuserdata(L, sizeof(*handle));
+ int ret = uv_udp_init(luv_loop(L), handle);
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ handle->data = luv_setup_handle(L);
+ return 1;
+}
+
+static int luv_udp_open(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ uv_os_sock_t sock = luaL_checkinteger(L, 2);
+ int ret = uv_udp_open(handle, sock);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_udp_bind(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ const char* host = luaL_checkstring(L, 2);
+ int port = luaL_checkinteger(L, 3);
+ unsigned int flags = 0;
+ struct sockaddr_storage addr;
+ int ret;
+ if (uv_ip4_addr(host, port, (struct sockaddr_in*)&addr) &&
+ uv_ip6_addr(host, port, (struct sockaddr_in6*)&addr)) {
+ return luaL_error(L, "Invalid IP address or port [%s:%d]", host, port);
+ }
+ if (lua_type(L, 4) == LUA_TTABLE) {
+ luaL_checktype(L, 4, LUA_TTABLE);
+ lua_getfield(L, 4, "reuseaddr");
+ if (lua_toboolean(L, -1)) flags |= UV_UDP_REUSEADDR;
+ lua_pop(L, 1);
+ lua_getfield(L, 4, "ipv6only");
+ if (lua_toboolean(L, -1)) flags |= UV_UDP_IPV6ONLY;
+ lua_pop(L, 1);
+ }
+ ret = uv_udp_bind(handle, (struct sockaddr*)&addr, flags);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_udp_getsockname(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ struct sockaddr_storage address;
+ int addrlen = sizeof(address);
+ int ret = uv_udp_getsockname(handle, (struct sockaddr*)&address, &addrlen);
+ if (ret < 0) return luv_error(L, ret);
+ parse_sockaddr(L, &address, addrlen);
+ return 1;
+}
+
+// These are the same order as uv_membership which also starts at 0
+static const char *const luv_membership_opts[] = {
+ "leave", "join", NULL
+};
+
+static int luv_udp_set_membership(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ const char* multicast_addr = luaL_checkstring(L, 2);
+ const char* interface_addr = luaL_checkstring(L, 3);
+ uv_membership membership = luaL_checkoption(L, 4, NULL, luv_membership_opts);
+ int ret = uv_udp_set_membership(handle, multicast_addr, interface_addr, membership);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_udp_set_multicast_loop(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ int on, ret;
+ luaL_checktype(L, 2, LUA_TBOOLEAN);
+ on = lua_toboolean(L, 2);
+ ret = uv_udp_set_multicast_loop(handle, on);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_udp_set_multicast_ttl(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ int ttl, ret;
+ ttl = luaL_checkinteger(L, 2);
+ ret = uv_udp_set_multicast_ttl(handle, ttl);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_udp_set_multicast_interface(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ const char* interface_addr = luaL_checkstring(L, 2);
+ int ret = uv_udp_set_multicast_interface(handle, interface_addr);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_udp_set_broadcast(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ int on, ret;
+ luaL_checktype(L, 2, LUA_TBOOLEAN);
+ on = lua_toboolean(L, 2);
+ ret =uv_udp_set_broadcast(handle, on);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_udp_set_ttl(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ int ttl, ret;
+ ttl = luaL_checknumber(L, 2);
+ ret = uv_udp_set_ttl(handle, ttl);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static void luv_udp_send_cb(uv_udp_send_t* req, int status) {
+ lua_State* L = luv_state(req->handle->loop);
+ luv_status(L, status);
+ luv_fulfill_req(L, req->data, 1);
+ luv_cleanup_req(L, req->data);
+ req->data = NULL;
+}
+
+static int luv_udp_send(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ uv_udp_send_t* req;
+ uv_buf_t buf;
+ int ret, port, ref;
+ const char* host;
+ struct sockaddr_storage addr;
+ luv_check_buf(L, 2, &buf);
+ host = luaL_checkstring(L, 3);
+ port = luaL_checkinteger(L, 4);
+ if (uv_ip4_addr(host, port, (struct sockaddr_in*)&addr) &&
+ uv_ip6_addr(host, port, (struct sockaddr_in6*)&addr)) {
+ return luaL_error(L, "Invalid IP address or port [%s:%d]", host, port);
+ }
+ ref = luv_check_continuation(L, 5);
+ req = lua_newuserdata(L, sizeof(*req));
+ req->data = luv_setup_req(L, ref);
+ ret = uv_udp_send(req, handle, &buf, 1, (struct sockaddr*)&addr, luv_udp_send_cb);
+ if (ret < 0) {
+ lua_pop(L, 1);
+ return luv_error(L, ret);
+ }
+ return 1;
+
+}
+
+static int luv_udp_try_send(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ uv_buf_t buf;
+ int ret, port;
+ const char* host;
+ struct sockaddr_storage addr;
+ luv_check_buf(L, 2, &buf);
+ host = luaL_checkstring(L, 3);
+ port = luaL_checkinteger(L, 4);
+ if (uv_ip4_addr(host, port, (struct sockaddr_in*)&addr) &&
+ uv_ip6_addr(host, port, (struct sockaddr_in6*)&addr)) {
+ return luaL_error(L, "Invalid IP address or port [%s:%d]", host, port);
+ }
+ ret = uv_udp_try_send(handle, &buf, 1, (struct sockaddr*)&addr);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static void luv_udp_recv_cb(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags) {
+ lua_State* L = luv_state(handle->loop);
+
+ // err
+ if (nread < 0) {
+ luv_status(L, nread);
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ // data
+ if (nread == 0) {
+ if (addr) {
+ lua_pushstring(L, "");
+ }
+ else {
+ lua_pushnil(L);
+ }
+ }
+ else if (nread > 0) {
+ lua_pushlstring(L, buf->base, nread);
+ }
+ if (buf) free(buf->base);
+
+ // address
+ if (addr) {
+ parse_sockaddr(L, (struct sockaddr_storage*)addr, sizeof *addr);
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ // flags
+ lua_newtable(L);
+ if (flags & UV_UDP_PARTIAL) {
+ lua_pushboolean(L, 1);
+ lua_setfield(L, -2, "partial");
+ }
+
+ luv_call_callback(L, handle->data, LUV_RECV, 4);
+}
+
+static int luv_udp_recv_start(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ int ret;
+ luv_check_callback(L, handle->data, LUV_RECV, 2);
+ ret = uv_udp_recv_start(handle, luv_alloc_cb, luv_udp_recv_cb);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int luv_udp_recv_stop(lua_State* L) {
+ uv_udp_t* handle = luv_check_udp(L, 1);
+ int ret = uv_udp_recv_stop(handle);
+ if (ret < 0) return luv_error(L, ret);
+ lua_pushinteger(L, ret);
+ return 1;
+}
diff --git a/3rdparty/luv/src/util.c b/3rdparty/luv/src/util.c
new file mode 100644
index 00000000000..c7b98c1759a
--- /dev/null
+++ b/3rdparty/luv/src/util.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "luv.h"
+
+void luv_stack_dump(lua_State* L, const char* name) {
+ int i, l;
+ fprintf(stderr, "\nAPI STACK DUMP %p %d: %s\n", L, lua_status(L), name);
+ for (i = 1, l = lua_gettop(L); i <= l; i++) {
+ int type = lua_type(L, i);
+ switch (type) {
+ case LUA_TSTRING:
+ fprintf(stderr, " %d %s \"%s\"\n", i, lua_typename(L, type), lua_tostring(L, i));
+ break;
+ case LUA_TNUMBER:
+ fprintf(stderr, " %d %s %ld\n", i, lua_typename(L, type), (long int) lua_tointeger(L, i));
+ break;
+ case LUA_TUSERDATA:
+ fprintf(stderr, " %d %s %p\n", i, lua_typename(L, type), lua_touserdata(L, i));
+ break;
+ default:
+ fprintf(stderr, " %d %s\n", i, lua_typename(L, type));
+ break;
+ }
+ }
+ assert(l == lua_gettop(L));
+}
+
+static int luv_error(lua_State* L, int status) {
+ lua_pushnil(L);
+ lua_pushfstring(L, "%s: %s", uv_err_name(status), uv_strerror(status));
+ lua_pushstring(L, uv_err_name(status));
+ return 3;
+}
+
+static void luv_status(lua_State* L, int status) {
+ if (status < 0) {
+ lua_pushstring(L, uv_err_name(status));
+ }
+ else {
+ lua_pushnil(L);
+ }
+}
diff --git a/3rdparty/luv/src/util.h b/3rdparty/luv/src/util.h
new file mode 100644
index 00000000000..c669c0430db
--- /dev/null
+++ b/3rdparty/luv/src/util.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2014 The Luvit Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef LUV_UTIL_H
+#define LUV_UTIL_H
+
+#include "luv.h"
+
+void luv_stack_dump(lua_State* L, const char* name);
+static int luv_error(lua_State* L, int ret);
+static void luv_status(lua_State* L, int status);
+
+#endif
diff --git a/3rdparty/luv/src/work.c b/3rdparty/luv/src/work.c
new file mode 100644
index 00000000000..e40212f1e7c
--- /dev/null
+++ b/3rdparty/luv/src/work.c
@@ -0,0 +1,224 @@
+/*
+* Copyright 2014 The Luvit Authors. All Rights Reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+#include "luv.h"
+
+#include "lthreadpool.h"
+
+typedef struct {
+ lua_State* L; /* vm in main */
+ char* code; /* thread entry code */
+ size_t len;
+
+ uv_async_t async;
+ int async_cb; /* ref, run in main, call when async message received, NYI */
+ int after_work_cb; /* ref, run in main ,call after work cb*/
+} luv_work_ctx_t;
+
+typedef struct {
+ uv_work_t work;
+ luv_work_ctx_t* ctx;
+
+ luv_thread_arg_t arg;
+} luv_work_t;
+
+static uv_key_t L_key;
+
+static luv_work_ctx_t* luv_check_work_ctx(lua_State* L, int index)
+{
+ luv_work_ctx_t* ctx = luaL_checkudata(L, index, "luv_work_ctx");
+ return ctx;
+}
+
+static int luv_work_ctx_gc(lua_State *L)
+{
+ luv_work_ctx_t* ctx = luv_check_work_ctx(L, 1);
+ free(ctx->code);
+ luaL_unref(L, LUA_REGISTRYINDEX, ctx->after_work_cb);
+ luaL_unref(L, LUA_REGISTRYINDEX, ctx->async_cb);
+
+ return 0;
+}
+
+static int luv_work_ctx_tostring(lua_State* L)
+{
+ luv_work_ctx_t* ctx = luv_check_work_ctx(L, 1);
+ lua_pushfstring(L, "luv_work_ctx_t: %p", ctx);
+ return 1;
+}
+
+static void luv_work_cb(uv_work_t* req)
+{
+ luv_work_t* work = req->data;
+ luv_work_ctx_t* ctx = work->ctx;
+ lua_State *L = uv_key_get(&L_key);
+ int top;
+ if (L == NULL) {
+ /* vm reuse in threadpool */
+ L = acquire_vm_cb();
+ uv_key_set(&L_key, L);
+ }
+
+ top = lua_gettop(L);
+ lua_pushlstring(L, ctx->code, ctx->len);
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ if (lua_isnil(L, -1))
+ {
+ lua_pop(L, 1);
+
+ lua_pushlstring(L, ctx->code, ctx->len);
+ if (luaL_loadbuffer(L, ctx->code, ctx->len, "=pool") != 0)
+ {
+ fprintf(stderr, "Uncaught Error: %s\n", lua_tostring(L, -1));
+ lua_pop(L, 2);
+
+ lua_pushnil(L);
+ } else
+ {
+ lua_pushvalue(L, -1);
+ lua_insert(L, lua_gettop(L) - 2);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+ }
+ }
+
+ if (lua_isfunction(L, -1))
+ {
+ int i = luv_thread_arg_push(L, &work->arg);
+ if (lua_pcall(L, i, LUA_MULTRET, 0)) {
+ fprintf(stderr, "Uncaught Error in thread: %s\n", lua_tostring(L, -1));
+ }
+ luv_thread_arg_clear(&work->arg);
+ luv_thread_arg_set(L, &work->arg, top + 1, lua_gettop(L), 0);
+ lua_settop(L, top);
+ } else {
+ fprintf(stderr, "Uncaught Error: %s can't be work entry\n",
+ lua_typename(L, lua_type(L,-1)));
+ }
+}
+
+static void luv_after_work_cb(uv_work_t* req, int status) {
+ luv_work_t* work = req->data;
+ luv_work_ctx_t* ctx = work->ctx;
+ lua_State*L = ctx->L;
+ int i;
+ (void)status;
+ lua_rawgeti(L, LUA_REGISTRYINDEX, ctx->after_work_cb);
+ i = luv_thread_arg_push(L, &work->arg);
+ if (lua_pcall(L, i, 0, 0))
+ {
+ fprintf(stderr, "Uncaught Error in thread: %s\n", lua_tostring(L, -1));
+ }
+
+ //ref down to ctx
+ lua_pushlightuserdata(L, work);
+ lua_pushnil(L);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+
+ luv_thread_arg_clear(&work->arg);
+ free(work);
+}
+
+static void async_cb(uv_async_t *handle)
+{
+ luv_work_t*work = handle->data;
+ luv_work_ctx_t* ctx = work->ctx;
+ lua_State*L = ctx->L;
+ int i;
+ lua_rawgeti(L, LUA_REGISTRYINDEX, ctx->async_cb);
+ i = luv_thread_arg_push(L, &work->arg);
+ if (lua_pcall(L, i, 0, 0))
+ {
+ fprintf(stderr, "Uncaught Error in thread: %s\n", lua_tostring(L, -1));
+ }
+}
+
+static int luv_new_work(lua_State* L) {
+ size_t len;
+ const char* buff;
+ luv_work_ctx_t* ctx;
+
+ buff = luv_thread_dumped(L, 1, &len);
+ luaL_checktype(L, 2, LUA_TFUNCTION);
+ if(!lua_isnoneornil(L, 3))
+ luaL_checktype(L, 3, LUA_TFUNCTION);
+
+ ctx = lua_newuserdata(L, sizeof(*ctx));
+ memset(ctx, 0, sizeof(*ctx));
+
+ ctx->len = len;
+ ctx->code = malloc(ctx->len);
+ memcpy(ctx->code, buff, len);
+
+ lua_pushvalue(L, 2);
+ ctx->after_work_cb = luaL_ref(L, LUA_REGISTRYINDEX);
+ if (lua_gettop(L) == 4) {
+ lua_pushvalue(L, 3);
+ ctx->async_cb = luaL_ref(L, LUA_REGISTRYINDEX);
+ uv_async_init(luv_loop(L), &ctx->async, async_cb);
+ } else
+ ctx->async_cb = LUA_REFNIL;
+ ctx->L = L;
+ luaL_getmetatable(L, "luv_work_ctx");
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int luv_queue_work(lua_State* L) {
+ int top = lua_gettop(L);
+ luv_work_ctx_t* ctx = luv_check_work_ctx(L, 1);
+ luv_work_t* work = malloc(sizeof(*work));
+ int ret;
+
+ luv_thread_arg_set(L, &work->arg, 2, top, 0);
+ work->ctx = ctx;
+ work->work.data = work;
+ ret = uv_queue_work(luv_loop(L), &work->work, luv_work_cb, luv_after_work_cb);
+ if (ret < 0) {
+ free(work);
+ return luv_error(L, ret);
+ }
+
+ //ref up to ctx
+ lua_pushlightuserdata(L, work);
+ lua_pushvalue(L, 1);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+
+ lua_pushboolean(L, 1);
+ return 1;
+}
+
+static const luaL_Reg luv_work_ctx_methods[] = {
+ {"queue", luv_queue_work},
+ {NULL, NULL}
+};
+
+static int key_inited = 0;
+static void luv_work_init(lua_State* L) {
+ luaL_newmetatable(L, "luv_work_ctx");
+ lua_pushcfunction(L, luv_work_ctx_tostring);
+ lua_setfield(L, -2, "__tostring");
+ lua_pushcfunction(L, luv_work_ctx_gc);
+ lua_setfield(L, -2, "__gc");
+ lua_newtable(L);
+ luaL_setfuncs(L, luv_work_ctx_methods, 0);
+ lua_setfield(L, -2, "__index");
+ lua_pop(L, 1);
+
+ if (key_inited==0) {
+ key_inited = 1;
+ uv_key_create(&L_key);
+ }
+}
diff --git a/3rdparty/luv/tests/manual-test-cluster.lua b/3rdparty/luv/tests/manual-test-cluster.lua
new file mode 100644
index 00000000000..304e4be634d
--- /dev/null
+++ b/3rdparty/luv/tests/manual-test-cluster.lua
@@ -0,0 +1,213 @@
+-- This is quite the involved test. Basically it binds
+-- to a tcp port, spawns n children (one per CPU core)
+-- who all listen on the same shared port and act as a
+-- load balancing cluster.
+-- Then N clients are spawned that connect to the cluster
+-- The application itself kills the worker upon connection
+-- All N workers should accept exactly one request and all close.
+
+return require('lib/tap')(function (test)
+
+ -- This function will be run in a child process
+ local worker_code = string.dump(function ()
+ local dump = require('lib/utils').dump
+
+ local function print(...)
+ local n = select('#', ...)
+ local arguments = {...}
+ for i = 1, n do
+ arguments[i] = tostring(arguments[i])
+ end
+
+ local text = table.concat(arguments, "\t")
+ text = " " .. string.gsub(text, "\n", "\n ")
+ _G.print(text)
+ end
+
+ local function p(...)
+ local n = select('#', ...)
+ local arguments = { ... }
+
+ for i = 1, n do
+ arguments[i] = dump(arguments[i])
+ end
+
+ print(table.concat(arguments, "\t"))
+ end
+
+ local uv = require('luv')
+ local answer = -1
+
+ -- The parent is going to pass us the server handle over a pipe
+ -- This will be our local file descriptor at PIPE_FD
+ local pipe = uv.new_pipe(true)
+ local pipe_fd = tonumber(os.getenv("PIPE_FD"))
+ assert(uv.pipe_open(pipe, pipe_fd))
+
+ -- Configure the server handle
+ local server = uv.new_tcp()
+ local done = false
+ local function onconnection()
+ print("NOT ACCEPTING, already done")
+ if done then return end
+ local client = uv.new_tcp()
+ assert(uv.accept(server, client))
+ p("New TCP", client, "on", server)
+ p{client=client}
+ assert(uv.write(client, "BYE!\n"));
+ assert(uv.shutdown(client, function ()
+ uv.close(client)
+ uv.unref(server)
+ done = true
+ answer = 42
+ end))
+ end
+
+ -- Read the server handle from the parent
+ local function onread(err, data)
+ p("onread", {err=err,data=data})
+ assert(not err, err)
+ if uv.pipe_pending_count(pipe) > 0 then
+ local pending_type = uv.pipe_pending_type(pipe)
+ p("pending_type", pending_type)
+ assert(pending_type == "tcp")
+ assert(uv.accept(pipe, server))
+ assert(uv.listen(server, 0, onconnection))
+ p("Received server handle from parent process", server)
+ elseif data then
+ p("ondata", data)
+ else
+ p("onend", data)
+ end
+ end
+ uv.read_start(pipe, onread)
+
+ -- Start the event loop!
+ uv.run()
+
+ os.exit(answer)
+ end)
+
+ local client_code = string.dump(function ()
+ local dump = require('lib/utils').dump
+
+ local function print(...)
+ local n = select('#', ...)
+ local arguments = {...}
+ for i = 1, n do
+ arguments[i] = tostring(arguments[i])
+ end
+
+ local text = table.concat(arguments, "\t")
+ text = " " .. string.gsub(text, "\n", "\n ")
+ _G.print(text)
+ end
+
+ local function p(...)
+ local n = select('#', ...)
+ local arguments = { ... }
+
+ for i = 1, n do
+ arguments[i] = dump(arguments[i])
+ end
+
+ print(table.concat(arguments, "\t"))
+ end
+
+ local uv = require('luv')
+
+ local host = os.getenv("HOST")
+ local port = tonumber(os.getenv("PORT"))
+
+ local socket = uv.new_tcp()
+
+ assert(uv.tcp_connect(socket, host, port, function (err)
+ p("client connected", {err=err})
+ assert(not err, err)
+ end))
+
+ -- Start the event loop!
+ uv.run()
+ end)
+
+ test("tcp cluster", function (print, p, expect, uv)
+
+ local exepath = assert(uv.exepath())
+ local cpu_count = # assert(uv.cpu_info())
+ local left = cpu_count
+
+ local server = uv.new_tcp()
+ assert(uv.tcp_bind(server, "::1", 0))
+
+ local address = uv.tcp_getsockname(server)
+ p{server=server,address=address}
+
+ print("Master process bound to TCP port " .. address.port .. " on " .. address.ip)
+
+ local function spawnWorker()
+ local pipe = uv.new_pipe(true)
+ local input = uv.new_pipe(false)
+ local child, pid
+ child, pid = assert(uv.spawn(exepath, {
+ cwd = uv.cwd(),
+ stdio = {input,1,2,pipe},
+ env= {"PIPE_FD=3"}
+ }, expect(function (status, signal)
+ p("Worker exited", {status=status,signal=signal})
+ assert(status == 42, "worker should return 42")
+ assert(signal == 0)
+ left = left - 1
+ uv.close(child)
+ uv.close(input)
+ uv.close(pipe)
+ if left == 0 then
+ p("All workers are now dead")
+ uv.close(server)
+ end
+ end)))
+ p("Spawned worker", pid, "and sending handle", server)
+ assert(uv.write(input, worker_code))
+ assert(uv.write2(pipe, "123", server))
+ assert(uv.shutdown(input))
+ assert(uv.shutdown(pipe))
+ end
+
+ local function spawnClient()
+ local input = uv.new_pipe(false)
+ local child, pid
+ child, pid = assert(uv.spawn(exepath, {
+ stdio = {input,1,2},
+ cwd = uv.cwd(),
+ env= {
+ "HOST=" .. address.ip,
+ "PORT=" .. address.port,
+ }
+ }, expect(function (status, signal)
+ p("Client exited", {status=status,signal=signal})
+ assert(status == 0)
+ assert(signal == 0)
+ uv.close(child)
+ end, left)))
+ p("Spawned client", pid)
+ assert(uv.write(input, client_code))
+ assert(uv.shutdown(input))
+ uv.close(input)
+ end
+
+ -- Spawn a child process for each CPU core
+ for _ = 1, cpu_count do
+ spawnWorker()
+ end
+
+ -- Spawn the clients after a short delay
+ local timer = uv.new_timer()
+ uv.timer_start(timer, 1000, 0, expect(function ()
+ for _ = 1, cpu_count do
+ spawnClient()
+ end
+ uv.close(timer)
+ end))
+
+ end)
+end)
+
diff --git a/3rdparty/luv/tests/run.lua b/3rdparty/luv/tests/run.lua
new file mode 100644
index 00000000000..ea94e9bd58b
--- /dev/null
+++ b/3rdparty/luv/tests/run.lua
@@ -0,0 +1,33 @@
+-- Run this from the parent directory as
+--
+-- luajit tests/run.lua
+--
+
+local tap = require("lib/tap")
+local uv = require("luv")
+
+local isWindows
+if jit and jit.os then
+ -- Luajit provides explicit platform detection
+ isWindows = jit.os == "Windows"
+else
+ -- Normal lua will only have \ for path separator on windows.
+ isWindows = package.config:find("\\") and true or false
+end
+_G.isWindows = isWindows
+
+local req = uv.fs_scandir("tests")
+
+while true do
+ local name = uv.fs_scandir_next(req)
+ if not name then break end
+ local match = string.match(name, "^test%-(.*).lua$")
+ if match then
+ local path = "tests/test-" .. match
+ tap(match)
+ require(path)
+ end
+end
+
+-- run the tests!
+tap(true)
diff --git a/3rdparty/luv/tests/test-async.lua b/3rdparty/luv/tests/test-async.lua
new file mode 100644
index 00000000000..88527cdb88d
--- /dev/null
+++ b/3rdparty/luv/tests/test-async.lua
@@ -0,0 +1,32 @@
+return require('lib/tap')(function (test)
+
+ test("test pass async between threads", function(p, p, expect, uv)
+ local before = os.time()
+ local async
+ async = uv.new_async(expect(function (a,b,c)
+ p('in async notify callback')
+ p(a,b,c)
+ assert(a=='a')
+ assert(b==true)
+ assert(c==250)
+ uv.close(async)
+ end))
+ local args = {500, 'string', nil, false, 5, "helloworld",async}
+ local unpack = unpack or table.unpack
+ uv.new_thread(function(num,s,null,bool,five,hw,asy)
+ local uv = require'luv'
+ assert(type(num) == "number")
+ assert(type(s) == "string")
+ assert(null == nil)
+ assert(bool == false)
+ assert(five == 5)
+ assert(hw == 'helloworld')
+ assert(type(asy)=='userdata')
+ assert(uv.async_send(asy,'a',true,250)==0)
+ uv.sleep(1000)
+ end, unpack(args)):join()
+ local elapsed = (os.time() - before) * 1000
+ assert(elapsed >= 1000, "elapsed should be at least delay ")
+ end)
+
+end)
diff --git a/3rdparty/luv/tests/test-conversions.lua b/3rdparty/luv/tests/test-conversions.lua
new file mode 100644
index 00000000000..f14056ddfb5
--- /dev/null
+++ b/3rdparty/luv/tests/test-conversions.lua
@@ -0,0 +1,6 @@
+return require('lib/tap')(function (test)
+ test("basic 64bit conversions", function (print, p, expect, uv)
+ assert(string.format("%x", 29913653248) == "6f6fe2000")
+ assert(string.format("%x", 32207650816) == "77fb9c000")
+ end)
+end)
diff --git a/3rdparty/luv/tests/test-dns.lua b/3rdparty/luv/tests/test-dns.lua
new file mode 100644
index 00000000000..c24adba7164
--- /dev/null
+++ b/3rdparty/luv/tests/test-dns.lua
@@ -0,0 +1,125 @@
+return require('lib/tap')(function (test)
+
+ test("Get all local http addresses", function (print, p, expect, uv)
+ assert(uv.getaddrinfo(nil, "http", nil, expect(function (err, res)
+ p(res, #res)
+ assert(not err, err)
+ assert(res[1].port == 80)
+ end)))
+ end)
+
+ test("Get all local http addresses sync", function (print, p, expect, uv)
+ local res = assert(uv.getaddrinfo(nil, "http"))
+ p(res, #res)
+ assert(res[1].port == 80)
+ end)
+
+ test("Get only ipv4 tcp adresses for luvit.io", function (print, p, expect, uv)
+ assert(uv.getaddrinfo("luvit.io", nil, {
+ socktype = "stream",
+ family = "inet",
+ }, expect(function (err, res)
+ assert(not err, err)
+ p(res, #res)
+ assert(#res == 1)
+ end)))
+ end)
+
+ -- FIXME: this test always fails on AppVeyor for some reason
+ if _G.isWindows and not os.getenv'APPVEYOR' then
+ test("Get only ipv6 tcp adresses for luvit.io", function (print, p, expect, uv)
+ assert(uv.getaddrinfo("luvit.io", nil, {
+ socktype = "stream",
+ family = "inet6",
+ }, expect(function (err, res)
+ assert(not err, err)
+ p(res, #res)
+ assert(#res == 1)
+ end)))
+ end)
+ end
+
+ test("Get ipv4 and ipv6 tcp adresses for luvit.io", function (print, p, expect, uv)
+ assert(uv.getaddrinfo("luvit.io", nil, {
+ socktype = "stream",
+ }, expect(function (err, res)
+ assert(not err, err)
+ p(res, #res)
+ assert(#res > 0)
+ end)))
+ end)
+
+ test("Get all adresses for luvit.io", function (print, p, expect, uv)
+ assert(uv.getaddrinfo("luvit.io", nil, nil, expect(function (err, res)
+ assert(not err, err)
+ p(res, #res)
+ assert(#res > 0)
+ end)))
+ end)
+
+ test("Lookup local ipv4 address", function (print, p, expect, uv)
+ assert(uv.getnameinfo({
+ family = "inet",
+ }, expect(function (err, hostname, service)
+ p{err=err,hostname=hostname,service=service}
+ assert(not err, err)
+ assert(hostname)
+ assert(service)
+ end)))
+ end)
+
+ test("Lookup local ipv4 address sync", function (print, p, expect, uv)
+ local hostname, service = assert(uv.getnameinfo({
+ family = "inet",
+ }))
+ p{hostname=hostname,service=service}
+ assert(hostname)
+ assert(service)
+ end)
+
+ test("Lookup local 127.0.0.1 ipv4 address", function (print, p, expect, uv)
+ assert(uv.getnameinfo({
+ ip = "127.0.0.1",
+ }, expect(function (err, hostname, service)
+ p{err=err,hostname=hostname,service=service}
+ assert(not err, err)
+ assert(hostname)
+ assert(service)
+ end)))
+ end)
+
+ test("Lookup local ipv6 address", function (print, p, expect, uv)
+ assert(uv.getnameinfo({
+ family = "inet6",
+ }, expect(function (err, hostname, service)
+ p{err=err,hostname=hostname,service=service}
+ assert(not err, err)
+ assert(hostname)
+ assert(service)
+ end)))
+ end)
+
+ test("Lookup local ::1 ipv6 address", function (print, p, expect, uv)
+ assert(uv.getnameinfo({
+ ip = "::1",
+ }, expect(function (err, hostname, service)
+ p{err=err,hostname=hostname,service=service}
+ assert(not err, err)
+ assert(hostname)
+ assert(service)
+ end)))
+ end)
+
+ test("Lookup local port 80 service", function (print, p, expect, uv)
+ assert(uv.getnameinfo({
+ port = 80,
+ family = "inet6",
+ }, expect(function (err, hostname, service)
+ p{err=err,hostname=hostname,service=service}
+ assert(not err, err)
+ assert(hostname)
+ assert(service == "http")
+ end)))
+ end)
+
+end)
diff --git a/3rdparty/luv/tests/test-fs.lua b/3rdparty/luv/tests/test-fs.lua
new file mode 100644
index 00000000000..4bfd67e6578
--- /dev/null
+++ b/3rdparty/luv/tests/test-fs.lua
@@ -0,0 +1,90 @@
+return require('lib/tap')(function (test)
+
+ test("read a file sync", function (print, p, expect, uv)
+ local fd = assert(uv.fs_open('README.md', 'r', tonumber('644', 8)))
+ p{fd=fd}
+ local stat = assert(uv.fs_fstat(fd))
+ p{stat=stat}
+ local chunk = assert(uv.fs_read(fd, stat.size, 0))
+ assert(#chunk == stat.size)
+ assert(uv.fs_close(fd))
+ end)
+
+ test("read a file async", function (print, p, expect, uv)
+ uv.fs_open('README.md', 'r', tonumber('644', 8), expect(function (err, fd)
+ assert(not err, err)
+ p{fd=fd}
+ uv.fs_fstat(fd, expect(function (err, stat)
+ assert(not err, err)
+ p{stat=stat}
+ uv.fs_read(fd, stat.size, 0, expect(function (err, chunk)
+ assert(not err, err)
+ p{chunk=#chunk}
+ assert(#chunk == stat.size)
+ uv.fs_close(fd, expect(function (err)
+ assert(not err, err)
+ end))
+ end))
+ end))
+ end))
+ end)
+
+ test("fs.write", function (print, p, expect, uv)
+ local path = "_test_"
+ local fd = assert(uv.fs_open(path, "w", 438))
+ uv.fs_write(fd, "Hello World\n", -1)
+ uv.fs_write(fd, {"with\n", "more\n", "lines\n"}, -1)
+ uv.fs_close(fd)
+ uv.fs_unlink(path)
+ end)
+
+ test("fs.stat sync", function (print, p, expect, uv)
+ local stat = assert(uv.fs_stat("README.md"))
+ assert(stat.size)
+ end)
+
+ test("fs.stat async", function (print, p, expect, uv)
+ assert(uv.fs_stat("README.md", expect(function (err, stat)
+ assert(not err, err)
+ assert(stat.size)
+ end)))
+ end)
+
+ test("fs.stat sync error", function (print, p, expect, uv)
+ local stat, err, code = uv.fs_stat("BAD_FILE!")
+ p{err=err,code=code,stat=stat}
+ assert(not stat)
+ assert(err)
+ assert(code == "ENOENT")
+ end)
+
+ test("fs.stat async error", function (print, p, expect, uv)
+ assert(uv.fs_stat("BAD_FILE@", expect(function (err, stat)
+ p{err=err,stat=stat}
+ assert(err)
+ assert(not stat)
+ end)))
+ end)
+
+ test("fs.scandir", function (print, p, expect, uv)
+ local req = uv.fs_scandir('.')
+ local function iter()
+ return uv.fs_scandir_next(req)
+ end
+ for name, ftype in iter do
+ p{name=name, ftype=ftype}
+ assert(name)
+ -- ftype is not available in all filesystems; for example it's
+ -- provided for HFS+ (OSX), NTFS (Windows) but not for ext4 (Linux).
+ end
+ end)
+
+ test("fs.realpath", function (print, p, expect, uv)
+ p(assert(uv.fs_realpath('.')))
+ assert(uv.fs_realpath('.', expect(function (err, path)
+ assert(not err, err)
+ p(path)
+ end)))
+ end)
+
+end)
diff --git a/3rdparty/luv/tests/test-leaks.lua b/3rdparty/luv/tests/test-leaks.lua
new file mode 100644
index 00000000000..06c6e49a0cf
--- /dev/null
+++ b/3rdparty/luv/tests/test-leaks.lua
@@ -0,0 +1,186 @@
+return require('lib/tap')(function (test)
+
+ local function bench(uv, p, count, fn)
+ collectgarbage()
+ local before
+ local notify = count / 8
+ for i = 1, count do
+ fn()
+ if i % notify == 0 then
+ uv.run()
+ collectgarbage()
+ local now = uv.resident_set_memory()
+ if not before then before = now end
+ p(i, now)
+ end
+ end
+ uv.run()
+ collectgarbage()
+ local after = uv.resident_set_memory()
+ p{
+ before = before,
+ after = after,
+ }
+ assert(after < before * 1.5)
+ end
+
+ test("fs-write", function (print, p, expect, uv)
+ bench(uv, p, 0x7000, function ()
+ local path = "_test_"
+ local fd = assert(uv.fs_open(path, "w", 438))
+ uv.fs_write(fd, "Hello World\n", -1)
+ uv.fs_write(fd, {"with\n", "more\n", "lines\n"}, -1)
+ uv.fs_close(fd)
+ uv.fs_unlink(path)
+ end)
+ end)
+
+ test("lots-o-timers", function (print, p, expect, uv)
+ bench(uv, p, 0x10000, function ()
+ local timer = uv.new_timer()
+ uv.close(timer)
+ end)
+ end)
+
+ test("lots-o-timers with canceled callbacks", function (print, p, expect, uv)
+ bench(uv, p, 0x10000, function ()
+ local timer = uv.new_timer()
+ uv.timer_start(timer, 100, 100, function ()
+ end)
+ uv.timer_stop(timer)
+ uv.close(timer, function ()
+ end)
+ uv.run()
+ end)
+ end)
+
+ test("lots-o-timers with real timeouts", function (print, p, expect, uv)
+ bench(uv, p, 0x500, function ()
+ local timer = uv.new_timer()
+ uv.timer_start(timer, 10, 0, expect(function ()
+ uv.timer_stop(timer)
+ uv.close(timer, function ()
+ end)
+ end))
+ end)
+ end)
+
+ test("reading file async", function (print, p, expect, uv)
+ local mode = tonumber("644", 8)
+ bench(uv, p, 0x500, function ()
+ local onOpen, onStat, onRead, onClose
+ local fd, stat
+
+ onOpen = expect(function (err, result)
+ assert(not err, err)
+ fd = result
+ uv.fs_fstat(fd, onStat)
+ end)
+
+ onStat = expect(function (err, result)
+ assert(not err, err)
+ stat = result
+ uv.fs_read(fd, stat.size, 0, onRead)
+ end)
+
+ onRead = expect(function (err, data)
+ assert(not err, err)
+ assert(#data == stat.size)
+ uv.fs_close(fd, onClose)
+ end)
+
+ onClose = expect(function (err)
+ assert(not err, err)
+ end)
+
+ assert(uv.fs_open("README.md", "r", mode, onOpen))
+ end)
+ end)
+
+ test("reading file sync", function (print, p, expect, uv)
+ local mode = tonumber("644", 8)
+ bench(uv, p, 0x2000, function ()
+ local fd = assert(uv.fs_open("README.md", "r", mode))
+ local stat = assert(uv.fs_fstat(fd))
+ local data = assert(uv.fs_read(fd, stat.size, 0))
+ assert(#data == stat.size)
+ assert(uv.fs_close(fd))
+ end)
+ end)
+
+ test("invalid file", function (print, p, expect, uv)
+ local mode = tonumber("644", 8)
+ bench(uv, p, 0x1500, function ()
+ local req = uv.fs_open("BAD_FILE", "r", mode, expect(function (err, fd)
+ assert(not fd)
+ assert(err)
+ end))
+ end)
+ end)
+
+ test("invalid file sync", function (print, p, expect, uv)
+ local mode = tonumber("644", 8)
+ bench(uv, p, 0x20000, function ()
+ local fd, err = uv.fs_open("BAD_FILE", "r", mode)
+ assert(not fd)
+ assert(err)
+ end)
+ end)
+
+ test("invalid spawn args", function (print, p, expect, uv)
+ -- Regression test for #73
+ bench(uv, p, 0x10000, function ()
+ local ret, err = pcall(function ()
+ return uv.spawn("ls", {
+ args = {"-l", "-h"},
+ stdio = {0, 1, 2},
+ env = {"EXTRA=true"},
+ gid = false, -- Should be integer
+ })
+ end)
+ assert(not ret)
+ assert(err)
+ end)
+ end)
+
+ test("stream writing with string and array", function (print, p, expect, uv)
+ local port = 0
+ local server = uv.new_tcp()
+ local data
+ local count = 0x800
+ server:unref()
+ server:bind("127.0.0.1", port)
+ server:listen(128, expect(function (err)
+ assert(not err, err)
+ local client = uv.new_tcp()
+ server:accept(client)
+ client:write(data)
+ client:read_start(expect(function (err, data)
+ assert(not err, err)
+ assert(data)
+ client:close()
+ end))
+ end, count))
+ local address = server:getsockname()
+ bench(uv, p, count, function ()
+ data = string.rep("Hello", 500)
+ local socket = uv.new_tcp()
+ socket:connect(address.ip, address.port, expect(function (err)
+ assert(not err, err)
+ socket:read_start(expect(function (err, chunk)
+ assert(not err, err)
+ assert(chunk)
+ local data = {}
+ for i = 0, 100 do
+ data[i + 1] = string.rep(string.char(i), 100)
+ end
+ socket:write(data)
+ socket:close()
+ end))
+ end))
+ uv.run()
+ end)
+ server:close()
+ end)
+
+end)
diff --git a/3rdparty/luv/tests/test-misc.lua b/3rdparty/luv/tests/test-misc.lua
new file mode 100644
index 00000000000..72a7b30785e
--- /dev/null
+++ b/3rdparty/luv/tests/test-misc.lua
@@ -0,0 +1,85 @@
+return require('lib/tap')(function (test)
+
+ test("uv.guess_handle", function (print, p, expect, uv)
+ local types = {
+ [0] = assert(uv.guess_handle(0)),
+ assert(uv.guess_handle(1)),
+ assert(uv.guess_handle(2)),
+ }
+ p("stdio fd types", types)
+ end)
+
+ test("uv.version and uv.version_string", function (print, p, expect, uv)
+ local version = assert(uv.version())
+ local version_string = assert(uv.version_string())
+ p{version=version, version_string=version_string}
+ assert(type(version) == "number")
+ assert(type(version_string) == "string")
+ end)
+
+ test("memory size", function (print, p, expect, uv)
+ local rss = uv.resident_set_memory()
+ local total = uv.get_total_memory()
+ local free = uv.get_free_memory()
+ p{rss=rss,total=total,free=free}
+ assert(rss < total)
+ end)
+
+ test("uv.uptime", function (print, p, expect, uv)
+ local uptime = assert(uv.uptime())
+ p{uptime=uptime}
+ end)
+
+ test("uv.getrusage", function (print, p, expect, uv)
+ local rusage = assert(uv.getrusage())
+ p(rusage)
+ end)
+
+ test("uv.cpu_info", function (print, p, expect, uv)
+ local info = assert(uv.cpu_info())
+ p(info)
+ end)
+
+ test("uv.interface_addresses", function (print, p, expect, uv)
+ local addresses = assert(uv.interface_addresses())
+ for name, info in pairs(addresses) do
+ p(name, addresses[name])
+ end
+ end)
+
+ test("uv.loadavg", function (print, p, expect, uv)
+ local avg = {assert(uv.loadavg())}
+ p(avg)
+ assert(#avg == 3)
+ end)
+
+ test("uv.exepath", function (print, p, expect, uv)
+ local path = assert(uv.exepath())
+ p(path)
+ end)
+
+ test("uv.os_homedir", function (print, p, expect, uv)
+ local path = assert(uv.os_homedir())
+ p(path)
+ end)
+
+ test("uv.cwd and uv.chdir", function (print, p, expect, uv)
+ local old = assert(uv.cwd())
+ p(old)
+ assert(uv.chdir("/"))
+ local cwd = assert(uv.cwd())
+ p(cwd)
+ assert(cwd ~= old)
+ assert(uv.chdir(old))
+ end)
+
+ test("uv.hrtime", function (print, p, expect, uv)
+ local time = assert(uv.hrtime())
+ p(time)
+ end)
+
+ test("test_getpid", function (print, p, expect, uv)
+ assert(uv.getpid())
+ end)
+
+end)
diff --git a/3rdparty/luv/tests/test-prepare-check-idle-async.lua b/3rdparty/luv/tests/test-prepare-check-idle-async.lua
new file mode 100644
index 00000000000..389c2633efb
--- /dev/null
+++ b/3rdparty/luv/tests/test-prepare-check-idle-async.lua
@@ -0,0 +1,49 @@
+return require('lib/tap')(function (test)
+
+ test("simple prepare", function (print, p, expect, uv)
+ local prepare = uv.new_prepare()
+ uv.prepare_start(prepare, expect(function ()
+ p("prepare", prepare)
+ uv.prepare_stop(prepare)
+ uv.close(prepare, expect(function ()
+ end))
+ end))
+ end)
+
+ test("simple check", function (print, p, expect, uv)
+ local check = uv.new_check()
+ uv.check_start(check, expect(function ()
+ p("check", check)
+ uv.check_stop(check)
+ uv.close(check, expect(function ()
+ end))
+ end))
+
+ -- Trigger with a timer
+ local timer = uv.new_timer()
+ uv.timer_start(timer, 10, 0, expect(function()
+ p("timeout", timer)
+ uv.timer_stop(timer)
+ uv.close(timer)
+ end))
+ end)
+
+ test("simple idle", function (print, p, expect, uv)
+ local idle = uv.new_idle()
+ uv.idle_start(idle, expect(function ()
+ p("idle", idle)
+ uv.idle_stop(idle)
+ uv.close(idle, expect(function ()
+ end))
+ end))
+ end)
+
+ test("simple async", function (print, p, expect, uv)
+ local async
+ async = uv.new_async(expect(function ()
+ uv.close(async)
+ end))
+ uv.async_send(async)
+ end)
+
+end)
diff --git a/3rdparty/luv/tests/test-process.lua b/3rdparty/luv/tests/test-process.lua
new file mode 100644
index 00000000000..4d2b6fbfdab
--- /dev/null
+++ b/3rdparty/luv/tests/test-process.lua
@@ -0,0 +1,101 @@
+return require('lib/tap')(function (test)
+
+ test("test disable_stdio_inheritance", function (print, p, expect, uv)
+ uv.disable_stdio_inheritance()
+ end)
+
+ test("process stdout", function (print, p, expect, uv)
+ local stdout = uv.new_pipe(false)
+
+ local handle, pid
+ handle, pid = uv.spawn(uv.exepath(), {
+ args = {"-e", "print 'Hello World'"},
+ stdio = {nil, stdout},
+ }, expect(function (code, signal)
+ p("exit", {code=code, signal=signal})
+ uv.close(handle)
+ end))
+
+ p{
+ handle=handle,
+ pid=pid
+ }
+
+ uv.read_start(stdout, expect(function (err, chunk)
+ p("stdout", {err=err,chunk=chunk})
+ assert(not err, err)
+ uv.close(stdout)
+ end))
+
+ end)
+
+ if _G.isWindows then return end
+
+ test("spawn and kill by pid", function (print, p, expect, uv)
+ local handle, pid
+ handle, pid = uv.spawn("sleep", {
+ args = {1},
+ }, expect(function (status, signal)
+ p("exit", handle, {status=status,signal=signal})
+ assert(status == 0)
+ assert(signal == 2)
+ uv.close(handle)
+ end))
+ p{handle=handle,pid=pid}
+ uv.kill(pid, "sigint")
+ end)
+
+ test("spawn and kill by handle", function (print, p, expect, uv)
+ local handle, pid
+ handle, pid = uv.spawn("sleep", {
+ args = {1},
+ }, expect(function (status, signal)
+ p("exit", handle, {status=status,signal=signal})
+ assert(status == 0)
+ assert(signal == 15)
+ uv.close(handle)
+ end))
+ p{handle=handle,pid=pid}
+ uv.process_kill(handle, "sigterm")
+ end)
+
+ test("invalid command", function (print, p, expect, uv)
+ local handle, err
+ handle, err = uv.spawn("ksjdfksjdflkjsflksdf", {}, function(exit, code)
+ assert(false)
+ end)
+ assert(handle == nil)
+ assert(err)
+ end)
+
+ test("process stdio", function (print, p, expect, uv)
+ local stdin = uv.new_pipe(false)
+ local stdout = uv.new_pipe(false)
+
+ local handle, pid
+ handle, pid = uv.spawn("cat", {
+ stdio = {stdin, stdout},
+ }, expect(function (code, signal)
+ p("exit", {code=code, signal=signal})
+ uv.close(handle)
+ end))
+
+ p{
+ handle=handle,
+ pid=pid
+ }
+
+ uv.read_start(stdout, expect(function (err, chunk)
+ p("stdout", {err=err,chunk=chunk})
+ assert(not err, err)
+ uv.close(stdout)
+ end))
+
+ uv.write(stdin, "Hello World")
+ uv.shutdown(stdin, expect(function ()
+ uv.close(stdin)
+ end))
+
+ end)
+
+end)
diff --git a/3rdparty/luv/tests/test-sigchld-after-lua_close.sh b/3rdparty/luv/tests/test-sigchld-after-lua_close.sh
new file mode 100644
index 00000000000..e7d22d3df36
--- /dev/null
+++ b/3rdparty/luv/tests/test-sigchld-after-lua_close.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+# Verifies that luv will cleanup libuv process handles correctly even if
+# not done by "userspace".
+# Details: https://github.com/luvit/luv/issues/193
+
+# This test modifies one of the examples to skip libuv process cleanup,
+# purposely making it leave SIGCHLD signal handler.
+#
+patch -p1 << "EOF"
+diff --git a/examples/talking-to-children.lua b/examples/talking-to-children.lua
+index 10a53ef..6c6c53f 100644
+--- a/examples/talking-to-children.lua
++++ b/examples/talking-to-children.lua
+@@ -41,7 +41,3 @@ uv.read_start(stdout, onread)
+ uv.read_start(stderr, onread)
+ uv.write(stdin, "Hello World")
+ uv.shutdown(stdin, onshutdown)
+-
+-uv.run()
+-uv.walk(uv.close)
+-uv.run()
+EOF
+
+# It also requires a patched lua standalone interpreter that sends SIGCHLD to
+# itself after calling lua_close, which would have freed all memory of the libuv
+# event loop associated with the lua state.
+(
+cd deps/lua
+patch -p1 << "EOF"
+diff --git a/src/lua.c b/src/lua.c
+index 7a47582..4dc19d5 100644
+--- a/src/lua.c
++++ b/src/lua.c
+@@ -608,6 +608,7 @@ int main (int argc, char **argv) {
+ result = lua_toboolean(L, -1); /* get result */
+ report(L, status);
+ lua_close(L);
++ kill(0, SIGCHLD);
+ return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
+ }
+EOF
+)
+
+WITH_LUA_ENGINE=Lua make
+./build/lua examples/talking-to-children.lua
diff --git a/3rdparty/luv/tests/test-signal.lua b/3rdparty/luv/tests/test-signal.lua
new file mode 100644
index 00000000000..c05db77c888
--- /dev/null
+++ b/3rdparty/luv/tests/test-signal.lua
@@ -0,0 +1,40 @@
+local child_code = string.dump(function ()
+ local uv = require('luv')
+ local signal = uv.new_signal()
+ uv.ref(signal)
+ uv.signal_start(signal, "sigint", function ()
+ uv.unref(signal)
+ end)
+ uv.run()
+ os.exit(7)
+end)
+
+return require('lib/tap')(function (test)
+
+ if _G.isWindows then return end
+
+ test("Catch SIGINT", function (print, p, expect, uv)
+ local child, pid
+ local input = uv.new_pipe(false)
+ child, pid = assert(uv.spawn(uv.exepath(), {
+ args = {"-"},
+ -- cwd = uv.cwd(),
+ stdio = {input,1,2}
+ }, expect(function (code, signal)
+ p("exit", {pid=pid,code=code,signal=signal})
+ assert(code == 7)
+ assert(signal == 0)
+ uv.close(input)
+ uv.close(child)
+ end)))
+ uv.write(input, child_code)
+ uv.shutdown(input)
+ local timer = uv.new_timer()
+ uv.timer_start(timer, 200, 0, expect(function ()
+ print("Sending child SIGINT")
+ uv.process_kill(child, "sigint")
+ uv.close(timer)
+ end))
+ end)
+
+end)
diff --git a/3rdparty/luv/tests/test-tcp.lua b/3rdparty/luv/tests/test-tcp.lua
new file mode 100644
index 00000000000..885d381ebce
--- /dev/null
+++ b/3rdparty/luv/tests/test-tcp.lua
@@ -0,0 +1,114 @@
+return require('lib/tap')(function (test)
+ test("basic tcp server and client", function (print, p, expect, uv)
+ local server = uv.new_tcp()
+ uv.tcp_bind(server, "::", 0)
+ uv.listen(server, 128, expect(function (err)
+ p("server on connection", server)
+ assert(not err, err)
+ uv.close(server)
+ end))
+
+ local address = uv.tcp_getsockname(server)
+ p{server=server,address=address}
+
+ local client = uv.new_tcp()
+ local req = uv.tcp_connect(client, "::1", address.port, expect(function (err)
+ p("client on connect", client, err)
+ assert(not err, err)
+ uv.shutdown(client, expect(function (err)
+ p("client on shutdown", client, err)
+ assert(not err, err)
+ uv.close(client, expect(function ()
+ p("client on close", client)
+ end))
+ end))
+ end))
+ p{client=client,req=req}
+ end)
+
+ test("tcp echo server and client", function (print, p, expect, uv)
+ local server = uv.new_tcp()
+ assert(uv.tcp_bind(server, "127.0.0.1", 0))
+ assert(uv.listen(server, 1, expect(function ()
+ local client = uv.new_tcp()
+ assert(uv.accept(server, client))
+ assert(uv.read_start(client, expect(function (err, data)
+ p("server read", {err=err,data=data})
+ assert(not err, err)
+ if data then
+ assert(uv.write(client, data))
+ else
+ assert(uv.read_stop(client))
+ uv.close(client)
+ uv.close(server)
+ end
+ end, 2)))
+ end)))
+
+ local address = uv.tcp_getsockname(server)
+ p{server=server,address=address}
+
+ local socket = assert(uv.new_tcp())
+ assert(uv.tcp_connect(socket, "127.0.0.1", address.port, expect(function ()
+ assert(uv.read_start(socket, expect(function (err, data)
+ p("client read", {err=err,data=data})
+ assert(not err, err)
+ assert(uv.read_stop(socket))
+ uv.close(socket)
+ end)))
+ local req = assert(uv.write(socket, "Hello", function (err)
+ p("client onwrite", socket, err)
+ assert(not err, err)
+ end))
+ p{socket=socket,req=req}
+ end)))
+ end)
+
+ test("tcp echo server and client with methods", function (print, p, expect, uv)
+ local server = uv.new_tcp()
+ assert(server:bind("127.0.0.1", 0))
+ assert(server:listen(1, expect(function ()
+ local client = uv.new_tcp()
+ assert(server:accept(client))
+ assert(client:read_start(expect(function (err, data)
+ p("server read", {err=err,data=data})
+ assert(not err, err)
+ if data then
+ assert(client:write(data))
+ else
+ assert(client:read_stop())
+ client:close()
+ server:close()
+ end
+ end, 2)))
+ end)))
+
+ local address = server:getsockname()
+ p{server=server,address=address}
+
+ local socket = assert(uv.new_tcp())
+ assert(socket:connect("127.0.0.1", address.port, expect(function ()
+ assert(socket:read_start(expect(function (err, data)
+ p("client read", {err=err,data=data})
+ assert(not err, err)
+ assert(socket:read_stop())
+ socket:close()
+ end)))
+ local req = assert(socket:write("Hello", function (err)
+ p("client onwrite", socket, err)
+ assert(not err, err)
+ end))
+ p{socket=socket,req=req}
+ end)))
+ end)
+
+ test("tcp invalid ip address", function (print, p, expect, uv)
+ local ip = '127.0.0.100005'
+ local server = uv.new_tcp()
+ local status, err = pcall(function() uv.tcp_bind(server, ip, 1000) end)
+ assert(not status)
+ p(err)
+ assert(err:find(ip))
+ uv.close(server)
+ end)
+end)
diff --git a/3rdparty/luv/tests/test-thread.lua b/3rdparty/luv/tests/test-thread.lua
new file mode 100644
index 00000000000..838b51e4fff
--- /dev/null
+++ b/3rdparty/luv/tests/test-thread.lua
@@ -0,0 +1,47 @@
+return require('lib/tap')(function (test)
+
+ test("test thread create", function(print, p, expect, uv)
+ local delay = 1000
+ local before = os.time()
+ local thread = uv.new_thread(function(delay)
+ require('luv').sleep(delay)
+ end,delay)
+ uv.thread_join(thread)
+ local elapsed = (os.time() - before) * 1000
+ p({
+ delay = delay,
+ elapsed = elapsed
+ })
+ assert(elapsed >= delay, "elapsed should be at least delay ")
+ end)
+
+ test("test thread create with arguments", function(print, p, expect, uv)
+ local before = os.time()
+ local args = {500, 'string', nil, false, 5, "helloworld"}
+ local unpack = unpack or table.unpack
+ uv.new_thread(function(num,s,null,bool,five,hw)
+ assert(type(num) == "number")
+ assert(type(s) == "string")
+ assert(null == nil)
+ assert(bool == false)
+ assert(five == 5)
+ assert(hw == 'helloworld')
+ require('luv').sleep(1000)
+ end, unpack(args)):join()
+ local elapsed = (os.time() - before) * 1000
+ assert(elapsed >= 1000, "elapsed should be at least delay ")
+ end)
+
+ test("test thread sleep msecs in main thread", function(print, p, expect, uv)
+ local delay = 1000
+ local before = os.time()
+ uv.sleep(delay)
+ local elapsed = (os.time() - before) * 1000
+ p({
+ delay = delay,
+ elapsed = elapsed
+ })
+ assert(elapsed >= delay, "elapsed should be at least delay ")
+ end)
+
+end)
diff --git a/3rdparty/luv/tests/test-timer.lua b/3rdparty/luv/tests/test-timer.lua
new file mode 100644
index 00000000000..f9eb9d89c5f
--- /dev/null
+++ b/3rdparty/luv/tests/test-timer.lua
@@ -0,0 +1,87 @@
+return require('lib/tap')(function (test)
+
+ -- This tests using timers for a simple timeout.
+ -- It also tests the handle close callback and
+ test("simple timeout", function (print, p, expect, uv)
+ local timer = uv.new_timer()
+ local function onclose()
+ p("closed", timer)
+ end
+ local function ontimeout()
+ p("timeout", timer)
+ uv.close(timer, expect(onclose))
+ end
+ uv.timer_start(timer, 10, 0, expect(ontimeout))
+ end)
+
+ -- This is like the previous test, but using repeat.
+ test("simple interval", function (print, p, expect, uv)
+ local timer = uv.new_timer()
+ local count = 3
+ local onclose = expect(function ()
+ p("closed", timer)
+ end)
+ local function oninterval()
+ p("interval", timer)
+ count = count - 1
+ if count == 0 then
+ uv.close(timer, onclose)
+ end
+ end
+ uv.timer_start(timer, 10, 10, oninterval)
+ end)
+
+ -- Test two concurrent timers
+ -- There is a small race condition, but there are 100ms of wiggle room.
+ -- 400ms is halfway between 100+200ms and 100+400ms
+ test("timeout with interval", function (print, p, expect, uv)
+ local a = uv.new_timer()
+ local b = uv.new_timer()
+ uv.timer_start(a, 400, 0, expect(function ()
+ p("timeout", a)
+ uv.timer_stop(b)
+ uv.close(a)
+ uv.close(b)
+ end))
+ uv.timer_start(b, 100, 200, expect(function ()
+ p("interval", b)
+ end, 2))
+ end)
+
+ -- This advanced test uses the rest of the uv_timer_t functions
+ -- to create an interval that shrinks over time.
+ test("shrinking interval", function (print, p, expect, uv)
+ local timer = uv.new_timer()
+ uv.timer_start(timer, 10, 0, expect(function ()
+ local r = uv.timer_get_repeat(timer)
+ p("interval", timer, r)
+ if r == 0 then
+ uv.timer_set_repeat(timer, 8)
+ uv.timer_again(timer)
+ elseif r == 2 then
+ uv.timer_stop(timer)
+ uv.close(timer)
+ else
+ uv.timer_set_repeat(timer, r / 2)
+ end
+ end, 4))
+ end)
+
+ test("shrinking interval using methods", function (print, p, expect, uv)
+ local timer = uv.new_timer()
+ timer:start(10, 0, expect(function ()
+ local r = timer:get_repeat()
+ p("interval", timer, r)
+ if r == 0 then
+ timer:set_repeat(8)
+ timer:again()
+ elseif r == 2 then
+ timer:stop()
+ timer:close()
+ else
+ timer:set_repeat(r / 2)
+ end
+ end, 4))
+ end)
+
+end)
diff --git a/3rdparty/luv/tests/test-work.lua b/3rdparty/luv/tests/test-work.lua
new file mode 100644
index 00000000000..3a98b15e6bc
--- /dev/null
+++ b/3rdparty/luv/tests/test-work.lua
@@ -0,0 +1,48 @@
+return require('lib/tap')(function (test)
+ test("test threadpool", function(print,p,expect,_uv)
+ p('Please be patient, the test cost a lots of time')
+ local count = 1000 --for memleaks dected
+ local step = 0
+ local ctx
+ ctx = _uv.new_work(
+ function(n,s) --work,in threadpool
+ local uv = require('luv')
+ local t = uv.thread_self()
+ uv.sleep(100)
+ return n,n*n, tostring(uv.thread_self()),s
+ end,
+ function(n,r,id, s)
+ assert(n*n==r)
+ if step < count then
+ _uv.queue_work(ctx,n,s)
+ step = step + 1
+ if (step % 100==0) then
+ p(string.format('run %d%%', math.floor(step*100/count)))
+ end
+ end
+ end --after work, in loop thread
+ )
+ local ls = string.rep('-',4096)
+
+ _uv.queue_work(ctx,2,ls)
+ _uv.queue_work(ctx,4,ls)
+ _uv.queue_work(ctx,6,ls)
+ _uv.queue_work(ctx,-2,ls)
+ _uv.queue_work(ctx,-11,ls)
+ _uv.queue_work(ctx,2,ls)
+ _uv.queue_work(ctx,4,ls)
+ _uv.queue_work(ctx,6,ls)
+ _uv.queue_work(ctx,-2,ls)
+ _uv.queue_work(ctx,-11,ls)
+ _uv.queue_work(ctx,2,ls)
+ _uv.queue_work(ctx,4,ls)
+ _uv.queue_work(ctx,6,ls)
+ _uv.queue_work(ctx,-2,ls)
+ _uv.queue_work(ctx,-11,ls)
+ _uv.queue_work(ctx,2,ls)
+ _uv.queue_work(ctx,4,ls)
+ _uv.queue_work(ctx,6,ls)
+ _uv.queue_work(ctx,-2,ls)
+ _uv.queue_work(ctx,-11,ls)
+ end)
+end)
diff --git a/3rdparty/rapidjson/.gitignore b/3rdparty/rapidjson/.gitignore
new file mode 100644
index 00000000000..2c412c2bba9
--- /dev/null
+++ b/3rdparty/rapidjson/.gitignore
@@ -0,0 +1,24 @@
+/bin/*
+!/bin/data
+!/bin/encodings
+!/bin/jsonchecker
+!/bin/types
+/build
+/doc/html
+/doc/doxygen_*.db
+*.a
+
+# Temporary files created during CMake build
+CMakeCache.txt
+CMakeFiles
+cmake_install.cmake
+CTestTestfile.cmake
+Makefile
+RapidJSON*.cmake
+RapidJSON.pc
+Testing
+/googletest
+install_manifest.txt
+Doxyfile
+DartConfiguration.tcl
+*.nupkg
diff --git a/3rdparty/rapidjson/.gitmodules b/3rdparty/rapidjson/.gitmodules
new file mode 100644
index 00000000000..8e9d1f376c2
--- /dev/null
+++ b/3rdparty/rapidjson/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "thirdparty/gtest"]
+ path = thirdparty/gtest
+ url = https://chromium.googlesource.com/external/googletest.git
diff --git a/3rdparty/rapidjson/.travis.yml b/3rdparty/rapidjson/.travis.yml
new file mode 100644
index 00000000000..78fe1d54615
--- /dev/null
+++ b/3rdparty/rapidjson/.travis.yml
@@ -0,0 +1,54 @@
+language: cpp
+
+compiler:
+ - clang
+ - gcc
+
+env:
+ matrix:
+ - CONF=debug ARCH=x86_64 CXX11=ON
+ - CONF=release ARCH=x86_64 CXX11=ON
+ - CONF=debug ARCH=x86 CXX11=ON
+ - CONF=release ARCH=x86 CXX11=ON
+ - CONF=debug ARCH=x86_64 CXX11=OFF
+ - CONF=debug ARCH=x86 CXX11=OFF
+ global:
+ - ARCH_FLAGS_x86='-m32' # #266: don't use SSE on 32-bit
+ - ARCH_FLAGS_x86_64='-msse4.2' # use SSE4.2 on 64-bit
+ - GITHUB_REPO='miloyip/rapidjson'
+ - secure: "HrsaCb+N66EG1HR+LWH1u51SjaJyRwJEDzqJGYMB7LJ/bfqb9mWKF1fLvZGk46W5t7TVaXRDD5KHFx9DPWvKn4gRUVkwTHEy262ah5ORh8M6n/6VVVajeV/AYt2C0sswdkDBDO4Xq+xy5gdw3G8s1A4Inbm73pUh+6vx+7ltBbk="
+
+before_install:
+ - sudo apt-get update -qq
+ - sudo apt-get install -qq cmake valgrind
+ - sudo apt-get --no-install-recommends install doxygen # Don't install LaTeX stuffs
+ - if [ "$ARCH" = "x86" ]; then sudo apt-get install -qq g++-multilib libc6-dbg:i386; fi
+ - if [ "$CC" = "gcc" ] && [ "$CONF" = "debug" ]; then sudo pip install cpp-coveralls; export GCOV_FLAGS='--coverage'; fi
+
+install: true
+
+before_script:
+# hack to avoid Valgrind bug (https://bugs.kde.org/show_bug.cgi?id=326469),
+# exposed by merging PR#163 (using -march=native)
+ - sed -i "s/-march=native//" CMakeLists.txt
+ - mkdir build
+ - >
+ eval "ARCH_FLAGS=\${ARCH_FLAGS_${ARCH}}" ;
+ (cd build && cmake
+ -DRAPIDJSON_HAS_STDSTRING=ON
+ -DRAPIDJSON_BUILD_CXX11=$CXX11
+ -DCMAKE_VERBOSE_MAKEFILE=ON
+ -DCMAKE_BUILD_TYPE=$CONF
+ -DCMAKE_CXX_FLAGS="$ARCH_FLAGS $GCOV_FLAGS"
+ -DCMAKE_EXE_LINKER_FLAGS=$GCOV_FLAGS
+ ..)
+
+script:
+ - cd build
+ - make tests
+ - make examples
+ - ctest -V `[ "$CONF" = "release" ] || echo "-E perftest"`
+ - make travis_doc
+
+after_success:
+ - coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h
diff --git a/3rdparty/rapidjson/CHANGELOG.md b/3rdparty/rapidjson/CHANGELOG.md
new file mode 100644
index 00000000000..8ad9b3c351f
--- /dev/null
+++ b/3rdparty/rapidjson/CHANGELOG.md
@@ -0,0 +1,79 @@
+# Change Log
+All notable changes to this project will be documented in this file.
+This project adheres to [Semantic Versioning](http://semver.org/).
+
+## [Unreleased]
+
+## [1.0.2] - 2015-05-14
+
+### Added
+* Add Value::XXXMember(...) overloads for std::string (#335)
+
+### Fixed
+* Include rapidjson.h for all internal/error headers.
+* Parsing some numbers incorrectly in full-precision mode (`kFullPrecisionParseFlag`) (#342)
+* Fix alignment of 64bit platforms (#328)
+* Fix MemoryPoolAllocator::Clear() to clear user-buffer (0691502573f1afd3341073dd24b12c3db20fbde4)
+
+### Changed
+* CMakeLists for include as a thirdparty in projects (#334, #337)
+* Change Document::ParseStream() to use stack allocator for Reader (ffbe38614732af8e0b3abdc8b50071f386a4a685)
+
+## [1.0.1] - 2015-04-25
+
+### Added
+* Changelog following [Keep a CHANGELOG](https://github.com/olivierlacan/keep-a-changelog) suggestions.
+
+### Fixed
+* Parsing of some numbers (e.g. "1e-00011111111111") causing assertion (#314).
+* Visual C++ 32-bit compilation error in `diyfp.h` (#317).
+
+## [1.0.0] - 2015-04-22
+
+### Added
+* 100% [Coverall](https://coveralls.io/r/miloyip/rapidjson?branch=master) coverage.
+* Version macros (#311)
+
+### Fixed
+* A bug in trimming long number sequence (4824f12efbf01af72b8cb6fc96fae7b097b73015).
+* Double quote in unicode escape (#288).
+* Negative zero roundtrip (double only) (#289).
+* Standardize behavior of `memcpy()` and `malloc()` (0c5c1538dcfc7f160e5a4aa208ddf092c787be5a, #305, 0e8bbe5e3ef375e7f052f556878be0bd79e9062d).
+
+### Removed
+* Remove an invalid `Document::ParseInsitu()` API (e7f1c6dd08b522cfcf9aed58a333bd9a0c0ccbeb).
+
+## 1.0-beta - 2015-04-8
+
+### Added
+* RFC 7159 (#101)
+* Optional Iterative Parser (#76)
+* Deep-copy values (#20)
+* Error code and message (#27)
+* ASCII Encoding (#70)
+* `kParseStopWhenDoneFlag` (#83)
+* `kParseFullPrecisionFlag` (881c91d696f06b7f302af6d04ec14dd08db66ceb)
+* Add `Key()` to handler concept (#134)
+* C++11 compatibility and support (#128)
+* Optimized number-to-string and vice versa conversions (#137, #80)
+* Short-String Optimization (#131)
+* Local stream optimization by traits (#32)
+* Travis & Appveyor Continuous Integration, with Valgrind verification (#24, #242)
+* Redo all documentation (English, Simplified Chinese)
+
+### Changed
+* Copyright ownership transfered to THL A29 Limited (a Tencent company).
+* Migrating from Premake to CMAKE (#192)
+* Resolve all warning reports
+
+### Removed
+* Remove other JSON libraries for performance comparison (#180)
+
+## 0.11 - 2012-11-16
+
+## 0.1 - 2011-11-18
+
+[Unreleased]: https://github.com/miloyip/rapidjson/compare/v1.0.2...HEAD
+[1.0.2]: https://github.com/miloyip/rapidjson/compare/v1.0.1...v1.0.2
+[1.0.1]: https://github.com/miloyip/rapidjson/compare/v1.0.0...v1.0.1
+[1.0.0]: https://github.com/miloyip/rapidjson/compare/v1.0-beta...v1.0.0
diff --git a/3rdparty/rapidjson/CMakeLists.txt b/3rdparty/rapidjson/CMakeLists.txt
new file mode 100644
index 00000000000..fcacbd3c5ec
--- /dev/null
+++ b/3rdparty/rapidjson/CMakeLists.txt
@@ -0,0 +1,128 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules)
+
+PROJECT(RapidJSON CXX)
+
+set(LIB_MAJOR_VERSION "1")
+set(LIB_MINOR_VERSION "0")
+set(LIB_PATCH_VERSION "2")
+set(LIB_VERSION_STRING "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_PATCH_VERSION}")
+
+# compile in release with debug info mode by default
+if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
+endif()
+
+# Build all binaries in a separate directory
+SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+
+option(RAPIDJSON_BUILD_DOC "Build rapidjson documentation." ON)
+option(RAPIDJSON_BUILD_EXAMPLES "Build rapidjson examples." ON)
+option(RAPIDJSON_BUILD_TESTS "Build rapidjson perftests and unittests." ON)
+option(RAPIDJSON_BUILD_THIRDPARTY_GTEST
+ "Use gtest installation in `thirdparty/gtest` by default if available" OFF)
+
+option(RAPIDJSON_BUILD_CXX11 "Build rapidjson with C++11 (gcc/clang)" ON)
+
+option(RAPIDJSON_HAS_STDSTRING "" OFF)
+if(RAPIDJSON_HAS_STDSTRING)
+ add_definitions(-DRAPIDJSON_HAS_STDSTRING)
+endif()
+
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror")
+ if (RAPIDJSON_BUILD_CXX11)
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.7.0")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
+ else()
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+ endif()
+ endif()
+elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -Wextra -Werror -Wno-missing-field-initializers")
+ if (RAPIDJSON_BUILD_CXX11)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+ endif()
+elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
+endif()
+
+#add extra search paths for libraries and includes
+SET(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "The directory the headers are installed in")
+SET(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE STRING "Directory where lib will install")
+SET(DOC_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/share/doc/${PROJECT_NAME}" CACHE PATH "Path to the documentation")
+
+IF(UNIX OR CYGWIN)
+ SET(_CMAKE_INSTALL_DIR "${LIB_INSTALL_DIR}/cmake/${PROJECT_NAME}")
+ELSEIF(WIN32)
+ SET(_CMAKE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/cmake")
+ENDIF()
+SET(CMAKE_INSTALL_DIR "${_CMAKE_INSTALL_DIR}" CACHE PATH "The directory cmake fiels are installed in")
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
+
+if(RAPIDJSON_BUILD_DOC)
+ add_subdirectory(doc)
+endif()
+
+add_custom_target(travis_doc)
+add_custom_command(TARGET travis_doc
+ COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/travis-doxygen.sh)
+
+if(RAPIDJSON_BUILD_EXAMPLES)
+ add_subdirectory(example)
+endif()
+
+if(RAPIDJSON_BUILD_TESTS)
+ if(MSVC11)
+ # required for VS2012 due to missing support for variadic templates
+ add_definitions(-D_VARIADIC_MAX=10)
+ endif(MSVC11)
+ add_subdirectory(test)
+ include(CTest)
+endif()
+
+# pkg-config
+IF (UNIX OR CYGWIN)
+ CONFIGURE_FILE (${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pc.in
+ ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc
+ @ONLY)
+ INSTALL (FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc
+ DESTINATION "${LIB_INSTALL_DIR}/pkgconfig"
+ COMPONENT pkgconfig)
+ENDIF()
+
+install(FILES readme.md
+ DESTINATION "${DOC_INSTALL_DIR}"
+ COMPONENT doc)
+
+install(DIRECTORY include/rapidjson
+ DESTINATION "${INCLUDE_INSTALL_DIR}"
+ COMPONENT dev)
+
+install(DIRECTORY example/
+ DESTINATION "${DOC_INSTALL_DIR}/examples"
+ COMPONENT examples
+ # Following patterns are for excluding the intermediate/object files
+ # from an install of in-source CMake build.
+ PATTERN "CMakeFiles" EXCLUDE
+ PATTERN "Makefile" EXCLUDE
+ PATTERN "cmake_install.cmake" EXCLUDE)
+
+# Provide config and version files to be used by other applications
+# ===============================
+
+export(PACKAGE ${PROJECT_NAME})
+
+# cmake-modules
+CONFIGURE_FILE(${PROJECT_NAME}Config.cmake.in
+ ${PROJECT_NAME}Config.cmake
+ @ONLY)
+CONFIGURE_FILE(${PROJECT_NAME}ConfigVersion.cmake.in
+ ${PROJECT_NAME}ConfigVersion.cmake
+ @ONLY)
+INSTALL(FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
+ DESTINATION "${CMAKE_INSTALL_DIR}"
+ COMPONENT dev)
diff --git a/3rdparty/rapidjson/CMakeModules/FindGTestSrc.cmake b/3rdparty/rapidjson/CMakeModules/FindGTestSrc.cmake
new file mode 100644
index 00000000000..f942a8dafcd
--- /dev/null
+++ b/3rdparty/rapidjson/CMakeModules/FindGTestSrc.cmake
@@ -0,0 +1,30 @@
+
+SET(GTEST_SEARCH_PATH
+ "${GTEST_SOURCE_DIR}"
+ "${CMAKE_CURRENT_LIST_DIR}/../thirdparty/gtest")
+
+IF(UNIX)
+ IF(RAPIDJSON_BUILD_THIRDPARTY_GTEST)
+ LIST(APPEND GTEST_SEARCH_PATH "/usr/src/gtest")
+ ELSE()
+ LIST(INSERT GTEST_SEARCH_PATH 1 "/usr/src/gtest")
+ ENDIF()
+ENDIF()
+
+FIND_PATH(GTEST_SOURCE_DIR
+ NAMES CMakeLists.txt src/gtest_main.cc
+ PATHS ${GTEST_SEARCH_PATH})
+
+
+# Debian installs gtest include directory in /usr/include, thus need to look
+# for include directory separately from source directory.
+FIND_PATH(GTEST_INCLUDE_DIR
+ NAMES gtest/gtest.h
+ PATH_SUFFIXES include
+ HINTS ${GTEST_SOURCE_DIR}
+ PATHS ${GTEST_SEARCH_PATH})
+
+INCLUDE(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(GTestSrc DEFAULT_MSG
+ GTEST_SOURCE_DIR
+ GTEST_INCLUDE_DIR)
diff --git a/3rdparty/rapidjson/RapidJSON.pc.in b/3rdparty/rapidjson/RapidJSON.pc.in
new file mode 100644
index 00000000000..7467f9779b8
--- /dev/null
+++ b/3rdparty/rapidjson/RapidJSON.pc.in
@@ -0,0 +1,7 @@
+includedir=@INCLUDE_INSTALL_DIR@
+
+Name: @PROJECT_NAME@
+Description: A fast JSON parser/generator for C++ with both SAX/DOM style API
+Version: @LIB_VERSION_STRING@
+URL: https://github.com/miloyip/rapidjson
+Cflags: -I${includedir}
diff --git a/3rdparty/rapidjson/RapidJSONConfig.cmake.in b/3rdparty/rapidjson/RapidJSONConfig.cmake.in
new file mode 100644
index 00000000000..9fa12186ab6
--- /dev/null
+++ b/3rdparty/rapidjson/RapidJSONConfig.cmake.in
@@ -0,0 +1,3 @@
+get_filename_component(RAPIDJSON_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+set(RAPIDJSON_INCLUDE_DIRS "@INCLUDE_INSTALL_DIR@")
+message(STATUS "RapidJSON found. Headers: ${RAPIDJSON_INCLUDE_DIRS}")
diff --git a/3rdparty/rapidjson/RapidJSONConfigVersion.cmake.in b/3rdparty/rapidjson/RapidJSONConfigVersion.cmake.in
new file mode 100644
index 00000000000..25741fc0976
--- /dev/null
+++ b/3rdparty/rapidjson/RapidJSONConfigVersion.cmake.in
@@ -0,0 +1,10 @@
+SET(PACKAGE_VERSION "@LIB_VERSION_STRING@")
+
+IF (PACKAGE_FIND_VERSION VERSION_EQUAL PACKAGE_VERSION)
+ SET(PACKAGE_VERSION_EXACT "true")
+ENDIF (PACKAGE_FIND_VERSION VERSION_EQUAL PACKAGE_VERSION)
+IF (NOT PACKAGE_FIND_VERSION VERSION_GREATER PACKAGE_VERSION)
+ SET(PACKAGE_VERSION_COMPATIBLE "true")
+ELSE (NOT PACKAGE_FIND_VERSION VERSION_GREATER PACKAGE_VERSION)
+ SET(PACKAGE_VERSION_UNSUITABLE "true")
+ENDIF (NOT PACKAGE_FIND_VERSION VERSION_GREATER PACKAGE_VERSION)
diff --git a/3rdparty/rapidjson/appveyor.yml b/3rdparty/rapidjson/appveyor.yml
new file mode 100644
index 00000000000..7d586e83a48
--- /dev/null
+++ b/3rdparty/rapidjson/appveyor.yml
@@ -0,0 +1,28 @@
+version: 1.0.2.{build}
+
+configuration:
+- Debug
+- Release
+
+environment:
+ matrix:
+ - VS_VERSION: 11
+ VS_PLATFORM: win32
+ - VS_VERSION: 11
+ VS_PLATFORM: x64
+ - VS_VERSION: 12
+ VS_PLATFORM: win32
+ - VS_VERSION: 12
+ VS_PLATFORM: x64
+
+before_build:
+- git submodule update --init --recursive
+- cmake -H. -BBuild/VS -G "Visual Studio %VS_VERSION%" -DCMAKE_GENERATOR_PLATFORM=%VS_PLATFORM% -DBUILD_SHARED_LIBS=true -Wno-dev
+
+build:
+ project: Build\VS\RapidJSON.sln
+ parallel: true
+ verbosity: minimal
+
+test_script:
+- cd Build\VS && if %CONFIGURATION%==Debug (ctest --verbose -E perftest --build-config %CONFIGURATION%) else (ctest --verbose --build-config %CONFIGURATION%)
diff --git a/3rdparty/rapidjson/bin/data/glossary.json b/3rdparty/rapidjson/bin/data/glossary.json
new file mode 100644
index 00000000000..d5ca56d1950
--- /dev/null
+++ b/3rdparty/rapidjson/bin/data/glossary.json
@@ -0,0 +1,22 @@
+{
+ "glossary": {
+ "title": "example glossary",
+ "GlossDiv": {
+ "title": "S",
+ "GlossList": {
+ "GlossEntry": {
+ "ID": "SGML",
+ "SortAs": "SGML",
+ "GlossTerm": "Standard Generalized Markup Language",
+ "Acronym": "SGML",
+ "Abbrev": "ISO 8879:1986",
+ "GlossDef": {
+ "para": "A meta-markup language, used to create markup languages such as DocBook.",
+ "GlossSeeAlso": ["GML", "XML"]
+ },
+ "GlossSee": "markup"
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/data/menu.json b/3rdparty/rapidjson/bin/data/menu.json
new file mode 100644
index 00000000000..acdf930ea5f
--- /dev/null
+++ b/3rdparty/rapidjson/bin/data/menu.json
@@ -0,0 +1,27 @@
+{"menu": {
+ "header": "SVG Viewer",
+ "items": [
+ {"id": "Open"},
+ {"id": "OpenNew", "label": "Open New"},
+ null,
+ {"id": "ZoomIn", "label": "Zoom In"},
+ {"id": "ZoomOut", "label": "Zoom Out"},
+ {"id": "OriginalView", "label": "Original View"},
+ null,
+ {"id": "Quality"},
+ {"id": "Pause"},
+ {"id": "Mute"},
+ null,
+ {"id": "Find", "label": "Find..."},
+ {"id": "FindAgain", "label": "Find Again"},
+ {"id": "Copy"},
+ {"id": "CopyAgain", "label": "Copy Again"},
+ {"id": "CopySVG", "label": "Copy SVG"},
+ {"id": "ViewSVG", "label": "View SVG"},
+ {"id": "ViewSource", "label": "View Source"},
+ {"id": "SaveAs", "label": "Save As"},
+ null,
+ {"id": "Help"},
+ {"id": "About", "label": "About Adobe CVG Viewer..."}
+ ]
+}} \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/data/readme.txt b/3rdparty/rapidjson/bin/data/readme.txt
new file mode 100644
index 00000000000..c53bfb8b726
--- /dev/null
+++ b/3rdparty/rapidjson/bin/data/readme.txt
@@ -0,0 +1 @@
+sample.json is obtained from http://code.google.com/p/json-test-suite/downloads/detail?name=sample.zip
diff --git a/3rdparty/rapidjson/bin/data/sample.json b/3rdparty/rapidjson/bin/data/sample.json
new file mode 100644
index 00000000000..30930e765dc
--- /dev/null
+++ b/3rdparty/rapidjson/bin/data/sample.json
@@ -0,0 +1,3315 @@
+{
+ "a": {
+ "6U閆崬밺뀫颒myj츥휘:$è–ˆmYí–š#rzé£+玭V㭢뾿愴Yî°‘ê–šX亥ᮉ푊\u0006åž¡ã­ë£\"厓ᔧḅ^Sqpv媫\"⤽걒\"˽Ἆ?ꇆ䬔未tv{DV鯀Tἆl凸g\\㈭ĭ즿UH㽤": null,
+ "b茤z\\î¨.N": [[
+ "ZL:ᅣዎ*Y|çŒ«åŠæ«•è¾Oj为1糕쪥æ³S룂w࡛á²â¸¥èš™)",
+ {
+ "\"䬰á»wDæ¾V`邀⠕VDãºsH6[칑.:醥葹*뻵倻aD\"": true,
+ "e浱uî¿£p蔽Crà· JK軵xCʨ<뜡癙Yç©ï½¹é½ˆX/螗唻?<蘡+뷄㩤쳖3å‘犾&\\첊xzå崦ݻé´\"åµ¥B3㰃詤豺嚼aqJ⑆∥韼@\u000b㢊\u0015L臯.샥": false,
+ "l?Ǩ喳e6㔡$M꼄I,(3á縢,䊀疅뉲B㴔傳䂴\u0088㮰钘ꜵ!ᅛ韽>": -5514085325291784739,
+ "o㮚?\"춛㵉<\/﬊ࠃ䃪ä£wp6ἀ䱄[s*S嬈貒pᛥ㰉'ë€": [{
+ "(QP윤懊FI<ꃣ『䕷[\"ç’å¶®?%Ḭå£à²»ä‡Ÿ0è¤!è—²ë¹bdæµ¶tl\u2049#쯀@僞": {"î—i妾8홫": {
+ ",Mï£ë§ƒäž›K5nAㆴVNã’Ší–¬$n꩑&êŽæ¤žî·é˜«?/á¹ì„¸ë‰ª1x쥼㻤㪙`\"$쟒薟B煌܀ì¨à­2掳7㙟鴙Xå©¢\u0002": "Vዉèˆï ’᧷⦌kîŒï®žà°ˆnz*<?੃'ahhCFX(\u0007⮊Eã­ä±¾Gxꥩrâ£.æ´Ž",
+ "ë»´5bDDí¯O傆盓왻U?êž…êŠNé­á§¢Ï„\"迳豲8\u001b䃥ꂻ䴺ྸHç­´,": {
+ "\"L鸔SE㬡XV&~ÍŽ'놅蔞눶l匛?'.Kæ°\\ƢẨ疇má¿›'ê½³&!é¹ m'|{Pç—Š ç§„ì’¿u\u00111ä‹§î´¼gÏ©x7t丗D䊨䠻z0.A0": -1.50139930144708198E18,
+ "8é‹‚ë›·ïž”?ì²’B☚>ï·œFM\"è­7ê€-VR<\/';ä™E9$䩉\f @s?íªo3^è¡´cî˜à¶Žä§ªaK鼟q䆨c{ä³ 5mᒲՙ蘹ᮩ": {
+ "Fã²·JGoâ¯Pëµxë’³p䘧☔\"+ꨲå¿JfR㔹)4nç´¬G练Qáž!C|": true,
+ "p^㫮솎ocî’£.೚A㤠??r\u000f)⾽⌲們M2.䴘䩳:⫭胃\\á¾@Fá­Œ\\K": false,
+ "蟌Tk愙潦伩": {
+ "aï‘<\/@ᾛ慂侇瘎": -7271305752851720826,
+ "艓藬/>á„ṯ,XW~㲆w": {"Eç—§î–郶)㜓ha朗!N赻瞉駠uC\u20adè¾ <Ve?í±!ImäŽî­Ÿæ„:*s 9諚Prᵾ뒰髶B̌qWA8梸vS⫊⢳{t㺲q㺈랊뮣RqK밢쳪": [
+ false,
+ {
+ "\u000b=>x퓮⣫P1à «LMMX'M刼唳ë¤": null,
+ "P쓫晥%k覛ዩIUᇸ滨:å™í˜²lMR5䋈V梗>%å¹½ué –\\)쟟": null,
+ "eg+昉~矠䧞难\b?gQì­·ç­\\eê® Nl{ಢ哭|]Mn銌╥zê–˜zⱷ⭤ᮜ^": [
+ -1.30142114406914976E17,
+ -1.7555215491128452E-19,
+ null,
+ "渾ã¨ß牄귛r?ëŒ?w[âšžÓ»~廩輫㼧/",
+ -4.5737191805302129E18,
+ null,
+ "xyà¿‘M[ocì…’ç«“â’ºx?뜓y䊦>-Dì¼(&&?XKkc꩖ﺸá‹ëµžK伕6à§€)딀PæœyWæ™îž¢?훻魢傎EG碸9類៌g踲C⟌aEX舲:z꒸许",
+ 3808159498143417627,
+ null,
+ {"m試\u20df1{G8&뚈h홯J<\/": {
+ "3ஸ厠zs#1K7:rᥞoꅔꯧ&ë‡éµ¼éž«6è·œ#赿5l'8{7㕳(b/j\"厢aqç±€êš\u0015厼稥": [
+ -2226135764510113982,
+ true,
+ null,
+ {
+ "h%'ë§žï–±Sì‹…Hs&dï”l슾W0jé¿M×D놯L~S-㇡Rì­¬%": null,
+ "⟓咔謡칲\u0000孺ꛭx旑檉㶆?": null,
+ "æ‡I転;￸B2Y`z\\ç“w,ë†æ¿æ’埵䂄)!ä¶¢D=à´­ã´ŸjyY": {
+ "$ࡘt厛毣ൢIèŠ<겿骫⫦6tr惺a": [
+ 6.385779736989334E-20,
+ false,
+ true,
+ true,
+ [
+ -6.891946211462334E-19,
+ null,
+ {
+ "]-\\êŸ1/è–“â§á½Š\\l牑\u0007A郃)阜ᇒᓌ-塯`W峬G}SDb㬨Q臉⮻빌O鞟톴첂B㺱<ƈmu챑J㴹㷳픷Oㆩs": {
+ "\"â—‰B\"pᶉt骔J꩸ᄇá›iâ•°æ ›K쉷㉯é©!ãˆnì¹äŸ…難>盥yé“¿eà­”è’M貹ヅ8å˜‹í€¯ä‰¶áŒ¥ã¢æ®Šë»³\"絧╿ꉑ䠥?∃蓊{}㣣Gk긔H1哵峱": false,
+ "6.瀫cN䇮F㧺?\\椯=ÚˆT䘆4â˜ïšŒ8qv": -3.5687501019676885E-19,
+ "Q?yऴr혴{஀䳘p惭f1ﹸ䅷䕋贲<ྃᄊ繲hq\\b|#QSTî“¶s1c-7(äµ¢\u2069åŒçµ˜ê¯‰:læ¯´ï›æ±žt戀oà·Ÿáµ¶ë®±á£-醇Jx䙬äí–¢0࣫á¡grã„›": "\u0011_xM/蘇Chv;dhA5.嗀绱V爤ﰦiëµ²M",
+ "â‘[\"ugoy^儣횎~U\\섯겜ï¥l2jw஌yD腅̂\u0019": true,
+ "ⵯɇä²á«¿à¢š!㯢l샅笶戮1꣖0Xe": null,
+ "劅fë„€ï‹ï§¼bå®ç„ŠE찓橵G!ʱç“뭔雩괛": [{"p⹣켙[q>燣äƒãž½î›œá©²x:쓤삘7玑퇼0<\/qç’‚á‘[ï ™Z\\3䅵䧳\u0011㤧|妱緒C['ì·“Yꞟ3Z鳱雼P錻BUì”§U`ᢶg蓱>.1Ó§è­«'L_5VäµÐ¦": [
+ false,
+ false,
+ {"22ä‚盥N霂얢<F8î±ê¼µ7Gà°¸yhë€g᦭ꄢx硴嬢\u001a?Eê´†T|;7犟\"Wt%ä©O⨵t&#ᬋK'èœá²«æ”⾠鲂Të©·éƒ\u0018䓞cE": {"f=ä츜瞾zw?å­¡é£\\铀᫞yẆg(\u0011M6(s2]`ਫ": [[[{
+ "'y몱纣4S@\\,i㷯럹Ua充Tᣢ9躘Zଞ쥿äŠs<\/刎\\\"뉦-8/": "蜑.X0꭛낢륹iì ¨êš<8?s볕è¡|Q✬᯦@\\G㑢屿Mn졾J굤⥟JW뤵苑rì•툄嵵?â¾¥O",
+ "^1挲~[n귆誈央碠멪gI洷": -8214236471236116548,
+ "sሣ%娌暡clr蟜㑓2\u000bSâŸ_X㨔⚴5~蔷ꀇ|Xu㬖,꤭å¹îµ¿r(g믇ì©ïЍ%췸앙|æ £U\\2]䤉+å• è¡ê¯ŽT鉹m\n/`SzDᅼ鞶": 1.1217523390167132E-19,
+ "u톇=黚\\ ꂮ췵L>躰îe9â‘©_뵜斌n@B}$ê´»Yá±@ä§‹î´½V\"☒-諯cVë¯Ê ": true,
+ "Ű螧ᔼæªéŽë•’딜qꄃH뜣<ç§à¥‚CYå“â¸>XQ㵡趌oë¬k픀빯a(ܵç”ë†à­¯/6Nᪧ}æšá†šì§ŒP牰泱鈷^d꣟#Lì‚€\"㕹襻;k㸊\\f+": true,
+ "쎣\",|⫝̸阊x庿k잣v庅$éˆê´Žç‚”k쬪O_": [
+ "ìž©AzZGz3v愠ꉈⵎ?㊱}Så°³à¯p\r2>ì·IP䘈M)w|\u000eE",
+ -9222726055990423201,
+ null,
+ [
+ false,
+ {"´킮'뮤쯽Wxè®V,6ᩪ1ç´²aႈ\u205czD": [
+ -930994432421097536,
+ 3157232031581030121,
+ "l貚PY䃛5@䭄<nW\u001e",
+ [
+ 3.801747732605161E18,
+ [
+ null,
+ false,
+ {
+ "": 4.0442013775147072E16,
+ "2J[sᡪ㞿|n'#廲꯬乞": true,
+ "B[ç¹°`\\ãa̼㨀å›ã½“<\/꥖ᵈO让\r43⡩徑ﬓ๨ﮕx:㣜oçŽê‰Ÿã¢Cçµï›‰á½†á“žì‡“Qs氯였9é§µq혃Ljê‚”<\/昺+tä‹à¼»çŒ™c沪~櫆bpJ9Uá:칣妙!çš—F4㑄탎䕀櫳振讓": 7.3924182188256287E18,
+ "H磵ai委曷n柋T<\/å‹¿F&:ꣴfU@㿗榻Lb+?í„sp\"᪟~>ê·»m㎮ç¸fî§¡": 1.0318894506812084E-19,
+ "࢜⩢Ш䧔1肽씮+༎ᣰ闺馺窃䕨8Mƶqè…½xc(៯å¤J5굄ä•Qj_훨/~価.䢵慯틠퇱豠㼇Qﵘ$DuSp(8Uà¸<\/ಟ룴𥳐ݩ$": 8350772684161555590,
+ "ㆎQ䄾\u001bpᩭ${[諟^^骴᤮b^ㅥI┧T㉇⾞\"绦<AYJ⒃-oF<\/蛎mm;obh婃ᦢ": false,
+ "䔤䣈?æ±.p襟&dã±…\\Jᚠ@?Oì²à¢½íœ”VR蔩|㒢柺": [[
+ "-ꕨ岓棻r@鿆^3~䪤Ѐ狼︌ﹲ\\á¸MlEìµ Q+",
+ null,
+ false,
+ 3346674396990536343,
+ null,
+ {
+ "": null,
+ "/ä¨S쨑,&繷㉥8C엮赸3馢|뇲{鄎ꗇqFﶉ雕UD躢?Ꟛအï–꽡[hᕱᗅ㦋쭞MユèŒ?L槽암V#성å”%㣕嘵\\Ú¹(å˜èº¿&q": [
+ -1364715155337673920,
+ false,
+ -8197733031775379251,
+ "E팗鮲JwH\\觡܈áœ\"+뉞娂N휗vå™™á‚ê¹¼\u001dD帒l%-æ–”N",
+ -3.844267973858711E-20,
+ [{"쬯(褈Q 蟚뿢 /ⱖ㻥\u0017/?v邘䃡0U.Z1î­­x?鯔Vå° 8Emï•<": [[[
+ null,
+ [
+ null,
+ -5841406347577698873,
+ "í‚·\"S⋄籞繗솸ᵣ浵w쑿ퟗ7náŽx3ì•™z㘌쿸I葥覯ã¬0á†b汆狺뷘ႀnꋋ",
+ -1227911573141158702,
+ {
+ "u㉮PᾺV鵸A\\g*à¡—9슟晭+ͧↀ쿅H\u001c꾣犓}癇æ›á—¬é»©äŸ˜X梑é†e>rä°‚f矩'-î½7ä¡­æ¡¥Dz兔V9è°¶å±…ãºá”Šä©¯ë².\u001eL0ὅㅷ釣": [{
+ "<쯬Jå·^숞u࠯䌗艞R9닪gã¾ë³Ža䂈歖æ„:%é”|ﵤ|y}î¡»>;2,覂⶚啵tb*ä»›8ä¹’ã“¶B࿠㯉戩oX 貘5V嗆렽ë‚߼4hä§›êºM空\\b꿋貼": 8478577078537189402,
+ "VD*|吝z~h譺aᯒ": {
+ "YIì·¢K<\/濳xNne玗rJo쾘3í•°é´Š\"↱AR:ࢷ\"9?\"è‡ï¦¡)?誚êŠe)_D翾W?&F6J@뺾ê°NZ醊Z쾈വHï±å¶¿?炫㷱鬰M겈<bïž²S}㎥l|刖k": {"H7鷮퇢_k": [
+ true,
+ "s㟑瀭좾쮀â‘î¬Yì°ºk맢戲쀸俻àº6å„®ë—æ‰–puߖꜻ馶rꈞ痘?3ྚ畊惘䎗\"vv)*臔웅鿈䧲^v,껛㰙J <áš¶5",
+ 7950276470944656796,
+ 4.9392301536234746E17,
+ -4796050478201554639,
+ "yꬴc<3㻚",
+ "oå¡\u20a4蒵鮬裢Cá´§nBã­±f.",
+ false,
+ [
+ false,
+ "ã¡å¼‘V?瀆䰺q!출㇞yᘪ꼼(IS~Ka 烿ꟿ샕桤\u0005HQҹ㯪罂qè¾âš‡æ‡‹â¦•ë‘¡v",
+ 1862560050083946970,
+ "\u20b6[|(ë­¹gê’펉O轄Dl묽]ﯨ髯QEbAã’¾m@롴礠㕓2ë•«n6ْ엘঵篳R잷꙲m색摪|@ã¿«5aK设f胭r8/NI4ì¶«æ µ\\꯬2]",
+ false,
+ {
+ "\u000b7*ã™›ç‡.~?䔊pæ•e_拺艿ë·f{ê”»1sé©™`$Ė戧?q⋬沭?å¡·á­šè¹€unoa5": {
+ "Sê·¯o紞㾕ᅶä¾î—¶éЇ12|ÊŸç•´ï–iNAo?|Sw$M拲գ㭄紧螆+,梔": null,
+ "ã­š0?xB疱敻ேBPwv뾃熉(Ó pJ]ê°¢\"Bj'\u0016GE椱<\/zgៅx黢礇h},M9ï´¦?LḨ": "Si ïŸB%~㬒E",
+ "핇㉊살ã¢ìˆ¨~ȪRo䦅D桺0z]﬽蠆c9ᣨyPP㿷U~ãž?쯟í¸å®’뉆U|}㉓郾ࣻ*櫎꼪ä—s?~7\u001e㘔h9{aáž‹}:ã¶’P8": [{"\\R囡ì¬nNæŸ‹çØ›7ì¹¾ :㶃衇徜V æ·±f1æ·â™ i?3Sè§’íž^ᆞ\u20e8á¹°D\u0007ç§¡+躒臔&-6": {
+ "䨑g.fhã”—=8!\"狿ൻLU^ë»±g䲚ã»'W}k欤?๒鲇S꧗䫾$ĥ피": -794055816303360636,
+ "外頮詋~텡竆î™ç¹ƒä©è‹¨ë¾ºæœê¼ƒç˜¹f*㉀枙NH/\u2027ê¢}j묎ïƒvペq︉ì‹ëœ¡Od5 N顯ି烅仟Qfㆤ嚢(i䬅c;ë§§?嶰㩼츱ç¡?-": {
+ "e݆ã¡â¬¬î›–'2ã»’?U篲鿄\"隻Ҭ5NꭰꤺBꀈ拾᩺îº[刯î…5곑Na램ﴦ዆]ã“qwé’„\u001b\"Yæ´Šä—¿î¼ç¥å¡¥è¿µ[⼞⠳P$ê ±5먃0ï¦`": [{"ç°Eè³ï«šb먭N긆Ⰹå²2逶ꜛ?H짉~?P}jj}ä¾·ç¿_T>á­¨b,â»éˆµP䕡䀠८ⱄ홎鄣": {
+ "@?k2é¶–ã‹®\"Oರ K㨇廪儲\u0017ä¾î¿‚J?);\b*묀㗠섳햭1MC V": null,
+ "UIICP!BUA`î€á¢ˆã‹¸~袩㗪⾒=fBï®´l1ꡛ죘R辂여ҳ7쮡<䩲`熕8é ": 4481809488267626463,
+ "Y?+8먙ᚔ鋳蜩ï–럶1㥔y璜౩`": [
+ null,
+ 1.2850335807501874E-19,
+ "~V2",
+ 2035406654801997866,
+ {
+ "<숻1>\"": -8062468865199390827,
+ "Mã¿£ï€E]}qwG莎Gná¶(ê”™\\D⬲iꇲs寢t駇S뀡ꢜ": false,
+ "pê¤ãŽ9W%>M;-Uç’fî£(^j1?&RBéš§ å¿“b똊îƒE": "#G?C8.躬ꥯ'?냪#< 渟&헿란zpo왓Kj}é·§XﻘMツbä•–;㪻",
+ "vE풤幉xz뱕쫥Ug㦲aH} ᣟp:鬼Yá°Ÿ<Fɋ잣緂頒âºä‰²ç‘‘ä…‚,C~Þ…G!f熢-B7~9Pqà¡¢[츑#3ꕎ,Öඳèâ©…ãµ§ì¶€ë¿xyäŒÍ‚tdj!箧᳆|9èš¡ë¬": -2.54467378964089632E17,
+ "䵈䅦5ë¹–,궆-:໿댾仫î»0ᙚyá¦hqáš„": null,
+ "侯Y\"湛졯劇Uì…ŽYXçâ…¸2ä¼´|ç­§\\ä’ã¶¶á·ì‘WaᦵᗱãœëŠ¾è† <Jc63<G\u20fe䇹66僣k0O\"_@U": null,
+ "姪y$#sæ¼´JH璌Ӊ脛Jã¾íŽ”ï¹´oꈶ㚸PD:薠ì–%說ážè¹‚1]⾕5튄": {
+ "á¾Huw3䮅如쿺äŸå«]<鰨ݷ?꯯䫓傩|á¶à·ƒåª½\\澒≡闢": "Mm\"ì‡á¯„졽\"楇<\/ꥆí­å±€néš´@é¿£wâ Š4Pï«å¾ŽW㊋;䤞'.팇è’ä¡´egpxå—Žwà®…ç—å ®á›nË︖䀤4å™™?໚éƒá±‹Þ˜à¥Žtæ‘姫籕殥ï­é™ƒ\"4[ê¬qL4Wê Žx",
+ "ℇjéŒïš›5Bë’š\" U": "ç¡„ê˜{憠êµ:&t䌨m Cઌ쿣鞛XFê Ÿsä­ï¶ƒ\"æ ¼a0x闊昵å²L\\æšèˆaê¸j싹ç…\"î ²çŸï±¡é¦†*êµ–ç³ <ê”躎",
+ "톌賠弳êŸb\"èž–X50sĶ晠3fç§‚å¯Iⓟ:è˜": 5.573183333596288E18,
+ "%䴺": [[[[
+ -6957233336860166165,
+ false,
+ null,
+ {
+ "\"ïŸ\\௮茒袀ᕥ23ୃ괶?䕎.嚲◉ãžL+ᵡ艱hL콇붆@": null,
+ "%螥9ꭌ<\/-t": true,
+ ",9|î«è€¢æ¤¸ä“Xk죱\u0015$Ώ鲞[ï’—?ì—¢á²í˜ªì¦ˆâ´‚â–‚â„´ã—¯\"gî´ëº˜\\êœ#\u0002ヮ}ሎ芲P[鹮轧@냲䃦=#(": 2.78562909315899616E17,
+ "R?H䧰ⵇ<,憰쮼Q總iR>H3镔ᴚ斦\\é‘r*2橱Gâ¼”F/.j": true,
+ "RK좬뎂aí™ f*f㱉á®â¦‹æ½™ã¨‹Gu곌SGI3Ië¿\\F',)t`è蘯囯ﮉ裲뇟쥼_ገ驪▵æ’ᕤV": 1.52738225997956557E18,
+ "^k굲䪿꠹B逤%F㱢漥O披M㽯镞竇霒i꼂焅륓\u00059=皫之눃\u2047娤é–銤唫á•b<\/w踲䔼u솆맚,ä’á³'/it": "B餹饴is権ꖪ怯ꦂẉဎt\"!凢谵⧿ï™0\\<=(uLä·åˆ¨ì‘ª>俆æ“Cy襸Q힆䆭涷<\/á±0î É§îŠ‹䗾䚹\\ኜ?ꄢᇘ`ä´¢{囇}᠈䴥X4퓪檄]ꥷ/3謒ሴn+gé¨X",
+ "GgG꽬[(å«“ëª6\u0004ê¶宩㙻/>\u0011^è¾dTè…ªhxÇ‘%ꊇk,8(Wâ§‚çµP鬜O": [{
+ "Mã´¾c>\\ᓲ\u0019V{>ꤩ혙넪㭪躂TS-痴໸闓âµ/徯O.Mã¥Ê·D囎⧔ì³íœ¤T??鉬뇙=#ꢫ숣BXä­¼<\/d똬졬g榿)eꨋﯪ좇첻<?2K)": null,
+ "Z17縬z]愀䖌 ᾋBCg5ë”’êµ­æ†ê¾“aâ²·í„·u:U촳驿?雺楶\u0001\u001c{q*á°—è‹‘B@kæ°z.*è“—7ረIm\"Oá±@7?_": true,
+ "㺃Z<": -4349275766673120695,
+ "휃䠂fa塆ffixKe'ë¬é—੄뺾w࠾鑎kë•¢m*á‚‘î§·í–žé®6攊&虜h黚,Yä±³Sﭼ둺pN6": [
+ false,
+ "IΎ䣲,\"ᬮ˪癘P~Qlnxå–Sᮔ༬˨IçŒm䜛酛\u0003iê¸ã¦§cQ帲晼D' \\(粋ï›wQcN\\ëµ°è·ˆ",
+ [
+ "D0\\L?M1ì¥KaêŒsd+盌귤憊tz䌣ëŒ×‘Oå‚wÏ¢%á½’gpî•—,Aiï™âŽ§á¶†Iî«˜é¤¾ê¦æ£©å˜…᳉怴%m]á¶is纖D凜镧o심b Uî»·",
+ {
+ "?଼\u0011Rv&^[+匚I趈T媫\u0010.䥤ᆯ1q僤HydⲰl㒽K'ᅾiౕ豲초딨@\u0013J'쪪VD౼P4Ezg#8*㋤W馓]c쿯8": false,
+ "c/擯X5~JmKäµ¶^ìŽà´š|B|u[ì†(X뚤6v}W㤘⠛aR弌臌쾭諦eⒷ僡-;㩩⭖ⷴ徆龄갬{䱓ᥩ!ï¯âŠšá‡¨<v燡露`:볉癮꨽り★Ax7Ꮀ譥~舑\\Vê‹\"$)v": "e&sFF쬘OBï–†d슊寮f蠛জ봞mn~锆竒Gè„\"è¶µG刕䕳&L唽붵<\/I,X팚Bâ¥î¼¶X,kԇҗ眄_æ…¡:U附ᓚAè•§>\u001a\u0011\";~쓆BH4勿”Š7힪",
+ "iT:L闞椕윚*æ»›gI≀Wਟඊ'ꢆ縺뱹鮚Nê©á§¬è•¼21줧\\䋯``â\\ã±é³¨": 1927052677739832894,
+ "ì®ç¼¦è…ƒg]礿Y㬙 fî¼ãƒºSɪ꾾N㞈": [
+ null,
+ null,
+ {
+ "!t,çY 1䗉罵?c饃호䉂Cá­ì’˜z(즽sZG㬣sഖE4ï‚뢜㓕äžä¸®Qpç°6EZឪ겛fx'ꩱQ0ç½£i{k锩*㤴㯞r迎jTⲤ渔m炅肳": [
+ -3.3325685522591933E18,
+ [{"ã“5]A䢕1룥Bï²C?Ꙍ`r룔Ⳛ䙡uä¼²+\u0001àµo": [
+ null,
+ 4975309147809803991,
+ null,
+ null,
+ {"T팘8Dﯲ稟MM☻㧚䥧/8ﻥ⥯aXLaH\"顾S☟耲ît7fSà·‰ë†ë®”/ꕼ䓈ìº4\\霶䠴ᩢ<\/t4?죵>uDï›5➶༆쉌럮⢀秙䘥\u20972ETR3æ¿¡æ†vB? ~鸆\u0005": {
+ "`é––mç’㥉b뜴?Wf;?DV콜\u2020í‰à±“æ“å®ZMj3mJ먡-å‚·ë±™yח㸷꥿ ໘u=Mì!5å­L4v\\?ÇŽ7C홫": null,
+ "|": false,
+ "~Ztᛋ䚘\\æ“­ã—傪Wé™–+ã—¶qᵿ蘥ᙄp%䫎)}=â ”6ᮢS湟-èž¾-mXH?cp": 448751162044282216,
+ "\u209fad놹j檋䇌ᶾ梕ã‰bוּ<dä—±:줰Mé…„\u0000X#_rç¢A饓ê—ÙKo_è·”?ᪧ嵜鼲<": null,
+ "ꆘ)ubI@h@洭Ai㜎ä±k\u0003?Tä‰3é—´%j6jæ£j=â\\U毮ᬹ*8䀔v6cpjâ­¬~Q꿾뺶ï‰íŽµæ‚¡!ì©­åŽl六㽫6퇓ޭ2>": {"?è‹´ê© D䋓帘5騱qï±–PF?☸ç—é¡’yU á¡«cb䫎 S@㥚gꮒ쎘泴멖\\:Ié®±TZ듒ᶨQ3+f7캙\"?\fí’¾\\oæžç´Ÿï»½M.âŽï˜¸é‘OP": [
+ -2.6990368911551596E18,
+ [{"ä’–@<á°¿<\/⽬tTrè…ž&G%᳊秩蜰擻f㎳?Sãµ§\r*k뎾-乢겹隷j軛겷0ë£é®ï µ": {")DO0è…¦:ì¶é€¿:1㥨่!è›æ¨‹2": [{
+ ",ꌣf侴笾m๫ꆽ?1?U?\u0011ꌈꂇ": {
+ "xæ—ç” nVqä…¦w`CD⦂惺嘴0I#vỵ} \\ê·‚Së´Dì–¾?Ô’j溯\"v餄a": {
+ "@ç¿™c⢃趚痋i\u0015OQâlqë†Y0pࢥ3쉨䜩^<8g懥0w)]䊑næ´ºo5ì­QL댊랖L镈Qnt⪟㒅십q헎鳒⮤眉ᔹ梠@O縠u泌ㄘb榚癸Xî©­Þ”Ftj;iC": false,
+ "I&뱋゘|ï£è“”䔕측瓯%6á—»HW\\N1貇#?åƒá—œghá­ªo'䗈꽹Rcìš/蔳迄à¼!0邔䨷푪8ç–©)[쭶緄㇈୧á": {
+ "B+:ꉰ`sì¾­)ë¹¼Cç¾A䫊pMgjdxäHf9᥸W0!C樃'ï¤f䫤סи\u0017Jve? è¦f둀⬣퓉Whk\"஼=չï³î•¤çš†ç¬BIW虨쫓F廰饞": -642906201042308791,
+ "sb,XcZ<\/m㉹ ;䑷@c䵀s奤⬷7`ꘖ蕘戚?Feb#輜}p4nH⬮eKL트}": [
+ "RK鳗z=袤Pf|[,u욺",
+ "Ẏá»ç½¯ë‰‹âº–锅젯㷻{H䰞쬙-ì©“D]~\u0013Oã³¢gb@æ¶è”‰|kᦂâ—!\u001ebMè¤sca쨜襒y⺉룓",
+ null,
+ null,
+ true,
+ -1.650777344339075E-19,
+ false,
+ "☑lꄆs힨꤇]'uTന⌳ë†].1â‹”ê´æ²°\"IWà´©\u0019æ°œ8쟇䔻;3衲æ‹,窌zíŽå–íš—?4?Cë„é—®?ᥙ橭{稻Ⴗ_ì”",
+ "n?]讇빽å—}1å­…9#ê­¨é¶v\u0014å–ˆ)vw祔}룼쮿I",
+ -2.7033457331882025E18,
+ {
+ ";⚃^㱋x:饬ኡj'ê§µT☽O㔬RO婎?향ᒭæ©$渣y4i;(Q>꿘e8q": "j~錘}0g;Lèº*;á•­ê„®0l潛烢5H▄쳂ê’ï­‹ê™¶T犘≫x閦웧v",
+ "~î¢æ¯\u2018c4è·ë E~ᑅቚꈂ?nq뎤.:æ…¹`F햘+%鉎Oç€œìŸæ•›è®âŒæµ¢<\/㮺紿P鳆ࠉ8I-o?#jﮨîŸ7v3Dt赻J9": null,
+ "à£W䌈0êŽqC逖,íš…î·Žcáƒswj;jJSæ«5æ§—OaB>D踾Y": {"ã’°äµF%î©®?59.î„„ãˆcᕨï†í•틎á¸ã‹©B=9IÛⓌ{:9.ywï½å‘°ã†®è‚’᎒tIã¾´62\"ዃ抡C﹬B<\/<EO꽓ᇕu&é‹«\\禞í¹uê’.7훯ಶ2䩦͉ᶱf깵ᷣ늎": [
+ 5.5099570884646902E18,
+ "uQNæ¿¿m臇<%?谣鮢s]]x0躩慌闋<;(î³¥ 鋤.0á µd1#벘a:Gs?í–·'.)ㅴ䞟ç¯å´ˆFS@O㌛ᓬ抢íŒáž¾ëƒ·ì¿Ÿíˆ¥IZn[惵ê§3ë™[&v憙J>ì´‹jo朣",
+ [
+ -7675533242647793366,
+ {"ᙧ呃ï£:[㒺쳀쌡ì‚H稈㢤\u001dá¶—GG-{GHྻຊꡃ哸䵬;$?&d\\⥬ã“Nåœ´ë¤æŒ¨-'ê•®$î“‹PU%?冕눖ié­q騎Q": [
+ false,
+ [[
+ 7929823049157504248,
+ [[
+ true,
+ "Zè™\u0017'eꕤ᱕l,0\\X\u001c[=雿8è ¬L<\/낲긯W99g톉4ퟋbãº\u0007åŠ'!麕Q궈oW:@XáŽïœ¬z蘻m絙璩귓죉+3柚怫tSæ‡è’£ä -æ“¶D[0=퉿8)q0ÙŸ",
+ "唉\nFA椭穒巯\\䥴䅺鿤S#bè¿…ç˜ ï¶—ê¬˜\\?q1qN犠pX꜅^䤊⛤㢌[⬛휖岺q唻ⳡí‹\"ã™™Eh@oA賑㗠yå¿…Nꊑᗘ",
+ -2154220236962890773,
+ -3.2442003245397908E18,
+ "Wᄿ筠:瘫퀩?o貸q⊻(᎞KWf宛尨h^残3[U(='橄",
+ -7857990034281549164,
+ 1.44283696979059942E18,
+ null,
+ {"ꫯAwè·­å–€ ?_ï““9\"Aty背F=9缉ྦྷ@;?^鞀w:uN㘢Rá»": [
+ 7.393662029337442E15,
+ 3564680942654233068,
+ [
+ false,
+ -5253931502642112194,
+ "ç…‰\\îš¶î¶è¾Žî›¢à³†ç½5â’­1äªäƒ‘s䎢:[e5}峳ﴱn騎3?è…³Hyêƒè†¼N潭錖,Yá‹ËœYAá“㬠bG렣䰣:",
+ true,
+ null,
+ {
+ "⒛'P&%죮|:⫶춞": -3818336746965687085,
+ "钖m<\/0ݎMtF2Pk=瓰୮洽겎.": [[
+ -8757574841556350607,
+ -3045234949333270161,
+ null,
+ {
+ "áœî…½rè¼³>⫇9hU#î¦#w@ê·ªA\\Cî’¢ é‹ºã˜“ê–æ¢’뒬묹㹻+郸å¬ìœ¤'+g<\/碴,}ꙫ>ì†;情d齆Jä¬àº©æ’›ì±íƒ¹/R澡7剌tꤼ?ặ!`â²ç¤\u00002똥଴âŸ": null,
+ "\u20f2ܹe\\tAê¥Æ°\\x当뿖ï»ë ‰ç¦›;G檳ﯪï…Sà«°3~㘠#[J<}{奲 5箉⨔{ë†<\/釿抋,åš /曳m&WaOvT赋皺璑ï“í…": [[
+ false,
+ null,
+ true,
+ -5.7131445659795661E18,
+ "è­m䓪D5|3å©à°ž>î‰è ‡æ™¼6nï´ºPp禽羱î¤DS<ç“닫屚ì‚å§¿",
+ true,
+ [
+ -8759747687917306831,
+ {
+ ">ⓛ\t,odKr{䘠?b퓸C嶈=DyEᙬï¿@ᴔ쨺芛髿UT퓻春<\/yê¸>豚W釺N뜨^?꽴﨟5殺ᗃç¿%>í‚ဿ䄸沂Ea;A_\u0005閹殀W+窊?Ꭼd\u0013Pæ±´G5ì“æ˜": 4.342729067882445E-18,
+ "Q^즾眆@AN\u0011Kb榰냎Y#ä€ê€’ᳺ'q暇çµs\"!3#I⊆畼寤@HxJ9": false,
+ "⿾D[)袨㇩i]웪䀤ᛰMvR<èŸã£¨": {"v퇓L㪱ꖣ豛톤î£\\ê³±#ï–©kDTN": [{
+ "(ì¾´ä¡£,寴ph(C\"ã³¶w\"憳2s馆E!n!&柄<\/0Pꈗſ?㿳Qdéµ”": {"娇堰孹L錮h嵅⛤èºé¡’?CglNæŸ+쨣ﺜ\\MrH": {"çžäŽ‡ë‘ƒá‰²å¼­íŒ­^ꄞ踦涟XK錆쳞ឌ`;੶S炥騞ଋ褂B៎{Ú’ä­·á¶¼éœpIè—è™¶K$": [{"â—–S~躘蒉꫿輜è­Qã½™é—@ᢗ¥Eæ¦iØ¡5┄^B[絮跉ᰥé™PWi3wㄾⵀDJ9!w㞣ᄎ{ë“’ê““b6\\篴??c⼰鶹⟧\\鮇ꮇ": [[
+ 654120831325413520,
+ -1.9562073916357608E-19,
+ {
+ "DC(æ˜è¡µá¼¡ê¸™ê°µå§­|Ö›[t": 7.6979110359897907E18,
+ "Jâ…))嫼â³9Xfd飉j7猬ᩉ+⤻î®çœ—벎Eé°‰Zï¾¶63zá69}Zá¶L崭ᦥ⡦éšâ‹›êŽ¨î´µ~i㨃咊ꧭo䰠阀3C(": -3.5844809362512589E17,
+ "p꣑팱쒬ꎑ뛡Ꙩ挴æèƒ”&7ᔈ묒4Hdç¡¶í›ãŽ–zꢼè±ã¿¢aሃ=<\/湉鵲Eî„¡Ó…%$F!í¶æ£Œå­¼{Oé§à¨ºgeu+": ")\u001bìž“kÅ€Xì©«Aë°Â®Ú£ç™¦ç‹¢)扔弒p}k縕ꩋ,䃉tࣼi",
+ "ã‚¡F肿輸<솄G-䢹䛸êŠl`Tqê•—îŠè’ža氷⸅ᴉ蠰]S/{J왲m5{9.uá½³~㕚㣹u>x8Uè®Bëºè¥ªç›ŽQhVS맅킃i识{벂磄Ià·„ä™…xZy/æŠà«­Zï–Šé²î¦š-霳Væ®æŒ¦â„’": null,
+ "㯛|Nî½™ê¸b7âµb?æ‹ O\u0014Þ†?-(EꞨ4ꕷᄤYᯕï‘OW瞺~螸\"욿ќ<u鵵઎⸊î˜å€¾ì‘·à·»rT⪄牤銱;W殆͢芄ਰåší›šìƒ¢î™‡âŠ¿+ã²½": null,
+ "å˜ïƒé€†àº»%_ë§›d)zJ%3ì¹§_릟#95䌨怡\u001ci턠ॣî’i冘4èµ–'à¨ä§_æ ”!": {
+ "*?2~4㲌᭳ì¯ftá‚·1#oJ\bäŠ‡é•‡ë” \u2079xä›ãŠá®‚N;穽跖s휇ᣄ홄傷z⸷(霸!3yëºMì’¿í–Û½v㳉tở心3黎vì­» Rp཮Vr~T?&Ë´k糒븥쩩r*D": null,
+ "8@~홟ꔘk1[": -5570970366240640754,
+ "BZté¦ê¡¬c餖 s(má›´\u0000◄dè…‘t84CâŸå¯VṊ뉙'å™±ê”ç½GCé¡€?허0êž¹&ë‡ä›­Cä·«](": 2.4303828213012387E-20,
+ "yæ’”Z외放+}ḑ骈á™&\u0016`G便2|-e]঳?QF㜹YF\"ã¿’ç·„í–·ï€ãˆŸïƒ¦ï¨ä·¦à­€áŒ¤lM蘸N㾆▛럪㞂tᕬ镈ì‡å– l amcxPnm\u001a᱋<\/]_]ﻹïª?H": false,
+ "áæ°ë¬¢뜚I[♺뽛x?0Hë´¬Wpn꨹Raä¿ïŒ›ìŒ‘{㴂ni祻윸A'y|⺴ᚘ庌9{$æ²{톽=m#@ï–—6ᨧfgs44陎J#<Ễ쨓瀵â©a୛㷉㙉ܸ◠냔嬯~å‘„ç±ç¾¥é•³": false,
+ "㘱{<é ¬22?IF@곊I겂嶻Lá›D{@rì’‚?IAᣧ洪惒誸b徂zì·ºê¾ã ­\\刊%禨ìŒâ¶£ä»µ\\P[:47;<ᇅ<\/": {
+ "^U釳-v㢈ê—â—„è˜rᜨi;èµ·kR犺䵫\u0000é”ì™m-Ô™!lḃ꛸뻾F(Wê·›y": "#á ºH㸢5v8_æ´‘C",
+ "䔵໳$á™ 6èž\u206e摎q圩P|æ…sV4:㜾(I溞I?": -6569206717947549676,
+ "é€êž‚ç·µí‡8 >e㺰\"'㌢ÆW\u0004çž•>0?V鷵엳": true,
+ "뤥G\\î¡‹è¿‹ä ¿[庩'꼡\u001aiá©®Vì¯á³ªä¦ªÃ”î²…;倱ନë›èªˆ": null,
+ "쥹䄆䚟Qæ¦äŽá¢­<\/2ã•£p}HW蟔|äƒî‚꿈ꚉ锳2Pb7㙑Tⅹᵅ": {
+ "Y?Ö­$>#cVBꩨ:>ï†eLè’å‹™": {
+ "86柡0po äš&-æ‘Ћ祌<\/휃-G*㶢הּì©s㶟餇c걺yu꽎還5*í„§ç°•Ogå©¥Sê": null,
+ "a+葞h٥ࠆ裈嗫ﵢ5輙퀟ᛜ,QDﹼ⟶Y騠锪E_|x죗j侵;m蜫轘趥?븅w5+mi콛L": {
+ ";⯭ﱢ!ä¹°Fâ½æŸ¤é¶‚näµ£V㫚墱2ë ¾ELEl⣆": [
+ true,
+ -3.6479311868339015E-18,
+ -7270785619461995400,
+ 3.334081886177621E18,
+ 2.581457786298155E18,
+ -6.605252412954115E-20,
+ -3.9232347037744167E-20,
+ {
+ "B6㊕.k1": null,
+ "ZAꄮJ鮷ᳱo갘硥鈠䠒츼": {
+ "á•…}럡}.@y陪é¶r業'æ´î‰°í€‰x䉴ﵴlí˜):씭脴ᥞhiꃰblﲂ䡲엕8߇Mã¶­0燋標æŒ-?PCwe⾕J碻Ᾱ䬈䈥뷰憵賣뵓痬+": {"aì·©v礗X⋈耓áŠfç½…é®!㔽YYᣓwæ¾33⎔芲F|\"äœT↮輦挑6ᓘL侘?ᅥ]ë†1R௯✎餘6ê½<\/௨\\?qå–·ê«j~@ulq": {"嗫欆뾔Xꆹ4H㌋Fåµ§]à Ž]ã –1ꞤT<$më«O i댳0ä²iï—Œ": {"?à·©?\u20cd슮|ꯆjs{?îž…d7?eNs⢚嫥氂䡮쎱:鑵롟2hJꎒﯭ鱢3춲亄:ë¼£v䊭諱Yj択cVmR䩃㘬T\"Ní™*ै%x^F\\_s9ë³´zz4æ·—?q": [
+ null,
+ "?",
+ 2941869570821073737,
+ "{5{殇0ä¾ïž¢g6ë°–í‹è‡©ç¶¹R$ä–­j紋釰7î‹‘sXI繳漪행y",
+ false,
+ "aH磂?뛡#惇då©…?Fe,ì˜+늵ä˜\"3r瘆唊å‹ï¢Šj⳧࠴ꇓ<\/唕윈x⬌讣䋵%拗ᛆⰿ妴á”M2ã³—å¿…ê§‚æ·²?ゥ젯檢<8ë’ï¶MidXä’3á³»Qî”â–®ä½UT|⤪봦éâŠ",
+ [[{
+ "颉(&뜸귙{yîš’^\"P퟉ì¶á²Ÿä®­î‹ºDé¡¡9=?}Y誱<$bë±£RvO8cH煉@tk~4ǂ⤧â©å±‹Sî›ïž¢S;J{vV#剤餓ᯅc?#a6D,s": [
+ -7.8781018564821536E16,
+ true,
+ [
+ -2.28770899315832371E18,
+ false,
+ -1.0863912140143876E-20,
+ -6282721572097446995,
+ 6767121921199223078,
+ -2545487755405567831,
+ false,
+ null,
+ -9065970397975641765,
+ [
+ -5.928721243413937E-20,
+ {"6ì´Š\u001a홯kB0w撨燠룉{绎6⳹!í„è´‘y▾鱧ժ[;7ᨷ∀*땒䪮1x霆Hᩭ☔\"rî¹›ä7毟á°r惃3ꉭE+>僒æ¾": [
+ "Ta쎩aÆt쵯ⰪVb",
+ [
+ -5222472249213580702,
+ null,
+ -2851641861541559595,
+ null,
+ 4808804630502809099,
+ 5657671602244269874,
+ "5犲﨣4mᥣ?yf젫꾯|䋬ìž$`Iⳉﴷ扳å…,'î±c",
+ false,
+ [
+ null,
+ {
+ "DyUIN쎾M仼惀⮥裎岶泭lh扠\u001e礼.tEC癯튻@_Qd4cï…«5S熯A<\/ï¼¼6U윲蹴Q=%푫汹\\\u20614b[௒Câ’¥Xe⊇囙b,ï®æœ3ss땊ë¢i~逇PA쇸1": -2.63273619193485312E17,
+ "Mq꺋貘k휕=nKç¡ë«žè¼©>㾆~á¼žà¡¹ê¸æ¦µlâ‹™Hw뮢帋M엳뢯î¹…vâ…ƒ^": 1877913476688465125,
+ "á¶´ë»—`~ç­—å…⚽টW˃â½b犳䓺Iz篤p;乨A\u20efì©?ç–Šmã€ì»©ë«¡b탔鄃ᾈV(é¢ç³=뎲ିeF仢䆡谨8t0醄7㭧瘵⻰컆r厡궥d)a阄á·Ed&c﯄伮1p": null,
+ "â¯w4曢\"(欷輡": "\"Má­«]䣒頳B\\燧ࠃN㡇j姈g⊸⺌忉ꡥF矉স%^",
+ "㣡Oᄦ昵⫮Y祎Sì級㭻撥>{I$": -378474210562741663,
+ "䛒掷留Q%ì“—1*1J*ë“헩ᦢ﫫哉쩧EↅIcê…¡\\?â´Šl귛顮4": false,
+ "寔愆샠5]ä—„IHï©¥=d﯊/å¶?ॊn%晥D視Nò—˜ˆ'᫂⚦|X쵩넽z질tsî¦kxDQ莮Aoﱻ뛓": true,
+ "钣xp?&\u001e侉/y䴼~?U篔蘚缣/I畚�Q绊": -3034854258736382234,
+ "꺲໣眀)â¿·J暘î©pИfAVì‚•ì³­Nꯗ4々'唄ⶑ伻㷯騑倭D*Okï¯ê§3bâ½_ï„¡<\/ì±£Xm톰á•䆄`*fl㭀暮滠毡?": [
+ "Dç”·p`V뙸擨å¿ë¸ª9c麺`淂⢦Yw⡢+kzÜ–\fY1䬡Hæ­)ë²¾Z♤溊-혰셢?1ï”<-\u0005;æ¢Tále\\ᛵߓﭩ榩<QF;t=?Qꀞ",
+ [
+ null,
+ [{"-ì·«æ²î«§á¬¨å¢Šè‡¸<à ’Hè·¥ 㔭쥃㫯W=z[wধ╌<~yW楄S!â‘»h즓lÄ–N￧篌W듷튗乵᪪템먵Pf悥ᘀk䷭焼\\讄ræ“é¬y6VF<\/6ëž¿p)麡ê ãª\"pà®´e": [
+ "#幎æ´é¢’嶈)ã„›J.嶤26_⋌东챯ꠉ⤋ؚ/âš%ç§¼Q룠QGztᄎ㎷អIç¿°Xpç”éœê¨",
+ {",T?": [
+ false,
+ [[
+ true,
+ 7974824014498027996,
+ false,
+ [
+ 4.3305464880956252E18,
+ {
+ "᱿W^A]'rᮢ)é¥zï­é¤;Hu\\Fk?ï´º?IGæµ…-ä™§>è¨-xJ;å·¡8깊è ï»“U$K": {
+ "Vê•¡è«…æ“W=斸s︪vﲜ츧$)iꡟ싉eî®å¯³?ጭムVથ嵬iæ¥Fg<\/Z|៪ꩆ-5'@ꃱ80!燱R쇤tç³³]罛逇dṌ֣XHiͦ{": true,
+ "Ya矲Cë©—Q9膲墅æºíœ»c\\ë”¶Gç””<\/.齵휴": -1.1456247877031811E-19,
+ "z#.OOï¿J": -8263224695871959017,
+ "å´_3夼ᮟ1Fë¸ë½¯á¦“é´­V豈Ь": [{
+ "Nè’¬74": null,
+ "yuB?厅vK笗!ᔸcXQ旦컶P-ë…«mᄉ麟_": "1R@ 톘xa_|﩯é˜î¥§sæ§žd!d껀筤⬫è–焵먑D{\\ïƒïŽ¿6k共倌☀G~AS_D\"딟쬚뮥馲렓쓠攥WTMÜ­8nX㩴䕅檹E\u0007ï­¨N 2 ℆æ¶ê¥ê µï“3▙玽|ë¨_\u2048",
+ "æA Cä§©G": {":Mí£5e들\\ê€æ¼á”„é¸|Iï¨$)n": {
+ "|U䬫㟯SKV6ꛤ㗮\bn봻䲄fXT:㾯쳤'笓0b/à³¢Cì³–?2浓uO.ä°´": "à½ê¼‹e?``,ᚇæ…^8ꜙNM䂱\u0001Iá–™ê§M'vKdꌊH牮r\\O@䊷ᓵ쀆(fî »yè»i툺\"?<\/峧ࣞ⓺ᤤ쵒߯ꎺ騬?)刦\u2072læ…ªy꺜ﲖTjî’•+u",
+ "뽫<G;稳UL⸙q2n쵿C396炿Jè“¡zâ£zဩSOU?<\/ë™oEí¸Oé¿…à·´êˆEm#\"[瑦⤫á†glâ¡—q8\"í˜ë¥ä¿‚@ᆤ=\u0001爖ç¾ì·€ã¸©b9\\jeqt㟿㮸龾m㳳긄": {
+ "9\"î²–V霟釜{/o0嫲Cå’€-饷äˆ[ë…©î)\r䤴tMW\\龟ϣ^ي㪙忩䞞N湆Y笕)è¨ê–¤èª¥ç…½:14â«»57U$æ“’ä²è–¡Qvↇ櫲현誧?nà®·6": {"l웾䌵.ä…‹ä¦ic碳g[糲Ƿ-ឈᚱ4ì‘§\u0004C࿼\u0018&쬑?멲<\/fD_檼픃pd쪼n㕊渪V䛉mæˆW儅톳뗳䓆7㭽諤Tç… ï–ŠNey?î¼…0᪵鈑&": [
+ false,
+ null,
+ {
+ "\rî´’;é¼¶já ‚ê¼RLz~â™”9gf?Ó¡æµ": -1.4843072575250897E-19,
+ "&ꊒ\"ꋟä­E诮ﯚO?SWë’훪mb旙⎕ᗕ⶙|á·¤5y4甥": "j5|庠t铱?v íš‹0\"'rxz䃢æºêž«!\u0002",
+ "Q á©ãŸ§": {"Hﬔ\u2058䪠틙izZㅛ탟H^ﶲA??R6å‘ Z솋R.à¿¶g8": [
+ -8762672252886298799,
+ -1.9486830507000208E17,
+ null,
+ -7157359405410123024,
+ null,
+ null,
+ -995856734219489233,
+ "呧㫹A4!",
+ null,
+ -1.9105609358624648E-19,
+ 5888184370445333848,
+ 2.25460605078245E-19,
+ 2.5302739297121987E18,
+ "뢹sbEfæµ2丯ï‡?뗾耸(Wdë™SବꭖrtU?ç­¤P똙Qpbbï‘¡KqaE$æ¥Vì›°3i/lK퉜,8︸e= gèž“t竦컼?.寋8éµ—",
+ 7377742975895263424,
+ 2.4218442017790503E-19,
+ {
+ "y꒚ཫ쨘醬킃糟}î‘yTSt䡀⇂뿽4ൢ戰U": [[
+ 3600537227234741875,
+ 4435474101760273035,
+ -1.42274517007951795E18,
+ -5567915915496026866,
+ null,
+ null,
+ [
+ -3204084299154861161,
+ {
+ "7梧慸æ†.a瘎\u00041Uéµ®CkÖ¨d惥è€â³¡Y,â­ì¨EåžFFI鱑ⳬ줢7â§µBﴠ耘줕햸qì»´~*ç‘W.떛ࡆ@'á€+è½³": -961121410259132975,
+ "⥅]l黭㣓绶;!!⎃=朼ã¿e&ἂ繤C﯀lä£ãŒ€6TMì‘®w懃ꡡ#ᤆ䰓,墼湼゙뽸㲿䧽쫨xᵖ듨<\/ T0峸iQ:溫è„\\\"쎪ὴ砇宖^Mæ³¼í¥âž…鈫@ᄟ༩\u2008⥼": true,
+ "â©\"籽汎P싯鲘蟼sRá¯ä…©\u0019R(kRá–&ಌ 0\"é³¶!馼YH": null,
+ "鮼ꚇ싋։刟\rRLd步Nⴗ5Eࡆ訛갚[I醵NC(郴ṉy5D뤺౳QY壯5苴y훨(W\\Cଇ姚C艄깹\u001c歷㋵ZC᥂": [
+ -6806235313106257498,
+ null,
+ "}N⸿讽sꚪ;ï‘¶\\p繇jè‹„î¡ä«¨\u20e7%5x?î•¥t#",
+ {
+ "O〗k<墻yV$à°rs-c1ఌ唪.C7_Yobᦜ褷'b帰mã„‘l⌅": {"qB뗗擄3éš‚5ëºæ«‚䱟eì´¸P/é©,3æŽê—©=冉棓㑉|ËžF襴뿴,:㞦<퓂⧙礞♗g뚎ᛩ<\/뉽ⶳ⸻A?_x2Iã½å‹’*Ií™±î¢é§ç²¿~曟㤙2绥Ly6+ìƒuu鿜בfí˜|æ­à£–É": [
+ ">hh䈵î”w>1â²ì­V[â…Ž\\헑벑F_ã–⠗㫇hæ½;á¿æ±°á±¼ç€–J옆9RRì…vsZ柺鶶툤r뢱橾/ꉇ囦FGm\"謗ꉦ⨶쒿⥡%]鵩#ᖣ_蹎 u5|祥?O",
+ null,
+ 2.0150326776036215E-19,
+ null,
+ true,
+ false,
+ true,
+ {"\faá­¶Pæ¤WWcá Ÿf뚉á¬í“—â³€Wç¹5:HXH=q7xì°™X$)모r뚥ᆟ!Jﳸf": [
+ -2995806398034583407,
+ [
+ 6441377066589744683,
+ "Mﶒ醹i)Gἦ廃s6몞 KJ౹礎VZ螺费힀\u0000冺업{è°¥'꡾뱻:.ꘘ굄奉攼Diá·‘Ké¶²y繈욊阓v㻘}枭캗e矮1c?íœ\"4\u0005厑莔뀾墓ë‚⽴洗ṹ䇃糞@b1\u0016즽Yè½¹",
+ {
+ "1⽕⌰鉟í”M㤭n⧴ỼD#%é˜âŠ¯ì¿¼ç¨ë¸£ëªç´§á…‡ã“•ᛖcw嬀~ഌ㖓(0r⧦Qä‘•é«à´°é“‚㓻Rå„®\"@ꇱmâˆà¯¿á¦¯é Œ8}㿹犴?xn잆꥽R": 2.07321075750427366E18,
+ "˳b18㗈䃟柵Z曆VTAu7+㛂cb0﯑Wp執<\/臋뭡뚋刼틮è‹ë²²î·´TLP预庰܈G\\O@VD'鱃#ä¹–ëº*鑪ꬳ?MÞždï­¹{â‡åœ¯ì‡œã¼ž顄︖Y홡g": [{
+ "0a,FZ": true,
+ "2z̬è£î’®ê§¦é©¸\u0006L↛Ḣ4๚뿀'?lcwá„§ã®!蓚䃦-|7.飑挴.樵*+1ﮊ\u0010ꛌ%貨啺/JdM:ë˜ïˆ!FBe?鰴㨗0Oè´¢I藻ʔWAá«“Gì³›u`<\/I": [{
+ "$Ï„5Vé´a뾆両環iZp頻යn븃v": -4869131188151215571,
+ "*즢[⦃b礞R◚nΰꕢH=귰燙[yc誘g䆌?ଜ臛": {
+ "洤湌鲒)⟻\\䥳va}PeAMnï¼®[": "ã³Éª/(軆lZR,Cpæ®È®Nå•·\"3Bå©´?i=r$펽á¤ì€¸",
+ "阄R4㒿㯔ڀ69ZᲦ2ç™í•Œå™—På´œîž#\\-ì­è¢›îˆµ&é‘/$4ç«¥Vê©‘_ZHAæ¾¢fZ3": {"x;P{긳:Gé–‰:9?æ´»H": [
+ "繺漮6?z犞焃슳\">á»[Ⳛ䌜ë…䂹>èµâ¼¶ç…œï’˜Yæ¡¥[泥뚩MvK$4ï‰jtï¾›",
+ "E#갶霠좭㦻ୗ먵F+䪀oè’ba쮎4X㣵 h",
+ -335836610224228782,
+ null,
+ null,
+ [
+ "r1᫩0>danjY짿bs{",
+ [
+ -9.594464059325631E-23,
+ 1.0456894622831624E-20,
+ null,
+ 5.803973284253454E-20,
+ -8141787905188892123,
+ true,
+ -4735305442504973382,
+ 9.513150514479281E-20,
+ "7넳$螔忷㶪}䪪lì§´\u0007é¹Pé°šHFéŠZJﳴ/âŽ1ᷓ忉ç‡áœ‹ì“ˆxëµ mä·çª¥á”^\u0019á¶Œå­#ヂt☆áƒpáŽè‡¶äŸ±5ï‰$ä°µ&๵分ìˆ]äˆë‰â™‚åŽ\u0011<>",
+ "C蒑貑è—lï°°}X喇몛;të°¿O7/᯹f\u0015îµ¼kI嘦<ዴ㟮ᗎZ`GWퟩ瑹࡮ᅴB꿊칈??Ræ ¡s脚",
+ {
+ "9çµæˆ¬+AU^洘拻ቒy柭床'ç²™XG鞕᠜繀伪%]hï ¾C,$è¼™?Utä¹–Qmë–šWï¶8઼}~qâ ªrU䤶CQ痗ig@#≲t샌f㈥酧l;yé—¥ZHæ–¦e⸬]j⸗?ঢ拻퀆滌": null,
+ "畯}ã§¢J罚å¸VX㨑>1ꢶkT⿄蘥ã‘o|<嗸層沈挄GEOM@-äžšä§°$만峬è¼ä ±V✩5宸-æ‚î¡§D'ã—ªyP掶7bâ ŸJã•»SfP?d}v㼂á…'猘": {
+ "陓y잀v>╪": null,
+ "鬿L+7:ë‘Y=ç„ U;킻䯌잫!韎ஔ\f": {
+ "駫WmGጶ": {
+ "\\~m6ç‹©K": -2586304199791962143,
+ "ႜࠀ%Í‘lâ¿…D.ç‘¢Dk%0ç´ªdḨTI픸%뗜☓s榗኉\"?V籄7w髄♲쟗翛歂E䤓皹t ?)ᄟ鬲éœ6Cî³´": {
+ "_ì·¤a圷1\u000eB-XOy缿請∎$`쳌eZ~æï€§íŠ»/蜞`塣৙\"⪰\"æ²’l}蕌\\ë¡ƒè«æ°Œ.望wZ|o!)Hnçqg}": null,
+ "kOSܧ䖨钨:಼é‰ê­O醧Sî…¨`ì‹­`ꓭì­ï¯¢N&Et㺪馻ã¢â…³ã¢ºå´¡àºŠèœšé”«\\%ahx켨|ż劻ꎄ㢄ìŸA躊᰹p譞綨Ir쿯\u0016ﵚOd럂*僨郀N*bã•·63z": {
+ ":L5r+T㡲": [{
+ "VK泓ë²á®™Ry㓤➙Ⱗ38oi}LJቨ7Ó㹡৘*q)1豢⛃e᫛뙪壥镇æž7Gè—¯g㨛oI䄽 孂L缊ꋕ'EN`": -2148138481412096818,
+ "`â›á˜‘$(खꊲ⤖á„ꤒ䦦3=)]Y㢌跨NĴ驳줟秠++då­³>8ᎊ떩Eê¡£Sv룃 쯫أ?#Eî·°|á­™ãŽ?zv:5ï©^â‹‘V": [
+ -1.4691944435285607E-19,
+ 3.4128661569395795E17,
+ "ãƒì´—^G9ä½­é¾¶n募8R厞eEw⺡_ㆱ%⼨D뉄퉠2ê©µá›…â³æ¿L팹Là·€n=\"æ…‰ë…á›®y>!`g!í’²î¦ï¨’[/;?[vï®ê²è»‡}⤳â¤í•∌Tã½²R홓é‰ã“¥",
+ "æ„°_⮹T䓒妒閤둥?0î°šaB@㈧gç„»-#~è·¬x<\/èˆPÝ„ê¡=\\׳P\u0015jᳪá¢qï‹¶;ã¯l%á­—;砢觨â–,è¬ê°Gy?躤O黩í‹Yã’a擯\n7覌똟_䔡]fJ晋IAS",
+ 4367930106786121250,
+ -4.9421193149720582E17,
+ null,
+ {
+ ";ᄌ똾柉곟ⰺKpá‡ä±»à¸ºä–{o~h!ï½…ê¿àª»ìš„Úš\u0002y?xUd\u207c悜ꌭ": [
+ 1.6010824122815255E-19,
+ [
+ "宨︩9앉檥pr쇷?WxLb",
+ "æ°‡9】J玚\u000f옛呲~ è¼ 1D嬛,î•*mW3?n휂糊γ虻*á´«ê¾ ?qîžå‡è¶—Ko↦GTé“®",
+ "ã¶¢ážmOã”k'诔栀Z蛟}GZé’¹D",
+ false,
+ -6.366995517736813E-20,
+ -4894479530745302899,
+ null,
+ "V%᫡IIç’…ï»ä…›ä“Ží’¹ï±¢/pU9seë˜ë›žx梔~C)䨧䩻蜺(g㘚R?/á»°[å¿“C뾠ࢤc왈邠买?嫥挤풜隊枕",
+ ",vç¢å–”㌲쟚蔚톬៓ꭶ",
+ 3.9625444752577524E-19,
+ null,
+ [
+ "kO8란뿒䱕馔b臻âŸéš¨\"㜮鲣Yq5mí”<u뷆cè­†\u001bN?<",
+ [{
+ ";涉c蒀ᴧN䘱䤳 ÿꭷ,핉dSTDB>K#ꢘug㼈á¦=P^6탲@ä§”%$CqSw铜랊0&m⟭<\/a逎ym\u0013îš¡vᯗ": true,
+ "æ´«`|XN뤮\u0018詞=ç´©é´˜_sX)㯅鿻á»ì‹¹": 7.168252736947373E-20,
+ "ꛊ饤ï´è¢(逊+~⽫얢鈮ï«è‰¬O힉7Dç­—S곯wæ“I斞᠈븘蓷x": [[[[
+ -7.3136069426336952E18,
+ -2.13572396712722688E18,
+ {
+ "ç¡¢3㇩R:o칢行E<=\u0018á¬YuH!\u00044U%å炼2>\u001eSi$â“·ê’ˆ'ï‘¿ë ¢gᙫ番ꯒ㛹럥嶀澈v;è‘·é„•x蓎\\惩+稘Uî“´Eᖸﳊ㊈壋Nå«¿â¾æŒŽ,袯苷ኢ\\x|3c": 7540762493381776411,
+ "?!*^á¢çª¯?\u0001ڔꙃw虜ë³îšFgJ?&⨫*uo籤:?}ꃹ=ٴ惨瓜Z媊@ત戹ã”똩Ԛ耦Wtè½\\æž’^\\ꩵ}}}ꀣD\\]6M_⌫)Hè±£:36섘㑜": {
+ ";í™—á°°U஋㙛`D왔ཿЃS회çˆ\u001b-㢈`ë´†?盂㛣듿ᦾ蒽_AD~EEຆ㊋(eNwk=RÉ å³­qï’«\"5Ἠ婾^>'ls\n8QAK<l_⭨穟": [
+ true,
+ true,
+ {"ﳷm箅6qⷈ?ﲈ憟b۷⫉἞V뚴少U呡瓴ꉆs~嘵得㌶4XR漊": [
+ "í†ä»‹fM暪$9K[ㄇìƒí³æ’¦gæ’Ÿæ¸jÒFã¹¹aj bHᘀ踉êŽï¼£ç²„ a?\u000fKì¦‰î¶¯éƒ å¹¨9D舢槷Xh뵎u훩Ꜿ턾ƅ埂P埆kë©€{䢹~?D<\/ê¼¢XR\u001b〱ä½ê¼¨i㘀ḟ㚺A-挸",
+ false,
+ null,
+ -1.1710758021294953E-20,
+ 3996737830256461142,
+ true,
+ null,
+ -8271596984134071193,
+ "_1Gí‰í…‘m䮔鰼6멲Nmꇩſt쓟íŠN许FDï¡€j+3^ﶜ⎸\u0019⤕橥!\"sî•—-뾞lz北׸êšëž¬)?l⻮고iä‘°\u001f䪬",
+ 4.459124464204517E-19,
+ -4.0967172848578447E18,
+ 5643211135841796287,
+ -9.482336221192844E-19,
+ "౪å†é‡¶9D?sèž­X榈枸j2ç§€vï ˜î ]泌鰚岒èµè½€ìŒ¶ïŠ›ií…½qMbL]R,",
+ null,
+ [
+ null,
+ {"M쪊ꯪ@;\u0011罙ꕅ<eáº|爑Yâµ<\/&ᩎ<腊ሑᮔ੃Fè±­": [
+ "^0࡟1ë³Pí‹áæˆF⨥Iê‚´\"z磣Vâ…¡=8í€2]䢹h1\u0017{jT<Iç…›5%Dì…Sâ‘™â…J*ìƒ å·™àº”ï€¢;᧡䙞",
+ [{
+ "'ã¶¡í¾é„§`è·Š\"gV[?u᭒Ʊ髷%葉굵aë¦Nì¼§Qﯳy%y䩟髒L䯜Säµ³r絅肾킂á'ꔦg긓a'@혔যWè°á¬F栩ŷ+7wéžš": 6.3544416675584832E17,
+ "苎脷v改hmìµ|㋊g_ᔠ뒨蹨峟ìŽã·¸|Ο刢?Gͨ옛-?î¨Gꦱî«î“©IEYUX4?%ꘋᆊ㱺": -2.8418378709165287E-19,
+ "誰?(H]N맘]kæ´³\"qï±è’§è˜ž!Rí«\\(Q$T5Nå â«£ìœ¿6|럦ì†ï¸…ï­—(": [
+ "峩_\u0003A瘘?✓[硫䎯á½uጭ\"@Y綅첞m榾=è´®9R벿῜Zï §",
+ null,
+ "䰉㗹㷾Iaáƒqcp쓘὾൫Q|ﵓ<\/ḙ>)- Q䲌mo펹L_îŽ¦ì¹æ¨–庫9ê©ìª¹á˜¹ä‘–ç€aK îž?*趤fë­“å»p=磕",
+ "î“å“‘z懅á¤-ê¹ux쀭",
+ [
+ true,
+ 3998739591332339511,
+ "ጻ㙙?᳸aK<\/囩U`B3袗ﱱ?\"/ké”ä§2ï…¤l@쿎VZ쨎/6ꃭ脥|B?31+on颼-ê®§,O嫚m à¡­`KH葦:粘i]aSUì“™$ì‚f+詛頖b",
+ [{"^<9<ç®&絡;%iï«¡2攑紴\\켉hì“™-柂äšven\u20f7浯-Ꮏ\r^í›ä“ší—¬\u000e?\\ã…¡ÖºJë–·VOt": [{
+ "-௄å¶k㘆í˜à®½y⎱㢬sS઄+^瞥h;á¾·jî­;抭\u0003ë°«f<\/5â°§ï§§ï¡™_朻ï—%*[-撵䷮彈-芈": {
+ "㩩p3篊G|宮hz䑊o곥j^Co0": [
+ 653239109285256503,
+ {"ê¶²?|\":N1Û¿æ°ƒNZ#깩:쇡o8킗ࡊ[\"ë¸Po핇1(6é°$膓}â½*)渽J'DN<ì™ê¸˜æ¯¦ë²Ysì¹–": {
+ "2Pr?Xjㆠ?æ®/?㓦柖馃5뚣Nᦼ|é“¢rè¡´ã©–\"ç”æ¹—Üæ†": "\"뾯ië‡ç­ç‰»$ç²/4ka $åŒíœ´ï‹è¯‘zbAá©ê‡¸ç‘…&뵲衯ꎀᆿ7@ꈋ'ᶨH@á ´l+",
+ "7뢽ëšv?4^ꊥ_⪛.>pởr渲<\/⢕疻c\"g䇘vU剺dஔ鮥꒚(dïŸv祴Xâ¼¹\\îºa8y5å†": true,
+ "o뼄Bìšžç¾hrï·”í˜ë’šâ¿›U5pꪴfg!6\\\"爑ì䢱W<ï¶•î\\í…£ç‡oI/BK뺡'谑♟[Ut븷亮g(\"t⡎有?ꬊ躺ç¿è‰©nl F⤿蠜": 1695826030502619742,
+ "ÛŠê¹–>ࡹ햹^ⵕ쌾BnN〳2C䌕tʬ]ì° ?ݾ2饺蹳ã¶êŒ­è¨\"â—¹á¬D鯎4e滨T輀ﵣ੃3\u20f3í‚™D瘮g\\擦+泙᧠鬹ﯨַ肋7놷郟lPå†{ß’hà§œr5,ê“‹": null,
+ "ΉN$y{}2\\N﹯ⱙK'8ɜͣwt,.钟廣䎘ꆚk媄_": null,
+ "䎥eᾆá¦î‘§ì‰,JÞªn岪ã¥sî­•æ–謽䚔5tã¯ï–µï£šã°³ã±ŠZhD䃭f絕s鋡篟îža`Q鬃┦鸳n_é‚(E4è¿ _è§…ë·_宪D(NLî²ç–¶hL追V熑%]vè‚«=惂!㇫5⬒\u001fï²å–º4랪옑": {
+ "2aè¼85먙R㮧㚪Sm}E2yîŠê†£ê«¨rRymã±è†¶á”¨\\tç¶¾A☰.ç„„ë™—9<쫷챻䒵셴᭛䮜.<\/慌꽒9å»Okä°ŠZ㥪幸k": [
+ null,
+ true,
+ {"쌞ì": {
+ "â–ŸGL K2ië›±iï¼±\"Ì .옛1X$}涺]éŽæ‡ Ú¦ëŠ·?tfçŸÝžã‚Ÿ{": 1.227740268699265E-19,
+ "ê’¶]퓚%ฬKâ…": [{
+ "(à·›@Ç®ã£ä§¼äµ¤[aテൖvEnAdUë –ë—ˆ@볓yꈪ,mÔ´|꟢ìº(而첸죕CX4Y믅": "2⯩㳿ꢚ훀~迯?᪑\\啚;4X\u20c2è¥B箹)ä¿£eá»»w䇄",
+ "75༂f詳䅫ê§é¿ }3\u20b5'∓ä±è™€fè¼î‘”Iq鈆﨤gí©)BFa왢d0뮪痮Mé‹¡nw∵謊;ê§f美箈ḋ*\u001cî±ïœŸ`퇚í‹ä³«$!V#N㹲抗ⱉçŽ(V嵟ï«_bã³…\u0019": null,
+ "e_m@(i㜀3ꦗ䕯䭰Oc+-ë ¨0뭦⢹苿蟰ê‚SVä°­å‹¢ë¥.ྈ爑Vd,á•¥=í€)vz뱊ꈊB_6듯\"?{ã’²&㵞뵫ç–ë¡ë¯ˆ%Qwé™,?\ræž®\"? N~癃ruà¡—dn&": null,
+ "㉹&'Pfs䑜공j<\/?|8oc᧨L7\\pX᭠9᪘": -2.423073789014103E18,
+ "ä„瑄䢸穊f盈᥸,Bî§§ë¾§í‘—íšµB1쟢f\u001f凄": "é­–âš2儉j꼂긾껢嗎0ࢇ纬xI4]ï„(à©“`蕞;픬\fC\"æ–’\")2æ«·I﹥迧",
+ "ퟯ詔xæ‚ë ¹+T?Bg⥄섅kOeQí¼ã»´*{Eé¼6æ°¿L缋\u001c둌๶-㥂2==-츫I즃ã ï–˜Lg踞ꙂEG貨鞠\"\u0014d'.ç¼—ï¡gI-lIb䋱ᎂDy缦?": null,
+ "î’¢ç´Mã¦çŠ¿w浴詟棓쵫G:äœ?V2íž½7N*n&ã–ŠNd-'ຊ?-樹DIv⊜)g䑜9뉂ㄹí‘阉~ê…쵃#R^\u000bïž®B䌎䦾]p.䀳": [{"ϒ爛\"ꄱ︗竒G䃓-î†ã¾å¸³ã‚.j)qguæ‰å¾£à¨Zé¼—A9A鸦甈!kè”å–™:3Tî†%&ã ˜+,ä·ž|ì±½v䚞문H<\/醯rì…“ã¶¾\\a볜åºzEä·_죤ဵ뿰᎟CB": [
+ 6233512720017661219,
+ null,
+ -1638543730522713294,
+ false,
+ -8901187771615024724,
+ [
+ 3891351109509829590,
+ true,
+ false,
+ -1.03836679125188032E18,
+ {
+ "<?起HCᷭ죎åŠîŒŽèއ逰/{gs\u0014⽛㰾愫tï¿–<솞ڢëŒç…²è†ºà¨»9x닳xà¡­Q訽,ᶭඦtt掾\"秧㺌d˪䙻꫗:á­ˆh4ç·žç—䤴c뫚떩త<?ᕢ謚6]í›Oé°é‹›é• è´©èµŸ\"<Gâ™·1'": true,
+ "቙ht4ßBqꦤ+\u0006멲趫ç”)椾": -1100102890585798710,
+ "ç·å…Žê³‡ë‡¸ç²ŸF醇;朠?厱楛㶆â¶7râ¾›o꯬᳡F\\머幖 㜦\f[æ¦á¥½ã®£0䕊?J㊳뀄e㔔+?<n↴å¤î§·": [
+ "4~ê‰ç¾\\å®(泤å•빜\u0014>j랎:g曞ѕᘼ}链N",
+ -1.1103819473845426E-19,
+ true,
+ [
+ true,
+ null,
+ -7.9091791735309888E17,
+ true,
+ {"}蔰鋈+ê¨å•µ0?g*사%`J?*": [{
+ "\"2wG?yn,癷BK\\龞䑞x?蠢": -3.7220345009853505E-19,
+ ";饹়â€)çš‹`噿焒j(3â¿w>å5X<np?<줯<Y]æ˜!J೸UⳂNे7v௸㛃ᄧ톿䨷鯻v焇=烻TQ!F⦰䣣눿Ké·šëˆ'â­²mæ (äš»": [
+ "蹕 淜੃b\"+몾ⴕ",
+ null,
+ 35892237756161615,
+ {
+ " 듹ã)5æ…ç®±&$~:é°ì®<\/å ‹?% \\勽唅zì†å¸‹ä˜ºH髀麡M퇖uz\u0012m諦d᳤콌æ¨\rX싹̡á²": -433791617729505482,
+ "-j溗ࢵcz!:î€}✽5à´‡,욨Ýs#ë«=å—æµº^}E\\Y\\T*뼈cdêºcÛ˜ïµëŽä¨¸ë±K䠴㉿æ¿é€³îŽœ@wî·¿fì¢<\/[L[": -9.3228549642908109E17,
+ "Ms킭uà®—%\\uâŽ/家欲ἅ答㓽/꯳齳|㭘Pr\"v<\/禇䔆$GA䊻˔-:틊[h?倬è¤á¾žà§³.Gw\u000b": [
+ "0宜塙I@ä´è‰\\Uyë’…=2<hæš’ï…£K._è´¡ç’Yi檻_⮵uá㘗è [f\u0015힢Hê”®}጑;ï´èªyf0\"\u20cc?(=qæ– âž½5ꎾ鞘kⲃ",
+ -2.9234211354411E-19,
+ false,
+ true,
+ {
+ "\u0011⟴GH_;#怵:\u001c\u0002nîž»1U\\p/ì™”(┫]hêšî·ƒ7\r0䵷첗岷O௷?î·°ãŽ[殇|J=?韷pᶟ儜犆?5კ1kê–iH竧뛈ପdmk游y(콪팱ê¾k慧 yè¾£": [
+ false,
+ "O\"ëp覈ykv磂㢠ãµ~뀬íŠlC&4솎䇃:Mj",
+ -7.009964654003924E-20,
+ false,
+ -49306078522414046,
+ null,
+ null,
+ 2160432477732354319,
+ true,
+ "4íš¡h+!踹ê¬P鮄{0&ë±¥M?ìƒéž…n㮞ᨹ?쒆毪l'ç®…^ꚥ頛`e㻨52柳⮙嫪࡟딯a.ï‘„~äµ®1få˜N&zÈ­L榓ۃ鳠5d㟆M@㣥ï Ó‹AÎq0縶$",
+ -3.848996532974368E16,
+ true,
+ null,
+ -3.5240055580952525E18,
+ {
+ " vï­·áµ#ce乃5僞?Z D`묨粇á”ç» vWLè­¢uë½€\\J|tâ“™tâ„–\"ꨋnT凮ᒩè‚ç¯b騩:䢭Hbvì»å³¨z㹚T趗햆귣학津Xiï¼¹@á–¥K": true,
+ "!F 醌yï䉸W2ꇬ\u0006/ä’7~%9擛햀徉9â›°+?㌘;ê “X䇻Dfië¼§ì’’\u0012F謞Õ絺+臕kà¤LSQìŒX쎬幦HZ98è’Šæž³": "澤令#\u001dæŠâ›³@Næ•퀂[5,✄ꘇ~䘷?\u0011Xꈺ[硸⠘⛯X醪è¡x\u0007쌇MiX/|ï¾ëšK8ä¡î¿¥W)銀q僞綂蔕E",
+ "6â²ä£–Rà§ž@ငg?<\/à³´xé™™Xꈺ崸⠅ᇾ\\0X,H쟴셭A稂ힿã‚F\\쑞\u0012懦(Aᯕç­~î½”\u0001ê»®X?逊": 5.7566819207732864E17,
+ "[c?椓": false,
+ "kä’‡": 2583824107104166717,
+ "꙯N훙ã…ﮒ燣㨊瞯咽jî™Mxby뻭뵫װ[\"1畈?à§±L": "ë£á”‚魠羓犴ꚃ+|rY",
+ "ë…ºZ?îˆä¬ï“©é‰‰îˆ­:?â³™ç˜Cኯ.Vs[釿䨉ì§\\\\*쵢猒$\\y溔^,㑳": {"藶꺟": [{
+ "\"d훣N2zq]?'檿죸忷篇ﮟ擤m'9!죶≓pë­»\\ᇷ\f퇶_ä°¸hà¹Q嵃訾㘑従ꯦ䞶jL틊ræ¾µOmᾫ!H䱤팼/;|á­ºI7슎YhuXiâš¼": -1.352716906472438E-19,
+ "M⽇倻5Jä‚«à¤”á”æ¥¸#î „î¾–J[Fﹱ쫮W誻bWz?}1\"9硪뻶fe": "盬:Ѹ砿íšë•£T凊(mç¦å‘œï»R㿎艴䂵h",
+ "Rë¾k힪CHé’™_i苮ⰵoᾨ紑퉎7h؉\"柀è½z0့\"<?嘭$èœ?礲7岇槀묡?Vé’¿T⣜v+솒çšÔ›2ç±³mH?>è–™å©è¿3aFÆÃ": "2,ê“´g?_섦_>Y쪥션钺;=趘F~?D㨫\bX?㹤+>/믟kᠪ멅쬂Uzỵ]$ç§`mé›ç‘Šî’ඖ鯬cꙉ梢f묛bB",
+ "♽n$YjKiXX*GOè´©éƒè±®ç¥´éžK醞眡}ê—¨v嵎꼷0à­¸+Mè‹eH徸Jîžê£†:â¼æ‚¥B켽迚㯃bè«‚\u000bjꠜ碱逮m8": [
+ "푷᣺ﻯd8ﱖ嬇ភHîªé¹Žâ¡±á±…0g:æžœ6$GQ췎{vá·§Yy-è„•xå¹ç ¡ï¨¬â®¸Cï§‚êš=軄H犠Gè°–ES詤Zè ‚3î§™lë´Ÿhï¿’7䦹1GPQG癸숟~[#é§¥8zQ뛣J소obg,",
+ null,
+ 1513751096373485652,
+ null,
+ -6.851466660824754E-19,
+ {"ä©‚-â´®2Ù°K솖풄꾚ႻP앳1Hî³é·›wmR䗂皎칄?醜<\/&à §ã¬X濬䵈K`vJ륒Q/IC묛!;$vÏ‘": {
+ "@-êš—xྐྵ@m瘬\u0010U絨ﮌé©\\켑寛넆T=tQã­¤Lì—°@脸삯e-ï–…î–‘:⩼u㎳VQ㋱襗ຓ<Ⅶ䌸cML3+\u001e_C)r\\9+Jn\\Pﺔ8蠱檾è…Pqé³è¯î¦§Tä„I": -1.80683891195530061E18,
+ "á·­á‹»U~ཷsgSJ`᪅'%ã–”n5픆桪砳峣3ç®æž¾äŒ·âа呀ïŒ": {
+ "Ş੉䓰邟自~X耤pl7间懑徛s첦5ਕXexh⬖鎥á€nNr(J컗|ૃF\"Q겮葲놔엞^겄+㈆è¯ã€¾í¬ç´G'E?飕1fâ¼í…¬æ‚šï•¦æ³¬ë¨Uç¬í›¶Qs": false,
+ "î³…(\u20dag8í½íŠ£>^Y{뤋.袊䂓î†;_ïg]S\u202a꽬L;^'#î—™ë•bႌ?Cç·¡<ä²ä²æ–­ê6\u001asD7IK5Wxo8\u0006på¼Šâ¼‚ê¯æ‰µ\u0003`뵂픋%ꄰ⫙ë¶lå›å°›ïˆ®+ä—…E쟇\\": [
+ true,
+ {
+ "\n鱿aKã¡â’ã¼™2ì´¹f;`ì¾qIà¡”G}ã·äç“°w늮*ç²…9뒪ㄊCj倡翑閳R渚MiUO~仨䜶RꙀA僈㉋⦋n{ã–¥0딿벑î§é€¦â¥»0î¾®h薓쯴ê»": [
+ 5188716534221998369,
+ 2579413015347802508,
+ 9.010794400256652E-21,
+ -6.5327297761238093E17,
+ 1.11635352494065523E18,
+ -6656281618760253655,
+ {
+ "": ")?",
+ "TWKLꑙ裑꺔UE俸塑炌Ũ᜕-ï’‚o\"徚#": {"M/癟6!oI51niíš=댡>xê¨\u0004 ?": {
+ "çš­": {"⢫䋖>u%wî²´ìž¼<ä•ê˜P䋵$é­‹æ‹U䮎緧皇Y훂&|羋ꋕ잿cJ䨈跓齳5\u001a삱籷I꿾뤔S8㌷繖_Yឯ䲱B턼Oæ­µF\\l醴o_欬6ç±=D": [
+ false,
+ true,
+ {"Mt|êžD|Fê¶£MQ뵕T,ëºk+?ãµi": [
+ 7828094884540988137,
+ false,
+ {
+ "!༦鯠,&aﳑ>[euJê½ç¶·æB.h": -7648546591767075632,
+ "-n켧嘰{7æŒæ¯„Y,>â螵煫乌pv醑Qå¶š!|âŒè²¬0왾ë¢ê…蛨S\\)ç«°'舓Q}A釡5#v": 3344849660672723988,
+ "8é–ªéºV=鈢1녈幬6棉⪮둌\u207d᚛驉ꛃ'r䆉æƒà¥ˆ|bἧﺢᒙ<=穊强s혧eꮿ慩⌡ \\æ§³W븧J檀C,ᘉì˜0俯퀉M;筷ࣴ瓿{늊埂鄧_4æ¸Nn阼Jੵ˥(社": true,
+ "oë¼€vwï…®)4A뢵(î¼±a䵢)p姃뛸\u000fK#KiQp\u0005ê…芅ì…îª": null,
+ "ç ¥$ꥸ┇耽uæ–®Gc{z빔깎밇\\숰\u001eê´·å„㶇쵿_á´„+hç©¢p촀Ნ䃬zäé…³Ó‚31xꔄ1_ç šWë ˜G#2葊P ": [
+ -3709692921720865059,
+ null,
+ [
+ 6669892810652602379,
+ -135535375466621127,
+ "뎴iO}Z? 馢녱稹ᄾä©rSt帤넆&7ié¨ë©—ç•–ï”9誧鄜'w{Ͻ^2窭외b㑎粖i矪ꦨ탪跣)KEㆹ\u0015V8[W?⽉>'kc$䨘ᮛ뉻٬M5",
+ 1.10439588726055846E18,
+ false,
+ -4349729830749729097,
+ null,
+ [
+ false,
+ "_è ¢ã ^䟪/D녒㡋ỎCä’ˆíŒïŒ¢\u0006àªq@O펢%;é¹ìŒo戥~A[ꡉ濽ỳ&虃᩾è£å”™ï¤£èŒ¨Ig楡꒻M窓冉?",
+ true,
+ 2.17220752996421728E17,
+ -5079714907315156164,
+ -9.960375974658589E-20,
+ "ᾎ戞༒",
+ true,
+ false,
+ [[
+ "ⶉᖌX⧕홇)g엃⹪xëšç™Ÿ\u0002",
+ -5185853871623955469,
+ {
+ "L㜤9ợㇶKé°â‹“V뽋˖!æ–«as|9"á¬ä†ª?î¾¶7胜&n薑~": -2.11545634977136992E17,
+ "O8뀩D}캖qè‚6༣ã—䈓煮å½à¨†á޼Dᣘí›;": false,
+ "YTá¡…^ï—Lã—ŽcbY$pᣞ縿#fh!ꘂb삵玊颟샞ဢ$ä—é¼’ëª~rkH^:닮먖츸륈⪺쒉砉?㙓扫㆕꣒`R䢱Bé…‚?C뇞<5Iޚ讳騕S瞦z": null,
+ "\\RB?`mG댵鉡å¹ç‰©äµŽæœ‰5*e骄T㌓ᛪç¾é§’Ku\u001a[柆jUq8⋈5鿋츿myï»—?é›ux঴?": 5828963951918205428,
+ "n0æ™…:黯 î¶·xu씪^퓞cB㎊á¬âº˜Ù¤Öƒ~B岚3㥕擄vᲂ~F?Cä¶–@$mï›~å¿”S왖㲚?챴⊟W#벌{'ã°Iä ç¸s樘\\X뢻9í•¡I6èㄛî‚î«8쯶]wॽ0L\"q": null,
+ "x增줖j⦦tä¢áŽ™ïŠ­ã›¿Yf鼘~ê«“æ„4惊\u209c": "oOhbᤃ᛽z&Bi犑\\3B㩬劇䄑oÅ쨅孥ë©àº–acA㖫借ãžvg싰샂ãœ#譞⢤@k]鋰嘘䜾L熶塥_<\/â¾å±ˆï®Š_mYè¹t뙺}Ox=wé®®4S1ê©ï¬¾'å·‘",
+ "㗓蟵ꂾe蠅匳(JPä—à·¸\u0089耀왲": [{
+ "ᤃ㵥韎뤽\r?挥O쯡⇔㞚3ä¼–\u0005Pî•⋪\"Dê¶£QLn(⚘罩䩢Ŏv䤘尗뼤ë›O淽鋋î¡é—šrå´©a{4ç®™{煷m6〈": {
+ "l곺1L": {
+ "T'ਤ?ç …|੬Km]ä„©\"(à¿¶<\/6U爢䫈倔郴l2ã´±^줣k'Læµ–Lé°„Rp今鎗⒗Cì–¨Mí›ã¡§Î˜X粜뫈N꤇輊㌻켑#㮮샶-ä—룲è ç™œã±V>=\\I尬癤t=": 7648082845323511446,
+ "鋞EP:<\/_`á§e混ㇹBd⯢㮂驋\\q碽饩跓྿ᴜ+j箿ë ã—‘yK毢宸p謹h䦹乕U媣\\炤": [[
+ "3",
+ [
+ true,
+ 3.4058271399411134E-20,
+ true,
+ "æ€+憱f逮@먻BpW曉\u001aã£âŽŠ$n劈D枤㡞좾\u001aá›ïŒƒè‹”౩é—1B䷒Ṋ݋âžê€žêƒç£$t੤_:蘺⮼(#N",
+ 697483894874368636,
+ [
+ "vᘯ锴)0訶}䳅⩚0O壱韈ߜ\u0018*Ué¾ä–=䧉뽑å•휻ID쿇嘗?ꌸῬ07",
+ -5.4858784319382006E18,
+ 7.5467775182251151E18,
+ -8911128589670029195,
+ -7531052386005780140,
+ null,
+ [
+ null,
+ true,
+ [[{
+ "1欯twG<uä®â½ê‡£_ჟﱴଶ-쪋\"?홺k:èŽêœª*⺵꽹댅釔좵}P?=9ë ¿46b\u001c\\S?(筈僦⇶爷谰1ྷa": true,
+ "TҫJYxÚª\\鰔℮혡)m_WVi眪1[71><\/ï†Q:0怯押殃탷è«ì‚¬<ỗꕧ蚨ä¡ï¨î³‰nDꌕ\u001cë…¬~è“©<N蹑\"{ä«¥lKcí˜ë«–앺:vⵑ": "gæ§µ?",
+ "aꨩ뻃싥렌1`ë¡—}Yg>鲃g儊>ê¡l㻿/â‘·*ì±³6㻜W毤緛ﹺᨪ4\u0013뺚J髬e3쳸䘦伧?æª&{L掾p+꬜MäŠd娘6": {
+ "2p첼양棜h䜢﮶aQ*c扦v︥뮓kC寵횂S銩&Ç{O*य़iH`Uí…à¡“rä©•5ꄸ?`\\á§«?ᮼ?t〟崾훈kè–ì/iy꤃뵰z1<\/AQ#ë¿©8jJ1z@u䕥": 1.82135747285215155E18,
+ "ZdN &=dë…„á…†'ì‘â…‰:烋5&áŸï”‹á„‚汎æ¥L㯄固{é’§u\\ãŠíŠšeæ‘‘&tå—„ê–„UbâŒ?m䴘熚9EW": [{
+ "ଛ{i*a(": -8.0314147546006822E17,
+ "⫾ꃆY\u000e+W`௸ \"Më’¶+\\ë·lKE}(NTí‚¶Yjé¸ç¯’î©¥ì¶'jNQ硾(똡\\\"逌â´y? IRꜘ὞鄬﨧:M\\fâ ‹Cꚜ쫊ᚴNV^Dä•—ã…–á¼”Iao꿬Câ8": [
+ 287156137829026547,
+ {
+ "H丞N逕<rO䎗:í…•<\/䶩샌Sd%^ᵯëˆ엑者g䖩똭蕮1U驣?Pâ°°\u001fp(W]67\u0015ï«£6굺OR羸#ì´Fè’ˆ;嘙i✵@_æ’¶yã¤â¤(:᧗뼢༌朆@â°ã¤¨ê­²?-n>⯲": {"": {
+ "7-;枮阕梒9ᑄZ": [[[[
+ null,
+ {
+ "": [[[[
+ -7.365909561486078E-19,
+ 2948694324944243408,
+ null,
+ [
+ true,
+ "荒\"并孷䂡쵼9o䀘F\u0002龬7⮹Wz%厖/*? a*R枈㌦ë¾g뒠䤈q딄㺿$쮸tᶎ릑弣^éŽ<\/Y鷇驜L鿽<\/ì¶‹9Mᲆឨ^<\/庲3'lë‚¢",
+ "c鮦\u001bë‘\\~?眾ಢu݆綑෪蘛轋◜gȃ<\/â´ƒcpkDt誩܅\"Y",
+ [[
+ null,
+ null,
+ [
+ 3113744396744005402,
+ true,
+ "v(y",
+ {
+ "AQ幆h쾜O+꺷铀ꛉ練A蚗⼺螔jãŒ3꽂楎䥯뎸먩?": null,
+ "蠗渗iz鱖w]擪E": 1.2927828494783804E-17,
+ "튷|䀭n*曎b✿~æ¤U]î­¡Gz鄭kW|ã´š#㟗ഠ8u擨": [[
+ true,
+ null,
+ null,
+ {"⾪壯톽g7?㥜ώQê‘㦀æƒã§½î“¡ä¼“\\î¦*᧰閖樧뢇赸N휶䎈pIæ°‡ï®é•Šmaᬠ탷#X?î³A+kÐM ༑᩟Ø?5꧎鰜ṚY즫궔 =ঈî³;ﳈ?*s|켦蜌wM笙莔": [
+ null,
+ -3808207793125626469,
+ [
+ -469910450345251234,
+ 7852761921290328872,
+ -2.7979740127017492E18,
+ 1.4458504352519893E-20,
+ true,
+ "㽙깹?ë¨ä†¢:ä´ŽÛ»gæ® JBTU⇞}ꄹꗣi#Iî’¡ëµ£é‰r혯~脀ìƒ#釯:场:ä”>ä°®o'ã¼½HZ擓௧nd",
+ [
+ 974441101787238751,
+ null,
+ -2.1647718292441327E-19,
+ 1.03602824249831488E18,
+ [
+ null,
+ 1.0311977941822604E-17,
+ false,
+ true,
+ {
+ "": -3.7019778830816707E18,
+ "Eå³¾æ†èŒ6xLIm縂0n2视֯J-ᤜz+ᨣè·mYDè±ç¹¹â¹ºäŠ“ëª“ï´€E(@è©®(!ï’Y膽#᎙2䟓섣A䈀㟎,囪QbKæ’wcG湎ꤧtGì—xâ¥ä¿Žj'A一ᯥ뛙6ㅑ鬀": 8999803005418087004,
+ "よ殳\\zDâ§…%Y泥簳Uꈩ*wîRL{3#3FYHା[d岀䉯T稉駅䞘礄P:é—ˆWæ€ElBã¤å–¬èµ”bGä ¼U଄Nw鰯闀楈ePsDꥷ꭬⊊": [
+ 6.77723657904486E-20,
+ null,
+ [
+ "ཚ_뷎꾑è¹q'㾱ꂓ钚蘞慵렜떆`ⴹ⎼櫯]J?[t9Ⓢ !컶躔I᮸uz>3aã •i,錃L$æ°°í…°@7ë…«W㸮?ç¾§W뇧ꃞ,î—‘N鋮숪2ɼì½â”ä²6",
+ "&y?뢶=킕올Za惻HZk>c\u20b58i?ꦶcfBv잉ETî…9jä¡¡",
+ "imçŠÕƒbì¹§<D-è«‚*u2ꡜ췛~䬢(텸ﵦ>æ ¡\\뼾쯀",
+ 9.555715121193197E-20,
+ true,
+ {
+ "<㫚v6腓㨭e1ã•”&&V∌ᗈT奄5Lጥ>탤?튣瑦㳆ꉰ!(ᙪ㿬擇_n쌯IMá¿‹î£ã•¨â°æ«ˆá±·5풔蟹&L.ì²½e鰷쯃劼﫭b#ï­¶í“€7ë·„Wr㢈๧Tʴશ㶑澕é%": -1810142373373748101,
+ "fg晌o?߲ꗄ;>C>?=鑰監侯Kt굅": true,
+ "䫡蓺ꑷ]C蒹㦘\"1à°ƒ@å‘«\u0014NLä¾egå‘®á³,r$裢k>/\\<z": [[
+ null,
+ "Cä¡>?ㄤᇰﻛ쉕1஥'ÄŠ\" \\_?쨔\"ʾr: 9Sä˜ç¦ºáª§ê„‚㲄",
+ [[{
+ "*ç¡™^+E쌺I1䀖ju?:⦈Ꞓl๴竣迃xKC/饉:\fl\"XTFᄄ蟭,芢<\/骡軺ëœhê˜\u001f銿<棔햳▨(궆*=ä¹¥b8\\媦ä·€ë«}닶ꇭ(Kej䤑M": [{
+ "1á¬?>옿Iâ•…C<ÞŽ?ꊌ冉SV5A㢊㶆z-๎玶绢2F뵨@㉌뀌oå¶”f9-庒茪ç“ë·³4": null,
+ ";lá°³": "CbB+è‚»aä„·è‹*/볳+/4fq=ã°h6瘉샴4é“¢Yéª.⌖@哼猎㦞+'gꋸ㒕ߤï—ãž‘(ä¶’è·²tiâ‘´aî¥ç¡‚#Noë³”",
+ "t?/jE幸YHT셵⩎Kî¹!Eq糦ꗣv刴w\"l$ο:=6:ç§»": {
+ "z]鑪醊嫗J-Xm銌ç¿çµ¨c里ëç‚™Ep㣋é£ë˜¼åšŒä€“GPï¹–cmf4é¹­T䅿꣭姧â¸wy6ꦶ;S&(}ᎧKxᾂQ|tï¹ë»³k\"d6\"|Mlì·†hwLtê¼¼4$&8Պ褵婶鯀9": {"嵃닢ᒯ'î–›dá§«ä³³#Nî‡Xe3-붋鸿î¢à¬¢ë–“î§ž%dK\u0013䲎ê–YV.裸Râ‰rR3蟛\\:ì ¯:å—ĺLʆ넕>|텩鴷矔ꋅⒹ{tå­¶ã“‘4_": [
+ true,
+ null,
+ [
+ false,
+ "l怨콈lá’",
+ {
+ "0wä²å¬§-:`䉅쉇漧\\Ü‚yㄨb%㽄j7ᦶ涶<": 3.7899452730383747E-19,
+ "ꯛTẀq纤qå¶Vâ¿£?\"g}ი艹(쥯B î­T騠I=仵ë°X": {"KX6颠+&á…ƒ^fç•’y[": {
+ "H?뱜^?꤂-⦲1a㋞&î‘®êƒç²¾Ii᤾챪咽쬘唂쫷<땡劈훫놡o㥂\\ Kâ´™Dç§¼Fæ°®[{'좴:례晰Iq+Iì­¥_T綺砸GOç…䟪ᚪ`î‘↹l羉qì¼Dê½áœ…훦: vUV": true,
+ "u^yï³0㱓#[y뜌앸ꊬLã·©?蕶蘾â»KӼ": -7931695755102841701,
+ "䤬轉車>\u001c鴵惋\"$쯃྆⇻në½€Gæ° Såª]à²²ê¨æ‡Qxኻ椕駔\\9ࣼ﫻ìœç£¡ï©ˆëºªá¶šë³l㕆t+sζ": [[[
+ true,
+ false,
+ [
+ null,
+ 3363739578828074923,
+ true,
+ {
+ "\"鸣詩 î›ë³°ã‘µgLã¯¦á¿…ì¶æ—«}ED辗ﮈI쀤-ꧤ|ã ¦Z\"娑ᕸ4çˆé¨ã£\"]ì³Af]茛⬻싦oèšk䢯ä©è½3廇喑ޅ": 4.5017999150704666E17,
+ "TYႇ7ʠ值4챳唤~Zo&ݛ": false,
+ "`å¡„J袛㭆ëºã³€N㺣`ê½å¶¥Kï¯SVᶔ∲퀠ç¾N딂X\"á¤hNﬨvI": {"\u20bbã­˜I䖵䰼?sw䂷쇪]î(泒f\"~;꼪FÔsá¦": {"p,'ꉂ軿=Aèš¶?bƉãµä…°è«¬'LYKL6B깯⋩겦뎙(ᜭ\u0006噣d꾆㗼Z;ä„äš”cd<情@äž‚3苼㸲U{)<6&ꩻ钛\u001au〷N숨囖愙j=BXWìš•^x芜å á¿™çˆ‚ë›·ê’»t✘Q\b": [[
+ "ç±›&ଃ䩹.ꃩ㦔\\C颫#暪&!勹ꇶ놽攺J堬镙~軌C'꾖䣹㮅ï¶å²ƒá™´éµ£",
+ 4.317829988264744E15,
+ 6.013585322002147E-20,
+ false,
+ true,
+ null,
+ null,
+ -3.084633632357326E-20,
+ false,
+ null,
+ {
+ "\"짫愔昻 Xï«\"è—£j\"\"ë¨à½…ѻ㘤㬯0晲DU꟒㸃dë²€î¢ìœ’l䦾cà©»*3": null,
+ "è°ˆWm陧阦咟ฯ歖擓Nå–´ã‹éŠ­rCCnVࢥ^♼Ⅾ젲씗刊Sà¼+_tèµ”\\bäšë‰¨ê¬«6펛cL䊘᜼<\/澤pF懽&H": [
+ null,
+ {
+ "W\"HDUuΌ퀟M'P4à¿°H똆ⰱﮯ<\/å‡è˜²\"C鴫ﭒж}ꭩ쥾t5yd诪ﮡí‰â´°@?æ°é†³rj4I6Qt": 6.9090159359219891E17,
+ "絛ﳛ⺂": {"è«°Pã—®î˜è¦`ZQ?ꫦh*à´±cbâ§±}埌茥h{棩렛툽o3é’›5é®l7Q榛6_g)ὄ\u0013kj뤬^爖eO4Ⱈ槞鉨ͺ订%qX0Tì—å«·$?\\\"봅늆'%": [
+ -2.348150870600346E-19,
+ [[
+ true,
+ -6619392047819511778,
+ false,
+ [[
+ -1.2929189982356161E-20,
+ 1.7417192219309838E-19,
+ {"?åµ²2à¿2\u0001啑㷳c縯": [
+ null,
+ [
+ false,
+ true,
+ 2578060295690793218,
+ {
+ "?\"殃呎ïˆ#ã‘‘F": true,
+ "}F炊_æ®›oU헢兔êˆ,èµ­9703.Bæ•°gTz3â¬": {
+ "5&t3,í–“Mݸᵣ㴵;꣫ä©â†³#ï¢@ë«·ä …ï¦+W-ࣇzᓃ鿕ಔ梭?T䮑ꥬ旴]u뫵막bBè®:왳둛lEh=숾鱠på’î›î­ˆ$ì§#?gâ¹·á—Švã·µ.æ–ˆu頻\u0018-G.": "ë½™m-ouࣤ஫牷\"`Ksꕞ筼3HlȨvCï¢î›¦å ˆ\"I]㖡玎r먞#'W賜鴇k'c룼髋䆿飉㗆xgå·¤9;芔cáŒ/ax䊨♢í“rå“㸫೼䢗da᩾\"]å±£`",
+ ":M딪<䢥喠\u0013ã–…x9è•ã‘‚XO]f*Q呰瞊å­VP@9,㨣 D\\穎vˤƩs㜂-曱唅L걬/롬j㈹EB8g<\/ì„©o渀\"u0y&룣": ">æ°ç·©L/ä•‘ë¯êŸ˜îŸ”蕞^aBë’£+0jK⪄瑨痜LXK^힦1qK{æ·št츔X:Vm{2rçB뾄H첚7æ°¥?쉟䨗ꠂv팳圎è¸é½€\\",
+ "D彤5㢷Gꪻ[lㄆ@὜⓰絳[ଃç½ì®¹â˜’[*0ꑚ㜳": 9022717159376231865,
+ "Ò–aV銣tW+$é­¿\u20c3ïœäºœ~ë«¡ᙰ禿쨽ã¡fá¹¼zE/h": "5è‡ï’Œã‹‡á²¯ì®º? 昨탰Wム밎#'\"崲钅U?幫뺀â¾@4kh>騧\\0Ò¾EV=çˆî©®ÍŒUæ€%ꉼ 㮋<{j]{R>:gÔ©L\u001c瀈锌ﯲﳡꚒ'â«¿E4æšãŒ—뵉X\"Háœ",
+ "ᱚגּ;s醒}çŠSἿ㦣&{T$jkB\\\tḮ앾䤹o<é¿(tW": "vb⯽䴪䮢@|)",
+ "⥒í껉%惀뗌+녣迺顀qæ¢g⚯i⤭ë£Mç¹j̈́⽜A": -8385214638503106917,
+ "逨ꊶZ<\/W⫟솪㎮ᘇb?ê ”i\"H㧺x෷韒Xꫨฟ|]窽\u001a熑}Agn?Má¶–a<rà°„4Ů䢤슲AxÄ£eê³–ã´¤x竾éƒB謉鸵kè–½M)\"芣眜`è‰ê‰›ä´º": "é¹^ె캫?3耲]|Ü1ä¡’ã®]8e?ä¶^",
+ "뿸樅#P㡊1M룮Uꪭ绢ꑮZ9꽸": {"\nJ^Ñ”|3袄ã…7⨆銦yîµ”çâ‹·ä»´ct?[,<\/ã…¬`?갔髞%æA೚C": {
+ " 䇞3갫䅪": [{
+ "0|â©ã‘‚砕ㅻ": null,
+ "D箳᠉`|=â¼­)\"*࣊ã¦LjO誋": "",
+ "ࠚDZmê—¥}ᷴ╈r7í—´È¥4Kp5a)o}鎘门Læ°ä†“'✎k俎c#T68Óâ©¶î¶6L鎴<r൦$黊BQYã¼³\\è·¿F慮⡨拵贀!ç”¶Vå–…/": null,
+ "âµ£q⳹ﻨLk]晩1*y\\$%}ä–¶P煑㇆䈦E嫿«•Y࣓嫨ä“OL낮梚㸇洛洚BYtgl∛S☕䉓宑⋢粚ꔯ꠼붠": ")ꬑ윤`\"â°£<\/婽*Y䔸ᓰ_ï³t슲å©éš¥&S糧䛮闵诌è±sh쯽邴*ì„´ØÍŽ=㯨\"RVíž³,^t\"ac?䤒ꉀxHa=Uꛕã™î·“TkF껾",
+ "å¼¾cUAF?暤cë½.欀nKì•­]r傊䀓ﯳ馽垃[䥛oI0N砊鈥헅Co쟋钄ㅷ㊌뷚7": [
+ null,
+ "à«“é¨?^ä†{\u0006`X䧵儱&롡尙砡\u0006ë»ì‘¬sjâ–»Xfᬶgcã„¢V >9韲4$3á»´^=ì煤áë·2䣃%ï…Žé· /eQ9頸쥎",
+ 2398360204813891033,
+ false,
+ 3.2658897259932633E-19,
+ null,
+ "?ꚃ8Nnãž·å¹µd䲳䱲뀙ꪛQ瑓鎴]î’¶ä©‹-é°¾æ¡ï¾ä³¡??掊",
+ false,
+ -1309779089385483661,
+ "ᦲxu_/yecR.6èŠ.áœ‡éŽ ~",
+ -5658779764160586501,
+ "ì’Œ:æ› =lìœä¢œwk#s蕚\"互㮉m䉤~0ë“䋙#Gîš¿;h숄옥顇෤勹(C7㢅雚ã¯Lâ …VVç°…<",
+ null,
+ -4.664877097240962E18,
+ -4.1931322262828017E18,
+ {
+ ",": {
+ "v㮟麑䄠뤵g{Më®.\u001bzt뢜뵡0Ǥ龍떟Ᾰ怷ϓRT@Lꀌ樂Uã â¾•e扉|bJg(뵒㠶唺~ꂿ(땉x⻫싉ìŠ;%0鎻V(o\f,NéŠ%nk郼螺": -1.73631993428376141E18,
+ "쟧摑繮Q@Rᕾ㭚㾣4隅待㓎3蒟": [
+ 4971487283312058201,
+ 8973067552274458613,
+ {
+ "`aæ™á£—î\u0015i<S幼訃锭B0&槩✨[Wpçš©[g≊k葾x2ᡆ橲䲢W": true,
+ "kH皈Sê±qå‚‘u?솹풑~o^F=ï¦N*reî••J沤wW苯7pã¼¹äŽa=ꮧLã·©냴nWꌑ㞱uuè°lVNç¿á¤»(eè±¶5#L쪉ᅄ઄\u0015숟봊P瀚X蓎": false,
+ "䫯דּ〖Scä›­ì Lëµ¾pî«“CꙞ\"엇즓_ﰛ톣ꫀ먩㺣㮠⭴!\\Wâ”tä–°è»…y\u0014~ᇰ렢E7*俜䥪W䀩ä·hë´†vjஉ묣à¼G39.뼳輼:㮿á¦A饕TUL}~": [
+ null,
+ 8.8648298810470003E17,
+ 5.735561205600924E-20,
+ null,
+ -102555823658171644,
+ 1.2674932032973067E-19,
+ {
+ "D胣O㯨\u0017Ku눓ã’í…nᨊ!Ꚇ廫_>Bo¸": 4.3236479112537999E18,
+ "HW&퉡ãåœ<W)6æ‚°ê ‘HEp14xy峑ft\u0005s亘V튉䢮ꦈXåµê¬?lI_ë춇-6Ss噺Nk-ﮥíƒÜ郪*ï“­PR(S6â•‹@ä»™V懸뺵ﯜVç²¹": "9䗌斀4ãˆ^Qséš„ç¡j\u0003",
+ "Vké¶…Cæ³¹ç­HX훉朗*r\\z顊誌儖4?n7á¾6몋䎡ﳈ],Hé ¢pèšã‘„P4满Eä©V䬕à¸L廂쒬î®ì‘¨ê†·hè¿¡ê°è­–墎 î‡]鹿ฌ7ﶽ冭༽<ꈓS\\lä‹®?_ユ檒?": -8598528325153980065,
+ "t=qí£ç–»Ñ‚Z\\錅J.镎|nfḷ鴒1厰Lç¯çºœîŒ•E]୦⥪]á®'ç¾p/å’©0닳ï³qﳖཽk ?X1Ft%ś뭢v鋋⺃爵⒗": [[
+ 5.0824756359232045E-19,
+ [
+ 7.268480839079619E-19,
+ {"탿^굞⧕iјëŠê€›w껩6ꟳXsé…š\\>Y?ç‘¡Qyí›q!帰ï©s舠㫸zêš—aSæ­²v`G株巷Jp6킼 (ê·¶é”â¾î‹¥â¡ˆ>Mæ±ãžá‰´ê™²dv@i㳓ᇆ?é»": [
+ null,
+ 4997607199327183467,
+ "E㻎蠫á¾é«˜ä™Ÿè˜¬æ´¼æ—¾ï« í…›ã‡›?'M$㣒蔸=A_亀绉앭rN帮",
+ null,
+ [{
+ "Eᑞ)8<Zî¿—ã¡¿W镀䛒Cìƒî¿«V?0ꯦ+tL)`é½³AjBå§€Xà³³D빠㻲ƙgn9â‘°à¾á¿œ&\"ãš¹>餧A5u&ã—¾q?": [
+ -1.969987519306507E-19,
+ null,
+ [
+ 3.42437673373841E-20,
+ true,
+ "eê±·Må¢\"割Pâ›í§åŽ€R䱜3ï»´Oí“«r﹉⹊",
+ [
+ -8164221302779285367,
+ [
+ true,
+ null,
+ "爘y^-î¬?蘞Ⲽꪓaâ…ê¨}I",
+ 1.4645984996724427E-19,
+ [{
+ "tY좗⧑mrzïºã¿¥â´–᥷jè«…\u0000q賋è­êž„â®±S\nà¡£B/íƒêµª3ZÉ‘å¤o<\/;ë¡‹": null,
+ "彟hæµ _|V4䦭Dᙣ♞uì¿»=ì‚®ã¦\u001e哀鬌": [{"6횣楠,qʎꗇ鎆빙]ã±­R굋鈌%æ ²j分僅ペ䇰wí¦î¼‹p蛃N溈ê¡ê€?@(GI뉬$ﮄ9èªê“š2e甸ڋ[äº,\u0011\u001cࢃ=\\+衪䷨ᯕ鬸K": [[
+ "ㅩ拏鈩勥\u000etgWVî–¨Xs陂è¦p狵w퓼{뮵_i\u0002ퟑႢâ¬d6é‹«F~챿æŸ\u0096äš¼1ۼ칥0꣯å„=鋷牋ⅈêžé¾",
+ -7283717290969427831,
+ true,
+ [
+ 4911644391234541055,
+ {
+ "Iî¹éˆ’ì²½P릜朸W徨觘-HᎄíŸâ“º>8kr1{ê²µäƒã€›á¬¡Ì¨Oê·‘oä•'쿡鉕p5": "fvç²–RNçž–è›a?q꤄\u001d⸥}'ꣴ犿ꦼ?뤋?鵆쥴ë‹ä¡«s矷̄?à¶£/;괱絢oWfV<\/\u202cC,ã–¦0䑾%nè³¹g&T;|lj_欂N4w",
+ "짨䠗;䌕u i+rà¹0": [{"9ä¥\\à°©8\"馇z䇔<\/á‚¡Y3e狚ì¡\"ุ6ï°†Zé–c\"Ll:ïŠê®¾ç–£<\/᭙O◌납୕湞9⡳Und㫜\u0018^4pj1;ä§å„‚ä—·à­—>@e톬": {
+ "aâ‘‚Fé‹»Qèž°'<퇽Qè´ç€§{ᘪ,cP&~䮃Z?gI彃": [
+ -1.69158726118025933E18,
+ [
+ "ê¶‚z簽㔛㮨瘥⤜䛖Gℤ逆Y⪾j08î±²Sn昞ꘔ캻禀鴚P謦b{ê“®mNéMᥙ5\"ç2냑I\u0011.L&=?6á„ ë»·X鸌t刑\"#z)o꫚n쳟줋",
+ null,
+ 7517598198523963704,
+ "ኑQp襟`uᩄr方]*F48ꔵn俺ሙ9뇒",
+ null,
+ null,
+ 6645782462773449868,
+ 1219168146640438184,
+ null,
+ {
+ ")ယ넌竀Sdä°¾zqâ«£âŒÊ¥\u0010á¿“' |磪&p牢蔑mï³V蘸૰짬꺵;K": [
+ -7.539062290108008E-20,
+ [
+ true,
+ false,
+ null,
+ true,
+ 6574577753576444630,
+ [[
+ 1.2760162530699766E-19,
+ [
+ null,
+ [
+ "顊\\憎zXB,",
+ [{
+ "㇆{CVC9ï¼MN㜋ઘR눽#{h@ퟨ!鼚׼XOvXS\u0017á£=cS+梽៲綆16së½íœy屬?ᇳG2á´­\u00054쫖y룇nKcW̭炦s/鰘ᬽ?J|퓀髣n勌\u0010í™ P>j": false,
+ "ç®´": [
+ false,
+ "éžj\"ꮾ*엇칬瘫xṬ⭽ì©äƒ³\"-⋵?ᦽ<cਔ↎⩧%鱩涎삧u9K⦈\"á¿á¬‘V绩킯愌ṱv@Gê¾è·¶êš†(?ä–ƒvIá§ŠxV\r哦jã ’?*=S굤紴ꊀ鹭쬈s<DrIu솹꧑?",
+ {
+ ".}S㸼L?t\u000fK⑤s~hU鱜꘦}ìªC滈4ꓗ蛌):ྦ\"é¡¥ì´â¢·ïš­á¿³YLn\"?fꘌ>댎Ĝ": true,
+ "Pg帯佃籛n㔠⭹࠳ë·â‰»à¿Ÿ3ãž±ï“!î—-ì’¾!}쭪䃕!籿næ¶»J5ਲ਼yî˜vy;Rኂ%ᔡጀ裃;M⣼)쵂쑈": 1.80447711803435366E18,
+ "ꈑC⡂ᑆ㤉壂뎃Xub<\/쀆༈憓قì¨×§\\": [
+ 7706977185172797197,
+ {"": {"K╥踮砆NWࡆFy韣7ä밥{|紒︧䃀榫rᩛꦡTSy잺iH8}ퟴ,M?Ʂ勺ᴹ@T@~꾂=I㙕뾰_涀쑜嫴曣8IY?ҿo줫fऒ}\\S\"ᦨ뵼#nDX": {
+ "♘k6?଱癫d68?㽚乳䬳-Vé¡·\u0005è•?\u0018䞊V{邾zã˜l]é›k臤~ൖHë’iꢥ]g?.G碄懺䔛p<q꜉Så²—î¥_.%": 7688630934772863849,
+ "溗摽嗙Oã§€,⡢⼰呠ꅧ㓲/葇䢛icc@-r\b渂ꌳ뻨饑è§á–œ\\é®­\u0014엙㥀᧺@æµ¹W2꛵{W률G溮킀轡䬆g㨑'Qè¨ï†áŸªç½‘Hd\"Q늴ᱢﶨ邮昕纚枑?â–°hr羌驀[ç—¹<\/": [
+ -1.0189902027934687E-19,
+ {"窶椸릎뚻shE\"ꪗႥꎳU矖佟{SJ": [{"-æ…œx櫹XYîƒ-æ¾Ü¨â£·àª¢ïŸé¯™%Fu\u0000è¿‹â–’}᥷L嗭臖oញc넨\u0016/迎1b꯸g뢱ã§è“¤ä’8C散삭|\"컪輩鹩\"\\g$zG䥽긷?狸꿭扵ã²:URON&oU8": [
+ null,
+ true,
+ null,
+ -2.8907335031148883E17,
+ -3864019407187144121,
+ {
+ "`빬d⵺4H뜳⧈쓑ohஸ*ã¶ï»‡â¸•ä µ!iä¬ï¹‘h夘▥ê—푹갇㵳TA鳠嚵\\B<X}3訒câ‹{*ï«¢w]ç’¨-gæ­\\j໵侠Ei层\u0011": 3.758356090089446E-19,
+ "䄘ï®)Y놞씃㾱陰í:{\u2059/Sâ“´": [[
+ null,
+ [[
+ -3.8256602120220546E-20,
+ null,
+ 7202317607724472882,
+ "CWQëš¿",
+ null,
+ false,
+ true,
+ null,
+ 2857038485417498625,
+ 6.191302233218633E-20,
+ null,
+ -6795250594296208046,
+ [
+ true,
+ {
+ "%á‹§é°Yᚯ⚀x莰愒Vᔈ턗BNæ´ê¤ŸA1âŒl콹풪H;OX๫륞ìªá°šÑ†@͎黾a邬<L厒Xb龃7f웨窂二;": [[
+ null,
+ "耲?䙧㘓F6Xsí‹­ë©¢.v뚌?鄟æ â–½'묺競?WvᆾCî»txo?dZ;䨸疎",
+ {
+ "@hWê‰&\"빜4礚UO~C;ã†î”殩_ꀥè˜å¥¢^챟k→ᡱKMⵉ<\/Jㅲ붉LÍŸQ": false,
+ "tU뢂8é¾°I먽7,.Yî°î»´æ½Z툼=&⨥覽K乫햶㠸%#@Zë–æ„“^âŠâ¾‚몒3E_噆J(廊ឭyd䞜鈬Ћ档'⣘I": {
+ "tK*ꔵ銂u艗ԃì¿âˆ³ê„‚霫X3♢9y?=â²­dЊb&xy}": [
+ -4.097346784534325E-20,
+ null,
+ 6016848468610144624,
+ -8194387253692332861,
+ null,
+ {
+ "(祬诀譕쯠娣cë´r?ç•„kT뼾⌘⎨?noVä˜ì¥ç¡Žn?": [
+ 1.82679422844617293E18,
+ [
+ false,
+ 2.6849944122427694E18,
+ true,
+ [
+ false,
+ {
+ ";0zâ­†;í™”$bਔ瀓\"衱^ï—´?잢ᢛ⣿~`ꕉ薸⌳໿湘腌'&:ryБꋥá¼ê’¥ç­™ê¬œê¸¨?X": -3536753685245791530,
+ "c;Y7釚Uꃣ割J༨Y戣w}c峰뢨㽑㫈0N>R$ä…’X觨lë´œA刊8R梒',}u邩퉕?;91Eî¦a䈈ë¯G⊶芔h袪&廣㺄j;ã¡ç¶½\u001bN頸쳘橆": -2272208444812560733,
+ "æ‹‘Wﵚî²j鵼駳Oࣿ)#ã¾…é¡‚N傓çºy僱栜'Bê-!KF*ꭇK¦?䈴^:啤wG逭w᧯": "xᣱmYe1Û@霄F$ě꧘푫O䤕í€Pq52憬ꀜ兴㑗ᡚ?ï—ƒLé·íŸî—¼ë­zJê‘™}╆ᅨJB]\"袌㺲u8䯆f",
+ "꿽á…㔂긱Ǧ?SI": -1669030251960539193,
+ "ì‡É¨`!葎>瞺瘡驷錶â¤ï»®é…œ=": -6961311505642101651,
+ "?f7♄꫄Jᡔ훮eì‡îª¼í¾á£ä­´KhखT;Qty}O\\|ë«Iá¿’Ne(5æƒê¥¶ã†·Y9ﮡ\\ oyâ­–-䆩å©m#xë´‰>Y鈕Eç–£s驇↙ᙰm<": {"퉻:dê‚&efᅫ쫢[ï„™\"ëˆëŠ–êº™|Ôå‰1Í–-K:Êšá­•/;ì–㷛]Iç—èŒ4g<Oꗢ뫺N쯂륬J╆.`ᇵP轆&fd$?è‹…oê¶“vO侃沲â©åš…æ²— E%â¿°ì–¦wi\\*è¶«": [
+ 3504362220185634767,
+ false,
+ "qzXæœqT3軞T垈ꮲQ览ᚻ⻑쎎b驌䵆ꬠ5Fà­—ä²ç¼¿ê蒇潇Ltᆄ钯蜀W欥ሺ",
+ "ë³°É霬)ì é¶¼kwocì—·èr \u001d쒷⎹8{%澡K늒?iﺩd=&皼倚J9s@3å›twὡgjä íª5⭉⨺役&놎cﺉ㺡N5",
+ false,
+ null,
+ "D0st[ni锹r*0k6ꀎë‡UX2⽼৞䃚粭#)Zæ¡·36P]<\/`",
+ 4281410120849816730,
+ null,
+ -3256922126984394461,
+ 1.16174580369801549E18,
+ {
+ " ᆼꤗ~î…‰*TN긂<㡴턱℃酰^蘒涯잰淭傛2rൡetì¾£ä‡m*ã¸y\"\\糮᧺qv쌜镜T@yg1譬ﭧﳭ\f": null,
+ "圾ᨿ0xᮛ禵ਗ਼D-㟻ẵ錚e\"赜.˶m)é´‘B(I$<\/轴퉯æ·â‹âº*)宓쓌?*橯Lx\\f쩂㞼⇸\"ﺧ軂é³V\\ë•’\"캘c:G": null,
+ "?ïµ_ê³¢î™ç¿¸íˆ8ã¿ hì—´Q2ã­›}RY㯕YT놂⽻e^B<\/맫ﻇ繱\u0017Gц⟊ᢑﵩS:jt櫣嗒⟰Wã´šæ¦á…‰e[w䋺?藂翙Ⲱ芮ä˜â•¢å›¥lpdu7r볺I è¿‘qFyᗊ": [
+ "$b脬aᅠ襬育Bگ嵺Pw+'M<\/ï­näššvèžbNâ’‚}褺%lቦ阤\"ꓺá—Mç‰,Ûžï– Ò¶!矬?ke9銊Xê´¦)䈽í‹è„½á¹«äˆžá´†^=Yá—¿é›4I귺⋥%",
+ false,
+ 2.9444482723232051E18,
+ 2072621064799640026,
+ "/_뇴뫢jã’=Nꡦâ†Ôºèµ’â¬î»¼í†¥ä¨žç¯su*媸瀳鷔抡oíº-៳è¾å‹·fç»”:äµ¢æ¢2",
+ false,
+ "ì’œ Eî½·äŒ/í\u0018懺_<\\隺&{wF⤊谼(<죽é ïŸ‡8?@*rá¶ŠGd뻻갇&Ⳇq᣿e࢔t_ꩄ梸O詬Cá§§Kê© í’¤9눙醅ëž}竸rw?滨ӽK⥿ཊGé­²']`๖5ã„°",
+ -2375253967958699084,
+ {"嗱⿲\"få„„á¬": {"v?䚑킡`â—¤k3,骥曘뒤Oᒱ㲹^圮᠀YTê»›&ì´®P:G/Tâ£#튣k3ç‚©è k@橈ä·Sä§•,ç†œïŒæ™¬ï£žk1鮥玸먚7䤡fç»å—šìƒ´á¥’~îš¼0q拮垑aë»±Lâ°–_": [{
+ ":på°¢": -6.688985172863383E17,
+ "A0\u0001疠ﻵ爻鼀湶I~W^å²€mZx#ãˆ7r拣$Ꜷ疕≛⦒痋盩Vꬷá­â„¦Qêªï§éˆ‘A(劽詗ꭅo-ç¶é‘º\"Ⓠ@$j탥;": [
+ 8565614620787930994,
+ [
+ "å¶—PC?à¶‹Q㪣$&j幾㾷hæ…‘ 즊慧⪉霄M窊ê·'鮕)äŠé“¨m趦䗲(g罣ЮKVﯦé®î¦®5囗ﰼ鿦",
+ -7168038789747526632,
+ null,
+ -7.8069738975270288E16,
+ 2.25819579241348352E17,
+ -6.5597416611655936E18,
+ {
+ "瘕멦핓+?フZê·¢zé›V": {
+ "ᕾ": 1.7363275204701887E-19,
+ "ã­Œs뎹㳉": {"\u00187Fï–‰I6Yféº+UC쬸éºâ²ä‚¿ê¸•R\\ᆮC?Φ耭\rOத际핅홦*ë² W㸫㯼᡹cㅜ|Gã®—\u0013[o`?jHVì•?蒪꩚!í«áœ¦ãŒ‡äš‡é¿˜:@": [
+ "}푛Г콲<äŸCè—呈#2ã“‹#ྕáŸå°¿9qç«“gI%ëž™mê¬oaç•è´¿Jå’¿D_ç†Zz皳験Iè±¼B扳ḢQ≖㻹㱣Dä¦ï©—2'á—㗣▌ç ²8罿%à°¹F姦;0î·æ‚‡<\/\"påš§",
+ -710184373154164247,
+ "Vo쫬⬾ê«â´·Å»\u0004éŽHBê…¸_aVBHbN>Z4âœkเꛘZ⥺\\Bʫᇩ鄨魢弞&幟ᓮ2̊盜",
+ -9006004849098116748,
+ -3118404930403695681,
+ {
+ "_彃Y艘-\"Xx㤩㳷瑃?%2ä¡éµ›o<A?\"顜ᘌΈ;â·…Cæ´ºL蚴蚀voq:,Oo4쪂)": 5719065258177391842,
+ "l륪맽耞塻論å€Eã—‘/㲕QM辬I\"qi酨玑㖪5q]尾魨鲡ƞY}⮯蠇%衟ï„Fsf윔äšì°¤iè…³": {"ꢪ'a䣊糈": {"ë°‘/♋S8sã¼´5瓹O{댞\"9Xï°‡lJ近8}q{긧ⓈI᱑꿋腸D瀬H\"ﺬ'3?}\u0014#?丙㑯ᥨ圦',gé‘ (樴턇?": [
+ 2.5879275511391145E18,
+ null,
+ [
+ "3㼮ꔌ1Gẃ2Wé¾™jîªÍŠ{1å›ã¦­9xå® ã‘oRä•犽",
+ 1268729930083267852,
+ "땕軚⿦7C",
+ [
+ -3.757935946502082E18,
+ "\"赌'糬_2ë­¾áb",
+ {
+ "(a䕎ጽjÒ°D4.á´¡ïž½66ԃ畮<\/l`k癸\\㇋ࣆ욯R㫜픉녬挛;ڴ맺`.;ç„“q淞뮕ٹ趴r蔞ꯔ䟩vç²u5<\/pZ埖Skrvj帛=\u0005aaï”›": null,
+ "璄≩ v몛ᘮ%?:1頌챀H㷪뉮k滘e": [
+ "ꤾ{`c샬왌펡[俊络vmz㪀悫⸹ᷥ5o'ã¾µ L蹦qjYIYណԠWëƒå‰«<\/W嗂0,}",
+ 2.4817616702666762E18,
+ false,
+ null,
+ null,
+ -8.6036958071260979E17,
+ null,
+ -1.2744078022652468E-19,
+ -4.4752020268429594E17,
+ 1.13672865156637872E17,
+ [
+ false,
+ false,
+ null,
+ -4.178004168554046E-20,
+ true,
+ 2927542512798605527,
+ {
+ ".ꔓ뉤1䵬cHyæ±¼äŠ†è³“á‡Æ©|樷â‡é†Žã¬…4\u0003èµµ}#yD5è†æ™¹ë±“9ê–è™›J㺕 t䊛膎ؤ": {
+ "rVtᓸ5^`েNâ¹»Yv᥋lꌫt拘?<é®°ë„¿ZC?ã’½^": {"âªî©k_:>귵옔夘v*탋èŒ&㳈챗|Oé’§": [
+ false,
+ "daꧺdᗹ羞쯧Hã¤é„³é ³<型孒ン냆㹀f4ã¹°\u000f|C*ሟ鰠(O<ꨭ峹ipຠ*yà³§4VQè””hVæ·¬{?ᵌEfrI_",
+ "j;ꗣ밷é‚副]á—“",
+ -4299029053086432759,
+ -5610837526958786727,
+ [
+ null,
+ [
+ -1.3958390678662759E-19,
+ {
+ "lh좈T_ë¯Y\"伨\u001cꔌG爔겕ꫳ晚è¸â¿»ìT䯎]~e#฽燇\"5hٔ嶰`泯r;ᗜ쮪Q):/tç­‘,榄&5ï¤ëŽ«ç‹(": [{
+ "2áâ“›]r3C攟וּ9è³µsâ›”6'ஂ|\"ⵈ鶆ä¹ç¦3\"痰ࢤéœäµ©ì˜†äŒ€?æ •r7Oç°‚Isd?K᫜`^è®¶}zî°’8?zì–°î§T:X倫⨎ꑹ": -6731128077618251511,
+ "|︦僰~m漿햭\\Y1'Vvخ굇á‰ì±¢cè¶–": [null]
+ }],
+ "虌魿閆5⛔煊뎰㞤ᗴꥰF䮥蘦䂪樳-Ká·-(^\u20dd_": 2.11318679791770592E17
+ }
+ ]
+ ]
+ ]},
+ "묗E䀳㧯᳀逞GMc\bï•¹å¢¹ã“„ë–Æ &U??íŽŒé‘ åª‹k))ᄊ": null,
+ "묥7콽벼諌J_DɯﮪMæ®´ä£,煚ྼ`Y:ì”§<\/â©«%yf䦀!1á²¶kì¶ŽQç±³W∠WC跉鬽*á›±i<?,l<崣炂骵*?8í‘៣ⰵ憉⎑.,Nwç½£q+ο컆弎": false
+ },
+ "e[|଀+î±³lꑸãˆTT?ë¿¿|ê«›9`㱯䊸楋-곳賨?ì³k棽擋wQ餈âŸNq[q霩䵀뷮锅ꚢ": 5753148631596678144,
+ "sá“鴻߸d렶ὕ蜗ဟ툑!诉౿": false,
+ "|4䕳鵻?䈔(]í‹/Ui#æ¹»{듲ーMá‹€t7潔泄Ch⸨}ì£`î¤èž§éŠšã‹¼å£¯kâ°¥Q戵峉갑xè¾™'ì²›": "jd䘯$䕌茷!auw眶ㅥä£ê†¢æ°‘i",
+ "剖駰Ɜî¶sM2]á¾´2ࡷ祅拌Av狔꩛'ê“—í‚§ê£0酜✘O'": false,
+ "澩뢣ê€eU~D\\ꮡ킠": "v^YC嚈ί\u0007죋h>ã´•L꘻ê€ì“ª\"_gé¿„'#tâ½™?,Wg㥖|D鑆eâ¥ìª¸åƒ¬h鯔咼ඡ;4TKèŽî¾‘졠嫞"
+ }
+ ]
+ ]
+ }
+ ]
+ ]
+ ]}}
+ }
+ ]}
+ },
+ "뿋뀾淣截䔲踀&XJ펖꙯^Xb訅ꫥgá¬>棟S\"혧騾밫ê²7-": "擹8C憎W\"ìµ®yR뢩浗絆䠣簿9äˆå¼•Wcy䤶孖ꯥïž;íŒ]輩ä3@{å 뽸0ï€á¡ˆìµ¡î›„Ⲇ\u001dLåŒê§2F~ݕ㪂@W^é½L襒ᦘî¢~沦zZ棸!꒲栬R"
+ }
+ ]
+ ],
+ "Z:ëƒàµ›5Iz찇䅄駠㭧蓡K1": "e8᧤좱U%?ⵇ䯿é¿\u0013縮R∱骒EO\u000fg?幤îš@֗퉙vU`",
+ "äƒìªˆï‘’埽້=Ij,쭗쓇చ": false
+ }]}}
+ ]
+ }
+ ]}
+ }
+ ]
+ ]
+ ],
+ "咰긖VM]á¼6䓑쇎çºetDÒŒ?ãžê©„퇫밉gj8è ƒ\"â©5䛹1ࣚ㵪": "ക蹊?⎲⧘⾚̀I#\"䈈⦞ë·`wo窭戕෱휾䃼)앷嵃꾞稧,Ⴆ윧9S?೗EMk3Მ3+e{â¹”Te驨7äµ’?타Ulg悳o43ï“¢"
+ }
+ ],
+ "zQᤚ纂땺6#ٽ﹧vï¿¿#ࠫ휊冟蹧텈ꃊʆ?&a䥯Deæ½|ì¿“pt瓞㭻啹^盚2êŠf醪,ì–T窧\\Di䕎谄nn父ꋊE": -2914269627845628872,
+ "䉩è·|㨻ᷢã‰B{蓧瞸`î°²I!℄욃힕#ೲᙾ竛ᔺCjk췒늕貭è¯\u0017署?W딚%(pê⤼ë³^=on뺲l䆼bzrﳨ[&j狸䠠=ᜑꦦ\u2061Õµnj=牲攑)Mî»\\é¾": false,
+ "뎕y絬᫡⥮Ϙᯑ㌔/NF*Ë“.ïž¿,QEzvK!Iwz?|쥾\"ê©»Lê¼—Bê”§è³´ç·œs뉣隤茛>ロ?(?^îµ­`>冺飒=噸泥⺭Ᲊ婓鎔븜z^å·è£®Ãªâ“…à»—jM7ﶕ找\\O": 1.376745434746303E-19
+ },
+ "ä›ræ»–wã¤<k;l8ꡔጵ⮂ny辶⋃í¼åƒ®z\"﮲X@t5෼暧퓞猋♅䦖QCé¹®|픨( ,>,|Nዜ": false
+ }
+ ]],
+ "@ê¿™?è–•å°¬ gd晆(ë„5躕ﻫS蔺4)떒錸ç“?~": 1665108992286702624,
+ "wë¯ná =`঺ᅥC>'從ë槷ä¤çœ·èž„ãŽ»æ°æ‰°XᅧCè´½uáƒë‚ŸjKD03T!lDV쀉Ӊy뢖,袛!终캨G?鉮Q)â‘—1쾅庅O4ê‰H7?d\u0010蠈줘월Þ粯Q!낇껉6í…|{": null,
+ "~˷jg쿤촖쉯y": -5.5527605669177098E18,
+ "펅Wᶺzê†ã¨í‘­e?4j仪열[D<鈑皶婆䵽ehS?袪;Hê¨Më—Žã°[(å—M3qíŸg4y╸鰧茀[Bi盤~ï«å”Žé‹†å½ºî½«â¦Šq?î–³B4쉓癚O洙킋툈䶯_?ퟲ": null
+ }
+ ]
+ ]]
+ ]],
+ "꟱Ԕã¤7æ›ï¦—ಃéŒVä·°?v㪃૦~K\"$%请|ꇹn\"kä«›ã¨é²¨\u2023ä„¢\u0004[<S8á¬ë­©è„¥7U.m࿹:Dè‘┆2蘸^U'w1ì …;䠆ꋪBê»®>︊Vï‹•J?䶟ាꮈ䗱=깘U빩": -4863152493797013264
+ }
+ ]}]}
+ ]
+ }}}
+ ],
+ "ì·ì²Û¹í‰ƒ~aEå”™a챑,9㮹gLHd'ä”|í‚—ãžäŽ¥&KZYTë§µ7䥺N<Hp4ê•­â¹ ê½c~çš½z": "课|á–¾ä¡å»‹è„äªW\u0016&Jnê´b~æ‘“M>â±³åŒèŽžé¿§w\\༌疣n/+ꎥU\"å°ëž¾â—‹íŸ™AJá­Œ?9ä›$?é©”9è®ì§˜é­¡TÖ¯cè—³`虉Cì‡ì¦T"
+ }
+ ],
+ "è°¶ê°œgTRï¿>áµÍšdtæ™‘ä‰‡é™æ»º}9㉸P漄": -3350307268584339381
+ }]
+ ]
+ ]
+ ]]
+ ]
+ ],
+ "0y꟭馋X뱔瑇:䌚ï¿å»¿jîžg-懲鸭䷭垤㒬茭u賚찶ಽ+\\mT땱\u20821殑ã„J쩩䭛ꬿNSæ½”*d\\X,壠뒦e殟%LxG9:摸": 3737064585881894882,
+ "í’µO^-â§§â…¶vѪ8廸鉵㈉רâ†Q㿴뺟EႳvNM:磇>wî·/៻唎뷭୥!냹D䯙iëµ±è²C#⼉NH6`柴ʗ#\\!2ä‚—â±§f?諳.Pëˆ-è¿”I꘶6?8î“ê˜": -8934657287877777844,
+ "溎-è˜å¯ƒi诖ര\"æ±µ\"\ftl,?d⼡쾪⺋h匱[,à·©I8MÒ§F{kç“¿PAî…§'橸ꩯ綷퉲翓": null
+ }
+ ]
+ ],
+ "ោ係Øî½<å…ƒ": 1.7926963090826924E-18
+ }}]
+ }
+ ]
+ ]]}]
+ }]
+ ]
+ ]
+ ]
+ ],
+ "ጩV<\"ڸsOᤘ": 2.0527167903723048E-19
+ }]
+ ]}
+ ]
+ ]],
+ "∳㙰3ì ´pá§—ä±™?`<U὇<\/æ„E[ᮚAî›j诂ᒽ阚uv徢ဎ떗尔ê½í›€ì©‘Jä´?âª=륪ᆩ푰ஓã•?럽VK\"X?檨လ齿I/耉A(AWA~â¯ç¨è¹«": false,
+ "å’å¦ë¾‡}䀼链i⇃%⋜&ç’ªIx渥5æ¶§qq棩á¥-â «AA낇yY颕A*ïˆè£¦O|n?䭬혗F": null,
+ "ç­CLì–­B혆Kॎ`鎃nrî€sZiÕªWç )?p~K~A眱ä²QO妣\u001b\u001b]ᵆᆯ&ã‹á¹è±‰ëº˜$ê­§#j=C)祤⫢歑1o㒙諩": 7028426989382601021,
+ "쳱冲&ဤäŒì•§h胺-é½±H忱8왪RDKᅒ䬋ᔶS*J}ስ漵'㼹뮠9ê±¢9p봋경ጕtởꚳT䶽瘙%ì¶´`@nಆ4<d??#僜ᙤ钴=薔ꭂbLXNam蹈": "樭る蹿= Uî ƒurwkn뙧⌲%\"쑃牪\"cq윕o@",
+ "溌[H]焎SLã…?뀼䫨ç½W": 1.1714289118497062E-19,
+ "ﬢp븇剌燇kĔ尘㶿㴞ç ê¾˜Ia;sâº^)$ç©®?sHᢥíªl": null
+ }
+ ]
+ }
+ ]
+ },
+ "TKnzj5o<\/K㊗ꗣ藠⦪駇î€>yZA8Ez0,^á™›4_0븢\u001ft:~䎼s.bb룦明yNP8弆Cå¯;⪾ì§'蕴뮛": -6976654157771105701,
+ "íµê¦€\\㇑:nî‹™v+뒤燻䀪ﴣï·9ᚈ኷K㚊誦撪䚛,ꮪxሲ쳊\u0005HSf?asg昱dqꬌVꙇ㼺'k*'㈈": -5.937042203633044E-20
+ }
+ ]
+ }],
+ "?}\u20e0],så¶³è‹@#2uì’´sQSä©—=ꥮ;烌,|ꘔ䘆": "á…©ì˜Nç’ kZ먕眻?2ቲ芋眑D륟渂⸑ﴃIRE]å•—`K'"
+ }},
+ "쨀jmV賂ﰊå§ä‚¦çŽžã¬™áªM᪟ïՎ씜~`uOn*ॠ8\u000ef6??\\@/?9見d筜ﳋB|Sä¬è‘«ã½o": true
+ },
+ "즛ꄤ酳艚â‚㺘봿㎨iGà§•à¡¿?1\"䘓您\u001fSáŠâº¿æºzៀ뻤B\u0019?ìœa䳵᭱䉺膷d:<\/": 3935553551038864272
+ }
+ ]
+ ]}
+ ]]
+ ]]
+ ]}
+ }
+ ]
+ }
+ ]]}},
+ "᥺3h↛!ê‹°y\"攜(ெl䪕oUkc1A㘞ᡲî촾ᣫ<\/ä’ŒEã›æ½¨i{ï  v?Wà±¾H\\RჅpzè¬R脾;v:碽✘↯삞鷱o㸧瑠jcmK7㶧뾥찲n": true,
+ "ⶸ?x䊺â¬-ä°…â‰!e쩆2ꎿ准G踌XXᩯ1ß}0?.í—€Z馟;稄\baDꟹ{-寪⚈ꉷ鮸_L7ƽᾚ<\u001bጨA䧆송뇵⨔\\ç¤ë—”d设룱㶉cq{Hyã±R㥽å¢ï¬…p": -7985372423148569301,
+ "ç·«#ì½®IB6<\/=5Eh礹\t8럭@饹韠r㰛斣$ç”LVì·a갵îŸ'请o0g:^": "䔨(.",
+ "ë³â„¡åœ¤pï¾à¯„Ä倧訜BìŸGä™”\"Sbâ“®;$$â–S1J뢙SF|赡gï„€*\"Vu䲌y": "䪈&í‹),\\kT鬜1í’¥;ë·´'Zေ䩹@Jéž½Nã¼M?å¥eWb6榀ƩZڮ淽⺞삳煳xჿ絯8eâ¶ç¾·V}ჿ쎱䄫R뱃9Z>'\u20f1â“•äœé½®"
+ }
+ ]
+ ]]]
+ }}
+ }
+ ]
+ ]},
+ "펮b.hç²”í¯2npXè©«g錰鷇㇒<ì™S値bBi@?镬矉`剔}c2壧ଭfhY깨R()痩⺃a\\â”?M&ﯟ<劜꺄ï‘멊ᄟA\"_=": null
+ },
+ "~æ½¹Rqn榢㆓aR鬨侅?䜑亡V_ç¿…ã­”(ä“·w劸á³Dp䀅<\/ï°Žé¶Šm䵱팱긽ꆘ<tD쇋>긓准D3掱;o:_Ñœ)껚콥8곤d矦8nP倥ꃸI": null,
+ "뾎/Q㣩㫸벯➡㠦◕挮aé¶§â‹“å¼\u00001뱓fm覞n?㛅\"": 2.8515592202045408E17
+ }],
+ ",": -5426918750465854828,
+ "2æ««@0柡g䢻/gꆑ6演&D稒肩Y?艘/놘p{f투`飷ᒉ챻ëŽîª–<늛ä˜ï´¡ì¤°ì«„": false,
+ "8î™–(鸑嵀⵹ퟡ<9㣎Tߗ┘d슒ل蘯&㠦뮮eà kç g ì—»": false,
+ "d-\u208b?0ﳮ嵙'(J`蔿d^踅⤔榥\\J⵲v7": 6.8002426206715341E17,
+ "ཎ耰í“ê•ï’ã±·\u0013y=詽I\"盈xm{0쾽倻䉚ષso#é°‘/8㸴짯%ꀄ떸b츟*\\鲷礬ZQå…©?np㋄椂榨kc᡹醅3": false,
+ "싊j20": false
+ }]]
+ ]],
+ "ä¿›\u0017nç·½Tu뫉èœé¼Ÿçƒ¬.ï‘ꭠIâ°“\"Ἀ᜾uC쎆J@å¤%ê›m뻨ᾀ画è›íœƒT:錖㑸ዚ9죡$": true
+ }
+ ]
+ ],
+ "ãµâ‡˜ê¦–辈s}㱮慀밒s`\"㞟j:`ií”»Z<C1衽$\"-饧?℃\u0010⼒{î°p飗%R\"ä²”\")ì¹€\\%": true,
+ "苧.8\u00120ݬ仓": 6912164821255417986,
+ "ë–Žé¡£ä¿X;.#Qí‹.笂'p쟨唒í랩냆¦aâ±{è°.b我$蜑SH\u000fç¾=äŸ¼â£¼ï©¿áœæ”•B&挰繗ã”ê…‚-Qv\\0ä¶äš¥ãºio[㑮-ᇼ䬰컪ṼiY){ë°\u0010q螰掻~\n輚x\u0014罺)è»´": 3.024364150712629E-20
+ }
+ ]
+ ]
+ ]
+ ]}
+ ]]
+ }
+ ]
+ ]]
+ ]
+ ]]]],
+ "\"凲o肉Iz絾豉J8?i~傠᫽䇂!Wï›—D溊J?á¡’vsè†åµ¹âž’ïŸæ·´î‡…>ì„«^諎0Ok{켿æ­à·£èƒ°a2﨤[탳뚬쎼嫭뉮m": 409440660915023105,
+ "w墄#*ᢄ峠밮jLa`ㆪ꺊漓Lã§ëŽ!Agkï¹ï¾'ê›ë¢ƒã¯å²¬D#ã’¦": false,
+ "ଦPGI䕺L몥罭ꃑ궩﮶#⮈ᢓӢ䚬p7웼臧%ï‘¥~Sè âŒíž€6îž’&t䳙y㪘ëƒ\\*;é‰ï¿Šé¿µ'å—•pa\"oL쇿꬈Cgî“": "ã¶½1ç¸D⟸䴅ᆤ뉎﷛渤csî¸x ä”цꬃ锚æ¬?ຽ+x~꘩uI࡞\u0007æ ²5呚ẓem?è¢\")=㥴䨃pac!/æŽY",
+ "á·±o\\||뎂몷r篙|#X䦜I#딌媸픕åžRDæ–³X4t⯩夬=[ï‹ë­²r=绥jhë·±ì¸âª˜%]⚋܈㖴スHí…¹m(WOæ›åЉ0~K3c柢Õã‰ïªªé€³~": false,
+ "ç…½_qb[첑\\륌wEâ½Ztï”´CNï­+餌ᕜOê›­": "{ﳾ쉌&s惧á­âµ†3䢫;䨞팑ï›ê’ªí˜è¤€à¢–Qä ¿V5뭀䎂澻%ë°›u5í…¸oA⮥U㎦;B䳌wzä•™$áž¿\\௅婺ëµâª¾í†\\`Kyौꋟ._\u0006L챯l뇠Hi䧈å’5",
+ "艊ä½à£ƒë¡‡ä± çˆ¬ï˜‚!*;⨣æŽïžæ…“qé“|儑ᨋL+è¿¥=6㒺딉6弄3è¾…J-㕎뛄듘SG㆛(\noAzQê±ä°©X*ã¢O퀌%펠낌moí‹®a^<\/F&_눊ᾉ㨦ы4\"8H": 2974648459619059400,
+ "鬙@뎣䫳á®ë¡?){y?5K;î§„TA*k溱䫜J汃ꂯ싔ì\u001dA}룖(<\/^,": false,
+ "ëª@QꋦFꊩá’뎶î‡lXl垨4î¤^郣|ꮇ;ä´á“}ìµ²zç–": null
+ }
+ ]]]],
+ ":_=ë‹§å¼—D䙋暨é›. 㱻붘ä‚Jå„’&ZK/녩䪜rå›â½¯D喠죥7ï“⹌䪥c\u001a\u2076￞妈朹oLkè®F౟覛ì§ã®7T;}è›™2{9\"å´“bB<\/⡷룀;즮鿹)丒툃୤뷠5W⊢嶜(fb뭳갣": "E{å“1WM"
+ }},
+ "䘨tjJ驳豨?y輊M*᳑梵瞻઻ofQG瑮e": 2.222802939724948E-19,
+ "ä®´=â‘âž¶Tà·‹wäžœ\"垦ꃼUt\u001dx;B$뵣䙶E↌艣ᡥ!á§Ÿ;ä±€[䔯k쬃`à©8饙른ç†î‹”'2_'袻tGfè’­J땟as꯳╖&å•’zWࡇᒫYSá¬\u0014ℑ첥鈤|cG~Pá“®\">\"": "ႆl\f7V儊㦬nHꄬꨧC{ì¢~C⮃⛓嶦vꄎ1w鰠嘩뿠魄&\"_qMâµ–é‡”ë…®îœ¡ê‡ ãš{ç³Jå“‹ cî°¸v?-jkﻯྌ鹑L舟r",
+ "龧葆yB✱H盋夔ﶉ?n*0(": "ꧣኆ㢓氥î³qZZ酒ຜ)鮢樛)X䣆gTSî»»Ò‘Gí…žï’˜k.J圬ç–ë¡«ïœì¯­z L:\\ྤ@w炋塜쿖ᾳy뢀䶃ë±N䥨㚔勇ê²#p",
+ "ë„畎Q娡\"@S/뼋:äµ!Pè¡…ì´šfVHQs✜á«i㻑殡B䜇%믚k*U#濨낄~": "êŸá‹•ì³¸êˆæ•‹&lå¦\u0005憡멗瘌uPgá…ªm<\/To쯬锩h뒓k"
+ }
+ ]
+ }],
+ "墥홞r绚<\/⸹ⰃB}<躅\\Y;๑@䔸>韫䜲뱀X뗩鿥쩗SI%ﴞ㳕䛇?<\/\u00018x\\&侂9é‹™a[LRã‹­W胕)â¡¿8ãž™0JF,}?í—ˆd1cDMáƒâ›é„ⱕ%X)!XQ": "â³ê—³=橇a;3t⦾꼑仈î¥á€°aᚯ⯋ꕃAsé´·Nâ•_䎃ꙎAz\u0016䯷\\<à¿«>8q{}ï½·?ᣰ}'0ᴕ펓B┦lF#趤厃T?㕊#撹圂䆲"
+ },
+ "Ü‹ë‹é¾«ï¥c웑": false,
+ "ㇿ/q\"6-co髨íœCí¦#\u001b4~?3ä¹E삇<<": 7.600917488140322E-20,
+ "äE6?㣖êƒé—´t祗*é‘ {ḣV(æµ¾h逇íž=W?ૉ?nꇽ8ꅉຉj으쮺@Ꚅ㰤u]Oyr": "vâ‰á«¸_*όAඤԆl)ۓᦇQ}í zà¼q滚",
+ "ソ᥊/넺I": true
+ }]]
+ ]
+ ]
+ ]
+ ]]
+ },
+ "䭑Ik攑\u0002QV烄:芩.麑㟴㘨≕": true,
+ "å„꿕C쇻풉~å´%碼\\8\"䬦꣙": null,
+ "欌L圬䅘Y8c(♺2?ON}o椳s宥2䉀eJ%é—¹rå†O^K諭%凞⺉⡻,掜?$ꥉ?略焕찳㯊艼誜4?\"﯎<ï±ã‚›XáˆINT:è©“ +": -1.0750456770694562E-19,
+ "ç’àc뜭싼ﺳ뎤K`ïŸ]p隨LtE": null,
+ "ç”™8䵊神EIꩤé¯á¢€,ïµ®Uä‘u疒ử驺䚿≚ഋ梶秓F`覤è­#짾蔀묊4<åªì¬¦éª_Yzgcà¡¶î²§4kç´¥`kc[Lï®—î°£ç°*I瀑[â¾°L殽鑥_mGÈ <\/|囹ç gæ¡°iri": true,
+ "챓ꖙꟻì¢è‡ou,å— 0\\jK핻뜠qwQ?ഩ㼕3Y彦b\u009bJ榶N棨f?ë¦é–綃6é³µM[OEë´¨uí–.Ꮁ癜蟳뽲ꩌ뻾rM豈Rï¨ç¾« uDꎚ%": null
+ },
+ "V傜2<": 7175127699521359521
+ }],
+ "é“«aG切<\/\"ী⊆e<^g࢛)Dé¡ï½Žï¬®é¥¼\u008c猪繩嵿ﱚCꡬ㻊g엺Aì—¦\u000fæš¿_f꿤ë³ã¦•桦`蒦䎔j甬%å²rj ç³": "䚢åŽëˆ´Au<4箞7礦Iï±”å eȧ䪸uï„€äµp|逹$嗫쨘ꖾï·!胠z寓팢^㨔|u8Nሇe텔ꅦ抷]،鹎ã³#༔繁 ",
+ "낂乕ꃻ볨ϱ-ꇋã–fsâ¿«)zꜦ/K?솞♞ꑌ宭hJ᤭瑥Fu": false,
+ "쟰ãœé­›G\u0003u?`㾕ℾ㣭5螠烶這趩ꖢ:@å’•ê¶xë’˜ëŠmä°¨bç—ƒë 0鳊喵熬딃$摉_~7*ⱦ녯1錾GKhJ惎秴6'H妈Tᧅ窹㺒疄矤铟wላ": null,
+ "쯆q4!3錕ã²âµ†ã‡›ê˜·Zç‘©ë­†\\â—ªNH\u001d\\ã½°U~㯶<\"쑣낞3ᵤ'峉eꢬ;鬹o꣒木X*é•·PXᘱu\"ä ¹n惞": null,
+ "ᅸ祊\"&ꥴCjࢼ﴿?䡉`U效5殼㮞V昽êª#ﺸ\\&t6x꠹盥꣰a[\u001aêªSpe鎿蠹": -1.1564713893659811E-19
+ }
+ ]]
+ ]
+ ]
+ ],
+ "羵䥳H,6ⱎ겾|@t\"#í–Šî¦1|稃 ì„­)ëœ=뻔ꡜ???櫎~*ῡ꫌/繣ﻠq": null
+ }
+ ]}
+ ]},
+ "츤": false
+ }},
+ "s": 3.7339341963399598E18
+ }
+ ],
+ "N,I?1+㢓|ࣱ嶃쩥V2\u0012(4EE虪朶$|w颇væ­¥": "~ì¢~_,Mzrã«YB溓Eæ·š\"â…¹äˆ”áºæŠ™ b,nt5Vã’J檶ê¨â»”?",
+ "Q껑ꡡ}$넎qHç…”æƒ/ez^!ẳF댙äŒé¦»å‰8": "梲;yté’°$i冄}Aî‘”L%a jëœå¥·ê±³ëš¾d꿽*ሬuDY3î…—?뮟鼯뮟wãªí‹±îŸ‚V",
+ "o{Q/K O胟ãzUdê€m&⨺J舕â¾é­¸è¨ŸãŒ¥[T籨櫉å”í‚ aṭ뱫촙莛>碶覆⧬짙쭰ׯdAiH໥벤í¥_æ¸[ 0î­¬e:죃TCå¼¼èŽëµDA:w唵ê£": null,
+ "á½æ¨Žäµ®è»§|?à±—aWH쩃1 ê…­su": null
+ }
+ ]
+ },
+ "勂\\&m鰈J釮=Ⲽ鳋+䂡郑": null,
+ "殣b綊倶5㥗惢⳷è¢á‘€ä¬„é•§M^ï±´3⣢翣næ«»1㨵}ኯ뗙顖Z.Q➷ꮨ뗇\u0004": "ê”™ä¼>n^[GीA䨟AMç¢á’ŠS쨲w?d㶣젊嘶çºéº“+æ„£a%気ྞScë“ᔘ:8bM7Xd8㶑臌]Ꙥ0ê­ì’™ä«£æŒµCè–½î€Dfⵃ떼᷸",
+ "?ç´¡.ì…ª_à·¨j\u0013Oxâ” $Xᶨ-á…‡oè–¹-}軫;yæ¯ãªœKã£?.EVì®±4둽⛻䤜'2盡\u001f60(|eì°ã¼Žá¦€ã’§-$l@ﻑå³\u0003ä­±å“å·—WFo5c㧆Tí„Y맸♤(": -2.50917882560589088E17
+ }}
+ ],
+ "侸\\릩.᳠뎠狣살cs项䭩畳H1s瀉븇19?.w骴崖㤊h痠볭㞳㞳ä®Ql怠㦵": "@䟴-=7f",
+ "鹟1x௢+d ;viä­´FSDS\u0004hꎹãš?â’â¦Ñž6u,扩@ë·Su)Pag휛Tá’—Vç—©!çžé‡€ê–žè˜¥&ೞè˜ê­°êž‡áŽ": "ah懱Ժ&\u20f7䵅♎඀䞧鿪굛ౕ湚粎蚵ᯋ幌YOE)५襦ãŠY*^\"R+ඈî¶å’·è¶9î—ꥂ榨艦멎헦é–ë¶v좛咊E)K㓷ྭr",
+ "æ†q쮦4綱켙ì….f4<\/g<籽늷?#蚴픘:fF\u00051㹉뀭.á°–í’ŽfÖ¦Hv蔎㧤.!ä­½=éž½]ìŒH:?\"-4": 8.740133984938656E-20
+ }]}
+ }
+ ],
+ "tVKn딩꘥⊾蹓᤹{\u0003lR꼽ᄲQFá…傅ﱋ猢⤊á”,E㓒秤nTà¶­v`â™›I\u0000]꫔ṞD\"麵cè¸î“²æ°X&æ¿¿ë˜ê£¹ê¹³à±¥è‘‚鿎\\aꡨ?": 3900062609292104525
+ }
+ ],
+ "ਉ샒⊩Lu@S䧰^g": -1.1487677090371648E18,
+ "⎢k⑊꬗yá«7^err糎Dt\u000bJç¤¯í™•ã†æ²‘サꋽeèµ”ã¢^J\u0004笲㿋idra剰-᪉C錇/Ĝ䂾ညSì§€?~ì½®gR敉⬹'ä§­": 1901472137232418266,
+ "ç—kä¶¥:?ì´½è´ì“‰ê“ˆã’¸gç˜[뵎\\胕?\u0014_榙p.j稶,$`糉妋0>Fá¡°ly㘽$?": "]ê™›O赎&#ã ƒë±å‰³î°·\"<â—†>0誉é½_|z|裵씪>áŒã¼\"Z[ç•}O?G뚇諦cs⠜撺5cuç—‘U圲\u001c?鴴計lì¶¥/╓哼䄗èŒîšªê®…뫈댽AëŒë¡–뤫V窗讬sHd&\nOi;_î´–u"
+ }
+ ],
+ "Uﺗ\\Y\\梷䄬~\u0002": null,
+ "k\"Y磓ᗔ휎@U冈<\/w컑)[": false,
+ "æ›Jè·âŒ»ë¦\u001f㙳s꥓âŸé‚«P늮쥄c∬ྡྷ舆렮칤Zè¶£5콡넛A쳨\\뀙骫(棻.*&è¼›LiIfi{@EA婳KᬰTXT": -4.3088230431977587E17
+ }]}
+ ]
+ ],
+ "곃㲧<\/dఓꂟs其ࡧ&N葶=?c㠤Ჴ'횠숄臼#\u001a~": false
+ }
+ ]
+ ]}]
+ }]
+ }}
+ ],
+ "2f`â½°E쵟>Jî•笂裭!〛觬囀ۺ쟰#桊l鹛ⲋ|RA_Vxá­gEë“h﵀mfá»|?juTUæ¡£[d⢼⺻p濚7E峿": 5613688852456817133
+ },
+ "濘ë¶gå¿®7ãµæ®¬W팕Qæ› ë«°)惃廊5%-î«è¹šzYZ樭ﴷQ锘쯤崫îŸgg": true,
+ "絥ᇑâ¦ì’“븣爚H.ã—Šß„o蘵貆ꂚ(쎔O᥉î¼ï®“]姨Wê“!RMA|o퉢THxè½®7Mê»U즨'i뾘舯o": "è·¥f꜃?"
+ }}
+ ],
+ "é·°é¹®K-9k;ï°°?_ݦѷ-ꅣ䩨Zꥱ\"mꠟ屎/콑Y╘2&鸞脇ã¢ê€‡à ºâ°¼æ‹¾å–­í‹®îL꽩bt俸墶 [l/웄\"꾦\u20d3iও-&+\u000fQ+໱뵞": -1.296494662286671E-19
+ },
+ "HX੹/⨇୕붷Uﮘ旧\\쾜͔3l鄈磣糂̖䟎Eá³wæ©–bá¿€_딕huè‘°î¤çª³é—¹Ð²U颵|染H죶.fPä—®:jä«¢\\b뎖i燕ꜚGâ® W-≚뉗lè¶•": "ଊ칭Oa᡺$IVã·§L\u0019脴셀붿餲햪$迳å‘ì¯ì¼‚PqfT\" ?î¹€I屉鴼쿕@ç¡™z^é•㊵M}ãš›T젣쓌-Wâ©-g%⺵<ë®±~빅╴瑿浂脬\u0005왦燲4áƒb|Då § <\/oEQh",
+ "䘶#㥘à©îººìº”ï” f巋ἡAJ䢚쭈ࣨ뫒*mᇊK,ࣺAꑱ\u000bR<\/A\"1a6鵌㯀bh곿w(\"$ê˜*rà²è¶£.dà¿©k/抶면䒎9W⊃9": "漩b挋Swè—Ž\u0000",
+ "畀e㨼mK꙼HglKb,\"'䤜": null
+ }]}]
+ ]
+ ]
+ }]
+ ]}
+ ]
+ ]}
+ ],
+ "æ­™>駿ꣂ숰Q`J΋方樛(d鱾뼣(ë«–í„­\u20f9lচ9æ­Œ8o]8윶lì–¶?é•–G摄탗6í‹íµ+g:䱫홊<멀뀿/س|ê­ºsê±è·¶ç¨šW々c㫣⎖": "㣮蔊깚Cꓔ舊|XRfé»ã†šï¸†'쾉ì·\\&言",
+ "æ®­\"cÞɨê™äž˜:嬮eæ½½Y펪㳅/\"O@à —ê²´]ì·–YÇž(t>R\"N?梳LDæ­=næ°¯Tè±°2R諸#N}*ç§ï¡§4}ã¶ŠGä£bì–š": null,
+ "襞<\/å•§ B|싞W瓇)6簭鼡艆lNì©`|펭佡\\é–“é‚[z릶&쭟愱ꅅ\\Tá°½1靝忠ˆ4̸s윜R7â’/똽?치X": "âŠèº–Cﱰ2Qẫè„&இ?%ëƒæ‚Š",
+ ",é°§åµì…£îˆ›ì‹¹xᎹ힨᯳EṬHïŽã¹–9": -4604276727380542356
+ }
+ }
+ ]]]],
+ "웺㚑xs}q䭵䪠馯8?LB犯zK'os䚛HZ\"L?셎s^㿧㴘Cv2": null
+ }]
+ ]
+ ]
+ ],
+ "Kdî©´2Kv+|z": 7367845130646124107,
+ "ᦂⶨ?ᢠ祂些ഷ牢㋇æ“\"腭䙾㖪\\(y4cE뽺ㆷ쫺ᔖ%zfÛ»$Ñž1柦,ã¶¢9r漢": -3.133230960444846E-20,
+ "ç˜Mç„€q%㢟f鸯Oâ£è“‘맕鯊$Oå™·|)z褫^㢦⠮ꚯ꫞`毕1qꢚ{ĭ䎀বώT\"뱘3G൴?ï¢ï¢^^oï…¯f": null
+ }
+ ],
+ "a8V᯺?:ﺃ/8ꉿBq|9啓댚;*i2": null,
+ "cpT瀇Hç°á»ªpೃi鎪Rrâ£ìˆ¬-鹸ҩ䠚z脚цGoN8å…¥y%è¶ŒI┽2ឪЀiJNcN)æ§£/â–Ÿ6S숆牟\"箑X僛G殱娇葱T%æ»:J諹昰qV쨰": 8331037591040855245
+ }],
+ "G5ᩜ䄗巢껳": true
+ }
+ },
+ "Ồ巢ゕ@_è­™A`碫é„㡥砄㠓(^K": "?܃B혢▦@犑ὺD~Tâ§|é†;o=J牌9냚⢽㨘{4è§èš”9#$∺\u0016p囅\\3Xk阖⪚\"UzA穕롬✎âžã­’춺C㣌ဉ\"2瓑员ᅽê¶ë«}꽚ꞇ鶂舟彺]ê½JCè§éЉ",
+ "â†Äšè†\"b-í‰ACR言J謈53~V튥x䜢?ꃽɄY뮩ꚜ": "K/↾eèƒ}]Bs⾿q룅鷦-膋?m+æ­»^魊镲6",
+ "粡霦cæž‹AHíŸo礼Ke?qWcA趸㡔ê‚?\u000eì¶‚8iতᦜ婪\u0015㢼nﵿê»!á´é–¢\u001d5j㨻gfá¿©UK5Juä¸tã‹TI'?ã“t>⼟o a>i}á°—;뤕Ü": false,
+ "ꄮ匴껢ꂰ涽+䜨B蛹H䛓-k蕞fu7kLè°–,'涃V~챳逋穞cT\"vQ쓕ObaCRQã“¡â²®?轭⫦輢墳?vA餽=h䮇킵ní²í‰…喙?\"'1ç–¬V嬗Qdç—'Lự": "6v!së¯ã­Ÿî€µî¦˜ã£¯çƒ!磸餠ቂh0C뿯봗Fé·­gê–¶~コkK<ᦈTtïŽ\\è·“w㭣횋钘ᆹ듡䑚W䟾X'ê…”4ï€FL勉Vܴ邨y)2'〚쭉⽵-鞣E,Q.?å—",
+ "?(˧쩯@å´Ÿå‹æ­„K": null
+ },
+ "Gc럃녧>?2DYIé´¿\\륨)æ¾”0ᔬlx'è§”7젘⤡縷螩%Sv׫묈/]↱&S ï…h\u0006æ­‹á‘›xi̘}ã²Y蔯_醨鯘煑橾8?䵎쨋z儬ê*@츾:": null
+ }
+ }
+ }
+ ]
+ ]
+ ]}
+ },
+ "HO츧G": 3.694949578823609E17,
+ "QC\u0012(翻曇Tfã·ŸbGBJ옉53\\嚇ᛎDï–/\u001b夾á‰4\"í•€@祎)쫆yD\"i먎Vnî¿ã¿¿V1Wá¨ä¶€": -6150931500380982286,
+ "Zã“®P翸é±é‰¼K䋞꘺튿â­Y": -7704503411315138850,
+ "]모开ꬖP븣c霤<[3aΠ\"é»ä––䰑뮋ꤦ秽∼㑷冹T+YUt\"싳F↭ä–&鋌": -2.7231911483181824E18,
+ "tꎖ": -4.9517948741799555E-19,
+ "䋘즊îŽ.⬅IꬃۣQ챢ꄑé»|f?C⾺|å…•ì¯sC鬸섾整腨솷V": "旆柩l<Ké«î–žM戶鯮t:wRî°2ꉱ`9'l픪*í芦㊢Pjjoå ¡^ ì‡ì–›å¶…있ষ0?F",
+ "下9T挞\\$yᮇk쌋⼇,ਉ": true,
+ "櫨:ㆣ,é‚lî ¬r崕祜ã®çƒœZ,XXD蕼㉴ kM꯽?P0﹉릗": null,
+ "îŠgv솠歽閘4镳䗄2æ¾¾>쪦sá–¸My㦅울ì‰ç˜—㎜檵9ï……ê‚駓ૉᚿ/u3ì”…å¾ï¤¥[Z䞸ࡗ1ꆱ&Q풘?Ç‚8\u0011BCDY2볨;é¸": null,
+ "幫 nç…¥sì‡íއ 왊-$C\"è¡:\u0014㣯舼.3ë™—Yl⋇\"K迎멎[ê½µs}9鉳UK8ì¥\"掄㹖h㙈!얄સ?Ꜳ봺R伕UTD媚I䜘Wé¨è”®": -4.150842714188901E-17,
+ "ﺯ^ã„„\b죵@fྉkf颡팋î¤êž¦{/Pm0V둳⻿/è½éŸ’ꊔᚬ@5螺G\\å’¸a谆⊪ቧ慷绖?è´¢(é·‡uéŒF=ráæ©¢áž³n:^iá´µtD볠覅Nèµ´": null
+ }]
+ }]
+ }
+ ]
+ ]}
+ ]},
+ "謯?w厓奰Tï§¡í——èážè²–o⪇弒L!캶$ᆅ": -4299324168507841322,
+ "뺊奉_åžæµ¸å»¶ëªå­„Z舰2i$q붿좾껇d▵é¤\"v暜Ҭì„mï¿´g>": -1.60911932510533427E18
+ }
+ ]
+ }
+ ]
+ ]],
+ "í‰êº”㠦楶Pê…±": 7517896876489142899,
+ "ï™°": false
+ }
+ ]},
+ "是u&I狻餼|è°–j\"7cë®sï­-踳鉷`䣷쉄_A艣鳞凃*m⯾☦椿q㎭Nîœæº”铉tlㆈ^": 1.93547720203604352E18,
+ "ï…µkⲨ\\%vr#\u000bâ’ºY\\t<\/3﬌R訤='﹠8è¤êž´ë ´æ›”r": false
+ }
+ ]},
+ "阨{c?C\u001d~K?鎌Ԭ8烫#뙣Pì´ˆé—tã­±E­ë’䆺}ç”—[R*1!\\~hã•…á°º@<9JêષIä³–æ ­6綘걹ᅩM\"▯是∔v鬽顭⋊譬": "ìš´ï¶Kæ•‚(欖C취پ℄爦賾"
+ }
+ }}
+ }],
+ "鷨赼鸙+\\ä­£t圙ڹx᜾ČN<\/踘\"S_ë§¶a鷺漇T彚⎲i㈥LT-xA캔$\u001cUH=a0츺l릦": "溣㣂0æ¿•=鉵氬駘>Pꌢpb솇쬤h힊줎çªãª¬CrQ矠a&è„꼬爼M茴/á¿®\u0017å¼è½¼y#êž c6ë‘´=?Rå´ë· éº–w?"
+ },
+ "閕ᘜ]CT)䵞l9z'xZF{:ØI/躅匽ì¡:䟇AGF૸\u001cퟗ9)駬慟ꡒꆒRS״툋A<>\u0010\"ꂔ炃7gëšEà§îˆbꅰ輤]oã±_뷕ܘ暂\"u": "芢+U^+㢩^鱆8*1鈶鮀\u0002뺰9⬳ꪮlL䃣괟,G8\u20a8DF㉪錖0ㄤ瓶8Nଷd?眡GLc陓\\_죌Vì°à¤²äºŒ?cë¦æ± \u0019JC\u0011b⤉zẒT볕\"绣蘨뚋cꡉkî« I\u001eé³´",
+ "ꃣI'{6u^㡃#཰Kq4逹y൒䧠䵮!㱙ï®/n??{Lí’“ZETã™ í¿X2᩟綳跠葿㚙w཮x캽扳B唕S|å°¾}ì´•%N?o䪨": null,
+ "ⰴFjà·Ÿì…ˆ[\u0018è¾·px?椯\\1<ﲻ栘á£ë´¢æ† ë‰´p": -5263694954586507640
+ }
+ ]
+ ]]
+ ]}
+ ]}]
+ ]
+ ],
+ "?#癘82禩鋆êŠty?&": -1.9419029518535086E-19
+ }
+ ]
+ ]
+ ]}
+ ]
+ ]
+ ],
+ "훊榲.|῕戄&.ãšZꛦ2\"䢥ሆ⤢fV_æ‘•å©”?â‰Fji冀탆꜕iã¬_ẑKᅢ꫄蔻XWc|饡Siẘ^㲦?羡2ã´1ç¸á™…?ì‰Ou": false
+ }]]
+ ]}}},
+ "æ…‚ë—„å“è“”á“åŒåš–/颹蘯/翻ㆼL?뇊,í…µ<\\ç·ã”Cボ": null
+ },
+ "p溉ᑟi짣z:䒤棇r^٫%G9缑r砌롧.물农g?0׼ሩ4ƸO㣥㯄쩞ጩ": null,
+ "껎繥YxK\"F젷쨹뤤1wq轫o?鱑뜀瘊?뎃hç‘\\ꛣ}Kå³^ኖâ¤ï§´ê‰“hy": null
+ }
+ ],
+ "á±€nè‚“ã„›\"å »2>mæ®®'1橌%êž´êµ°=Ӳ鯨9耛<\/n據0u彘8㬇៩fá¿è¯™]嚊": "䋯쪦S럶åŒã…›#î½)O`ሀX_éªæ¸²â›€ã¨»å®…闩➈ꢙஶDRâª"
+ },
+ "tAì“龇 â‹¥bj왎录r땽✒롰;羋^\\?툳*┎?ì€ma䵳넅U䳆૘〹䆀LQ0\bç–€U~u$M}(鵸gï­â³¾i抦뛹?䤈땚검.鹆?ê©¡tâ¶¥GÄ’;!ቹHïš©Så³»B츪ì¼f5≺": 2366175040075384032,
+ "ì „pJjleb]áž½": -7.5418493141528422E18,
+ "n.鎖ጲ\n?,$䪘": true
+ },
+ "欈Ar㉣螵᪚茩?O)": null
+ },
+ "쫸M#x}Dç§±æ¬K=侫们ä¸ï‡ª.KꕾxẠ\u001e㿯䣛FÜ캗ï¬qq8꟞ṢFD훎⵳簕꭛^鳜\u205cÙ«~⑟~冫ऊ2ì«°<\/戲윱o<\"": true
+ },
+ "ã·è¥/T뱂\u0010锕|内䞇xä¾â‰¦ã­–:M?iM᣿IJeç…œdG࣯尃⚩gPt*辂.{磼럾äª@a\\袛?}ᓺBç¼": true
+ }
+ }
+ ]]}]}},
+ "tn\"6î´ê«¤ìƒ¾ä„„;銞^%VBPwu묪`Y僑N.↺Ws?3C⤻9唩Sä ®á´m;sᇷ냞඘B/;툥B?lB∤)G+O9m裢0kC햪䪤": -4.5941249382502277E18,
+ "áš”t'\\æ„«?éµ€@\\ã³ê‚•Pí <<]ç…¹G-b!S?\nꖽ鼫,Ý›&é ºy踦?Eæ†î¬–릱H}햧캡b@手.p탻>췽㣬ꒅ`qeä½­P>á“‚&?u}毚ᜉ蟶頳졪áŽzl2wO": -2.53561440423275936E17
+ }]}
+ }
+ ]
+ ]],
+ "潈촒⿂å¡": 5495738871964062986
+ }
+ ]]
+ }
+ ]
+ ]}
+ ]]
+ ]]
+ ]}
+ ]
+ ]},
+ "á‚qí‚è“…R`謈èŸá¦î’³å„‚æ§åƒ»ï¹¶9å©Œî¬æ«žé‡ˆ~\"%匹躾ɢ뤥>࢟瀴愅?殕节/냔O✬H鲽엢?ᮈà©î“Žâ‹§dâ½ã«zCe*": 2.15062231586689536E17,
+ "ã¶µUi曚ç°é‹ªá¾¼è‡§P{ä䷪쨑̟A뼿T渠誈äšD1!ìž¶<\/ã¡7?)2l≣穷᛾ç¨{:;㡹nemיּ訊`Gî¹²": null,
+ "䀕\"飕辭påœf#뫆䶷뛮;â›´á©3çšëá°ìŽ“â¦·è©µ%᜖Մfs⇫(\u001e~P|ï­—CⲾផv湟W첋(텪બTî¾·<บSê‰à©—⋲X婵i ӵ⇮?L䬇|êˆ?졸": 1.548341247351782E-19
+ }
+ ]
+ },
+ "t;:N\u0015qé¦Rt缆{ê®C?஛㷱敪\\+鲊㉫㓪몗릙ç«(æ°µkYS": "Xá°‚T?൮ô",
+ "碕飦幑|+ 㚦é¶`é•¥ê© B<\/加륙": -4314053432419755959,
+ "秌孳(p!G?Vå‚«%8ሽ8w;5鲗㦙LI檸\u2098": "zG N볞䆭éŽí˜\\ONK3íš™<\/樚立圌Q튅k쩎Ffì‹aׂJK銆ઘì¦ç‹©6༥✙䩜篥CzP(è»é§‡HHퟲ讃%,ά{ë p而刲vy䦅ክ^톺M楒é¢ã¹³]Mdg2>䤉洞",
+ "踛M젧>忔芿㌜Zk": 2215369545966507819,
+ "ì”A`$æ§­é °í»^U覒\bG毲aᣴU;8!팲f꜇E⸃_åµ{å«ç¾ƒX쀳C7ë—®m(åš¼u NÜè°ŸD劯9]#": true,
+ "ﻩ!뵸-ç­šPá­›}á¼°å±¥lPh?౮ⶹꆛ穉뎃gè‘㑓溢CX뾇Gã–¬A錟]RKï’î´²aꄘ]Yo+@ä˜'s섎襠$^í™°}F": null
+ },
+ "粘ꪒ4HXᕘ蹵.$å€\r\u001dë¬77pPc^yî¶ç¬²Q<\/ê–¶ è¨äƒá¨•G?*": 1.73773035935040224E17
+ },
+ "婅拳?bkU;#D矠â´vVN쩆t㜷A풃갮娪a%é®çµª3dAv룒#tm쑬⌛qYwc4|L8KZ;xU⓭㳔밆拓EZ7襨eD|隰ऌ䧼u9Ô¢+]è´´Pè¿": 2.9628516456987075E18
+ }]}}]
+ ]}
+ }}
+ ]}]
+ ],
+ "|g翉F*湹̶\u0005â1脉̀eI쩓ᖂ㫱0碞l䴨ꑅ㵽7AtἈ턧yq䳥塑:z:é€ï¾¼X눔擉)`N3昛oQì…–y-ڨ⾶æ¢êˆµq^<\/": null,
+ "è¹\\ëž“G^璬x৴뭸ゆUSê²§ï®·Bꮤ ┉銜᯻0%N7}~fæ´‹å„Xꔼ<\/4妟Vꄟ9:౟곡t킅冩䧉笭裟炂4ë´‹â±³åºæ€Št+怯涗\"0ã–ˆHq": false,
+ "졬믟'ﺇফ圪쓬멤m邸QLà¦¬ä—æ„4jvsç¿™ à¾ê§€è‰³H-|": null,
+ "컮襱⣱뗠 R毪/鹙꾀%헳8&": -5770986448525107020
+ }
+ ],
+ "î½­B䔚bê»ë™å§“展槰T-똌鷺tcï§ç¿á«½^㓟ä€o3o$꘭趙è¬Ié¡©)뇭Ἑä“\f@{ᣨ`x3è”›": null
+ }
+ ]
+ ]
+ }],
+ "⦖扚vWꃱ꥙㾠壢輓{-⎳鹷è´ç’¿äœ‘bG倛â‹ç£Žc皇皩7a~ﳫUâ•£Q࠭ꎉS摅姽OW.홌ೞ.": null,
+ "蚪eVlH献r}á®ë¯ ï°©ê”„@ç‘„â²±": null,
+ "퀭$JWoê©¢gì—­ì䖔㑺h&à­¢tXX愰㱇?㾫I_6 OaB瑈q裿": null,
+ "꽦ﲼLyr纛ZduçB絟쬴糔?ã•‚ì§¹äµe": "ḱ\u2009cX9ë©€i䶛簆㳀k"
+ }
+ ]]]],
+ "(_ê®g່澮?ᩑyM<艷\u001aꪽ\\庼뙭Zë§·ã°©Vm\\lYç­º]3㋲2㌩㄀Eਟäµâ¨„ì¨á”ŸgङHné–⤇놋瓇Q탚單oY\"♆臾jHᶈå¾îž«á‰„??uㇰA?#1侓": null
+ },
+ "è§“^~ሢ&iIë†g륎ḱ캀.ᓡꀮ胙鈉": 1.0664523593012836E-19,
+ "yè©­GbᔶऽsëŒU:æœî „⤎ϲì—⮼D醄诿që™°I#즧v蔎xHᵿt᡽[**?崮耖p缫쿃Lè,ë´¬ï–ꤦC쯵#=X1çž»@OZc鱗CQTï‹„x": null
+ }
+ ]
+ }}],
+ "剘ç´\u0004\\Xn⊠6,á€×±;嵣崇}讃iႽ)d1\\䔓": null
+ },
+ "脨z\"{X,1u찜<'k&@?1}Yn$\u0015Rd輲ーa쮂굄+B$l": true,
+ "諳>*ì­®ê´äµŸÒ+<ç®}빀䅱⡔æªï€è‡’hIH脟ꩪCí•ଗP좕\"0i<\/C褻DÛžæ—+^5?'ꂱ䚫^7}ã¡ cq6\\쨪ꔞꥢ?纖䫀氮蒫侲빦敶q{Aç…²G": -6880961710038544266
+ }}]
+ },
+ "5s⨲JvಽῶꭂᄢI.a৊": null,
+ "?1qê½ì¿»ê›‹DR%Uå¨>DgNä¹­G": -1.2105047302732358E-19
+ }
+ ]
+ ]},
+ "qZz`撋뙹둣j碇ì\\ꆥ\u0018@ïœè—´ç–°Wz)O{Fä¶›l᷂绘訥$]ë®å¤»ä¢‹ä©‡è¿ç°æ¨§çŒµâ£­jè¶q)$꬚⵷0馢W:â°!Qoe": -1666634370862219540,
+ "t": "=î¹›wp|~碎Q鬳Ó\\l-<\/^ﳊhní–}ä”t碵ḛ혷?é»äŠ—",
+ "邙쇡㯇%#=,î‰E4勃驆V繚q[Y댻XV㡸[逹á°è‘¢B@u=JS5?bLRnì–®ã‰â…ï°³?a6[&íŸ!è—ˆ": 1.2722786745736667E-19
+ },
+ "X블땨4{ph鵋ꉯ웸 5p簂䦭s_E徔濧dç¨~No穔噕뽲)뉈c5M윅>âš‹[岦䲟懷æ?éŽê“†à¸¬çˆ‹ç äœ”s{\u001bméšå„¸ç…›%bﯿXT>ê—˜@8G": 1157841540507770724,
+ "媤娪Qæ¸ï‡\u0011SAyᡈ쿯": true,
+ "çš^ಸ%ê±<\/蛯<O\"-刷ã R(kO=䢊䅎l䰓팪A絫픧": "è­”\\ãš„ ?R7㔪G㋉⣰渆?\\#|gN⤴;Wì¹·A׫癮଼ೣã³ë’œ7dæ“ê¾²0扬S0ᆵi/贎ྡn䆋武",
+ "è‡ç ‡Gã“æœ¦ì¼‹Wq`㞲攊*å†î‘µî¨~霓L剢zI腧튴Tç¹™Cঅ뫬╈뮜ㄾ䦧촄椘B⊬츩r2f㶱厊8eϬ{挚â¯OM焄覤\\(KÓ¡>?\"祴å“\\\\'í": -3.4614808555942579E18,
+ "釴U:O湛㴑䀣렑縓\ta)<D8ï­³æ§é«­D.L|xsæ–‹æ• \"ë‹æ—©7wáŽ": true,
+ "쵈+쬎簨up䓬?q+~\u0019仇îŒëµˆá«¯3áµ£æ˜æž°åŠ«ãª¢uç˜-퀭:ì»™:u`⌿ï«A(9鄦!<çšnj3:Hà£¨å·‹ä€æ—¸ëŽˆë§»v\"\\(곘vO㤰aZe<\/W鹙鄜;l厮ë‘": null,
+ "î–·": -1.2019926774977002E-18,
+ "%者Oî–‹7.Nêªs梇接z蕜綛<\/䜭\"죊y<曋漵@Śâ¹sD⟓jݗᢜ?zî–†/9á²Ma쨮긗贎8ᔮ㦛;6p뾥໭䭊0B찛+)(Yã¿ é¸ä•’^옥": "鬃뫤&痽舎Jì½®è—󽸰ᨨMꈫ髿v<N\\î·.ì‚’ê»…Ñ1ê­¼5ä´·5쳬臨wjë¥"
+ }],
+ "é·Ž'ã³—@帚妇OAj' è°¬f94ǯ(횡ヒ%io쪖ì‚좛>(j:숾å´ä—ŒgCiB뽬Oyuqè¼¥åŽ/7)?今hY︺Q": null
+ }
+ ]
+ ]]]}]
+ ],
+ "I笔趠Ph!<ཛྷ㸞诘X$畉F\u0005笷èŸ.Esr릙!W☆ï›ä²–뗷莾뒭U\"䀸犜Uo3ï¯Gꯌx4r蔇᡹㧪쨢準<ä‚€%ࡡꟼç‘8ç‚Xs0ä€é”€?fi쥱ê†àª²BB": -8571484181158525797,
+ "Lâ¦o#J|\"⽩-ã±¢d㌛8d\\㶤傩儻E[Y熯)r噤὘勇 }": "e(濨쓌K䧚僒ã˜è ¤Vᛸ\"络QJL2,嬓ì™î¿‰ä¼¢ã‹’䴿考澰@(ã¾`kX$ë‘ÑE斡,èœ&~y",
+ "vj.|统圪ᵮPL?2oŶ`ë°§\"勃+0ue%⿥绬췈체$6:qaë Q;~晘3㙘鹑": true,
+ "à·Ø™4ç„â¶¿c︋iâš…:ã‚“é–Ⳙ苆籦kw{䙞셕pCì·ƒê¬âœêŸ¯êš“é…„bížhwkê­­M鬋8B耳쑘WQ\\å™ac'唀x᪌\u2048*hì§Ž#á‡é® ë¾áž¿ë€Œ": false,
+ "⎀jꄒ牺3Ⓝ컴~?親ꕽã¼Ü“å–瘘!@<튋ãŒê¿±â©¦{a?Yv%⪧笯Uܱ栅Eæši뚬:ꄃx7䙳ꦋ&䓹vq☶Iä˜á¾˜æ¶œ\\ì‰ëºŒLr%Bcãœ3?î¤ï…¨ê­ç ¿è£ž]": null,
+ "⭤뙓z(㡂%亳K䌽꫿AԾ岺㦦㼴輞낚Vꦴw냟鬓㹈뽈+o3譻K1잞": 2091209026076965894,
+ "ㇲ\t⋇轑ꠤ룫X긒\"zoYì‡í¬wjæ¢ì‘l侸`e%s": -9.9240075473576563E17,
+ "啸ꮑ㉰!áš“}éŠ": -4.0694813896301194E18,
+ "ï‰>]囋੽EK뇜>_ꀣ緳碖{ì裔[<ನ\"䇅\"5L?#îµ³xTwv#ç½\u0005래t应\\N?빗;": "v쮽瞭pë­ƒ"
+ }
+ ]],
+ "æ–´æ§¾?Zç¿\"~æ…弞ﻆ=꜡o5é‹ï’½dw\"?Kè ¡i샾ogDï²°_C*⬟iㇷ4nયèŸ[㟉U꽌娛苸 à§æ“贻洞펻)쿗૊許X⨪VY츚Zä¾ã¶­~튃ᵦ<\/E臭tve猑x嚢": null,
+ "锡⛩<\/칥ꈙᬙè€&êšç±¬â– 865?_>Lè©ì¿¨äˆŒæµ¿å¼¥ï©‰Ì«î¾½ï‘lj&zx<\/C쉾?覯n?": null,
+ "꾳鑤/꼩ï¨d=ᘈn挫ᑩ䰬ZC": "3錢爋6Ƹ䴗v⪿Wr益G韠[\u0010å±—9ì¡é’u?殢c䳀蓃樄욂NAq赟c튒ç˜ë ¶î‚³Aà«¡Éšæ"
+ }
+ ]
+ ]
+ ]}
+ ]
+ ]
+ }]]]}}
+ ]}],
+ "ï‚’Ejä—³U<\/Q=ç’샎䞦,å °é  @褙g_\u0003ꤾfâ¶½?퇋!łB〙ד3CC䌴鈌U:뭔咎(Qો臃䡬è‹BO7î¼§ã¢äŸ¸\"Yb": 2.36010731779814E-20,
+ "逸'0å²”j\u000e눘먷翌C츊秦=ꭣ棭ှ;鳸=麱$XP⩉駚橄A\\좱⛌jqvä°ž3Ь踌v㳆¹gT┌gvLBè³–ïžçƒ¡m?@E঳i": null
+ },
+ "曺vì°˜×?&绫OáŸ": 9107241066550187880
+ }
+ ]
+ ],
+ "(e屄\u0019昜훕ç–b蓘ᬄ0/۲묇Z蘮á€â¨è›˜èƒ¯ë¢ƒ@㘉8ሪWᨮ⦬ᅳ䅴HIá‡ì¨³z囕陻엣1赳o": true,
+ ",b刈Z,á æ™Tì†Å•B⩆ou'í¼â‰ƒç»—é›—dè­Š": null,
+ "a唥KB\"ï³è‚•$u\n^â…„P䟼냉䞸⩪u윗瀱ꔨ#yÅŸsî««ê’¬=ï‹•1ïš–|ﲤ爢`tà±íмî£ì³«_Az(Ṋ擬㦷좕耈6": 2099309172767331582,
+ "?ã´¸U<\/䢔ꯡ阽扆ã¤qé‹?f㔫wM嬙-;UV죫嚔픞G&\"Cá—äªí’ŠQ": "VM7ç–¹+陕枡툩窲}ç¿¡ä–¶8欞ÄsTë®}ç’¤:jﺋ鎴}HfAàµâ§»Zd#Qï¬u茅J髒皣Y-︴[?-~쉜vë”璮㹚䅊﩯<-#\u000eê±€h\u0004u抱﵊㼃U<㱷⊱IC進"
+ },
+ "숌dee節é½é‚ºp넱蹓+e罕U": true
+ }
+ ],
+ "b⧴ë£??á” 3ã±>%郿劃ç¿ê¬ê ›Wï¡°çž³á«ëˆ„躨狀ໄy੽\"ីuS=㨞馸k乆E": "トz݈^9R䬑<ﮛG<s~<\/?ⵆá¥è€ç†·uë“·"
+ }}
+ ]
+ }
+ ]}
+ }
+ }
+ }
+ }},
+ "宩j鬅쳜Qê–јyç”Zá­µï1væ“–}䨿F%cֲ᫺贴m塼딚NP亪\"ï¿‹sa뺯ꘓ2:9뛓ï à¼‚쌅䊈#>Rꨳ\u000fTT泠纷꽀MR<CBxPñ±’«X쇤": -2.22390568492330598E18,
+ "?䯣ᄽ@Z鸅->ᴱ纊:ã ­ë³®?%N56%鈕1ä—äœaä²—j陇=ë¿»å‚衋࿘ᓸ?ᕵZ+<\/}H耢bä€z^f$&ã’LkꢳI脚뙛u": 5.694374481577558E-20
+ }]
+ }
+ ]],
+ "obj": {"key": "wrong value"},
+ "퓲꽪m{ã¶©/뇿#â¼¢&᭙硞㪔E嚉c樱㬇1aç¶‘á–DḾä©": null
+ },
+ "key": "6.908319653520691E8",
+ "z": {
+ "6U閆崬밺뀫颒myj츥휘:$è–ˆmYí–š#rzé£+玭V㭢뾿愴Yî°‘ê–šX亥ᮉ푊\u0006åž¡ã­ë£\"厓ᔧḅ^Sqpv媫\"⤽걒\"˽Ἆ?ꇆ䬔未tv{DV鯀Tἆl凸g\\㈭ĭ즿UH㽤": null,
+ "b茤z\\î¨.N": [[
+ "ZL:ᅣዎ*Y|çŒ«åŠæ«•è¾Oj为1糕쪥æ³S룂w࡛á²â¸¥èš™)",
+ {
+ "\"䬰á»wDæ¾V`邀⠕VDãºsH6[칑.:醥葹*뻵倻aD\"": true,
+ "e浱uî¿£p蔽Crà· JK軵xCʨ<뜡癙Yç©ï½¹é½ˆX/螗唻?<蘡+뷄㩤쳖3å‘犾&\\첊xzå崦ݻé´\"åµ¥B3㰃詤豺嚼aqJ⑆∥韼@\u000b㢊\u0015L臯.샥": false,
+ "l?Ǩ喳e6㔡$M꼄I,(3á縢,䊀疅뉲B㴔傳䂴\u0088㮰钘ꜵ!ᅛ韽>": -5514085325291784739,
+ "o㮚?\"춛㵉<\/﬊ࠃ䃪ä£wp6ἀ䱄[s*S嬈貒pᛥ㰉'ë€": [{
+ "(QP윤懊FI<ꃣ『䕷[\"ç’å¶®?%Ḭå£à²»ä‡Ÿ0è¤!è—²ë¹bdæµ¶tl\u2049#쯀@僞": {"î—i妾8홫": {
+ ",Mï£ë§ƒäž›K5nAㆴVNã’Ší–¬$n꩑&êŽæ¤žî·é˜«?/á¹ì„¸ë‰ª1x쥼㻤㪙`\"$쟒薟B煌܀ì¨à­2掳7㙟鴙Xå©¢\u0002": "Vዉèˆï ’᧷⦌kîŒï®žà°ˆnz*<?੃'ahhCFX(\u0007⮊Eã­ä±¾Gxꥩrâ£.æ´Ž",
+ "ë»´5bDDí¯O傆盓왻U?êž…êŠNé­á§¢Ï„\"迳豲8\u001b䃥ꂻ䴺ྸHç­´,": {
+ "\"L鸔SE㬡XV&~ÍŽ'놅蔞눶l匛?'.Kæ°\\ƢẨ疇má¿›'ê½³&!é¹ m'|{Pç—Š ç§„ì’¿u\u00111ä‹§î´¼gÏ©x7t丗D䊨䠻z0.A0": -1.50139930144708198E18,
+ "8é‹‚ë›·ïž”?ì²’B☚>ï·œFM\"è­7ê€-VR<\/';ä™E9$䩉\f @s?íªo3^è¡´cî˜à¶Žä§ªaK鼟q䆨c{ä³ 5mᒲՙ蘹ᮩ": {
+ "Fã²·JGoâ¯Pëµxë’³p䘧☔\"+ꨲå¿JfR㔹)4nç´¬G练Qáž!C|": true,
+ "p^㫮솎ocî’£.೚A㤠??r\u000f)⾽⌲們M2.䴘䩳:⫭胃\\á¾@Fá­Œ\\K": false,
+ "蟌Tk愙潦伩": {
+ "aï‘<\/@ᾛ慂侇瘎": -7271305752851720826,
+ "艓藬/>á„ṯ,XW~㲆w": {"Eç—§î–郶)㜓ha朗!N赻瞉駠uC\u20adè¾ <Ve?í±!ImäŽî­Ÿæ„:*s 9諚Prᵾ뒰髶B̌qWA8梸vS⫊⢳{t㺲q㺈랊뮣RqK밢쳪": [
+ false,
+ {
+ "\u000b=>x퓮⣫P1à «LMMX'M刼唳ë¤": null,
+ "P쓫晥%k覛ዩIUᇸ滨:å™í˜²lMR5䋈V梗>%å¹½ué –\\)쟟": null,
+ "eg+昉~矠䧞难\b?gQì­·ç­\\eê® Nl{ಢ哭|]Mn銌╥zê–˜zⱷ⭤ᮜ^": [
+ -1.30142114406914976E17,
+ -1.7555215491128452E-19,
+ null,
+ "渾ã¨ß牄귛r?ëŒ?w[âšžÓ»~廩輫㼧/",
+ -4.5737191805302129E18,
+ null,
+ "xyà¿‘M[ocì…’ç«“â’ºx?뜓y䊦>-Dì¼(&&?XKkc꩖ﺸá‹ëµžK伕6à§€)딀PæœyWæ™îž¢?훻魢傎EG碸9類៌g踲C⟌aEX舲:z꒸许",
+ 3808159498143417627,
+ null,
+ {"m試\u20df1{G8&뚈h홯J<\/": {
+ "3ஸ厠zs#1K7:rᥞoꅔꯧ&ë‡éµ¼éž«6è·œ#赿5l'8{7㕳(b/j\"厢aqç±€êš\u0015厼稥": [
+ -2226135764510113982,
+ true,
+ null,
+ {
+ "h%'ë§žï–±Sì‹…Hs&dï”l슾W0jé¿M×D놯L~S-㇡Rì­¬%": null,
+ "⟓咔謡칲\u0000孺ꛭx旑檉㶆?": null,
+ "æ‡I転;￸B2Y`z\\ç“w,ë†æ¿æ’埵䂄)!ä¶¢D=à´­ã´ŸjyY": {
+ "$ࡘt厛毣ൢIèŠ<겿骫⫦6tr惺a": [
+ 6.385779736989334E-20,
+ false,
+ true,
+ true,
+ [
+ -6.891946211462334E-19,
+ null,
+ {
+ "]-\\êŸ1/è–“â§á½Š\\l牑\u0007A郃)阜ᇒᓌ-塯`W峬G}SDb㬨Q臉⮻빌O鞟톴첂B㺱<ƈmu챑J㴹㷳픷Oㆩs": {
+ "\"â—‰B\"pᶉt骔J꩸ᄇá›iâ•°æ ›K쉷㉯é©!ãˆnì¹äŸ…難>盥yé“¿eà­”è’M貹ヅ8å˜‹í€¯ä‰¶áŒ¥ã¢æ®Šë»³\"絧╿ꉑ䠥?∃蓊{}㣣Gk긔H1哵峱": false,
+ "6.瀫cN䇮F㧺?\\椯=ÚˆT䘆4â˜ïšŒ8qv": -3.5687501019676885E-19,
+ "Q?yऴr혴{஀䳘p惭f1ﹸ䅷䕋贲<ྃᄊ繲hq\\b|#QSTî“¶s1c-7(äµ¢\u2069åŒçµ˜ê¯‰:læ¯´ï›æ±žt戀oà·Ÿáµ¶ë®±á£-醇Jx䙬äí–¢0࣫á¡grã„›": "\u0011_xM/蘇Chv;dhA5.嗀绱V爤ﰦiëµ²M",
+ "â‘[\"ugoy^儣횎~U\\섯겜ï¥l2jw஌yD腅̂\u0019": true,
+ "ⵯɇä²á«¿à¢š!㯢l샅笶戮1꣖0Xe": null,
+ "劅fë„€ï‹ï§¼bå®ç„ŠE찓橵G!ʱç“뭔雩괛": [{"p⹣켙[q>燣äƒãž½î›œá©²x:쓤삘7玑퇼0<\/qç’‚á‘[ï ™Z\\3䅵䧳\u0011㤧|妱緒C['ì·“Yꞟ3Z鳱雼P錻BUì”§U`ᢶg蓱>.1Ó§è­«'L_5VäµÐ¦": [
+ false,
+ false,
+ {"22ä‚盥N霂얢<F8î±ê¼µ7Gà°¸yhë€g᦭ꄢx硴嬢\u001a?Eê´†T|;7犟\"Wt%ä©O⨵t&#ᬋK'èœá²«æ”⾠鲂Të©·éƒ\u0018䓞cE": {"f=ä츜瞾zw?å­¡é£\\铀᫞yẆg(\u0011M6(s2]`ਫ": [[[{
+ "'y몱纣4S@\\,i㷯럹Ua充Tᣢ9躘Zଞ쥿äŠs<\/刎\\\"뉦-8/": "蜑.X0꭛낢륹iì ¨êš<8?s볕è¡|Q✬᯦@\\G㑢屿Mn졾J굤⥟JW뤵苑rì•툄嵵?â¾¥O",
+ "^1挲~[n귆誈央碠멪gI洷": -8214236471236116548,
+ "sሣ%娌暡clr蟜㑓2\u000bSâŸ_X㨔⚴5~蔷ꀇ|Xu㬖,꤭å¹îµ¿r(g믇ì©ïЍ%췸앙|æ £U\\2]䤉+å• è¡ê¯ŽT鉹m\n/`SzDᅼ鞶": 1.1217523390167132E-19,
+ "u톇=黚\\ ꂮ췵L>躰îe9â‘©_뵜斌n@B}$ê´»Yá±@ä§‹î´½V\"☒-諯cVë¯Ê ": true,
+ "Ű螧ᔼæªéŽë•’딜qꄃH뜣<ç§à¥‚CYå“â¸>XQ㵡趌oë¬k픀빯a(ܵç”ë†à­¯/6Nᪧ}æšá†šì§ŒP牰泱鈷^d꣟#Lì‚€\"㕹襻;k㸊\\f+": true,
+ "쎣\",|⫝̸阊x庿k잣v庅$éˆê´Žç‚”k쬪O_": [
+ "ìž©AzZGz3v愠ꉈⵎ?㊱}Så°³à¯p\r2>ì·IP䘈M)w|\u000eE",
+ -9222726055990423201,
+ null,
+ [
+ false,
+ {"´킮'뮤쯽Wxè®V,6ᩪ1ç´²aႈ\u205czD": [
+ -930994432421097536,
+ 3157232031581030121,
+ "l貚PY䃛5@䭄<nW\u001e",
+ [
+ 3.801747732605161E18,
+ [
+ null,
+ false,
+ {
+ "": 4.0442013775147072E16,
+ "2J[sᡪ㞿|n'#廲꯬乞": true,
+ "B[ç¹°`\\ãa̼㨀å›ã½“<\/꥖ᵈO让\r43⡩徑ﬓ๨ﮕx:㣜oçŽê‰Ÿã¢Cçµï›‰á½†á“žì‡“Qs氯였9é§µq혃Ljê‚”<\/昺+tä‹à¼»çŒ™c沪~櫆bpJ9Uá:칣妙!çš—F4㑄탎䕀櫳振讓": 7.3924182188256287E18,
+ "H磵ai委曷n柋T<\/å‹¿F&:ꣴfU@㿗榻Lb+?í„sp\"᪟~>ê·»m㎮ç¸fî§¡": 1.0318894506812084E-19,
+ "࢜⩢Ш䧔1肽씮+༎ᣰ闺馺窃䕨8Mƶqè…½xc(៯å¤J5굄ä•Qj_훨/~価.䢵慯틠퇱豠㼇Qﵘ$DuSp(8Uà¸<\/ಟ룴𥳐ݩ$": 8350772684161555590,
+ "ㆎQ䄾\u001bpᩭ${[諟^^骴᤮b^ㅥI┧T㉇⾞\"绦<AYJ⒃-oF<\/蛎mm;obh婃ᦢ": false,
+ "䔤䣈?æ±.p襟&dã±…\\Jᚠ@?Oì²à¢½íœ”VR蔩|㒢柺": [[
+ "-ꕨ岓棻r@鿆^3~䪤Ѐ狼︌ﹲ\\á¸MlEìµ Q+",
+ null,
+ false,
+ 3346674396990536343,
+ null,
+ {
+ "": null,
+ "/ä¨S쨑,&繷㉥8C엮赸3馢|뇲{鄎ꗇqFﶉ雕UD躢?Ꟛအï–꽡[hᕱᗅ㦋쭞MユèŒ?L槽암V#성å”%㣕嘵\\Ú¹(å˜èº¿&q": [
+ -1364715155337673920,
+ false,
+ -8197733031775379251,
+ "E팗鮲JwH\\觡܈áœ\"+뉞娂N휗vå™™á‚ê¹¼\u001dD帒l%-æ–”N",
+ -3.844267973858711E-20,
+ [{"쬯(褈Q 蟚뿢 /ⱖ㻥\u0017/?v邘䃡0U.Z1î­­x?鯔Vå° 8Emï•<": [[[
+ null,
+ [
+ null,
+ -5841406347577698873,
+ "í‚·\"S⋄籞繗솸ᵣ浵w쑿ퟗ7náŽx3ì•™z㘌쿸I葥覯ã¬0á†b汆狺뷘ႀnꋋ",
+ -1227911573141158702,
+ {
+ "u㉮PᾺV鵸A\\g*à¡—9슟晭+ͧↀ쿅H\u001c꾣犓}癇æ›á—¬é»©äŸ˜X梑é†e>rä°‚f矩'-î½7ä¡­æ¡¥Dz兔V9è°¶å±…ãºá”Šä©¯ë².\u001eL0ὅㅷ釣": [{
+ "<쯬Jå·^숞u࠯䌗艞R9닪gã¾ë³Ža䂈歖æ„:%é”|ﵤ|y}î¡»>;2,覂⶚啵tb*ä»›8ä¹’ã“¶B࿠㯉戩oX 貘5V嗆렽ë‚߼4hä§›êºM空\\b꿋貼": 8478577078537189402,
+ "VD*|吝z~h譺aᯒ": {
+ "YIì·¢K<\/濳xNne玗rJo쾘3í•°é´Š\"↱AR:ࢷ\"9?\"è‡ï¦¡)?誚êŠe)_D翾W?&F6J@뺾ê°NZ醊Z쾈വHï±å¶¿?炫㷱鬰M겈<bïž²S}㎥l|刖k": {"H7鷮퇢_k": [
+ true,
+ "s㟑瀭좾쮀â‘î¬Yì°ºk맢戲쀸俻àº6å„®ë—æ‰–puߖꜻ馶rꈞ痘?3ྚ畊惘䎗\"vv)*臔웅鿈䧲^v,껛㰙J <áš¶5",
+ 7950276470944656796,
+ 4.9392301536234746E17,
+ -4796050478201554639,
+ "yꬴc<3㻚",
+ "oå¡\u20a4蒵鮬裢Cá´§nBã­±f.",
+ false,
+ [
+ false,
+ "ã¡å¼‘V?瀆䰺q!출㇞yᘪ꼼(IS~Ka 烿ꟿ샕桤\u0005HQҹ㯪罂qè¾âš‡æ‡‹â¦•ë‘¡v",
+ 1862560050083946970,
+ "\u20b6[|(ë­¹gê’펉O轄Dl묽]ﯨ髯QEbAã’¾m@롴礠㕓2ë•«n6ْ엘঵篳R잷꙲m색摪|@ã¿«5aK设f胭r8/NI4ì¶«æ µ\\꯬2]",
+ false,
+ {
+ "\u000b7*ã™›ç‡.~?䔊pæ•e_拺艿ë·f{ê”»1sé©™`$Ė戧?q⋬沭?å¡·á­šè¹€unoa5": {
+ "Sê·¯o紞㾕ᅶä¾î—¶éЇ12|ÊŸç•´ï–iNAo?|Sw$M拲գ㭄紧螆+,梔": null,
+ "ã­š0?xB疱敻ேBPwv뾃熉(Ó pJ]ê°¢\"Bj'\u0016GE椱<\/zgៅx黢礇h},M9ï´¦?LḨ": "Si ïŸB%~㬒E",
+ "핇㉊살ã¢ìˆ¨~ȪRo䦅D桺0z]﬽蠆c9ᣨyPP㿷U~ãž?쯟í¸å®’뉆U|}㉓郾ࣻ*櫎꼪ä—s?~7\u001e㘔h9{aáž‹}:ã¶’P8": [{"\\R囡ì¬nNæŸ‹çØ›7ì¹¾ :㶃衇徜V æ·±f1æ·â™ i?3Sè§’íž^ᆞ\u20e8á¹°D\u0007ç§¡+躒臔&-6": {
+ "䨑g.fhã”—=8!\"狿ൻLU^ë»±g䲚ã»'W}k欤?๒鲇S꧗䫾$ĥ피": -794055816303360636,
+ "外頮詋~텡竆î™ç¹ƒä©è‹¨ë¾ºæœê¼ƒç˜¹f*㉀枙NH/\u2027ê¢}j묎ïƒvペq︉ì‹ëœ¡Od5 N顯ି烅仟Qfㆤ嚢(i䬅c;ë§§?嶰㩼츱ç¡?-": {
+ "e݆ã¡â¬¬î›–'2ã»’?U篲鿄\"隻Ҭ5NꭰꤺBꀈ拾᩺îº[刯î…5곑Na램ﴦ዆]ã“qwé’„\u001b\"Yæ´Šä—¿î¼ç¥å¡¥è¿µ[⼞⠳P$ê ±5먃0ï¦`": [{"ç°Eè³ï«šb먭N긆Ⰹå²2逶ꜛ?H짉~?P}jj}ä¾·ç¿_T>á­¨b,â»éˆµP䕡䀠८ⱄ홎鄣": {
+ "@?k2é¶–ã‹®\"Oರ K㨇廪儲\u0017ä¾î¿‚J?);\b*묀㗠섳햭1MC V": null,
+ "UIICP!BUA`î€á¢ˆã‹¸~袩㗪⾒=fBï®´l1ꡛ죘R辂여ҳ7쮡<䩲`熕8é ": 4481809488267626463,
+ "Y?+8먙ᚔ鋳蜩ï–럶1㥔y璜౩`": [
+ null,
+ 1.2850335807501874E-19,
+ "~V2",
+ 2035406654801997866,
+ {
+ "<숻1>\"": -8062468865199390827,
+ "Mã¿£ï€E]}qwG莎Gná¶(ê”™\\D⬲iꇲs寢t駇S뀡ꢜ": false,
+ "pê¤ãŽ9W%>M;-Uç’fî£(^j1?&RBéš§ å¿“b똊îƒE": "#G?C8.躬ꥯ'?냪#< 渟&헿란zpo왓Kj}é·§XﻘMツbä•–;㪻",
+ "vE풤幉xz뱕쫥Ug㦲aH} ᣟp:鬼Yá°Ÿ<Fɋ잣緂頒âºä‰²ç‘‘ä…‚,C~Þ…G!f熢-B7~9Pqà¡¢[츑#3ꕎ,Öඳèâ©…ãµ§ì¶€ë¿xyäŒÍ‚tdj!箧᳆|9èš¡ë¬": -2.54467378964089632E17,
+ "䵈䅦5ë¹–,궆-:໿댾仫î»0ᙚyá¦hqáš„": null,
+ "侯Y\"湛졯劇Uì…ŽYXçâ…¸2ä¼´|ç­§\\ä’ã¶¶á·ì‘WaᦵᗱãœëŠ¾è† <Jc63<G\u20fe䇹66僣k0O\"_@U": null,
+ "姪y$#sæ¼´JH璌Ӊ脛Jã¾íŽ”ï¹´oꈶ㚸PD:薠ì–%說ážè¹‚1]⾕5튄": {
+ "á¾Huw3䮅如쿺äŸå«]<鰨ݷ?꯯䫓傩|á¶à·ƒåª½\\澒≡闢": "Mm\"ì‡á¯„졽\"楇<\/ꥆí­å±€néš´@é¿£wâ Š4Pï«å¾ŽW㊋;䤞'.팇è’ä¡´egpxå—Žwà®…ç—å ®á›nË︖䀤4å™™?໚éƒá±‹Þ˜à¥Žtæ‘姫籕殥ï­é™ƒ\"4[ê¬qL4Wê Žx",
+ "ℇjéŒïš›5Bë’š\" U": "ç¡„ê˜{憠êµ:&t䌨m Cઌ쿣鞛XFê Ÿsä­ï¶ƒ\"æ ¼a0x闊昵å²L\\æšèˆaê¸j싹ç…\"î ²çŸï±¡é¦†*êµ–ç³ <ê”躎",
+ "톌賠弳êŸb\"èž–X50sĶ晠3fç§‚å¯Iⓟ:è˜": 5.573183333596288E18,
+ "%䴺": [[[[
+ -6957233336860166165,
+ false,
+ null,
+ {
+ "\"ïŸ\\௮茒袀ᕥ23ୃ괶?䕎.嚲◉ãžL+ᵡ艱hL콇붆@": null,
+ "%螥9ꭌ<\/-t": true,
+ ",9|î«è€¢æ¤¸ä“Xk죱\u0015$Ώ鲞[ï’—?ì—¢á²í˜ªì¦ˆâ´‚â–‚â„´ã—¯\"gî´ëº˜\\êœ#\u0002ヮ}ሎ芲P[鹮轧@냲䃦=#(": 2.78562909315899616E17,
+ "R?H䧰ⵇ<,憰쮼Q總iR>H3镔ᴚ斦\\é‘r*2橱Gâ¼”F/.j": true,
+ "RK좬뎂aí™ f*f㱉á®â¦‹æ½™ã¨‹Gu곌SGI3Ië¿\\F',)t`è蘯囯ﮉ裲뇟쥼_ገ驪▵æ’ᕤV": 1.52738225997956557E18,
+ "^k굲䪿꠹B逤%F㱢漥O披M㽯镞竇霒i꼂焅륓\u00059=皫之눃\u2047娤é–銤唫á•b<\/w踲䔼u솆맚,ä’á³'/it": "B餹饴is権ꖪ怯ꦂẉဎt\"!凢谵⧿ï™0\\<=(uLä·åˆ¨ì‘ª>俆æ“Cy襸Q힆䆭涷<\/á±0î É§îŠ‹䗾䚹\\ኜ?ꄢᇘ`ä´¢{囇}᠈䴥X4퓪檄]ꥷ/3謒ሴn+gé¨X",
+ "GgG꽬[(å«“ëª6\u0004ê¶宩㙻/>\u0011^è¾dTè…ªhxÇ‘%ꊇk,8(Wâ§‚çµP鬜O": [{
+ "Mã´¾c>\\ᓲ\u0019V{>ꤩ혙넪㭪躂TS-痴໸闓âµ/徯O.Mã¥Ê·D囎⧔ì³íœ¤T??鉬뇙=#ꢫ숣BXä­¼<\/d똬졬g榿)eꨋﯪ좇첻<?2K)": null,
+ "Z17縬z]愀䖌 ᾋBCg5ë”’êµ­æ†ê¾“aâ²·í„·u:U촳驿?雺楶\u0001\u001c{q*á°—è‹‘B@kæ°z.*è“—7ረIm\"Oá±@7?_": true,
+ "㺃Z<": -4349275766673120695,
+ "휃䠂fa塆ffixKe'ë¬é—੄뺾w࠾鑎kë•¢m*á‚‘î§·í–žé®6攊&虜h黚,Yä±³Sﭼ둺pN6": [
+ false,
+ "IΎ䣲,\"ᬮ˪癘P~Qlnxå–Sᮔ༬˨IçŒm䜛酛\u0003iê¸ã¦§cQ帲晼D' \\(粋ï›wQcN\\ëµ°è·ˆ",
+ [
+ "D0\\L?M1ì¥KaêŒsd+盌귤憊tz䌣ëŒ×‘Oå‚wÏ¢%á½’gpî•—,Aiï™âŽ§á¶†Iî«˜é¤¾ê¦æ£©å˜…᳉怴%m]á¶is纖D凜镧o심b Uî»·",
+ {
+ "?଼\u0011Rv&^[+匚I趈T媫\u0010.䥤ᆯ1q僤HydⲰl㒽K'ᅾiౕ豲초딨@\u0013J'쪪VD౼P4Ezg#8*㋤W馓]c쿯8": false,
+ "c/擯X5~JmKäµ¶^ìŽà´š|B|u[ì†(X뚤6v}W㤘⠛aR弌臌쾭諦eⒷ僡-;㩩⭖ⷴ徆龄갬{䱓ᥩ!ï¯âŠšá‡¨<v燡露`:볉癮꨽り★Ax7Ꮀ譥~舑\\Vê‹\"$)v": "e&sFF쬘OBï–†d슊寮f蠛জ봞mn~锆竒Gè„\"è¶µG刕䕳&L唽붵<\/I,X팚Bâ¥î¼¶X,kԇҗ眄_æ…¡:U附ᓚAè•§>\u001a\u0011\";~쓆BH4勿”Š7힪",
+ "iT:L闞椕윚*æ»›gI≀Wਟඊ'ꢆ縺뱹鮚Nê©á§¬è•¼21줧\\䋯``â\\ã±é³¨": 1927052677739832894,
+ "ì®ç¼¦è…ƒg]礿Y㬙 fî¼ãƒºSɪ꾾N㞈": [
+ null,
+ null,
+ {
+ "!t,çY 1䗉罵?c饃호䉂Cá­ì’˜z(즽sZG㬣sഖE4ï‚뢜㓕äžä¸®Qpç°6EZឪ겛fx'ꩱQ0ç½£i{k锩*㤴㯞r迎jTⲤ渔m炅肳": [
+ -3.3325685522591933E18,
+ [{"ã“5]A䢕1룥Bï²C?Ꙍ`r룔Ⳛ䙡uä¼²+\u0001àµo": [
+ null,
+ 4975309147809803991,
+ null,
+ null,
+ {"T팘8Dﯲ稟MM☻㧚䥧/8ﻥ⥯aXLaH\"顾S☟耲ît7fSà·‰ë†ë®”/ꕼ䓈ìº4\\霶䠴ᩢ<\/t4?죵>uDï›5➶༆쉌럮⢀秙䘥\u20972ETR3æ¿¡æ†vB? ~鸆\u0005": {
+ "`é––mç’㥉b뜴?Wf;?DV콜\u2020í‰à±“æ“å®ZMj3mJ먡-å‚·ë±™yח㸷꥿ ໘u=Mì!5å­L4v\\?ÇŽ7C홫": null,
+ "|": false,
+ "~Ztᛋ䚘\\æ“­ã—傪Wé™–+ã—¶qᵿ蘥ᙄp%䫎)}=â ”6ᮢS湟-èž¾-mXH?cp": 448751162044282216,
+ "\u209fad놹j檋䇌ᶾ梕ã‰bוּ<dä—±:줰Mé…„\u0000X#_rç¢A饓ê—ÙKo_è·”?ᪧ嵜鼲<": null,
+ "ꆘ)ubI@h@洭Ai㜎ä±k\u0003?Tä‰3é—´%j6jæ£j=â\\U毮ᬹ*8䀔v6cpjâ­¬~Q꿾뺶ï‰íŽµæ‚¡!ì©­åŽl六㽫6퇓ޭ2>": {"?è‹´ê© D䋓帘5騱qï±–PF?☸ç—é¡’yU á¡«cb䫎 S@㥚gꮒ쎘泴멖\\:Ié®±TZ듒ᶨQ3+f7캙\"?\fí’¾\\oæžç´Ÿï»½M.âŽï˜¸é‘OP": [
+ -2.6990368911551596E18,
+ [{"ä’–@<á°¿<\/⽬tTrè…ž&G%᳊秩蜰擻f㎳?Sãµ§\r*k뎾-乢겹隷j軛겷0ë£é®ï µ": {")DO0è…¦:ì¶é€¿:1㥨่!è›æ¨‹2": [{
+ ",ꌣf侴笾m๫ꆽ?1?U?\u0011ꌈꂇ": {
+ "xæ—ç” nVqä…¦w`CD⦂惺嘴0I#vỵ} \\ê·‚Së´Dì–¾?Ô’j溯\"v餄a": {
+ "@ç¿™c⢃趚痋i\u0015OQâlqë†Y0pࢥ3쉨䜩^<8g懥0w)]䊑næ´ºo5ì­QL댊랖L镈Qnt⪟㒅십q헎鳒⮤眉ᔹ梠@O縠u泌ㄘb榚癸Xî©­Þ”Ftj;iC": false,
+ "I&뱋゘|ï£è“”䔕측瓯%6á—»HW\\N1貇#?åƒá—œghá­ªo'䗈꽹Rcìš/蔳迄à¼!0邔䨷푪8ç–©)[쭶緄㇈୧á": {
+ "B+:ꉰ`sì¾­)ë¹¼Cç¾A䫊pMgjdxäHf9᥸W0!C樃'ï¤f䫤סи\u0017Jve? è¦f둀⬣퓉Whk\"஼=չï³î•¤çš†ç¬BIW虨쫓F廰饞": -642906201042308791,
+ "sb,XcZ<\/m㉹ ;䑷@c䵀s奤⬷7`ꘖ蕘戚?Feb#輜}p4nH⬮eKL트}": [
+ "RK鳗z=袤Pf|[,u욺",
+ "Ẏá»ç½¯ë‰‹âº–锅젯㷻{H䰞쬙-ì©“D]~\u0013Oã³¢gb@æ¶è”‰|kᦂâ—!\u001ebMè¤sca쨜襒y⺉룓",
+ null,
+ null,
+ true,
+ -1.650777344339075E-19,
+ false,
+ "☑lꄆs힨꤇]'uTന⌳ë†].1â‹”ê´æ²°\"IWà´©\u0019æ°œ8쟇䔻;3衲æ‹,窌zíŽå–íš—?4?Cë„é—®?ᥙ橭{稻Ⴗ_ì”",
+ "n?]讇빽å—}1å­…9#ê­¨é¶v\u0014å–ˆ)vw祔}룼쮿I",
+ -2.7033457331882025E18,
+ {
+ ";⚃^㱋x:饬ኡj'ê§µT☽O㔬RO婎?향ᒭæ©$渣y4i;(Q>꿘e8q": "j~錘}0g;Lèº*;á•­ê„®0l潛烢5H▄쳂ê’ï­‹ê™¶T犘≫x閦웧v",
+ "~î¢æ¯\u2018c4è·ë E~ᑅቚꈂ?nq뎤.:æ…¹`F햘+%鉎Oç€œìŸæ•›è®âŒæµ¢<\/㮺紿P鳆ࠉ8I-o?#jﮨîŸ7v3Dt赻J9": null,
+ "à£W䌈0êŽqC逖,íš…î·Žcáƒswj;jJSæ«5æ§—OaB>D踾Y": {"ã’°äµF%î©®?59.î„„ãˆcᕨï†í•틎á¸ã‹©B=9IÛⓌ{:9.ywï½å‘°ã†®è‚’᎒tIã¾´62\"ዃ抡C﹬B<\/<EO꽓ᇕu&é‹«\\禞í¹uê’.7훯ಶ2䩦͉ᶱf깵ᷣ늎": [
+ 5.5099570884646902E18,
+ "uQNæ¿¿m臇<%?谣鮢s]]x0躩慌闋<;(î³¥ 鋤.0á µd1#벘a:Gs?í–·'.)ㅴ䞟ç¯å´ˆFS@O㌛ᓬ抢íŒáž¾ëƒ·ì¿Ÿíˆ¥IZn[惵ê§3ë™[&v憙J>ì´‹jo朣",
+ [
+ -7675533242647793366,
+ {"ᙧ呃ï£:[㒺쳀쌡ì‚H稈㢤\u001dá¶—GG-{GHྻຊꡃ哸䵬;$?&d\\⥬ã“Nåœ´ë¤æŒ¨-'ê•®$î“‹PU%?冕눖ié­q騎Q": [
+ false,
+ [[
+ 7929823049157504248,
+ [[
+ true,
+ "Zè™\u0017'eꕤ᱕l,0\\X\u001c[=雿8è ¬L<\/낲긯W99g톉4ퟋbãº\u0007åŠ'!麕Q궈oW:@XáŽïœ¬z蘻m絙璩귓죉+3柚怫tSæ‡è’£ä -æ“¶D[0=퉿8)q0ÙŸ",
+ "唉\nFA椭穒巯\\䥴䅺鿤S#bè¿…ç˜ ï¶—ê¬˜\\?q1qN犠pX꜅^䤊⛤㢌[⬛휖岺q唻ⳡí‹\"ã™™Eh@oA賑㗠yå¿…Nꊑᗘ",
+ -2154220236962890773,
+ -3.2442003245397908E18,
+ "Wᄿ筠:瘫퀩?o貸q⊻(᎞KWf宛尨h^残3[U(='橄",
+ -7857990034281549164,
+ 1.44283696979059942E18,
+ null,
+ {"ꫯAwè·­å–€ ?_ï““9\"Aty背F=9缉ྦྷ@;?^鞀w:uN㘢Rá»": [
+ 7.393662029337442E15,
+ 3564680942654233068,
+ [
+ false,
+ -5253931502642112194,
+ "ç…‰\\îš¶î¶è¾Žî›¢à³†ç½5â’­1äªäƒ‘s䎢:[e5}峳ﴱn騎3?è…³Hyêƒè†¼N潭錖,Yá‹ËœYAá“㬠bG렣䰣:",
+ true,
+ null,
+ {
+ "⒛'P&%죮|:⫶춞": -3818336746965687085,
+ "钖m<\/0ݎMtF2Pk=瓰୮洽겎.": [[
+ -8757574841556350607,
+ -3045234949333270161,
+ null,
+ {
+ "áœî…½rè¼³>⫇9hU#î¦#w@ê·ªA\\Cî’¢ é‹ºã˜“ê–æ¢’뒬묹㹻+郸å¬ìœ¤'+g<\/碴,}ꙫ>ì†;情d齆Jä¬àº©æ’›ì±íƒ¹/R澡7剌tꤼ?ặ!`â²ç¤\u00002똥଴âŸ": null,
+ "\u20f2ܹe\\tAê¥Æ°\\x当뿖ï»ë ‰ç¦›;G檳ﯪï…Sà«°3~㘠#[J<}{奲 5箉⨔{ë†<\/釿抋,åš /曳m&WaOvT赋皺璑ï“í…": [[
+ false,
+ null,
+ true,
+ -5.7131445659795661E18,
+ "è­m䓪D5|3å©à°ž>î‰è ‡æ™¼6nï´ºPp禽羱î¤DS<ç“닫屚ì‚å§¿",
+ true,
+ [
+ -8759747687917306831,
+ {
+ ">ⓛ\t,odKr{䘠?b퓸C嶈=DyEᙬï¿@ᴔ쨺芛髿UT퓻春<\/yê¸>豚W釺N뜨^?꽴﨟5殺ᗃç¿%>í‚ဿ䄸沂Ea;A_\u0005閹殀W+窊?Ꭼd\u0013Pæ±´G5ì“æ˜": 4.342729067882445E-18,
+ "Q^즾眆@AN\u0011Kb榰냎Y#ä€ê€’ᳺ'q暇çµs\"!3#I⊆畼寤@HxJ9": false,
+ "⿾D[)袨㇩i]웪䀤ᛰMvR<èŸã£¨": {"v퇓L㪱ꖣ豛톤î£\\ê³±#ï–©kDTN": [{
+ "(ì¾´ä¡£,寴ph(C\"ã³¶w\"憳2s馆E!n!&柄<\/0Pꈗſ?㿳Qdéµ”": {"娇堰孹L錮h嵅⛤èºé¡’?CglNæŸ+쨣ﺜ\\MrH": {"çžäŽ‡ë‘ƒá‰²å¼­íŒ­^ꄞ踦涟XK錆쳞ឌ`;੶S炥騞ଋ褂B៎{Ú’ä­·á¶¼éœpIè—è™¶K$": [{"â—–S~躘蒉꫿輜è­Qã½™é—@ᢗ¥Eæ¦iØ¡5┄^B[絮跉ᰥé™PWi3wㄾⵀDJ9!w㞣ᄎ{ë“’ê““b6\\篴??c⼰鶹⟧\\鮇ꮇ": [[
+ 654120831325413520,
+ -1.9562073916357608E-19,
+ {
+ "DC(æ˜è¡µá¼¡ê¸™ê°µå§­|Ö›[t": 7.6979110359897907E18,
+ "Jâ…))嫼â³9Xfd飉j7猬ᩉ+⤻î®çœ—벎Eé°‰Zï¾¶63zá69}Zá¶L崭ᦥ⡦éšâ‹›êŽ¨î´µ~i㨃咊ꧭo䰠阀3C(": -3.5844809362512589E17,
+ "p꣑팱쒬ꎑ뛡Ꙩ挴æèƒ”&7ᔈ묒4Hdç¡¶í›ãŽ–zꢼè±ã¿¢aሃ=<\/湉鵲Eî„¡Ó…%$F!í¶æ£Œå­¼{Oé§à¨ºgeu+": ")\u001bìž“kÅ€Xì©«Aë°Â®Ú£ç™¦ç‹¢)扔弒p}k縕ꩋ,䃉tࣼi",
+ "ã‚¡F肿輸<솄G-䢹䛸êŠl`Tqê•—îŠè’ža氷⸅ᴉ蠰]S/{J왲m5{9.uá½³~㕚㣹u>x8Uè®Bëºè¥ªç›ŽQhVS맅킃i识{벂磄Ià·„ä™…xZy/æŠà«­Zï–Šé²î¦š-霳Væ®æŒ¦â„’": null,
+ "㯛|Nî½™ê¸b7âµb?æ‹ O\u0014Þ†?-(EꞨ4ꕷᄤYᯕï‘OW瞺~螸\"욿ќ<u鵵઎⸊î˜å€¾ì‘·à·»rT⪄牤銱;W殆͢芄ਰåší›šìƒ¢î™‡âŠ¿+ã²½": null,
+ "å˜ïƒé€†àº»%_ë§›d)zJ%3ì¹§_릟#95䌨怡\u001ci턠ॣî’i冘4èµ–'à¨ä§_æ ”!": {
+ "*?2~4㲌᭳ì¯ftá‚·1#oJ\bäŠ‡é•‡ë” \u2079xä›ãŠá®‚N;穽跖s휇ᣄ홄傷z⸷(霸!3yëºMì’¿í–Û½v㳉tở心3黎vì­» Rp཮Vr~T?&Ë´k糒븥쩩r*D": null,
+ "8@~홟ꔘk1[": -5570970366240640754,
+ "BZté¦ê¡¬c餖 s(má›´\u0000◄dè…‘t84CâŸå¯VṊ뉙'å™±ê”ç½GCé¡€?허0êž¹&ë‡ä›­Cä·«](": 2.4303828213012387E-20,
+ "yæ’”Z외放+}ḑ骈á™&\u0016`G便2|-e]঳?QF㜹YF\"ã¿’ç·„í–·ï€ãˆŸïƒ¦ï¨ä·¦à­€áŒ¤lM蘸N㾆▛럪㞂tᕬ镈ì‡å– l amcxPnm\u001a᱋<\/]_]ﻹïª?H": false,
+ "áæ°ë¬¢뜚I[♺뽛x?0Hë´¬Wpn꨹Raä¿ïŒ›ìŒ‘{㴂ni祻윸A'y|⺴ᚘ庌9{$æ²{톽=m#@ï–—6ᨧfgs44陎J#<Ễ쨓瀵â©a୛㷉㙉ܸ◠냔嬯~å‘„ç±ç¾¥é•³": false,
+ "㘱{<é ¬22?IF@곊I겂嶻Lá›D{@rì’‚?IAᣧ洪惒誸b徂zì·ºê¾ã ­\\刊%禨ìŒâ¶£ä»µ\\P[:47;<ᇅ<\/": {
+ "^U釳-v㢈ê—â—„è˜rᜨi;èµ·kR犺䵫\u0000é”ì™m-Ô™!lḃ꛸뻾F(Wê·›y": "#á ºH㸢5v8_æ´‘C",
+ "䔵໳$á™ 6èž\u206e摎q圩P|æ…sV4:㜾(I溞I?": -6569206717947549676,
+ "é€êž‚ç·µí‡8 >e㺰\"'㌢ÆW\u0004çž•>0?V鷵엳": true,
+ "뤥G\\î¡‹è¿‹ä ¿[庩'꼡\u001aiá©®Vì¯á³ªä¦ªÃ”î²…;倱ନë›èªˆ": null,
+ "쥹䄆䚟Qæ¦äŽá¢­<\/2ã•£p}HW蟔|äƒî‚꿈ꚉ锳2Pb7㙑Tⅹᵅ": {
+ "Y?Ö­$>#cVBꩨ:>ï†eLè’å‹™": {
+ "86柡0po äš&-æ‘Ћ祌<\/휃-G*㶢הּì©s㶟餇c걺yu꽎還5*í„§ç°•Ogå©¥Sê": null,
+ "a+葞h٥ࠆ裈嗫ﵢ5輙퀟ᛜ,QDﹼ⟶Y騠锪E_|x죗j侵;m蜫轘趥?븅w5+mi콛L": {
+ ";⯭ﱢ!ä¹°Fâ½æŸ¤é¶‚näµ£V㫚墱2ë ¾ELEl⣆": [
+ true,
+ -3.6479311868339015E-18,
+ -7270785619461995400,
+ 3.334081886177621E18,
+ 2.581457786298155E18,
+ -6.605252412954115E-20,
+ -3.9232347037744167E-20,
+ {
+ "B6㊕.k1": null,
+ "ZAꄮJ鮷ᳱo갘硥鈠䠒츼": {
+ "á•…}럡}.@y陪é¶r業'æ´î‰°í€‰x䉴ﵴlí˜):씭脴ᥞhiꃰblﲂ䡲엕8߇Mã¶­0燋標æŒ-?PCwe⾕J碻Ᾱ䬈䈥뷰憵賣뵓痬+": {"aì·©v礗X⋈耓áŠfç½…é®!㔽YYᣓwæ¾33⎔芲F|\"äœT↮輦挑6ᓘL侘?ᅥ]ë†1R௯✎餘6ê½<\/௨\\?qå–·ê«j~@ulq": {"嗫欆뾔Xꆹ4H㌋Fåµ§]à Ž]ã –1ꞤT<$më«O i댳0ä²iï—Œ": {"?à·©?\u20cd슮|ꯆjs{?îž…d7?eNs⢚嫥氂䡮쎱:鑵롟2hJꎒﯭ鱢3춲亄:ë¼£v䊭諱Yj択cVmR䩃㘬T\"Ní™*ै%x^F\\_s9ë³´zz4æ·—?q": [
+ null,
+ "?",
+ 2941869570821073737,
+ "{5{殇0ä¾ïž¢g6ë°–í‹è‡©ç¶¹R$ä–­j紋釰7î‹‘sXI繳漪행y",
+ false,
+ "aH磂?뛡#惇då©…?Fe,ì˜+늵ä˜\"3r瘆唊å‹ï¢Šj⳧࠴ꇓ<\/唕윈x⬌讣䋵%拗ᛆⰿ妴á”M2ã³—å¿…ê§‚æ·²?ゥ젯檢<8ë’ï¶MidXä’3á³»Qî”â–®ä½UT|⤪봦éâŠ",
+ [[{
+ "颉(&뜸귙{yîš’^\"P퟉ì¶á²Ÿä®­î‹ºDé¡¡9=?}Y誱<$bë±£RvO8cH煉@tk~4ǂ⤧â©å±‹Sî›ïž¢S;J{vV#剤餓ᯅc?#a6D,s": [
+ -7.8781018564821536E16,
+ true,
+ [
+ -2.28770899315832371E18,
+ false,
+ -1.0863912140143876E-20,
+ -6282721572097446995,
+ 6767121921199223078,
+ -2545487755405567831,
+ false,
+ null,
+ -9065970397975641765,
+ [
+ -5.928721243413937E-20,
+ {"6ì´Š\u001a홯kB0w撨燠룉{绎6⳹!í„è´‘y▾鱧ժ[;7ᨷ∀*땒䪮1x霆Hᩭ☔\"rî¹›ä7毟á°r惃3ꉭE+>僒æ¾": [
+ "Ta쎩aÆt쵯ⰪVb",
+ [
+ -5222472249213580702,
+ null,
+ -2851641861541559595,
+ null,
+ 4808804630502809099,
+ 5657671602244269874,
+ "5犲﨣4mᥣ?yf젫꾯|䋬ìž$`Iⳉﴷ扳å…,'î±c",
+ false,
+ [
+ null,
+ {
+ "DyUIN쎾M仼惀⮥裎岶泭lh扠\u001e礼.tEC癯튻@_Qd4cï…«5S熯A<\/ï¼¼6U윲蹴Q=%푫汹\\\u20614b[௒Câ’¥Xe⊇囙b,ï®æœ3ss땊ë¢i~逇PA쇸1": -2.63273619193485312E17,
+ "Mq꺋貘k휕=nKç¡ë«žè¼©>㾆~á¼žà¡¹ê¸æ¦µlâ‹™Hw뮢帋M엳뢯î¹…vâ…ƒ^": 1877913476688465125,
+ "á¶´ë»—`~ç­—å…⚽টW˃â½b犳䓺Iz篤p;乨A\u20efì©?ç–Šmã€ì»©ë«¡b탔鄃ᾈV(é¢ç³=뎲ିeF仢䆡谨8t0醄7㭧瘵⻰컆r厡궥d)a阄á·Ed&c﯄伮1p": null,
+ "â¯w4曢\"(欷輡": "\"Má­«]䣒頳B\\燧ࠃN㡇j姈g⊸⺌忉ꡥF矉স%^",
+ "㣡Oᄦ昵⫮Y祎Sì級㭻撥>{I$": -378474210562741663,
+ "䛒掷留Q%ì“—1*1J*ë“헩ᦢ﫫哉쩧EↅIcê…¡\\?â´Šl귛顮4": false,
+ "寔愆샠5]ä—„IHï©¥=d﯊/å¶?ॊn%晥D視Nò—˜ˆ'᫂⚦|X쵩넽z질tsî¦kxDQ莮Aoﱻ뛓": true,
+ "钣xp?&\u001e侉/y䴼~?U篔蘚缣/I畚�Q绊": -3034854258736382234,
+ "꺲໣眀)â¿·J暘î©pИfAVì‚•ì³­Nꯗ4々'唄ⶑ伻㷯騑倭D*Okï¯ê§3bâ½_ï„¡<\/ì±£Xm톰á•䆄`*fl㭀暮滠毡?": [
+ "Dç”·p`V뙸擨å¿ë¸ª9c麺`淂⢦Yw⡢+kzÜ–\fY1䬡Hæ­)ë²¾Z♤溊-혰셢?1ï”<-\u0005;æ¢Tále\\ᛵߓﭩ榩<QF;t=?Qꀞ",
+ [
+ null,
+ [{"-ì·«æ²î«§á¬¨å¢Šè‡¸<à ’Hè·¥ 㔭쥃㫯W=z[wধ╌<~yW楄S!â‘»h즓lÄ–N￧篌W듷튗乵᪪템먵Pf悥ᘀk䷭焼\\讄ræ“é¬y6VF<\/6ëž¿p)麡ê ãª\"pà®´e": [
+ "#幎æ´é¢’嶈)ã„›J.嶤26_⋌东챯ꠉ⤋ؚ/âš%ç§¼Q룠QGztᄎ㎷អIç¿°Xpç”éœê¨",
+ {",T?": [
+ false,
+ [[
+ true,
+ 7974824014498027996,
+ false,
+ [
+ 4.3305464880956252E18,
+ {
+ "᱿W^A]'rᮢ)é¥zï­é¤;Hu\\Fk?ï´º?IGæµ…-ä™§>è¨-xJ;å·¡8깊è ï»“U$K": {
+ "Vê•¡è«…æ“W=斸s︪vﲜ츧$)iꡟ싉eî®å¯³?ጭムVથ嵬iæ¥Fg<\/Z|៪ꩆ-5'@ꃱ80!燱R쇤tç³³]罛逇dṌ֣XHiͦ{": true,
+ "Ya矲Cë©—Q9膲墅æºíœ»c\\ë”¶Gç””<\/.齵휴": -1.1456247877031811E-19,
+ "z#.OOï¿J": -8263224695871959017,
+ "å´_3夼ᮟ1Fë¸ë½¯á¦“é´­V豈Ь": [{
+ "Nè’¬74": null,
+ "yuB?厅vK笗!ᔸcXQ旦컶P-ë…«mᄉ麟_": "1R@ 톘xa_|﩯é˜î¥§sæ§žd!d껀筤⬫è–焵먑D{\\ïƒïŽ¿6k共倌☀G~AS_D\"딟쬚뮥馲렓쓠攥WTMÜ­8nX㩴䕅檹E\u0007ï­¨N 2 ℆æ¶ê¥ê µï“3▙玽|ë¨_\u2048",
+ "æA Cä§©G": {":Mí£5e들\\ê€æ¼á”„é¸|Iï¨$)n": {
+ "|U䬫㟯SKV6ꛤ㗮\bn봻䲄fXT:㾯쳤'笓0b/à³¢Cì³–?2浓uO.ä°´": "à½ê¼‹e?``,ᚇæ…^8ꜙNM䂱\u0001Iá–™ê§M'vKdꌊH牮r\\O@䊷ᓵ쀆(fî »yè»i툺\"?<\/峧ࣞ⓺ᤤ쵒߯ꎺ騬?)刦\u2072læ…ªy꺜ﲖTjî’•+u",
+ "뽫<G;稳UL⸙q2n쵿C396炿Jè“¡zâ£zဩSOU?<\/ë™oEí¸Oé¿…à·´êˆEm#\"[瑦⤫á†glâ¡—q8\"í˜ë¥ä¿‚@ᆤ=\u0001爖ç¾ì·€ã¸©b9\\jeqt㟿㮸龾m㳳긄": {
+ "9\"î²–V霟釜{/o0嫲Cå’€-饷äˆ[ë…©î)\r䤴tMW\\龟ϣ^ي㪙忩䞞N湆Y笕)è¨ê–¤èª¥ç…½:14â«»57U$æ“’ä²è–¡Qvↇ櫲현誧?nà®·6": {"l웾䌵.ä…‹ä¦ic碳g[糲Ƿ-ឈᚱ4ì‘§\u0004C࿼\u0018&쬑?멲<\/fD_檼픃pd쪼n㕊渪V䛉mæˆW儅톳뗳䓆7㭽諤Tç… ï–ŠNey?î¼…0᪵鈑&": [
+ false,
+ null,
+ {
+ "\rî´’;é¼¶já ‚ê¼RLz~â™”9gf?Ó¡æµ": -1.4843072575250897E-19,
+ "&ꊒ\"ꋟä­E诮ﯚO?SWë’훪mb旙⎕ᗕ⶙|á·¤5y4甥": "j5|庠t铱?v íš‹0\"'rxz䃢æºêž«!\u0002",
+ "Q á©ãŸ§": {"Hﬔ\u2058䪠틙izZㅛ탟H^ﶲA??R6å‘ Z솋R.à¿¶g8": [
+ -8762672252886298799,
+ -1.9486830507000208E17,
+ null,
+ -7157359405410123024,
+ null,
+ null,
+ -995856734219489233,
+ "呧㫹A4!",
+ null,
+ -1.9105609358624648E-19,
+ 5888184370445333848,
+ 2.25460605078245E-19,
+ 2.5302739297121987E18,
+ "뢹sbEfæµ2丯ï‡?뗾耸(Wdë™SବꭖrtU?ç­¤P똙Qpbbï‘¡KqaE$æ¥Vì›°3i/lK퉜,8︸e= gèž“t竦컼?.寋8éµ—",
+ 7377742975895263424,
+ 2.4218442017790503E-19,
+ {
+ "y꒚ཫ쨘醬킃糟}î‘yTSt䡀⇂뿽4ൢ戰U": [[
+ 3600537227234741875,
+ 4435474101760273035,
+ -1.42274517007951795E18,
+ -5567915915496026866,
+ null,
+ null,
+ [
+ -3204084299154861161,
+ {
+ "7梧慸æ†.a瘎\u00041Uéµ®CkÖ¨d惥è€â³¡Y,â­ì¨EåžFFI鱑ⳬ줢7â§µBﴠ耘줕햸qì»´~*ç‘W.떛ࡆ@'á€+è½³": -961121410259132975,
+ "⥅]l黭㣓绶;!!⎃=朼ã¿e&ἂ繤C﯀lä£ãŒ€6TMì‘®w懃ꡡ#ᤆ䰓,墼湼゙뽸㲿䧽쫨xᵖ듨<\/ T0峸iQ:溫è„\\\"쎪ὴ砇宖^Mæ³¼í¥âž…鈫@ᄟ༩\u2008⥼": true,
+ "â©\"籽汎P싯鲘蟼sRá¯ä…©\u0019R(kRá–&ಌ 0\"é³¶!馼YH": null,
+ "鮼ꚇ싋։刟\rRLd步Nⴗ5Eࡆ訛갚[I醵NC(郴ṉy5D뤺౳QY壯5苴y훨(W\\Cଇ姚C艄깹\u001c歷㋵ZC᥂": [
+ -6806235313106257498,
+ null,
+ "}N⸿讽sꚪ;ï‘¶\\p繇jè‹„î¡ä«¨\u20e7%5x?î•¥t#",
+ {
+ "O〗k<墻yV$à°rs-c1ఌ唪.C7_Yobᦜ褷'b帰mã„‘l⌅": {"qB뗗擄3éš‚5ëºæ«‚䱟eì´¸P/é©,3æŽê—©=冉棓㑉|ËžF襴뿴,:㞦<퓂⧙礞♗g뚎ᛩ<\/뉽ⶳ⸻A?_x2Iã½å‹’*Ií™±î¢é§ç²¿~曟㤙2绥Ly6+ìƒuu鿜בfí˜|æ­à£–É": [
+ ">hh䈵î”w>1â²ì­V[â…Ž\\헑벑F_ã–⠗㫇hæ½;á¿æ±°á±¼ç€–J옆9RRì…vsZ柺鶶툤r뢱橾/ꉇ囦FGm\"謗ꉦ⨶쒿⥡%]鵩#ᖣ_蹎 u5|祥?O",
+ null,
+ 2.0150326776036215E-19,
+ null,
+ true,
+ false,
+ true,
+ {"\faá­¶Pæ¤WWcá Ÿf뚉á¬í“—â³€Wç¹5:HXH=q7xì°™X$)모r뚥ᆟ!Jﳸf": [
+ -2995806398034583407,
+ [
+ 6441377066589744683,
+ "Mﶒ醹i)Gἦ廃s6몞 KJ౹礎VZ螺费힀\u0000冺업{è°¥'꡾뱻:.ꘘ굄奉攼Diá·‘Ké¶²y繈욊阓v㻘}枭캗e矮1c?íœ\"4\u0005厑莔뀾墓ë‚⽴洗ṹ䇃糞@b1\u0016즽Yè½¹",
+ {
+ "1⽕⌰鉟í”M㤭n⧴ỼD#%é˜âŠ¯ì¿¼ç¨ë¸£ëªç´§á…‡ã“•ᛖcw嬀~ഌ㖓(0r⧦Qä‘•é«à´°é“‚㓻Rå„®\"@ꇱmâˆà¯¿á¦¯é Œ8}㿹犴?xn잆꥽R": 2.07321075750427366E18,
+ "˳b18㗈䃟柵Z曆VTAu7+㛂cb0﯑Wp執<\/臋뭡뚋刼틮è‹ë²²î·´TLP预庰܈G\\O@VD'鱃#ä¹–ëº*鑪ꬳ?MÞždï­¹{â‡åœ¯ì‡œã¼ž顄︖Y홡g": [{
+ "0a,FZ": true,
+ "2z̬è£î’®ê§¦é©¸\u0006L↛Ḣ4๚뿀'?lcwá„§ã®!蓚䃦-|7.飑挴.樵*+1ﮊ\u0010ꛌ%貨啺/JdM:ë˜ïˆ!FBe?鰴㨗0Oè´¢I藻ʔWAá«“Gì³›u`<\/I": [{
+ "$Ï„5Vé´a뾆両環iZp頻යn븃v": -4869131188151215571,
+ "*즢[⦃b礞R◚nΰꕢH=귰燙[yc誘g䆌?ଜ臛": {
+ "洤湌鲒)⟻\\䥳va}PeAMnï¼®[": "ã³Éª/(軆lZR,Cpæ®È®Nå•·\"3Bå©´?i=r$펽á¤ì€¸",
+ "阄R4㒿㯔ڀ69ZᲦ2ç™í•Œå™—På´œîž#\\-ì­è¢›îˆµ&é‘/$4ç«¥Vê©‘_ZHAæ¾¢fZ3": {"x;P{긳:Gé–‰:9?æ´»H": [
+ "繺漮6?z犞焃슳\">á»[Ⳛ䌜ë…䂹>èµâ¼¶ç…œï’˜Yæ¡¥[泥뚩MvK$4ï‰jtï¾›",
+ "E#갶霠좭㦻ୗ먵F+䪀oè’ba쮎4X㣵 h",
+ -335836610224228782,
+ null,
+ null,
+ [
+ "r1᫩0>danjY짿bs{",
+ [
+ -9.594464059325631E-23,
+ 1.0456894622831624E-20,
+ null,
+ 5.803973284253454E-20,
+ -8141787905188892123,
+ true,
+ -4735305442504973382,
+ 9.513150514479281E-20,
+ "7넳$螔忷㶪}䪪lì§´\u0007é¹Pé°šHFéŠZJﳴ/âŽ1ᷓ忉ç‡áœ‹ì“ˆxëµ mä·çª¥á”^\u0019á¶Œå­#ヂt☆áƒpáŽè‡¶äŸ±5ï‰$ä°µ&๵分ìˆ]äˆë‰â™‚åŽ\u0011<>",
+ "C蒑貑è—lï°°}X喇몛;të°¿O7/᯹f\u0015îµ¼kI嘦<ዴ㟮ᗎZ`GWퟩ瑹࡮ᅴB꿊칈??Ræ ¡s脚",
+ {
+ "9çµæˆ¬+AU^洘拻ቒy柭床'ç²™XG鞕᠜繀伪%]hï ¾C,$è¼™?Utä¹–Qmë–šWï¶8઼}~qâ ªrU䤶CQ痗ig@#≲t샌f㈥酧l;yé—¥ZHæ–¦e⸬]j⸗?ঢ拻퀆滌": null,
+ "畯}ã§¢J罚å¸VX㨑>1ꢶkT⿄蘥ã‘o|<嗸層沈挄GEOM@-äžšä§°$만峬è¼ä ±V✩5宸-æ‚î¡§D'ã—ªyP掶7bâ ŸJã•»SfP?d}v㼂á…'猘": {
+ "陓y잀v>╪": null,
+ "鬿L+7:ë‘Y=ç„ U;킻䯌잫!韎ஔ\f": {
+ "駫WmGጶ": {
+ "\\~m6ç‹©K": -2586304199791962143,
+ "ႜࠀ%Í‘lâ¿…D.ç‘¢Dk%0ç´ªdḨTI픸%뗜☓s榗኉\"?V籄7w髄♲쟗翛歂E䤓皹t ?)ᄟ鬲éœ6Cî³´": {
+ "_ì·¤a圷1\u000eB-XOy缿請∎$`쳌eZ~æï€§íŠ»/蜞`塣৙\"⪰\"æ²’l}蕌\\ë¡ƒè«æ°Œ.望wZ|o!)Hnçqg}": null,
+ "kOSܧ䖨钨:಼é‰ê­O醧Sî…¨`ì‹­`ꓭì­ï¯¢N&Et㺪馻ã¢â…³ã¢ºå´¡àºŠèœšé”«\\%ahx켨|ż劻ꎄ㢄ìŸA躊᰹p譞綨Ir쿯\u0016ﵚOd럂*僨郀N*bã•·63z": {
+ ":L5r+T㡲": [{
+ "VK泓ë²á®™Ry㓤➙Ⱗ38oi}LJቨ7Ó㹡৘*q)1豢⛃e᫛뙪壥镇æž7Gè—¯g㨛oI䄽 孂L缊ꋕ'EN`": -2148138481412096818,
+ "`â›á˜‘$(खꊲ⤖á„ꤒ䦦3=)]Y㢌跨NĴ驳줟秠++då­³>8ᎊ떩Eê¡£Sv룃 쯫أ?#Eî·°|á­™ãŽ?zv:5ï©^â‹‘V": [
+ -1.4691944435285607E-19,
+ 3.4128661569395795E17,
+ "ãƒì´—^G9ä½­é¾¶n募8R厞eEw⺡_ㆱ%⼨D뉄퉠2ê©µá›…â³æ¿L팹Là·€n=\"æ…‰ë…á›®y>!`g!í’²î¦ï¨’[/;?[vï®ê²è»‡}⤳â¤í•∌Tã½²R홓é‰ã“¥",
+ "æ„°_⮹T䓒妒閤둥?0î°šaB@㈧gç„»-#~è·¬x<\/èˆPÝ„ê¡=\\׳P\u0015jᳪá¢qï‹¶;ã¯l%á­—;砢觨â–,è¬ê°Gy?躤O黩í‹Yã’a擯\n7覌똟_䔡]fJ晋IAS",
+ 4367930106786121250,
+ -4.9421193149720582E17,
+ null,
+ {
+ ";ᄌ똾柉곟ⰺKpá‡ä±»à¸ºä–{o~h!ï½…ê¿àª»ìš„Úš\u0002y?xUd\u207c悜ꌭ": [
+ 1.6010824122815255E-19,
+ [
+ "宨︩9앉檥pr쇷?WxLb",
+ "æ°‡9】J玚\u000f옛呲~ è¼ 1D嬛,î•*mW3?n휂糊γ虻*á´«ê¾ ?qîžå‡è¶—Ko↦GTé“®",
+ "ã¶¢ážmOã”k'诔栀Z蛟}GZé’¹D",
+ false,
+ -6.366995517736813E-20,
+ -4894479530745302899,
+ null,
+ "V%᫡IIç’…ï»ä…›ä“Ží’¹ï±¢/pU9seë˜ë›žx梔~C)䨧䩻蜺(g㘚R?/á»°[å¿“C뾠ࢤc왈邠买?嫥挤풜隊枕",
+ ",vç¢å–”㌲쟚蔚톬៓ꭶ",
+ 3.9625444752577524E-19,
+ null,
+ [
+ "kO8란뿒䱕馔b臻âŸéš¨\"㜮鲣Yq5mí”<u뷆cè­†\u001bN?<",
+ [{
+ ";涉c蒀ᴧN䘱䤳 ÿꭷ,핉dSTDB>K#ꢘug㼈á¦=P^6탲@ä§”%$CqSw铜랊0&m⟭<\/a逎ym\u0013îš¡vᯗ": true,
+ "æ´«`|XN뤮\u0018詞=ç´©é´˜_sX)㯅鿻á»ì‹¹": 7.168252736947373E-20,
+ "ꛊ饤ï´è¢(逊+~⽫얢鈮ï«è‰¬O힉7Dç­—S곯wæ“I斞᠈븘蓷x": [[[[
+ -7.3136069426336952E18,
+ -2.13572396712722688E18,
+ {
+ "ç¡¢3㇩R:o칢行E<=\u0018á¬YuH!\u00044U%å炼2>\u001eSi$â“·ê’ˆ'ï‘¿ë ¢gᙫ番ꯒ㛹럥嶀澈v;è‘·é„•x蓎\\惩+稘Uî“´Eᖸﳊ㊈壋Nå«¿â¾æŒŽ,袯苷ኢ\\x|3c": 7540762493381776411,
+ "?!*^á¢çª¯?\u0001ڔꙃw虜ë³îšFgJ?&⨫*uo籤:?}ꃹ=ٴ惨瓜Z媊@ત戹ã”똩Ԛ耦Wtè½\\æž’^\\ꩵ}}}ꀣD\\]6M_⌫)Hè±£:36섘㑜": {
+ ";í™—á°°U஋㙛`D왔ཿЃS회çˆ\u001b-㢈`ë´†?盂㛣듿ᦾ蒽_AD~EEຆ㊋(eNwk=RÉ å³­qï’«\"5Ἠ婾^>'ls\n8QAK<l_⭨穟": [
+ true,
+ true,
+ {"ﳷm箅6qⷈ?ﲈ憟b۷⫉἞V뚴少U呡瓴ꉆs~嘵得㌶4XR漊": [
+ "í†ä»‹fM暪$9K[ㄇìƒí³æ’¦gæ’Ÿæ¸jÒFã¹¹aj bHᘀ踉êŽï¼£ç²„ a?\u000fKì¦‰î¶¯éƒ å¹¨9D舢槷Xh뵎u훩Ꜿ턾ƅ埂P埆kë©€{䢹~?D<\/ê¼¢XR\u001b〱ä½ê¼¨i㘀ḟ㚺A-挸",
+ false,
+ null,
+ -1.1710758021294953E-20,
+ 3996737830256461142,
+ true,
+ null,
+ -8271596984134071193,
+ "_1Gí‰í…‘m䮔鰼6멲Nmꇩſt쓟íŠN许FDï¡€j+3^ﶜ⎸\u0019⤕橥!\"sî•—-뾞lz北׸êšëž¬)?l⻮고iä‘°\u001f䪬",
+ 4.459124464204517E-19,
+ -4.0967172848578447E18,
+ 5643211135841796287,
+ -9.482336221192844E-19,
+ "౪å†é‡¶9D?sèž­X榈枸j2ç§€vï ˜î ]泌鰚岒èµè½€ìŒ¶ïŠ›ií…½qMbL]R,",
+ null,
+ [
+ null,
+ {"M쪊ꯪ@;\u0011罙ꕅ<eáº|爑Yâµ<\/&ᩎ<腊ሑᮔ੃Fè±­": [
+ "^0࡟1ë³Pí‹áæˆF⨥Iê‚´\"z磣Vâ…¡=8í€2]䢹h1\u0017{jT<Iç…›5%Dì…Sâ‘™â…J*ìƒ å·™àº”ï€¢;᧡䙞",
+ [{
+ "'ã¶¡í¾é„§`è·Š\"gV[?u᭒Ʊ髷%葉굵aë¦Nì¼§Qﯳy%y䩟髒L䯜Säµ³r絅肾킂á'ꔦg긓a'@혔যWè°á¬F栩ŷ+7wéžš": 6.3544416675584832E17,
+ "苎脷v改hmìµ|㋊g_ᔠ뒨蹨峟ìŽã·¸|Ο刢?Gͨ옛-?î¨Gꦱî«î“©IEYUX4?%ꘋᆊ㱺": -2.8418378709165287E-19,
+ "誰?(H]N맘]kæ´³\"qï±è’§è˜ž!Rí«\\(Q$T5Nå â«£ìœ¿6|럦ì†ï¸…ï­—(": [
+ "峩_\u0003A瘘?✓[硫䎯á½uጭ\"@Y綅첞m榾=è´®9R벿῜Zï §",
+ null,
+ "䰉㗹㷾Iaáƒqcp쓘὾൫Q|ﵓ<\/ḙ>)- Q䲌mo펹L_îŽ¦ì¹æ¨–庫9ê©ìª¹á˜¹ä‘–ç€aK îž?*趤fë­“å»p=磕",
+ "î“å“‘z懅á¤-ê¹ux쀭",
+ [
+ true,
+ 3998739591332339511,
+ "ጻ㙙?᳸aK<\/囩U`B3袗ﱱ?\"/ké”ä§2ï…¤l@쿎VZ쨎/6ꃭ脥|B?31+on颼-ê®§,O嫚m à¡­`KH葦:粘i]aSUì“™$ì‚f+詛頖b",
+ [{"^<9<ç®&絡;%iï«¡2攑紴\\켉hì“™-柂äšven\u20f7浯-Ꮏ\r^í›ä“ší—¬\u000e?\\ã…¡ÖºJë–·VOt": [{
+ "-௄å¶k㘆í˜à®½y⎱㢬sS઄+^瞥h;á¾·jî­;抭\u0003ë°«f<\/5â°§ï§§ï¡™_朻ï—%*[-撵䷮彈-芈": {
+ "㩩p3篊G|宮hz䑊o곥j^Co0": [
+ 653239109285256503,
+ {"ê¶²?|\":N1Û¿æ°ƒNZ#깩:쇡o8킗ࡊ[\"ë¸Po핇1(6é°$膓}â½*)渽J'DN<ì™ê¸˜æ¯¦ë²Ysì¹–": {
+ "2Pr?Xjㆠ?æ®/?㓦柖馃5뚣Nᦼ|é“¢rè¡´ã©–\"ç”æ¹—Üæ†": "\"뾯ië‡ç­ç‰»$ç²/4ka $åŒíœ´ï‹è¯‘zbAá©ê‡¸ç‘…&뵲衯ꎀᆿ7@ꈋ'ᶨH@á ´l+",
+ "7뢽ëšv?4^ꊥ_⪛.>pởr渲<\/⢕疻c\"g䇘vU剺dஔ鮥꒚(dïŸv祴Xâ¼¹\\îºa8y5å†": true,
+ "o뼄Bìšžç¾hrï·”í˜ë’šâ¿›U5pꪴfg!6\\\"爑ì䢱W<ï¶•î\\í…£ç‡oI/BK뺡'谑♟[Ut븷亮g(\"t⡎有?ꬊ躺ç¿è‰©nl F⤿蠜": 1695826030502619742,
+ "ÛŠê¹–>ࡹ햹^ⵕ쌾BnN〳2C䌕tʬ]ì° ?ݾ2饺蹳ã¶êŒ­è¨\"â—¹á¬D鯎4e滨T輀ﵣ੃3\u20f3í‚™D瘮g\\擦+泙᧠鬹ﯨַ肋7놷郟lPå†{ß’hà§œr5,ê“‹": null,
+ "ΉN$y{}2\\N﹯ⱙK'8ɜͣwt,.钟廣䎘ꆚk媄_": null,
+ "䎥eᾆá¦î‘§ì‰,JÞªn岪ã¥sî­•æ–謽䚔5tã¯ï–µï£šã°³ã±ŠZhD䃭f絕s鋡篟îža`Q鬃┦鸳n_é‚(E4è¿ _è§…ë·_宪D(NLî²ç–¶hL追V熑%]vè‚«=惂!㇫5⬒\u001fï²å–º4랪옑": {
+ "2aè¼85먙R㮧㚪Sm}E2yîŠê†£ê«¨rRymã±è†¶á”¨\\tç¶¾A☰.ç„„ë™—9<쫷챻䒵셴᭛䮜.<\/慌꽒9å»Okä°ŠZ㥪幸k": [
+ null,
+ true,
+ {"쌞ì": {
+ "â–ŸGL K2ië›±iï¼±\"Ì .옛1X$}涺]éŽæ‡ Ú¦ëŠ·?tfçŸÝžã‚Ÿ{": 1.227740268699265E-19,
+ "ê’¶]퓚%ฬKâ…": [{
+ "(à·›@Ç®ã£ä§¼äµ¤[aテൖvEnAdUë –ë—ˆ@볓yꈪ,mÔ´|꟢ìº(而첸죕CX4Y믅": "2⯩㳿ꢚ훀~迯?᪑\\啚;4X\u20c2è¥B箹)ä¿£eá»»w䇄",
+ "75༂f詳䅫ê§é¿ }3\u20b5'∓ä±è™€fè¼î‘”Iq鈆﨤gí©)BFa왢d0뮪痮Mé‹¡nw∵謊;ê§f美箈ḋ*\u001cî±ïœŸ`퇚í‹ä³«$!V#N㹲抗ⱉçŽ(V嵟ï«_bã³…\u0019": null,
+ "e_m@(i㜀3ꦗ䕯䭰Oc+-ë ¨0뭦⢹苿蟰ê‚SVä°­å‹¢ë¥.ྈ爑Vd,á•¥=í€)vz뱊ꈊB_6듯\"?{ã’²&㵞뵫ç–ë¡ë¯ˆ%Qwé™,?\ræž®\"? N~癃ruà¡—dn&": null,
+ "㉹&'Pfs䑜공j<\/?|8oc᧨L7\\pX᭠9᪘": -2.423073789014103E18,
+ "ä„瑄䢸穊f盈᥸,Bî§§ë¾§í‘—íšµB1쟢f\u001f凄": "é­–âš2儉j꼂긾껢嗎0ࢇ纬xI4]ï„(à©“`蕞;픬\fC\"æ–’\")2æ«·I﹥迧",
+ "ퟯ詔xæ‚ë ¹+T?Bg⥄섅kOeQí¼ã»´*{Eé¼6æ°¿L缋\u001c둌๶-㥂2==-츫I즃ã ï–˜Lg踞ꙂEG貨鞠\"\u0014d'.ç¼—ï¡gI-lIb䋱ᎂDy缦?": null,
+ "î’¢ç´Mã¦çŠ¿w浴詟棓쵫G:äœ?V2íž½7N*n&ã–ŠNd-'ຊ?-樹DIv⊜)g䑜9뉂ㄹí‘阉~ê…쵃#R^\u000bïž®B䌎䦾]p.䀳": [{"ϒ爛\"ꄱ︗竒G䃓-î†ã¾å¸³ã‚.j)qguæ‰å¾£à¨Zé¼—A9A鸦甈!kè”å–™:3Tî†%&ã ˜+,ä·ž|ì±½v䚞문H<\/醯rì…“ã¶¾\\a볜åºzEä·_죤ဵ뿰᎟CB": [
+ 6233512720017661219,
+ null,
+ -1638543730522713294,
+ false,
+ -8901187771615024724,
+ [
+ 3891351109509829590,
+ true,
+ false,
+ -1.03836679125188032E18,
+ {
+ "<?起HCᷭ죎åŠîŒŽèއ逰/{gs\u0014⽛㰾愫tï¿–<솞ڢëŒç…²è†ºà¨»9x닳xà¡­Q訽,ᶭඦtt掾\"秧㺌d˪䙻꫗:á­ˆh4ç·žç—䤴c뫚떩త<?ᕢ謚6]í›Oé°é‹›é• è´©èµŸ\"<Gâ™·1'": true,
+ "቙ht4ßBqꦤ+\u0006멲趫ç”)椾": -1100102890585798710,
+ "ç·å…Žê³‡ë‡¸ç²ŸF醇;朠?厱楛㶆â¶7râ¾›o꯬᳡F\\머幖 㜦\f[æ¦á¥½ã®£0䕊?J㊳뀄e㔔+?<n↴å¤î§·": [
+ "4~ê‰ç¾\\å®(泤å•빜\u0014>j랎:g曞ѕᘼ}链N",
+ -1.1103819473845426E-19,
+ true,
+ [
+ true,
+ null,
+ -7.9091791735309888E17,
+ true,
+ {"}蔰鋈+ê¨å•µ0?g*사%`J?*": [{
+ "\"2wG?yn,癷BK\\龞䑞x?蠢": -3.7220345009853505E-19,
+ ";饹়â€)çš‹`噿焒j(3â¿w>å5X<np?<줯<Y]æ˜!J೸UⳂNे7v௸㛃ᄧ톿䨷鯻v焇=烻TQ!F⦰䣣눿Ké·šëˆ'â­²mæ (äš»": [
+ "蹕 淜੃b\"+몾ⴕ",
+ null,
+ 35892237756161615,
+ {
+ " 듹ã)5æ…ç®±&$~:é°ì®<\/å ‹?% \\勽唅zì†å¸‹ä˜ºH髀麡M퇖uz\u0012m諦d᳤콌æ¨\rX싹̡á²": -433791617729505482,
+ "-j溗ࢵcz!:î€}✽5à´‡,욨Ýs#ë«=å—æµº^}E\\Y\\T*뼈cdêºcÛ˜ïµëŽä¨¸ë±K䠴㉿æ¿é€³îŽœ@wî·¿fì¢<\/[L[": -9.3228549642908109E17,
+ "Ms킭uà®—%\\uâŽ/家欲ἅ答㓽/꯳齳|㭘Pr\"v<\/禇䔆$GA䊻˔-:틊[h?倬è¤á¾žà§³.Gw\u000b": [
+ "0宜塙I@ä´è‰\\Uyë’…=2<hæš’ï…£K._è´¡ç’Yi檻_⮵uá㘗è [f\u0015힢Hê”®}጑;ï´èªyf0\"\u20cc?(=qæ– âž½5ꎾ鞘kⲃ",
+ -2.9234211354411E-19,
+ false,
+ true,
+ {
+ "\u0011⟴GH_;#怵:\u001c\u0002nîž»1U\\p/ì™”(┫]hêšî·ƒ7\r0䵷첗岷O௷?î·°ãŽ[殇|J=?韷pᶟ儜犆?5კ1kê–iH竧뛈ପdmk游y(콪팱ê¾k慧 yè¾£": [
+ false,
+ "O\"ëp覈ykv磂㢠ãµ~뀬íŠlC&4솎䇃:Mj",
+ -7.009964654003924E-20,
+ false,
+ -49306078522414046,
+ null,
+ null,
+ 2160432477732354319,
+ true,
+ "4íš¡h+!踹ê¬P鮄{0&ë±¥M?ìƒéž…n㮞ᨹ?쒆毪l'ç®…^ꚥ頛`e㻨52柳⮙嫪࡟딯a.ï‘„~äµ®1få˜N&zÈ­L榓ۃ鳠5d㟆M@㣥ï Ó‹AÎq0縶$",
+ -3.848996532974368E16,
+ true,
+ null,
+ -3.5240055580952525E18,
+ {
+ " vï­·áµ#ce乃5僞?Z D`묨粇á”ç» vWLè­¢uë½€\\J|tâ“™tâ„–\"ꨋnT凮ᒩè‚ç¯b騩:䢭Hbvì»å³¨z㹚T趗햆귣학津Xiï¼¹@á–¥K": true,
+ "!F 醌yï䉸W2ꇬ\u0006/ä’7~%9擛햀徉9â›°+?㌘;ê “X䇻Dfië¼§ì’’\u0012F謞Õ絺+臕kà¤LSQìŒX쎬幦HZ98è’Šæž³": "澤令#\u001dæŠâ›³@Næ•퀂[5,✄ꘇ~䘷?\u0011Xꈺ[硸⠘⛯X醪è¡x\u0007쌇MiX/|ï¾ëšK8ä¡î¿¥W)銀q僞綂蔕E",
+ "6â²ä£–Rà§ž@ငg?<\/à³´xé™™Xꈺ崸⠅ᇾ\\0X,H쟴셭A稂ힿã‚F\\쑞\u0012懦(Aᯕç­~î½”\u0001ê»®X?逊": 5.7566819207732864E17,
+ "[c?椓": false,
+ "kä’‡": 2583824107104166717,
+ "꙯N훙ã…ﮒ燣㨊瞯咽jî™Mxby뻭뵫װ[\"1畈?à§±L": "ë£á”‚魠羓犴ꚃ+|rY",
+ "ë…ºZ?îˆä¬ï“©é‰‰îˆ­:?â³™ç˜Cኯ.Vs[釿䨉ì§\\\\*쵢猒$\\y溔^,㑳": {"藶꺟": [{
+ "\"d훣N2zq]?'檿죸忷篇ﮟ擤m'9!죶≓pë­»\\ᇷ\f퇶_ä°¸hà¹Q嵃訾㘑従ꯦ䞶jL틊ræ¾µOmᾫ!H䱤팼/;|á­ºI7슎YhuXiâš¼": -1.352716906472438E-19,
+ "M⽇倻5Jä‚«à¤”á”æ¥¸#î „î¾–J[Fﹱ쫮W誻bWz?}1\"9硪뻶fe": "盬:Ѹ砿íšë•£T凊(mç¦å‘œï»R㿎艴䂵h",
+ "Rë¾k힪CHé’™_i苮ⰵoᾨ紑퉎7h؉\"柀è½z0့\"<?嘭$èœ?礲7岇槀묡?Vé’¿T⣜v+솒çšÔ›2ç±³mH?>è–™å©è¿3aFÆÃ": "2,ê“´g?_섦_>Y쪥션钺;=趘F~?D㨫\bX?㹤+>/믟kᠪ멅쬂Uzỵ]$ç§`mé›ç‘Šî’ඖ鯬cꙉ梢f묛bB",
+ "♽n$YjKiXX*GOè´©éƒè±®ç¥´éžK醞眡}ê—¨v嵎꼷0à­¸+Mè‹eH徸Jîžê£†:â¼æ‚¥B켽迚㯃bè«‚\u000bjꠜ碱逮m8": [
+ "푷᣺ﻯd8ﱖ嬇ភHîªé¹Žâ¡±á±…0g:æžœ6$GQ췎{vá·§Yy-è„•xå¹ç ¡ï¨¬â®¸Cï§‚êš=軄H犠Gè°–ES詤Zè ‚3î§™lë´Ÿhï¿’7䦹1GPQG癸숟~[#é§¥8zQ뛣J소obg,",
+ null,
+ 1513751096373485652,
+ null,
+ -6.851466660824754E-19,
+ {"ä©‚-â´®2Ù°K솖풄꾚ႻP앳1Hî³é·›wmR䗂皎칄?醜<\/&à §ã¬X濬䵈K`vJ륒Q/IC묛!;$vÏ‘": {
+ "@-êš—xྐྵ@m瘬\u0010U絨ﮌé©\\켑寛넆T=tQã­¤Lì—°@脸삯e-ï–…î–‘:⩼u㎳VQ㋱襗ຓ<Ⅶ䌸cML3+\u001e_C)r\\9+Jn\\Pﺔ8蠱檾è…Pqé³è¯î¦§Tä„I": -1.80683891195530061E18,
+ "á·­á‹»U~ཷsgSJ`᪅'%ã–”n5픆桪砳峣3ç®æž¾äŒ·âа呀ïŒ": {
+ "Ş੉䓰邟自~X耤pl7间懑徛s첦5ਕXexh⬖鎥á€nNr(J컗|ૃF\"Q겮葲놔엞^겄+㈆è¯ã€¾í¬ç´G'E?飕1fâ¼í…¬æ‚šï•¦æ³¬ë¨Uç¬í›¶Qs": false,
+ "î³…(\u20dag8í½íŠ£>^Y{뤋.袊䂓î†;_ïg]S\u202a꽬L;^'#î—™ë•bႌ?Cç·¡<ä²ä²æ–­ê6\u001asD7IK5Wxo8\u0006på¼Šâ¼‚ê¯æ‰µ\u0003`뵂픋%ꄰ⫙ë¶lå›å°›ïˆ®+ä—…E쟇\\": [
+ true,
+ {
+ "\n鱿aKã¡â’ã¼™2ì´¹f;`ì¾qIà¡”G}ã·äç“°w늮*ç²…9뒪ㄊCj倡翑閳R渚MiUO~仨䜶RꙀA僈㉋⦋n{ã–¥0딿벑î§é€¦â¥»0î¾®h薓쯴ê»": [
+ 5188716534221998369,
+ 2579413015347802508,
+ 9.010794400256652E-21,
+ -6.5327297761238093E17,
+ 1.11635352494065523E18,
+ -6656281618760253655,
+ {
+ "": ")?",
+ "TWKLꑙ裑꺔UE俸塑炌Ũ᜕-ï’‚o\"徚#": {"M/癟6!oI51niíš=댡>xê¨\u0004 ?": {
+ "çš­": {"⢫䋖>u%wî²´ìž¼<ä•ê˜P䋵$é­‹æ‹U䮎緧皇Y훂&|羋ꋕ잿cJ䨈跓齳5\u001a삱籷I꿾뤔S8㌷繖_Yឯ䲱B턼Oæ­µF\\l醴o_欬6ç±=D": [
+ false,
+ true,
+ {"Mt|êžD|Fê¶£MQ뵕T,ëºk+?ãµi": [
+ 7828094884540988137,
+ false,
+ {
+ "!༦鯠,&aﳑ>[euJê½ç¶·æB.h": -7648546591767075632,
+ "-n켧嘰{7æŒæ¯„Y,>â螵煫乌pv醑Qå¶š!|âŒè²¬0왾ë¢ê…蛨S\\)ç«°'舓Q}A釡5#v": 3344849660672723988,
+ "8é–ªéºV=鈢1녈幬6棉⪮둌\u207d᚛驉ꛃ'r䆉æƒà¥ˆ|bἧﺢᒙ<=穊强s혧eꮿ慩⌡ \\æ§³W븧J檀C,ᘉì˜0俯퀉M;筷ࣴ瓿{늊埂鄧_4æ¸Nn阼Jੵ˥(社": true,
+ "oë¼€vwï…®)4A뢵(î¼±a䵢)p姃뛸\u000fK#KiQp\u0005ê…芅ì…îª": null,
+ "ç ¥$ꥸ┇耽uæ–®Gc{z빔깎밇\\숰\u001eê´·å„㶇쵿_á´„+hç©¢p촀Ნ䃬zäé…³Ó‚31xꔄ1_ç šWë ˜G#2葊P ": [
+ -3709692921720865059,
+ null,
+ [
+ 6669892810652602379,
+ -135535375466621127,
+ "뎴iO}Z? 馢녱稹ᄾä©rSt帤넆&7ié¨ë©—ç•–ï”9誧鄜'w{Ͻ^2窭외b㑎粖i矪ꦨ탪跣)KEㆹ\u0015V8[W?⽉>'kc$䨘ᮛ뉻٬M5",
+ 1.10439588726055846E18,
+ false,
+ -4349729830749729097,
+ null,
+ [
+ false,
+ "_è ¢ã ^䟪/D녒㡋ỎCä’ˆíŒïŒ¢\u0006àªq@O펢%;é¹ìŒo戥~A[ꡉ濽ỳ&虃᩾è£å”™ï¤£èŒ¨Ig楡꒻M窓冉?",
+ true,
+ 2.17220752996421728E17,
+ -5079714907315156164,
+ -9.960375974658589E-20,
+ "ᾎ戞༒",
+ true,
+ false,
+ [[
+ "ⶉᖌX⧕홇)g엃⹪xëšç™Ÿ\u0002",
+ -5185853871623955469,
+ {
+ "L㜤9ợㇶKé°â‹“V뽋˖!æ–«as|9"á¬ä†ª?î¾¶7胜&n薑~": -2.11545634977136992E17,
+ "O8뀩D}캖qè‚6༣ã—䈓煮å½à¨†á޼Dᣘí›;": false,
+ "YTá¡…^ï—Lã—ŽcbY$pᣞ縿#fh!ꘂb삵玊颟샞ဢ$ä—é¼’ëª~rkH^:닮먖츸륈⪺쒉砉?㙓扫㆕꣒`R䢱Bé…‚?C뇞<5Iޚ讳騕S瞦z": null,
+ "\\RB?`mG댵鉡å¹ç‰©äµŽæœ‰5*e骄T㌓ᛪç¾é§’Ku\u001a[柆jUq8⋈5鿋츿myï»—?é›ux঴?": 5828963951918205428,
+ "n0æ™…:黯 î¶·xu씪^퓞cB㎊á¬âº˜Ù¤Öƒ~B岚3㥕擄vᲂ~F?Cä¶–@$mï›~å¿”S왖㲚?챴⊟W#벌{'ã°Iä ç¸s樘\\X뢻9í•¡I6èㄛî‚î«8쯶]wॽ0L\"q": null,
+ "x增줖j⦦tä¢áŽ™ïŠ­ã›¿Yf鼘~ê«“æ„4惊\u209c": "oOhbᤃ᛽z&Bi犑\\3B㩬劇䄑oÅ쨅孥ë©àº–acA㖫借ãžvg싰샂ãœ#譞⢤@k]鋰嘘䜾L熶塥_<\/â¾å±ˆï®Š_mYè¹t뙺}Ox=wé®®4S1ê©ï¬¾'å·‘",
+ "㗓蟵ꂾe蠅匳(JPä—à·¸\u0089耀왲": [{
+ "ᤃ㵥韎뤽\r?挥O쯡⇔㞚3ä¼–\u0005Pî•⋪\"Dê¶£QLn(⚘罩䩢Ŏv䤘尗뼤ë›O淽鋋î¡é—šrå´©a{4ç®™{煷m6〈": {
+ "l곺1L": {
+ "T'ਤ?ç …|੬Km]ä„©\"(à¿¶<\/6U爢䫈倔郴l2ã´±^줣k'Læµ–Lé°„Rp今鎗⒗Cì–¨Mí›ã¡§Î˜X粜뫈N꤇輊㌻켑#㮮샶-ä—룲è ç™œã±V>=\\I尬癤t=": 7648082845323511446,
+ "鋞EP:<\/_`á§e混ㇹBd⯢㮂驋\\q碽饩跓྿ᴜ+j箿ë ã—‘yK毢宸p謹h䦹乕U媣\\炤": [[
+ "3",
+ [
+ true,
+ 3.4058271399411134E-20,
+ true,
+ "æ€+憱f逮@먻BpW曉\u001aã£âŽŠ$n劈D枤㡞좾\u001aá›ïŒƒè‹”౩é—1B䷒Ṋ݋âžê€žêƒç£$t੤_:蘺⮼(#N",
+ 697483894874368636,
+ [
+ "vᘯ锴)0訶}䳅⩚0O壱韈ߜ\u0018*Ué¾ä–=䧉뽑å•휻ID쿇嘗?ꌸῬ07",
+ -5.4858784319382006E18,
+ 7.5467775182251151E18,
+ -8911128589670029195,
+ -7531052386005780140,
+ null,
+ [
+ null,
+ true,
+ [[{
+ "1欯twG<uä®â½ê‡£_ჟﱴଶ-쪋\"?홺k:èŽêœª*⺵꽹댅釔좵}P?=9ë ¿46b\u001c\\S?(筈僦⇶爷谰1ྷa": true,
+ "TҫJYxÚª\\鰔℮혡)m_WVi眪1[71><\/ï†Q:0怯押殃탷è«ì‚¬<ỗꕧ蚨ä¡ï¨î³‰nDꌕ\u001cë…¬~è“©<N蹑\"{ä«¥lKcí˜ë«–앺:vⵑ": "gæ§µ?",
+ "aꨩ뻃싥렌1`ë¡—}Yg>鲃g儊>ê¡l㻿/â‘·*ì±³6㻜W毤緛ﹺᨪ4\u0013뺚J髬e3쳸䘦伧?æª&{L掾p+꬜MäŠd娘6": {
+ "2p첼양棜h䜢﮶aQ*c扦v︥뮓kC寵횂S銩&Ç{O*य़iH`Uí…à¡“rä©•5ꄸ?`\\á§«?ᮼ?t〟崾훈kè–ì/iy꤃뵰z1<\/AQ#ë¿©8jJ1z@u䕥": 1.82135747285215155E18,
+ "ZdN &=dë…„á…†'ì‘â…‰:烋5&áŸï”‹á„‚汎æ¥L㯄固{é’§u\\ãŠíŠšeæ‘‘&tå—„ê–„UbâŒ?m䴘熚9EW": [{
+ "ଛ{i*a(": -8.0314147546006822E17,
+ "⫾ꃆY\u000e+W`௸ \"Më’¶+\\ë·lKE}(NTí‚¶Yjé¸ç¯’î©¥ì¶'jNQ硾(똡\\\"逌â´y? IRꜘ὞鄬﨧:M\\fâ ‹Cꚜ쫊ᚴNV^Dä•—ã…–á¼”Iao꿬Câ8": [
+ 287156137829026547,
+ {
+ "H丞N逕<rO䎗:í…•<\/䶩샌Sd%^ᵯëˆ엑者g䖩똭蕮1U驣?Pâ°°\u001fp(W]67\u0015ï«£6굺OR羸#ì´Fè’ˆ;嘙i✵@_æ’¶yã¤â¤(:᧗뼢༌朆@â°ã¤¨ê­²?-n>⯲": {"": {
+ "7-;枮阕梒9ᑄZ": [[[[
+ null,
+ {
+ "": [[[[
+ -7.365909561486078E-19,
+ 2948694324944243408,
+ null,
+ [
+ true,
+ "荒\"并孷䂡쵼9o䀘F\u0002龬7⮹Wz%厖/*? a*R枈㌦ë¾g뒠䤈q딄㺿$쮸tᶎ릑弣^éŽ<\/Y鷇驜L鿽<\/ì¶‹9Mᲆឨ^<\/庲3'lë‚¢",
+ "c鮦\u001bë‘\\~?眾ಢu݆綑෪蘛轋◜gȃ<\/â´ƒcpkDt誩܅\"Y",
+ [[
+ null,
+ null,
+ [
+ 3113744396744005402,
+ true,
+ "v(y",
+ {
+ "AQ幆h쾜O+꺷铀ꛉ練A蚗⼺螔jãŒ3꽂楎䥯뎸먩?": null,
+ "蠗渗iz鱖w]擪E": 1.2927828494783804E-17,
+ "튷|䀭n*曎b✿~æ¤U]î­¡Gz鄭kW|ã´š#㟗ഠ8u擨": [[
+ true,
+ null,
+ null,
+ {"⾪壯톽g7?㥜ώQê‘㦀æƒã§½î“¡ä¼“\\î¦*᧰閖樧뢇赸N휶䎈pIæ°‡ï®é•Šmaᬠ탷#X?î³A+kÐM ༑᩟Ø?5꧎鰜ṚY즫궔 =ঈî³;ﳈ?*s|켦蜌wM笙莔": [
+ null,
+ -3808207793125626469,
+ [
+ -469910450345251234,
+ 7852761921290328872,
+ -2.7979740127017492E18,
+ 1.4458504352519893E-20,
+ true,
+ "㽙깹?ë¨ä†¢:ä´ŽÛ»gæ® JBTU⇞}ꄹꗣi#Iî’¡ëµ£é‰r혯~脀ìƒ#釯:场:ä”>ä°®o'ã¼½HZ擓௧nd",
+ [
+ 974441101787238751,
+ null,
+ -2.1647718292441327E-19,
+ 1.03602824249831488E18,
+ [
+ null,
+ 1.0311977941822604E-17,
+ false,
+ true,
+ {
+ "": -3.7019778830816707E18,
+ "Eå³¾æ†èŒ6xLIm縂0n2视֯J-ᤜz+ᨣè·mYDè±ç¹¹â¹ºäŠ“ëª“ï´€E(@è©®(!ï’Y膽#᎙2䟓섣A䈀㟎,囪QbKæ’wcG湎ꤧtGì—xâ¥ä¿Žj'A一ᯥ뛙6ㅑ鬀": 8999803005418087004,
+ "よ殳\\zDâ§…%Y泥簳Uꈩ*wîRL{3#3FYHା[d岀䉯T稉駅䞘礄P:é—ˆWæ€ElBã¤å–¬èµ”bGä ¼U଄Nw鰯闀楈ePsDꥷ꭬⊊": [
+ 6.77723657904486E-20,
+ null,
+ [
+ "ཚ_뷎꾑è¹q'㾱ꂓ钚蘞慵렜떆`ⴹ⎼櫯]J?[t9Ⓢ !컶躔I᮸uz>3aã •i,錃L$æ°°í…°@7ë…«W㸮?ç¾§W뇧ꃞ,î—‘N鋮숪2ɼì½â”ä²6",
+ "&y?뢶=킕올Za惻HZk>c\u20b58i?ꦶcfBv잉ETî…9jä¡¡",
+ "imçŠÕƒbì¹§<D-è«‚*u2ꡜ췛~䬢(텸ﵦ>æ ¡\\뼾쯀",
+ 9.555715121193197E-20,
+ true,
+ {
+ "<㫚v6腓㨭e1ã•”&&V∌ᗈT奄5Lጥ>탤?튣瑦㳆ꉰ!(ᙪ㿬擇_n쌯IMá¿‹î£ã•¨â°æ«ˆá±·5풔蟹&L.ì²½e鰷쯃劼﫭b#ï­¶í“€7ë·„Wr㢈๧Tʴશ㶑澕é%": -1810142373373748101,
+ "fg晌o?߲ꗄ;>C>?=鑰監侯Kt굅": true,
+ "䫡蓺ꑷ]C蒹㦘\"1à°ƒ@å‘«\u0014NLä¾egå‘®á³,r$裢k>/\\<z": [[
+ null,
+ "Cä¡>?ㄤᇰﻛ쉕1஥'ÄŠ\" \\_?쨔\"ʾr: 9Sä˜ç¦ºáª§ê„‚㲄",
+ [[{
+ "*ç¡™^+E쌺I1䀖ju?:⦈Ꞓl๴竣迃xKC/饉:\fl\"XTFᄄ蟭,芢<\/骡軺ëœhê˜\u001f銿<棔햳▨(궆*=ä¹¥b8\\媦ä·€ë«}닶ꇭ(Kej䤑M": [{
+ "1á¬?>옿Iâ•…C<ÞŽ?ꊌ冉SV5A㢊㶆z-๎玶绢2F뵨@㉌뀌oå¶”f9-庒茪ç“ë·³4": null,
+ ";lá°³": "CbB+è‚»aä„·è‹*/볳+/4fq=ã°h6瘉샴4é“¢Yéª.⌖@哼猎㦞+'gꋸ㒕ߤï—ãž‘(ä¶’è·²tiâ‘´aî¥ç¡‚#Noë³”",
+ "t?/jE幸YHT셵⩎Kî¹!Eq糦ꗣv刴w\"l$ο:=6:ç§»": {
+ "z]鑪醊嫗J-Xm銌ç¿çµ¨c里ëç‚™Ep㣋é£ë˜¼åšŒä€“GPï¹–cmf4é¹­T䅿꣭姧â¸wy6ꦶ;S&(}ᎧKxᾂQ|tï¹ë»³k\"d6\"|Mlì·†hwLtê¼¼4$&8Պ褵婶鯀9": {"嵃닢ᒯ'î–›dá§«ä³³#Nî‡Xe3-붋鸿î¢à¬¢ë–“î§ž%dK\u0013䲎ê–YV.裸Râ‰rR3蟛\\:ì ¯:å—ĺLʆ넕>|텩鴷矔ꋅⒹ{tå­¶ã“‘4_": [
+ true,
+ null,
+ [
+ false,
+ "l怨콈lá’",
+ {
+ "0wä²å¬§-:`䉅쉇漧\\Ü‚yㄨb%㽄j7ᦶ涶<": 3.7899452730383747E-19,
+ "ꯛTẀq纤qå¶Vâ¿£?\"g}ი艹(쥯B î­T騠I=仵ë°X": {"KX6颠+&á…ƒ^fç•’y[": {
+ "H?뱜^?꤂-⦲1a㋞&î‘®êƒç²¾Ii᤾챪咽쬘唂쫷<땡劈훫놡o㥂\\ Kâ´™Dç§¼Fæ°®[{'좴:례晰Iq+Iì­¥_T綺砸GOç…䟪ᚪ`î‘↹l羉qì¼Dê½áœ…훦: vUV": true,
+ "u^yï³0㱓#[y뜌앸ꊬLã·©?蕶蘾â»KӼ": -7931695755102841701,
+ "䤬轉車>\u001c鴵惋\"$쯃྆⇻në½€Gæ° Såª]à²²ê¨æ‡Qxኻ椕駔\\9ࣼ﫻ìœç£¡ï©ˆëºªá¶šë³l㕆t+sζ": [[[
+ true,
+ false,
+ [
+ null,
+ 3363739578828074923,
+ true,
+ {
+ "\"鸣詩 î›ë³°ã‘µgLã¯¦á¿…ì¶æ—«}ED辗ﮈI쀤-ꧤ|ã ¦Z\"娑ᕸ4çˆé¨ã£\"]ì³Af]茛⬻싦oèšk䢯ä©è½3廇喑ޅ": 4.5017999150704666E17,
+ "TYႇ7ʠ值4챳唤~Zo&ݛ": false,
+ "`å¡„J袛㭆ëºã³€N㺣`ê½å¶¥Kï¯SVᶔ∲퀠ç¾N딂X\"á¤hNﬨvI": {"\u20bbã­˜I䖵䰼?sw䂷쇪]î(泒f\"~;꼪FÔsá¦": {"p,'ꉂ軿=Aèš¶?bƉãµä…°è«¬'LYKL6B깯⋩겦뎙(ᜭ\u0006噣d꾆㗼Z;ä„äš”cd<情@äž‚3苼㸲U{)<6&ꩻ钛\u001au〷N숨囖愙j=BXWìš•^x芜å á¿™çˆ‚ë›·ê’»t✘Q\b": [[
+ "ç±›&ଃ䩹.ꃩ㦔\\C颫#暪&!勹ꇶ놽攺J堬镙~軌C'꾖䣹㮅ï¶å²ƒá™´éµ£",
+ 4.317829988264744E15,
+ 6.013585322002147E-20,
+ false,
+ true,
+ null,
+ null,
+ -3.084633632357326E-20,
+ false,
+ null,
+ {
+ "\"짫愔昻 Xï«\"è—£j\"\"ë¨à½…ѻ㘤㬯0晲DU꟒㸃dë²€î¢ìœ’l䦾cà©»*3": null,
+ "è°ˆWm陧阦咟ฯ歖擓Nå–´ã‹éŠ­rCCnVࢥ^♼Ⅾ젲씗刊Sà¼+_tèµ”\\bäšë‰¨ê¬«6펛cL䊘᜼<\/澤pF懽&H": [
+ null,
+ {
+ "W\"HDUuΌ퀟M'P4à¿°H똆ⰱﮯ<\/å‡è˜²\"C鴫ﭒж}ꭩ쥾t5yd诪ﮡí‰â´°@?æ°é†³rj4I6Qt": 6.9090159359219891E17,
+ "絛ﳛ⺂": {"è«°Pã—®î˜è¦`ZQ?ꫦh*à´±cbâ§±}埌茥h{棩렛툽o3é’›5é®l7Q榛6_g)ὄ\u0013kj뤬^爖eO4Ⱈ槞鉨ͺ订%qX0Tì—å«·$?\\\"봅늆'%": [
+ -2.348150870600346E-19,
+ [[
+ true,
+ -6619392047819511778,
+ false,
+ [[
+ -1.2929189982356161E-20,
+ 1.7417192219309838E-19,
+ {"?åµ²2à¿2\u0001啑㷳c縯": [
+ null,
+ [
+ false,
+ true,
+ 2578060295690793218,
+ {
+ "?\"殃呎ïˆ#ã‘‘F": true,
+ "}F炊_æ®›oU헢兔êˆ,èµ­9703.Bæ•°gTz3â¬": {
+ "5&t3,í–“Mݸᵣ㴵;꣫ä©â†³#ï¢@ë«·ä …ï¦+W-ࣇzᓃ鿕ಔ梭?T䮑ꥬ旴]u뫵막bBè®:왳둛lEh=숾鱠på’î›î­ˆ$ì§#?gâ¹·á—Švã·µ.æ–ˆu頻\u0018-G.": "ë½™m-ouࣤ஫牷\"`Ksꕞ筼3HlȨvCï¢î›¦å ˆ\"I]㖡玎r먞#'W賜鴇k'c룼髋䆿飉㗆xgå·¤9;芔cáŒ/ax䊨♢í“rå“㸫೼䢗da᩾\"]å±£`",
+ ":M딪<䢥喠\u0013ã–…x9è•ã‘‚XO]f*Q呰瞊å­VP@9,㨣 D\\穎vˤƩs㜂-曱唅L걬/롬j㈹EB8g<\/ì„©o渀\"u0y&룣": ">æ°ç·©L/ä•‘ë¯êŸ˜îŸ”蕞^aBë’£+0jK⪄瑨痜LXK^힦1qK{æ·št츔X:Vm{2rçB뾄H첚7æ°¥?쉟䨗ꠂv팳圎è¸é½€\\",
+ "D彤5㢷Gꪻ[lㄆ@὜⓰絳[ଃç½ì®¹â˜’[*0ꑚ㜳": 9022717159376231865,
+ "Ò–aV銣tW+$é­¿\u20c3ïœäºœ~ë«¡ᙰ禿쨽ã¡fá¹¼zE/h": "5è‡ï’Œã‹‡á²¯ì®º? 昨탰Wム밎#'\"崲钅U?幫뺀â¾@4kh>騧\\0Ò¾EV=çˆî©®ÍŒUæ€%ꉼ 㮋<{j]{R>:gÔ©L\u001c瀈锌ﯲﳡꚒ'â«¿E4æšãŒ—뵉X\"Háœ",
+ "ᱚגּ;s醒}çŠSἿ㦣&{T$jkB\\\tḮ앾䤹o<é¿(tW": "vb⯽䴪䮢@|)",
+ "⥒í껉%惀뗌+녣迺顀qæ¢g⚯i⤭ë£Mç¹j̈́⽜A": -8385214638503106917,
+ "逨ꊶZ<\/W⫟솪㎮ᘇb?ê ”i\"H㧺x෷韒Xꫨฟ|]窽\u001a熑}Agn?Má¶–a<rà°„4Ů䢤슲AxÄ£eê³–ã´¤x竾éƒB謉鸵kè–½M)\"芣眜`è‰ê‰›ä´º": "é¹^ె캫?3耲]|Ü1ä¡’ã®]8e?ä¶^",
+ "뿸樅#P㡊1M룮Uꪭ绢ꑮZ9꽸": {"\nJ^Ñ”|3袄ã…7⨆銦yîµ”çâ‹·ä»´ct?[,<\/ã…¬`?갔髞%æA೚C": {
+ " 䇞3갫䅪": [{
+ "0|â©ã‘‚砕ㅻ": null,
+ "D箳᠉`|=â¼­)\"*࣊ã¦LjO誋": "",
+ "ࠚDZmê—¥}ᷴ╈r7í—´È¥4Kp5a)o}鎘门Læ°ä†“'✎k俎c#T68Óâ©¶î¶6L鎴<r൦$黊BQYã¼³\\è·¿F慮⡨拵贀!ç”¶Vå–…/": null,
+ "âµ£q⳹ﻨLk]晩1*y\\$%}ä–¶P煑㇆䈦E嫿«•Y࣓嫨ä“OL낮梚㸇洛洚BYtgl∛S☕䉓宑⋢粚ꔯ꠼붠": ")ꬑ윤`\"â°£<\/婽*Y䔸ᓰ_ï³t슲å©éš¥&S糧䛮闵诌è±sh쯽邴*ì„´ØÍŽ=㯨\"RVíž³,^t\"ac?䤒ꉀxHa=Uꛕã™î·“TkF껾",
+ "å¼¾cUAF?暤cë½.欀nKì•­]r傊䀓ﯳ馽垃[䥛oI0N砊鈥헅Co쟋钄ㅷ㊌뷚7": [
+ null,
+ "à«“é¨?^ä†{\u0006`X䧵儱&롡尙砡\u0006ë»ì‘¬sjâ–»Xfᬶgcã„¢V >9韲4$3á»´^=ì煤áë·2䣃%ï…Žé· /eQ9頸쥎",
+ 2398360204813891033,
+ false,
+ 3.2658897259932633E-19,
+ null,
+ "?ꚃ8Nnãž·å¹µd䲳䱲뀙ꪛQ瑓鎴]î’¶ä©‹-é°¾æ¡ï¾ä³¡??掊",
+ false,
+ -1309779089385483661,
+ "ᦲxu_/yecR.6èŠ.áœ‡éŽ ~",
+ -5658779764160586501,
+ "ì’Œ:æ› =lìœä¢œwk#s蕚\"互㮉m䉤~0ë“䋙#Gîš¿;h숄옥顇෤勹(C7㢅雚ã¯Lâ …VVç°…<",
+ null,
+ -4.664877097240962E18,
+ -4.1931322262828017E18,
+ {
+ ",": {
+ "v㮟麑䄠뤵g{Më®.\u001bzt뢜뵡0Ǥ龍떟Ᾰ怷ϓRT@Lꀌ樂Uã â¾•e扉|bJg(뵒㠶唺~ꂿ(땉x⻫싉ìŠ;%0鎻V(o\f,NéŠ%nk郼螺": -1.73631993428376141E18,
+ "쟧摑繮Q@Rᕾ㭚㾣4隅待㓎3蒟": [
+ 4971487283312058201,
+ 8973067552274458613,
+ {
+ "`aæ™á£—î\u0015i<S幼訃锭B0&槩✨[Wpçš©[g≊k葾x2ᡆ橲䲢W": true,
+ "kH皈Sê±qå‚‘u?솹풑~o^F=ï¦N*reî••J沤wW苯7pã¼¹äŽa=ꮧLã·©냴nWꌑ㞱uuè°lVNç¿á¤»(eè±¶5#L쪉ᅄ઄\u0015숟봊P瀚X蓎": false,
+ "䫯דּ〖Scä›­ì Lëµ¾pî«“CꙞ\"엇즓_ﰛ톣ꫀ먩㺣㮠⭴!\\Wâ”tä–°è»…y\u0014~ᇰ렢E7*俜䥪W䀩ä·hë´†vjஉ묣à¼G39.뼳輼:㮿á¦A饕TUL}~": [
+ null,
+ 8.8648298810470003E17,
+ 5.735561205600924E-20,
+ null,
+ -102555823658171644,
+ 1.2674932032973067E-19,
+ {
+ "D胣O㯨\u0017Ku눓ã’í…nᨊ!Ꚇ廫_>Bo¸": 4.3236479112537999E18,
+ "HW&퉡ãåœ<W)6æ‚°ê ‘HEp14xy峑ft\u0005s亘V튉䢮ꦈXåµê¬?lI_ë춇-6Ss噺Nk-ﮥíƒÜ郪*ï“­PR(S6â•‹@ä»™V懸뺵ﯜVç²¹": "9䗌斀4ãˆ^Qséš„ç¡j\u0003",
+ "Vké¶…Cæ³¹ç­HX훉朗*r\\z顊誌儖4?n7á¾6몋䎡ﳈ],Hé ¢pèšã‘„P4满Eä©V䬕à¸L廂쒬î®ì‘¨ê†·hè¿¡ê°è­–墎 î‡]鹿ฌ7ﶽ冭༽<ꈓS\\lä‹®?_ユ檒?": -8598528325153980065,
+ "t=qí£ç–»Ñ‚Z\\錅J.镎|nfḷ鴒1厰Lç¯çºœîŒ•E]୦⥪]á®'ç¾p/å’©0닳ï³qﳖཽk ?X1Ft%ś뭢v鋋⺃爵⒗": [[
+ 5.0824756359232045E-19,
+ [
+ 7.268480839079619E-19,
+ {"탿^굞⧕iјëŠê€›w껩6ꟳXsé…š\\>Y?ç‘¡Qyí›q!帰ï©s舠㫸zêš—aSæ­²v`G株巷Jp6킼 (ê·¶é”â¾î‹¥â¡ˆ>Mæ±ãžá‰´ê™²dv@i㳓ᇆ?é»": [
+ null,
+ 4997607199327183467,
+ "E㻎蠫á¾é«˜ä™Ÿè˜¬æ´¼æ—¾ï« í…›ã‡›?'M$㣒蔸=A_亀绉앭rN帮",
+ null,
+ [{
+ "Eᑞ)8<Zî¿—ã¡¿W镀䛒Cìƒî¿«V?0ꯦ+tL)`é½³AjBå§€Xà³³D빠㻲ƙgn9â‘°à¾á¿œ&\"ãš¹>餧A5u&ã—¾q?": [
+ -1.969987519306507E-19,
+ null,
+ [
+ 3.42437673373841E-20,
+ true,
+ "eê±·Må¢\"割Pâ›í§åŽ€R䱜3ï»´Oí“«r﹉⹊",
+ [
+ -8164221302779285367,
+ [
+ true,
+ null,
+ "爘y^-î¬?蘞Ⲽꪓaâ…ê¨}I",
+ 1.4645984996724427E-19,
+ [{
+ "tY좗⧑mrzïºã¿¥â´–᥷jè«…\u0000q賋è­êž„â®±S\nà¡£B/íƒêµª3ZÉ‘å¤o<\/;ë¡‹": null,
+ "彟hæµ _|V4䦭Dᙣ♞uì¿»=ì‚®ã¦\u001e哀鬌": [{"6횣楠,qʎꗇ鎆빙]ã±­R굋鈌%æ ²j分僅ペ䇰wí¦î¼‹p蛃N溈ê¡ê€?@(GI뉬$ﮄ9èªê“š2e甸ڋ[äº,\u0011\u001cࢃ=\\+衪䷨ᯕ鬸K": [[
+ "ㅩ拏鈩勥\u000etgWVî–¨Xs陂è¦p狵w퓼{뮵_i\u0002ퟑႢâ¬d6é‹«F~챿æŸ\u0096äš¼1ۼ칥0꣯å„=鋷牋ⅈêžé¾",
+ -7283717290969427831,
+ true,
+ [
+ 4911644391234541055,
+ {
+ "Iî¹éˆ’ì²½P릜朸W徨觘-HᎄíŸâ“º>8kr1{ê²µäƒã€›á¬¡Ì¨Oê·‘oä•'쿡鉕p5": "fvç²–RNçž–è›a?q꤄\u001d⸥}'ꣴ犿ꦼ?뤋?鵆쥴ë‹ä¡«s矷̄?à¶£/;괱絢oWfV<\/\u202cC,ã–¦0䑾%nè³¹g&T;|lj_欂N4w",
+ "짨䠗;䌕u i+rà¹0": [{"9ä¥\\à°©8\"馇z䇔<\/á‚¡Y3e狚ì¡\"ุ6ï°†Zé–c\"Ll:ïŠê®¾ç–£<\/᭙O◌납୕湞9⡳Und㫜\u0018^4pj1;ä§å„‚ä—·à­—>@e톬": {
+ "aâ‘‚Fé‹»Qèž°'<퇽Qè´ç€§{ᘪ,cP&~䮃Z?gI彃": [
+ -1.69158726118025933E18,
+ [
+ "ê¶‚z簽㔛㮨瘥⤜䛖Gℤ逆Y⪾j08î±²Sn昞ꘔ캻禀鴚P謦b{ê“®mNéMᥙ5\"ç2냑I\u0011.L&=?6á„ ë»·X鸌t刑\"#z)o꫚n쳟줋",
+ null,
+ 7517598198523963704,
+ "ኑQp襟`uᩄr方]*F48ꔵn俺ሙ9뇒",
+ null,
+ null,
+ 6645782462773449868,
+ 1219168146640438184,
+ null,
+ {
+ ")ယ넌竀Sdä°¾zqâ«£âŒÊ¥\u0010á¿“' |磪&p牢蔑mï³V蘸૰짬꺵;K": [
+ -7.539062290108008E-20,
+ [
+ true,
+ false,
+ null,
+ true,
+ 6574577753576444630,
+ [[
+ 1.2760162530699766E-19,
+ [
+ null,
+ [
+ "顊\\憎zXB,",
+ [{
+ "㇆{CVC9ï¼MN㜋ઘR눽#{h@ퟨ!鼚׼XOvXS\u0017á£=cS+梽៲綆16së½íœy屬?ᇳG2á´­\u00054쫖y룇nKcW̭炦s/鰘ᬽ?J|퓀髣n勌\u0010í™ P>j": false,
+ "ç®´": [
+ false,
+ "éžj\"ꮾ*엇칬瘫xṬ⭽ì©äƒ³\"-⋵?ᦽ<cਔ↎⩧%鱩涎삧u9K⦈\"á¿á¬‘V绩킯愌ṱv@Gê¾è·¶êš†(?ä–ƒvIá§ŠxV\r哦jã ’?*=S굤紴ꊀ鹭쬈s<DrIu솹꧑?",
+ {
+ ".}S㸼L?t\u000fK⑤s~hU鱜꘦}ìªC滈4ꓗ蛌):ྦ\"é¡¥ì´â¢·ïš­á¿³YLn\"?fꘌ>댎Ĝ": true,
+ "Pg帯佃籛n㔠⭹࠳ë·â‰»à¿Ÿ3ãž±ï“!î—-ì’¾!}쭪䃕!籿næ¶»J5ਲ਼yî˜vy;Rኂ%ᔡጀ裃;M⣼)쵂쑈": 1.80447711803435366E18,
+ "ꈑC⡂ᑆ㤉壂뎃Xub<\/쀆༈憓قì¨×§\\": [
+ 7706977185172797197,
+ {"": {"K╥踮砆NWࡆFy韣7ä밥{|紒︧䃀榫rᩛꦡTSy잺iH8}ퟴ,M?Ʂ勺ᴹ@T@~꾂=I㙕뾰_涀쑜嫴曣8IY?ҿo줫fऒ}\\S\"ᦨ뵼#nDX": {
+ "♘k6?଱癫d68?㽚乳䬳-Vé¡·\u0005è•?\u0018䞊V{邾zã˜l]é›k臤~ൖHë’iꢥ]g?.G碄懺䔛p<q꜉Så²—î¥_.%": 7688630934772863849,
+ "溗摽嗙Oã§€,⡢⼰呠ꅧ㓲/葇䢛icc@-r\b渂ꌳ뻨饑è§á–œ\\é®­\u0014엙㥀᧺@æµ¹W2꛵{W률G溮킀轡䬆g㨑'Qè¨ï†áŸªç½‘Hd\"Q늴ᱢﶨ邮昕纚枑?â–°hr羌驀[ç—¹<\/": [
+ -1.0189902027934687E-19,
+ {"窶椸릎뚻shE\"ꪗႥꎳU矖佟{SJ": [{"-æ…œx櫹XYîƒ-æ¾Ü¨â£·àª¢ïŸé¯™%Fu\u0000è¿‹â–’}᥷L嗭臖oញc넨\u0016/迎1b꯸g뢱ã§è“¤ä’8C散삭|\"컪輩鹩\"\\g$zG䥽긷?狸꿭扵ã²:URON&oU8": [
+ null,
+ true,
+ null,
+ -2.8907335031148883E17,
+ -3864019407187144121,
+ {
+ "`빬d⵺4H뜳⧈쓑ohஸ*ã¶ï»‡â¸•ä µ!iä¬ï¹‘h夘▥ê—푹갇㵳TA鳠嚵\\B<X}3訒câ‹{*ï«¢w]ç’¨-gæ­\\j໵侠Ei层\u0011": 3.758356090089446E-19,
+ "䄘ï®)Y놞씃㾱陰í:{\u2059/Sâ“´": [[
+ null,
+ [[
+ -3.8256602120220546E-20,
+ null,
+ 7202317607724472882,
+ "CWQëš¿",
+ null,
+ false,
+ true,
+ null,
+ 2857038485417498625,
+ 6.191302233218633E-20,
+ null,
+ -6795250594296208046,
+ [
+ true,
+ {
+ "%á‹§é°Yᚯ⚀x莰愒Vᔈ턗BNæ´ê¤ŸA1âŒl콹풪H;OX๫륞ìªá°šÑ†@͎黾a邬<L厒Xb龃7f웨窂二;": [[
+ null,
+ "耲?䙧㘓F6Xsí‹­ë©¢.v뚌?鄟æ â–½'묺競?WvᆾCî»txo?dZ;䨸疎",
+ {
+ "@hWê‰&\"빜4礚UO~C;ã†î”殩_ꀥè˜å¥¢^챟k→ᡱKMⵉ<\/Jㅲ붉LÍŸQ": false,
+ "tU뢂8é¾°I먽7,.Yî°î»´æ½Z툼=&⨥覽K乫햶㠸%#@Zë–æ„“^âŠâ¾‚몒3E_噆J(廊ឭyd䞜鈬Ћ档'⣘I": {
+ "tK*ꔵ銂u艗ԃì¿âˆ³ê„‚霫X3♢9y?=â²­dЊb&xy}": [
+ -4.097346784534325E-20,
+ null,
+ 6016848468610144624,
+ -8194387253692332861,
+ null,
+ {
+ "(祬诀譕쯠娣cë´r?ç•„kT뼾⌘⎨?noVä˜ì¥ç¡Žn?": [
+ 1.82679422844617293E18,
+ [
+ false,
+ 2.6849944122427694E18,
+ true,
+ [
+ false,
+ {
+ ";0zâ­†;í™”$bਔ瀓\"衱^ï—´?잢ᢛ⣿~`ꕉ薸⌳໿湘腌'&:ryБꋥá¼ê’¥ç­™ê¬œê¸¨?X": -3536753685245791530,
+ "c;Y7釚Uꃣ割J༨Y戣w}c峰뢨㽑㫈0N>R$ä…’X觨lë´œA刊8R梒',}u邩퉕?;91Eî¦a䈈ë¯G⊶芔h袪&廣㺄j;ã¡ç¶½\u001bN頸쳘橆": -2272208444812560733,
+ "æ‹‘Wﵚî²j鵼駳Oࣿ)#ã¾…é¡‚N傓çºy僱栜'Bê-!KF*ꭇK¦?䈴^:啤wG逭w᧯": "xᣱmYe1Û@霄F$ě꧘푫O䤕í€Pq52憬ꀜ兴㑗ᡚ?ï—ƒLé·íŸî—¼ë­zJê‘™}╆ᅨJB]\"袌㺲u8䯆f",
+ "꿽á…㔂긱Ǧ?SI": -1669030251960539193,
+ "ì‡É¨`!葎>瞺瘡驷錶â¤ï»®é…œ=": -6961311505642101651,
+ "?f7♄꫄Jᡔ훮eì‡îª¼í¾á£ä­´KhखT;Qty}O\\|ë«Iá¿’Ne(5æƒê¥¶ã†·Y9ﮡ\\ oyâ­–-䆩å©m#xë´‰>Y鈕Eç–£s驇↙ᙰm<": {"퉻:dê‚&efᅫ쫢[ï„™\"ëˆëŠ–êº™|Ôå‰1Í–-K:Êšá­•/;ì–㷛]Iç—èŒ4g<Oꗢ뫺N쯂륬J╆.`ᇵP轆&fd$?è‹…oê¶“vO侃沲â©åš…æ²— E%â¿°ì–¦wi\\*è¶«": [
+ 3504362220185634767,
+ false,
+ "qzXæœqT3軞T垈ꮲQ览ᚻ⻑쎎b驌䵆ꬠ5Fà­—ä²ç¼¿ê蒇潇Ltᆄ钯蜀W欥ሺ",
+ "ë³°É霬)ì é¶¼kwocì—·èr \u001d쒷⎹8{%澡K늒?iﺩd=&皼倚J9s@3å›twὡgjä íª5⭉⨺役&놎cﺉ㺡N5",
+ false,
+ null,
+ "D0st[ni锹r*0k6ꀎë‡UX2⽼৞䃚粭#)Zæ¡·36P]<\/`",
+ 4281410120849816730,
+ null,
+ -3256922126984394461,
+ 1.16174580369801549E18,
+ {
+ " ᆼꤗ~î…‰*TN긂<㡴턱℃酰^蘒涯잰淭傛2rൡetì¾£ä‡m*ã¸y\"\\糮᧺qv쌜镜T@yg1譬ﭧﳭ\f": null,
+ "圾ᨿ0xᮛ禵ਗ਼D-㟻ẵ錚e\"赜.˶m)é´‘B(I$<\/轴퉯æ·â‹âº*)宓쓌?*橯Lx\\f쩂㞼⇸\"ﺧ軂é³V\\ë•’\"캘c:G": null,
+ "?ïµ_ê³¢î™ç¿¸íˆ8ã¿ hì—´Q2ã­›}RY㯕YT놂⽻e^B<\/맫ﻇ繱\u0017Gц⟊ᢑﵩS:jt櫣嗒⟰Wã´šæ¦á…‰e[w䋺?藂翙Ⲱ芮ä˜â•¢å›¥lpdu7r볺I è¿‘qFyᗊ": [
+ "$b脬aᅠ襬育Bگ嵺Pw+'M<\/ï­näššvèžbNâ’‚}褺%lቦ阤\"ꓺá—Mç‰,Ûžï– Ò¶!矬?ke9銊Xê´¦)䈽í‹è„½á¹«äˆžá´†^=Yá—¿é›4I귺⋥%",
+ false,
+ 2.9444482723232051E18,
+ 2072621064799640026,
+ "/_뇴뫢jã’=Nꡦâ†Ôºèµ’â¬î»¼í†¥ä¨žç¯su*媸瀳鷔抡oíº-៳è¾å‹·fç»”:äµ¢æ¢2",
+ false,
+ "ì’œ Eî½·äŒ/í\u0018懺_<\\隺&{wF⤊谼(<죽é ïŸ‡8?@*rá¶ŠGd뻻갇&Ⳇq᣿e࢔t_ꩄ梸O詬Cá§§Kê© í’¤9눙醅ëž}竸rw?滨ӽK⥿ཊGé­²']`๖5ã„°",
+ -2375253967958699084,
+ {"嗱⿲\"få„„á¬": {"v?䚑킡`â—¤k3,骥曘뒤Oᒱ㲹^圮᠀YTê»›&ì´®P:G/Tâ£#튣k3ç‚©è k@橈ä·Sä§•,ç†œïŒæ™¬ï£žk1鮥玸먚7䤡fç»å—šìƒ´á¥’~îš¼0q拮垑aë»±Lâ°–_": [{
+ ":på°¢": -6.688985172863383E17,
+ "A0\u0001疠ﻵ爻鼀湶I~W^å²€mZx#ãˆ7r拣$Ꜷ疕≛⦒痋盩Vꬷá­â„¦Qêªï§éˆ‘A(劽詗ꭅo-ç¶é‘º\"Ⓠ@$j탥;": [
+ 8565614620787930994,
+ [
+ "å¶—PC?à¶‹Q㪣$&j幾㾷hæ…‘ 즊慧⪉霄M窊ê·'鮕)äŠé“¨m趦䗲(g罣ЮKVﯦé®î¦®5囗ﰼ鿦",
+ -7168038789747526632,
+ null,
+ -7.8069738975270288E16,
+ 2.25819579241348352E17,
+ -6.5597416611655936E18,
+ {
+ "瘕멦핓+?フZê·¢zé›V": {
+ "ᕾ": 1.7363275204701887E-19,
+ "ã­Œs뎹㳉": {"\u00187Fï–‰I6Yféº+UC쬸éºâ²ä‚¿ê¸•R\\ᆮC?Φ耭\rOத际핅홦*ë² W㸫㯼᡹cㅜ|Gã®—\u0013[o`?jHVì•?蒪꩚!í«áœ¦ãŒ‡äš‡é¿˜:@": [
+ "}푛Г콲<äŸCè—呈#2ã“‹#ྕáŸå°¿9qç«“gI%ëž™mê¬oaç•è´¿Jå’¿D_ç†Zz皳験Iè±¼B扳ḢQ≖㻹㱣Dä¦ï©—2'á—㗣▌ç ²8罿%à°¹F姦;0î·æ‚‡<\/\"påš§",
+ -710184373154164247,
+ "Vo쫬⬾ê«â´·Å»\u0004éŽHBê…¸_aVBHbN>Z4âœkเꛘZ⥺\\Bʫᇩ鄨魢弞&幟ᓮ2̊盜",
+ -9006004849098116748,
+ -3118404930403695681,
+ {
+ "_彃Y艘-\"Xx㤩㳷瑃?%2ä¡éµ›o<A?\"顜ᘌΈ;â·…Cæ´ºL蚴蚀voq:,Oo4쪂)": 5719065258177391842,
+ "l륪맽耞塻論å€Eã—‘/㲕QM辬I\"qi酨玑㖪5q]尾魨鲡ƞY}⮯蠇%衟ï„Fsf윔äšì°¤iè…³": {"ꢪ'a䣊糈": {"ë°‘/♋S8sã¼´5瓹O{댞\"9Xï°‡lJ近8}q{긧ⓈI᱑꿋腸D瀬H\"ﺬ'3?}\u0014#?丙㑯ᥨ圦',gé‘ (樴턇?": [
+ 2.5879275511391145E18,
+ null,
+ [
+ "3㼮ꔌ1Gẃ2Wé¾™jîªÍŠ{1å›ã¦­9xå® ã‘oRä•犽",
+ 1268729930083267852,
+ "땕軚⿦7C",
+ [
+ -3.757935946502082E18,
+ "\"赌'糬_2ë­¾áb",
+ {
+ "(a䕎ጽjÒ°D4.á´¡ïž½66ԃ畮<\/l`k癸\\㇋ࣆ욯R㫜픉녬挛;ڴ맺`.;ç„“q淞뮕ٹ趴r蔞ꯔ䟩vç²u5<\/pZ埖Skrvj帛=\u0005aaï”›": null,
+ "璄≩ v몛ᘮ%?:1頌챀H㷪뉮k滘e": [
+ "ꤾ{`c샬왌펡[俊络vmz㪀悫⸹ᷥ5o'ã¾µ L蹦qjYIYណԠWëƒå‰«<\/W嗂0,}",
+ 2.4817616702666762E18,
+ false,
+ null,
+ null,
+ -8.6036958071260979E17,
+ null,
+ -1.2744078022652468E-19,
+ -4.4752020268429594E17,
+ 1.13672865156637872E17,
+ [
+ false,
+ false,
+ null,
+ -4.178004168554046E-20,
+ true,
+ 2927542512798605527,
+ {
+ ".ꔓ뉤1䵬cHyæ±¼äŠ†è³“á‡Æ©|樷â‡é†Žã¬…4\u0003èµµ}#yD5è†æ™¹ë±“9ê–è™›J㺕 t䊛膎ؤ": {
+ "rVtᓸ5^`েNâ¹»Yv᥋lꌫt拘?<é®°ë„¿ZC?ã’½^": {"âªî©k_:>귵옔夘v*탋èŒ&㳈챗|Oé’§": [
+ false,
+ "daꧺdᗹ羞쯧Hã¤é„³é ³<型孒ン냆㹀f4ã¹°\u000f|C*ሟ鰠(O<ꨭ峹ipຠ*yà³§4VQè””hVæ·¬{?ᵌEfrI_",
+ "j;ꗣ밷é‚副]á—“",
+ -4299029053086432759,
+ -5610837526958786727,
+ [
+ null,
+ [
+ -1.3958390678662759E-19,
+ {
+ "lh좈T_ë¯Y\"伨\u001cꔌG爔겕ꫳ晚è¸â¿»ìT䯎]~e#฽燇\"5hٔ嶰`泯r;ᗜ쮪Q):/tç­‘,榄&5ï¤ëŽ«ç‹(": [{
+ "2áâ“›]r3C攟וּ9è³µsâ›”6'ஂ|\"ⵈ鶆ä¹ç¦3\"痰ࢤéœäµ©ì˜†äŒ€?æ •r7Oç°‚Isd?K᫜`^è®¶}zî°’8?zì–°î§T:X倫⨎ꑹ": -6731128077618251511,
+ "|︦僰~m漿햭\\Y1'Vvخ굇á‰ì±¢cè¶–": [null]
+ }],
+ "虌魿閆5⛔煊뎰㞤ᗴꥰF䮥蘦䂪樳-Ká·-(^\u20dd_": 2.11318679791770592E17
+ }
+ ]
+ ]
+ ]},
+ "묗E䀳㧯᳀逞GMc\bï•¹å¢¹ã“„ë–Æ &U??íŽŒé‘ åª‹k))ᄊ": null,
+ "묥7콽벼諌J_DɯﮪMæ®´ä£,煚ྼ`Y:ì”§<\/â©«%yf䦀!1á²¶kì¶ŽQç±³W∠WC跉鬽*á›±i<?,l<崣炂骵*?8í‘៣ⰵ憉⎑.,Nwç½£q+ο컆弎": false
+ },
+ "e[|଀+î±³lꑸãˆTT?ë¿¿|ê«›9`㱯䊸楋-곳賨?ì³k棽擋wQ餈âŸNq[q霩䵀뷮锅ꚢ": 5753148631596678144,
+ "sá“鴻߸d렶ὕ蜗ဟ툑!诉౿": false,
+ "|4䕳鵻?䈔(]í‹/Ui#æ¹»{듲ーMá‹€t7潔泄Ch⸨}ì£`î¤èž§éŠšã‹¼å£¯kâ°¥Q戵峉갑xè¾™'ì²›": "jd䘯$䕌茷!auw眶ㅥä£ê†¢æ°‘i",
+ "剖駰Ɜî¶sM2]á¾´2ࡷ祅拌Av狔꩛'ê“—í‚§ê£0酜✘O'": false,
+ "澩뢣ê€eU~D\\ꮡ킠": "v^YC嚈ί\u0007죋h>ã´•L꘻ê€ì“ª\"_gé¿„'#tâ½™?,Wg㥖|D鑆eâ¥ìª¸åƒ¬h鯔咼ඡ;4TKèŽî¾‘졠嫞"
+ }
+ ]
+ ]
+ }
+ ]
+ ]
+ ]}}
+ }
+ ]}
+ },
+ "뿋뀾淣截䔲踀&XJ펖꙯^Xb訅ꫥgá¬>棟S\"혧騾밫ê²7-": "擹8C憎W\"ìµ®yR뢩浗絆䠣簿9äˆå¼•Wcy䤶孖ꯥïž;íŒ]輩ä3@{å 뽸0ï€á¡ˆìµ¡î›„Ⲇ\u001dLåŒê§2F~ݕ㪂@W^é½L襒ᦘî¢~沦zZ棸!꒲栬R"
+ }
+ ]
+ ],
+ "Z:ëƒàµ›5Iz찇䅄駠㭧蓡K1": "e8᧤좱U%?ⵇ䯿é¿\u0013縮R∱骒EO\u000fg?幤îš@֗퉙vU`",
+ "äƒìªˆï‘’埽້=Ij,쭗쓇చ": false
+ }]}}
+ ]
+ }
+ ]}
+ }
+ ]
+ ]
+ ],
+ "咰긖VM]á¼6䓑쇎çºetDÒŒ?ãžê©„퇫밉gj8è ƒ\"â©5䛹1ࣚ㵪": "ക蹊?⎲⧘⾚̀I#\"䈈⦞ë·`wo窭戕෱휾䃼)앷嵃꾞稧,Ⴆ윧9S?೗EMk3Მ3+e{â¹”Te驨7äµ’?타Ulg悳o43ï“¢"
+ }
+ ],
+ "zQᤚ纂땺6#ٽ﹧vï¿¿#ࠫ휊冟蹧텈ꃊʆ?&a䥯Deæ½|ì¿“pt瓞㭻啹^盚2êŠf醪,ì–T窧\\Di䕎谄nn父ꋊE": -2914269627845628872,
+ "䉩è·|㨻ᷢã‰B{蓧瞸`î°²I!℄욃힕#ೲᙾ竛ᔺCjk췒늕貭è¯\u0017署?W딚%(pê⤼ë³^=on뺲l䆼bzrﳨ[&j狸䠠=ᜑꦦ\u2061Õµnj=牲攑)Mî»\\é¾": false,
+ "뎕y絬᫡⥮Ϙᯑ㌔/NF*Ë“.ïž¿,QEzvK!Iwz?|쥾\"ê©»Lê¼—Bê”§è³´ç·œs뉣隤茛>ロ?(?^îµ­`>冺飒=噸泥⺭Ᲊ婓鎔븜z^å·è£®Ãªâ“…à»—jM7ﶕ找\\O": 1.376745434746303E-19
+ },
+ "ä›ræ»–wã¤<k;l8ꡔጵ⮂ny辶⋃í¼åƒ®z\"﮲X@t5෼暧퓞猋♅䦖QCé¹®|픨( ,>,|Nዜ": false
+ }
+ ]],
+ "@ê¿™?è–•å°¬ gd晆(ë„5躕ﻫS蔺4)떒錸ç“?~": 1665108992286702624,
+ "wë¯ná =`঺ᅥC>'從ë槷ä¤çœ·èž„ãŽ»æ°æ‰°XᅧCè´½uáƒë‚ŸjKD03T!lDV쀉Ӊy뢖,袛!终캨G?鉮Q)â‘—1쾅庅O4ê‰H7?d\u0010蠈줘월Þ粯Q!낇껉6í…|{": null,
+ "~˷jg쿤촖쉯y": -5.5527605669177098E18,
+ "펅Wᶺzê†ã¨í‘­e?4j仪열[D<鈑皶婆䵽ehS?袪;Hê¨Më—Žã°[(å—M3qíŸg4y╸鰧茀[Bi盤~ï«å”Žé‹†å½ºî½«â¦Šq?î–³B4쉓癚O洙킋툈䶯_?ퟲ": null
+ }
+ ]
+ ]]
+ ]],
+ "꟱Ԕã¤7æ›ï¦—ಃéŒVä·°?v㪃૦~K\"$%请|ꇹn\"kä«›ã¨é²¨\u2023ä„¢\u0004[<S8á¬ë­©è„¥7U.m࿹:Dè‘┆2蘸^U'w1ì …;䠆ꋪBê»®>︊Vï‹•J?䶟ាꮈ䗱=깘U빩": -4863152493797013264
+ }
+ ]}]}
+ ]
+ }}}
+ ],
+ "ì·ì²Û¹í‰ƒ~aEå”™a챑,9㮹gLHd'ä”|í‚—ãžäŽ¥&KZYTë§µ7䥺N<Hp4ê•­â¹ ê½c~çš½z": "课|á–¾ä¡å»‹è„äªW\u0016&Jnê´b~æ‘“M>â±³åŒèŽžé¿§w\\༌疣n/+ꎥU\"å°ëž¾â—‹íŸ™AJá­Œ?9ä›$?é©”9è®ì§˜é­¡TÖ¯cè—³`虉Cì‡ì¦T"
+ }
+ ],
+ "è°¶ê°œgTRï¿>áµÍšdtæ™‘ä‰‡é™æ»º}9㉸P漄": -3350307268584339381
+ }]
+ ]
+ ]
+ ]]
+ ]
+ ],
+ "0y꟭馋X뱔瑇:䌚ï¿å»¿jîžg-懲鸭䷭垤㒬茭u賚찶ಽ+\\mT땱\u20821殑ã„J쩩䭛ꬿNSæ½”*d\\X,壠뒦e殟%LxG9:摸": 3737064585881894882,
+ "í’µO^-â§§â…¶vѪ8廸鉵㈉רâ†Q㿴뺟EႳvNM:磇>wî·/៻唎뷭୥!냹D䯙iëµ±è²C#⼉NH6`柴ʗ#\\!2ä‚—â±§f?諳.Pëˆ-è¿”I꘶6?8î“ê˜": -8934657287877777844,
+ "溎-è˜å¯ƒi诖ര\"æ±µ\"\ftl,?d⼡쾪⺋h匱[,à·©I8MÒ§F{kç“¿PAî…§'橸ꩯ綷퉲翓": null
+ }
+ ]
+ ],
+ "ោ係Øî½<å…ƒ": 1.7926963090826924E-18
+ }}]
+ }
+ ]
+ ]]}]
+ }]
+ ]
+ ]
+ ]
+ ],
+ "ጩV<\"ڸsOᤘ": 2.0527167903723048E-19
+ }]
+ ]}
+ ]
+ ]],
+ "∳㙰3ì ´pá§—ä±™?`<U὇<\/æ„E[ᮚAî›j诂ᒽ阚uv徢ဎ떗尔ê½í›€ì©‘Jä´?âª=륪ᆩ푰ஓã•?럽VK\"X?檨လ齿I/耉A(AWA~â¯ç¨è¹«": false,
+ "å’å¦ë¾‡}䀼链i⇃%⋜&ç’ªIx渥5æ¶§qq棩á¥-â «AA낇yY颕A*ïˆè£¦O|n?䭬혗F": null,
+ "ç­CLì–­B혆Kॎ`鎃nrî€sZiÕªWç )?p~K~A眱ä²QO妣\u001b\u001b]ᵆᆯ&ã‹á¹è±‰ëº˜$ê­§#j=C)祤⫢歑1o㒙諩": 7028426989382601021,
+ "쳱冲&ဤäŒì•§h胺-é½±H忱8왪RDKᅒ䬋ᔶS*J}ስ漵'㼹뮠9ê±¢9p봋경ጕtởꚳT䶽瘙%ì¶´`@nಆ4<d??#僜ᙤ钴=薔ꭂbLXNam蹈": "樭る蹿= Uî ƒurwkn뙧⌲%\"쑃牪\"cq윕o@",
+ "溌[H]焎SLã…?뀼䫨ç½W": 1.1714289118497062E-19,
+ "ﬢp븇剌燇kĔ尘㶿㴞ç ê¾˜Ia;sâº^)$ç©®?sHᢥíªl": null
+ }
+ ]
+ }
+ ]
+ },
+ "TKnzj5o<\/K㊗ꗣ藠⦪駇î€>yZA8Ez0,^á™›4_0븢\u001ft:~䎼s.bb룦明yNP8弆Cå¯;⪾ì§'蕴뮛": -6976654157771105701,
+ "íµê¦€\\㇑:nî‹™v+뒤燻䀪ﴣï·9ᚈ኷K㚊誦撪䚛,ꮪxሲ쳊\u0005HSf?asg昱dqꬌVꙇ㼺'k*'㈈": -5.937042203633044E-20
+ }
+ ]
+ }],
+ "?}\u20e0],så¶³è‹@#2uì’´sQSä©—=ꥮ;烌,|ꘔ䘆": "á…©ì˜Nç’ kZ먕眻?2ቲ芋眑D륟渂⸑ﴃIRE]å•—`K'"
+ }},
+ "쨀jmV賂ﰊå§ä‚¦çŽžã¬™áªM᪟ïՎ씜~`uOn*ॠ8\u000ef6??\\@/?9見d筜ﳋB|Sä¬è‘«ã½o": true
+ },
+ "즛ꄤ酳艚â‚㺘봿㎨iGà§•à¡¿?1\"䘓您\u001fSáŠâº¿æºzៀ뻤B\u0019?ìœa䳵᭱䉺膷d:<\/": 3935553551038864272
+ }
+ ]
+ ]}
+ ]]
+ ]]
+ ]}
+ }
+ ]
+ }
+ ]]}},
+ "᥺3h↛!ê‹°y\"攜(ெl䪕oUkc1A㘞ᡲî촾ᣫ<\/ä’ŒEã›æ½¨i{ï  v?Wà±¾H\\RჅpzè¬R脾;v:碽✘↯삞鷱o㸧瑠jcmK7㶧뾥찲n": true,
+ "ⶸ?x䊺â¬-ä°…â‰!e쩆2ꎿ准G踌XXᩯ1ß}0?.í—€Z馟;稄\baDꟹ{-寪⚈ꉷ鮸_L7ƽᾚ<\u001bጨA䧆송뇵⨔\\ç¤ë—”d设룱㶉cq{Hyã±R㥽å¢ï¬…p": -7985372423148569301,
+ "ç·«#ì½®IB6<\/=5Eh礹\t8럭@饹韠r㰛斣$ç”LVì·a갵îŸ'请o0g:^": "䔨(.",
+ "ë³â„¡åœ¤pï¾à¯„Ä倧訜BìŸGä™”\"Sbâ“®;$$â–S1J뢙SF|赡gï„€*\"Vu䲌y": "䪈&í‹),\\kT鬜1í’¥;ë·´'Zေ䩹@Jéž½Nã¼M?å¥eWb6榀ƩZڮ淽⺞삳煳xჿ絯8eâ¶ç¾·V}ჿ쎱䄫R뱃9Z>'\u20f1â“•äœé½®"
+ }
+ ]
+ ]]]
+ }}
+ }
+ ]
+ ]},
+ "펮b.hç²”í¯2npXè©«g錰鷇㇒<ì™S値bBi@?镬矉`剔}c2壧ଭfhY깨R()痩⺃a\\â”?M&ﯟ<劜꺄ï‘멊ᄟA\"_=": null
+ },
+ "~æ½¹Rqn榢㆓aR鬨侅?䜑亡V_ç¿…ã­”(ä“·w劸á³Dp䀅<\/ï°Žé¶Šm䵱팱긽ꆘ<tD쇋>긓准D3掱;o:_Ñœ)껚콥8곤d矦8nP倥ꃸI": null,
+ "뾎/Q㣩㫸벯➡㠦◕挮aé¶§â‹“å¼\u00001뱓fm覞n?㛅\"": 2.8515592202045408E17
+ }],
+ ",": -5426918750465854828,
+ "2æ««@0柡g䢻/gꆑ6演&D稒肩Y?艘/놘p{f투`飷ᒉ챻ëŽîª–<늛ä˜ï´¡ì¤°ì«„": false,
+ "8î™–(鸑嵀⵹ퟡ<9㣎Tߗ┘d슒ل蘯&㠦뮮eà kç g ì—»": false,
+ "d-\u208b?0ﳮ嵙'(J`蔿d^踅⤔榥\\J⵲v7": 6.8002426206715341E17,
+ "ཎ耰í“ê•ï’ã±·\u0013y=詽I\"盈xm{0쾽倻䉚ષso#é°‘/8㸴짯%ꀄ떸b츟*\\鲷礬ZQå…©?np㋄椂榨kc᡹醅3": false,
+ "싊j20": false
+ }]]
+ ]],
+ "ä¿›\u0017nç·½Tu뫉èœé¼Ÿçƒ¬.ï‘ꭠIâ°“\"Ἀ᜾uC쎆J@å¤%ê›m뻨ᾀ画è›íœƒT:錖㑸ዚ9죡$": true
+ }
+ ]
+ ],
+ "ãµâ‡˜ê¦–辈s}㱮慀밒s`\"㞟j:`ií”»Z<C1衽$\"-饧?℃\u0010⼒{î°p飗%R\"ä²”\")ì¹€\\%": true,
+ "苧.8\u00120ݬ仓": 6912164821255417986,
+ "ë–Žé¡£ä¿X;.#Qí‹.笂'p쟨唒í랩냆¦aâ±{è°.b我$蜑SH\u000fç¾=äŸ¼â£¼ï©¿áœæ”•B&挰繗ã”ê…‚-Qv\\0ä¶äš¥ãºio[㑮-ᇼ䬰컪ṼiY){ë°\u0010q螰掻~\n輚x\u0014罺)è»´": 3.024364150712629E-20
+ }
+ ]
+ ]
+ ]
+ ]}
+ ]]
+ }
+ ]
+ ]]
+ ]
+ ]]]],
+ "\"凲o肉Iz絾豉J8?i~傠᫽䇂!Wï›—D溊J?á¡’vsè†åµ¹âž’ïŸæ·´î‡…>ì„«^諎0Ok{켿æ­à·£èƒ°a2﨤[탳뚬쎼嫭뉮m": 409440660915023105,
+ "w墄#*ᢄ峠밮jLa`ㆪ꺊漓Lã§ëŽ!Agkï¹ï¾'ê›ë¢ƒã¯å²¬D#ã’¦": false,
+ "ଦPGI䕺L몥罭ꃑ궩﮶#⮈ᢓӢ䚬p7웼臧%ï‘¥~Sè âŒíž€6îž’&t䳙y㪘ëƒ\\*;é‰ï¿Šé¿µ'å—•pa\"oL쇿꬈Cgî“": "ã¶½1ç¸D⟸䴅ᆤ뉎﷛渤csî¸x ä”цꬃ锚æ¬?ຽ+x~꘩uI࡞\u0007æ ²5呚ẓem?è¢\")=㥴䨃pac!/æŽY",
+ "á·±o\\||뎂몷r篙|#X䦜I#딌媸픕åžRDæ–³X4t⯩夬=[ï‹ë­²r=绥jhë·±ì¸âª˜%]⚋܈㖴スHí…¹m(WOæ›åЉ0~K3c柢Õã‰ïªªé€³~": false,
+ "ç…½_qb[첑\\륌wEâ½Ztï”´CNï­+餌ᕜOê›­": "{ﳾ쉌&s惧á­âµ†3䢫;䨞팑ï›ê’ªí˜è¤€à¢–Qä ¿V5뭀䎂澻%ë°›u5í…¸oA⮥U㎦;B䳌wzä•™$áž¿\\௅婺ëµâª¾í†\\`Kyौꋟ._\u0006L챯l뇠Hi䧈å’5",
+ "艊ä½à£ƒë¡‡ä± çˆ¬ï˜‚!*;⨣æŽïžæ…“qé“|儑ᨋL+è¿¥=6㒺딉6弄3è¾…J-㕎뛄듘SG㆛(\noAzQê±ä°©X*ã¢O퀌%펠낌moí‹®a^<\/F&_눊ᾉ㨦ы4\"8H": 2974648459619059400,
+ "鬙@뎣䫳á®ë¡?){y?5K;î§„TA*k溱䫜J汃ꂯ싔ì\u001dA}룖(<\/^,": false,
+ "ëª@QꋦFꊩá’뎶î‡lXl垨4î¤^郣|ꮇ;ä´á“}ìµ²zç–": null
+ }
+ ]]]],
+ ":_=ë‹§å¼—D䙋暨é›. 㱻붘ä‚Jå„’&ZK/녩䪜rå›â½¯D喠죥7ï“⹌䪥c\u001a\u2076￞妈朹oLkè®F౟覛ì§ã®7T;}è›™2{9\"å´“bB<\/⡷룀;즮鿹)丒툃୤뷠5W⊢嶜(fb뭳갣": "E{å“1WM"
+ }},
+ "䘨tjJ驳豨?y輊M*᳑梵瞻઻ofQG瑮e": 2.222802939724948E-19,
+ "ä®´=â‘âž¶Tà·‹wäžœ\"垦ꃼUt\u001dx;B$뵣䙶E↌艣ᡥ!á§Ÿ;ä±€[䔯k쬃`à©8饙른ç†î‹”'2_'袻tGfè’­J땟as꯳╖&å•’zWࡇᒫYSá¬\u0014ℑ첥鈤|cG~Pá“®\">\"": "ႆl\f7V儊㦬nHꄬꨧC{ì¢~C⮃⛓嶦vꄎ1w鰠嘩뿠魄&\"_qMâµ–é‡”ë…®îœ¡ê‡ ãš{ç³Jå“‹ cî°¸v?-jkﻯྌ鹑L舟r",
+ "龧葆yB✱H盋夔ﶉ?n*0(": "ꧣኆ㢓氥î³qZZ酒ຜ)鮢樛)X䣆gTSî»»Ò‘Gí…žï’˜k.J圬ç–ë¡«ïœì¯­z L:\\ྤ@w炋塜쿖ᾳy뢀䶃ë±N䥨㚔勇ê²#p",
+ "ë„畎Q娡\"@S/뼋:äµ!Pè¡…ì´šfVHQs✜á«i㻑殡B䜇%믚k*U#濨낄~": "êŸá‹•ì³¸êˆæ•‹&lå¦\u0005憡멗瘌uPgá…ªm<\/To쯬锩h뒓k"
+ }
+ ]
+ }],
+ "墥홞r绚<\/⸹ⰃB}<躅\\Y;๑@䔸>韫䜲뱀X뗩鿥쩗SI%ﴞ㳕䛇?<\/\u00018x\\&侂9é‹™a[LRã‹­W胕)â¡¿8ãž™0JF,}?í—ˆd1cDMáƒâ›é„ⱕ%X)!XQ": "â³ê—³=橇a;3t⦾꼑仈î¥á€°aᚯ⯋ꕃAsé´·Nâ•_䎃ꙎAz\u0016䯷\\<à¿«>8q{}ï½·?ᣰ}'0ᴕ펓B┦lF#趤厃T?㕊#撹圂䆲"
+ },
+ "Ü‹ë‹é¾«ï¥c웑": false,
+ "ㇿ/q\"6-co髨íœCí¦#\u001b4~?3ä¹E삇<<": 7.600917488140322E-20,
+ "äE6?㣖êƒé—´t祗*é‘ {ḣV(æµ¾h逇íž=W?ૉ?nꇽ8ꅉຉj으쮺@Ꚅ㰤u]Oyr": "vâ‰á«¸_*όAඤԆl)ۓᦇQ}í zà¼q滚",
+ "ソ᥊/넺I": true
+ }]]
+ ]
+ ]
+ ]
+ ]]
+ },
+ "䭑Ik攑\u0002QV烄:芩.麑㟴㘨≕": true,
+ "å„꿕C쇻풉~å´%碼\\8\"䬦꣙": null,
+ "欌L圬䅘Y8c(♺2?ON}o椳s宥2䉀eJ%é—¹rå†O^K諭%凞⺉⡻,掜?$ꥉ?略焕찳㯊艼誜4?\"﯎<ï±ã‚›XáˆINT:è©“ +": -1.0750456770694562E-19,
+ "ç’àc뜭싼ﺳ뎤K`ïŸ]p隨LtE": null,
+ "ç”™8䵊神EIꩤé¯á¢€,ïµ®Uä‘u疒ử驺䚿≚ഋ梶秓F`覤è­#짾蔀묊4<åªì¬¦éª_Yzgcà¡¶î²§4kç´¥`kc[Lï®—î°£ç°*I瀑[â¾°L殽鑥_mGÈ <\/|囹ç gæ¡°iri": true,
+ "챓ꖙꟻì¢è‡ou,å— 0\\jK핻뜠qwQ?ഩ㼕3Y彦b\u009bJ榶N棨f?ë¦é–綃6é³µM[OEë´¨uí–.Ꮁ癜蟳뽲ꩌ뻾rM豈Rï¨ç¾« uDꎚ%": null
+ },
+ "V傜2<": 7175127699521359521
+ }],
+ "é“«aG切<\/\"ী⊆e<^g࢛)Dé¡ï½Žï¬®é¥¼\u008c猪繩嵿ﱚCꡬ㻊g엺Aì—¦\u000fæš¿_f꿤ë³ã¦•桦`蒦䎔j甬%å²rj ç³": "䚢åŽëˆ´Au<4箞7礦Iï±”å eȧ䪸uï„€äµp|逹$嗫쨘ꖾï·!胠z寓팢^㨔|u8Nሇe텔ꅦ抷]،鹎ã³#༔繁 ",
+ "낂乕ꃻ볨ϱ-ꇋã–fsâ¿«)zꜦ/K?솞♞ꑌ宭hJ᤭瑥Fu": false,
+ "쟰ãœé­›G\u0003u?`㾕ℾ㣭5螠烶這趩ꖢ:@å’•ê¶xë’˜ëŠmä°¨bç—ƒë 0鳊喵熬딃$摉_~7*ⱦ녯1錾GKhJ惎秴6'H妈Tᧅ窹㺒疄矤铟wላ": null,
+ "쯆q4!3錕ã²âµ†ã‡›ê˜·Zç‘©ë­†\\â—ªNH\u001d\\ã½°U~㯶<\"쑣낞3ᵤ'峉eꢬ;鬹o꣒木X*é•·PXᘱu\"ä ¹n惞": null,
+ "ᅸ祊\"&ꥴCjࢼ﴿?䡉`U效5殼㮞V昽êª#ﺸ\\&t6x꠹盥꣰a[\u001aêªSpe鎿蠹": -1.1564713893659811E-19
+ }
+ ]]
+ ]
+ ]
+ ],
+ "羵䥳H,6ⱎ겾|@t\"#í–Šî¦1|稃 ì„­)ëœ=뻔ꡜ???櫎~*ῡ꫌/繣ﻠq": null
+ }
+ ]}
+ ]},
+ "츤": false
+ }},
+ "s": 3.7339341963399598E18
+ }
+ ],
+ "N,I?1+㢓|ࣱ嶃쩥V2\u0012(4EE虪朶$|w颇væ­¥": "~ì¢~_,Mzrã«YB溓Eæ·š\"â…¹äˆ”áºæŠ™ b,nt5Vã’J檶ê¨â»”?",
+ "Q껑ꡡ}$넎qHç…”æƒ/ez^!ẳF댙äŒé¦»å‰8": "梲;yté’°$i冄}Aî‘”L%a jëœå¥·ê±³ëš¾d꿽*ሬuDY3î…—?뮟鼯뮟wãªí‹±îŸ‚V",
+ "o{Q/K O胟ãzUdê€m&⨺J舕â¾é­¸è¨ŸãŒ¥[T籨櫉å”í‚ aṭ뱫촙莛>碶覆⧬짙쭰ׯdAiH໥벤í¥_æ¸[ 0î­¬e:죃TCå¼¼èŽëµDA:w唵ê£": null,
+ "á½æ¨Žäµ®è»§|?à±—aWH쩃1 ê…­su": null
+ }
+ ]
+ },
+ "勂\\&m鰈J釮=Ⲽ鳋+䂡郑": null,
+ "殣b綊倶5㥗惢⳷è¢á‘€ä¬„é•§M^ï±´3⣢翣næ«»1㨵}ኯ뗙顖Z.Q➷ꮨ뗇\u0004": "ê”™ä¼>n^[GीA䨟AMç¢á’ŠS쨲w?d㶣젊嘶çºéº“+æ„£a%気ྞScë“ᔘ:8bM7Xd8㶑臌]Ꙥ0ê­ì’™ä«£æŒµCè–½î€Dfⵃ떼᷸",
+ "?ç´¡.ì…ª_à·¨j\u0013Oxâ” $Xᶨ-á…‡oè–¹-}軫;yæ¯ãªœKã£?.EVì®±4둽⛻䤜'2盡\u001f60(|eì°ã¼Žá¦€ã’§-$l@ﻑå³\u0003ä­±å“å·—WFo5c㧆Tí„Y맸♤(": -2.50917882560589088E17
+ }}
+ ],
+ "侸\\릩.᳠뎠狣살cs项䭩畳H1s瀉븇19?.w骴崖㤊h痠볭㞳㞳ä®Ql怠㦵": "@䟴-=7f",
+ "鹟1x௢+d ;viä­´FSDS\u0004hꎹãš?â’â¦Ñž6u,扩@ë·Su)Pag휛Tá’—Vç—©!çžé‡€ê–žè˜¥&ೞè˜ê­°êž‡áŽ": "ah懱Ժ&\u20f7䵅♎඀䞧鿪굛ౕ湚粎蚵ᯋ幌YOE)५襦ãŠY*^\"R+ඈî¶å’·è¶9î—ꥂ榨艦멎헦é–ë¶v좛咊E)K㓷ྭr",
+ "æ†q쮦4綱켙ì….f4<\/g<籽늷?#蚴픘:fF\u00051㹉뀭.á°–í’ŽfÖ¦Hv蔎㧤.!ä­½=éž½]ìŒH:?\"-4": 8.740133984938656E-20
+ }]}
+ }
+ ],
+ "tVKn딩꘥⊾蹓᤹{\u0003lR꼽ᄲQFá…傅ﱋ猢⤊á”,E㓒秤nTà¶­v`â™›I\u0000]꫔ṞD\"麵cè¸î“²æ°X&æ¿¿ë˜ê£¹ê¹³à±¥è‘‚鿎\\aꡨ?": 3900062609292104525
+ }
+ ],
+ "ਉ샒⊩Lu@S䧰^g": -1.1487677090371648E18,
+ "⎢k⑊꬗yá«7^err糎Dt\u000bJç¤¯í™•ã†æ²‘サꋽeèµ”ã¢^J\u0004笲㿋idra剰-᪉C錇/Ĝ䂾ညSì§€?~ì½®gR敉⬹'ä§­": 1901472137232418266,
+ "ç—kä¶¥:?ì´½è´ì“‰ê“ˆã’¸gç˜[뵎\\胕?\u0014_榙p.j稶,$`糉妋0>Fá¡°ly㘽$?": "]ê™›O赎&#ã ƒë±å‰³î°·\"<â—†>0誉é½_|z|裵씪>áŒã¼\"Z[ç•}O?G뚇諦cs⠜撺5cuç—‘U圲\u001c?鴴計lì¶¥/╓哼䄗èŒîšªê®…뫈댽AëŒë¡–뤫V窗讬sHd&\nOi;_î´–u"
+ }
+ ],
+ "Uﺗ\\Y\\梷䄬~\u0002": null,
+ "k\"Y磓ᗔ휎@U冈<\/w컑)[": false,
+ "æ›Jè·âŒ»ë¦\u001f㙳s꥓âŸé‚«P늮쥄c∬ྡྷ舆렮칤Zè¶£5콡넛A쳨\\뀙骫(棻.*&è¼›LiIfi{@EA婳KᬰTXT": -4.3088230431977587E17
+ }]}
+ ]
+ ],
+ "곃㲧<\/dఓꂟs其ࡧ&N葶=?c㠤Ჴ'횠숄臼#\u001a~": false
+ }
+ ]
+ ]}]
+ }]
+ }}
+ ],
+ "2f`â½°E쵟>Jî•笂裭!〛觬囀ۺ쟰#桊l鹛ⲋ|RA_Vxá­gEë“h﵀mfá»|?juTUæ¡£[d⢼⺻p濚7E峿": 5613688852456817133
+ },
+ "濘ë¶gå¿®7ãµæ®¬W팕Qæ› ë«°)惃廊5%-î«è¹šzYZ樭ﴷQ锘쯤崫îŸgg": true,
+ "絥ᇑâ¦ì’“븣爚H.ã—Šß„o蘵貆ꂚ(쎔O᥉î¼ï®“]姨Wê“!RMA|o퉢THxè½®7Mê»U즨'i뾘舯o": "è·¥f꜃?"
+ }}
+ ],
+ "é·°é¹®K-9k;ï°°?_ݦѷ-ꅣ䩨Zꥱ\"mꠟ屎/콑Y╘2&鸞脇ã¢ê€‡à ºâ°¼æ‹¾å–­í‹®îL꽩bt俸墶 [l/웄\"꾦\u20d3iও-&+\u000fQ+໱뵞": -1.296494662286671E-19
+ },
+ "HX੹/⨇୕붷Uﮘ旧\\쾜͔3l鄈磣糂̖䟎Eá³wæ©–bá¿€_딕huè‘°î¤çª³é—¹Ð²U颵|染H죶.fPä—®:jä«¢\\b뎖i燕ꜚGâ® W-≚뉗lè¶•": "ଊ칭Oa᡺$IVã·§L\u0019脴셀붿餲햪$迳å‘ì¯ì¼‚PqfT\" ?î¹€I屉鴼쿕@ç¡™z^é•㊵M}ãš›T젣쓌-Wâ©-g%⺵<ë®±~빅╴瑿浂脬\u0005왦燲4áƒb|Då § <\/oEQh",
+ "䘶#㥘à©îººìº”ï” f巋ἡAJ䢚쭈ࣨ뫒*mᇊK,ࣺAꑱ\u000bR<\/A\"1a6鵌㯀bh곿w(\"$ê˜*rà²è¶£.dà¿©k/抶면䒎9W⊃9": "漩b挋Swè—Ž\u0000",
+ "畀e㨼mK꙼HglKb,\"'䤜": null
+ }]}]
+ ]
+ ]
+ }]
+ ]}
+ ]
+ ]}
+ ],
+ "æ­™>駿ꣂ숰Q`J΋方樛(d鱾뼣(ë«–í„­\u20f9lচ9æ­Œ8o]8윶lì–¶?é•–G摄탗6í‹íµ+g:䱫홊<멀뀿/س|ê­ºsê±è·¶ç¨šW々c㫣⎖": "㣮蔊깚Cꓔ舊|XRfé»ã†šï¸†'쾉ì·\\&言",
+ "æ®­\"cÞɨê™äž˜:嬮eæ½½Y펪㳅/\"O@à —ê²´]ì·–YÇž(t>R\"N?梳LDæ­=næ°¯Tè±°2R諸#N}*ç§ï¡§4}ã¶ŠGä£bì–š": null,
+ "襞<\/å•§ B|싞W瓇)6簭鼡艆lNì©`|펭佡\\é–“é‚[z릶&쭟愱ꅅ\\Tá°½1靝忠ˆ4̸s윜R7â’/똽?치X": "âŠèº–Cﱰ2Qẫè„&இ?%ëƒæ‚Š",
+ ",é°§åµì…£îˆ›ì‹¹xᎹ힨᯳EṬHïŽã¹–9": -4604276727380542356
+ }
+ }
+ ]]]],
+ "웺㚑xs}q䭵䪠馯8?LB犯zK'os䚛HZ\"L?셎s^㿧㴘Cv2": null
+ }]
+ ]
+ ]
+ ],
+ "Kdî©´2Kv+|z": 7367845130646124107,
+ "ᦂⶨ?ᢠ祂些ഷ牢㋇æ“\"腭䙾㖪\\(y4cE뽺ㆷ쫺ᔖ%zfÛ»$Ñž1柦,ã¶¢9r漢": -3.133230960444846E-20,
+ "ç˜Mç„€q%㢟f鸯Oâ£è“‘맕鯊$Oå™·|)z褫^㢦⠮ꚯ꫞`毕1qꢚ{ĭ䎀বώT\"뱘3G൴?ï¢ï¢^^oï…¯f": null
+ }
+ ],
+ "a8V᯺?:ﺃ/8ꉿBq|9啓댚;*i2": null,
+ "cpT瀇Hç°á»ªpೃi鎪Rrâ£ìˆ¬-鹸ҩ䠚z脚цGoN8å…¥y%è¶ŒI┽2ឪЀiJNcN)æ§£/â–Ÿ6S숆牟\"箑X僛G殱娇葱T%æ»:J諹昰qV쨰": 8331037591040855245
+ }],
+ "G5ᩜ䄗巢껳": true
+ }
+ },
+ "Ồ巢ゕ@_è­™A`碫é„㡥砄㠓(^K": "?܃B혢▦@犑ὺD~Tâ§|é†;o=J牌9냚⢽㨘{4è§èš”9#$∺\u0016p囅\\3Xk阖⪚\"UzA穕롬✎âžã­’춺C㣌ဉ\"2瓑员ᅽê¶ë«}꽚ꞇ鶂舟彺]ê½JCè§éЉ",
+ "â†Äšè†\"b-í‰ACR言J謈53~V튥x䜢?ꃽɄY뮩ꚜ": "K/↾eèƒ}]Bs⾿q룅鷦-膋?m+æ­»^魊镲6",
+ "粡霦cæž‹AHíŸo礼Ke?qWcA趸㡔ê‚?\u000eì¶‚8iতᦜ婪\u0015㢼nﵿê»!á´é–¢\u001d5j㨻gfá¿©UK5Juä¸tã‹TI'?ã“t>⼟o a>i}á°—;뤕Ü": false,
+ "ꄮ匴껢ꂰ涽+䜨B蛹H䛓-k蕞fu7kLè°–,'涃V~챳逋穞cT\"vQ쓕ObaCRQã“¡â²®?轭⫦輢墳?vA餽=h䮇킵ní²í‰…喙?\"'1ç–¬V嬗Qdç—'Lự": "6v!së¯ã­Ÿî€µî¦˜ã£¯çƒ!磸餠ቂh0C뿯봗Fé·­gê–¶~コkK<ᦈTtïŽ\\è·“w㭣횋钘ᆹ듡䑚W䟾X'ê…”4ï€FL勉Vܴ邨y)2'〚쭉⽵-鞣E,Q.?å—",
+ "?(˧쩯@å´Ÿå‹æ­„K": null
+ },
+ "Gc럃녧>?2DYIé´¿\\륨)æ¾”0ᔬlx'è§”7젘⤡縷螩%Sv׫묈/]↱&S ï…h\u0006æ­‹á‘›xi̘}ã²Y蔯_醨鯘煑橾8?䵎쨋z儬ê*@츾:": null
+ }
+ }
+ }
+ ]
+ ]
+ ]}
+ },
+ "HO츧G": 3.694949578823609E17,
+ "QC\u0012(翻曇Tfã·ŸbGBJ옉53\\嚇ᛎDï–/\u001b夾á‰4\"í•€@祎)쫆yD\"i먎Vnî¿ã¿¿V1Wá¨ä¶€": -6150931500380982286,
+ "Zã“®P翸é±é‰¼K䋞꘺튿â­Y": -7704503411315138850,
+ "]모开ꬖP븣c霤<[3aΠ\"é»ä––䰑뮋ꤦ秽∼㑷冹T+YUt\"싳F↭ä–&鋌": -2.7231911483181824E18,
+ "tꎖ": -4.9517948741799555E-19,
+ "䋘즊îŽ.⬅IꬃۣQ챢ꄑé»|f?C⾺|å…•ì¯sC鬸섾整腨솷V": "旆柩l<Ké«î–žM戶鯮t:wRî°2ꉱ`9'l픪*í芦㊢Pjjoå ¡^ ì‡ì–›å¶…있ষ0?F",
+ "下9T挞\\$yᮇk쌋⼇,ਉ": true,
+ "櫨:ㆣ,é‚lî ¬r崕祜ã®çƒœZ,XXD蕼㉴ kM꯽?P0﹉릗": null,
+ "îŠgv솠歽閘4镳䗄2æ¾¾>쪦sá–¸My㦅울ì‰ç˜—㎜檵9ï……ê‚駓ૉᚿ/u3ì”…å¾ï¤¥[Z䞸ࡗ1ꆱ&Q풘?Ç‚8\u0011BCDY2볨;é¸": null,
+ "幫 nç…¥sì‡íއ 왊-$C\"è¡:\u0014㣯舼.3ë™—Yl⋇\"K迎멎[ê½µs}9鉳UK8ì¥\"掄㹖h㙈!얄સ?Ꜳ봺R伕UTD媚I䜘Wé¨è”®": -4.150842714188901E-17,
+ "ﺯ^ã„„\b죵@fྉkf颡팋î¤êž¦{/Pm0V둳⻿/è½éŸ’ꊔᚬ@5螺G\\å’¸a谆⊪ቧ慷绖?è´¢(é·‡uéŒF=ráæ©¢áž³n:^iá´µtD볠覅Nèµ´": null
+ }]
+ }]
+ }
+ ]
+ ]}
+ ]},
+ "謯?w厓奰Tï§¡í——èážè²–o⪇弒L!캶$ᆅ": -4299324168507841322,
+ "뺊奉_åžæµ¸å»¶ëªå­„Z舰2i$q붿좾껇d▵é¤\"v暜Ҭì„mï¿´g>": -1.60911932510533427E18
+ }
+ ]
+ }
+ ]
+ ]],
+ "í‰êº”㠦楶Pê…±": 7517896876489142899,
+ "ï™°": false
+ }
+ ]},
+ "是u&I狻餼|è°–j\"7cë®sï­-踳鉷`䣷쉄_A艣鳞凃*m⯾☦椿q㎭Nîœæº”铉tlㆈ^": 1.93547720203604352E18,
+ "ï…µkⲨ\\%vr#\u000bâ’ºY\\t<\/3﬌R訤='﹠8è¤êž´ë ´æ›”r": false
+ }
+ ]},
+ "阨{c?C\u001d~K?鎌Ԭ8烫#뙣Pì´ˆé—tã­±E­ë’䆺}ç”—[R*1!\\~hã•…á°º@<9JêષIä³–æ ­6綘걹ᅩM\"▯是∔v鬽顭⋊譬": "ìš´ï¶Kæ•‚(欖C취پ℄爦賾"
+ }
+ }}
+ }],
+ "鷨赼鸙+\\ä­£t圙ڹx᜾ČN<\/踘\"S_ë§¶a鷺漇T彚⎲i㈥LT-xA캔$\u001cUH=a0츺l릦": "溣㣂0æ¿•=鉵氬駘>Pꌢpb솇쬤h힊줎çªãª¬CrQ矠a&è„꼬爼M茴/á¿®\u0017å¼è½¼y#êž c6ë‘´=?Rå´ë· éº–w?"
+ },
+ "閕ᘜ]CT)䵞l9z'xZF{:ØI/躅匽ì¡:䟇AGF૸\u001cퟗ9)駬慟ꡒꆒRS״툋A<>\u0010\"ꂔ炃7gëšEà§îˆbꅰ輤]oã±_뷕ܘ暂\"u": "芢+U^+㢩^鱆8*1鈶鮀\u0002뺰9⬳ꪮlL䃣괟,G8\u20a8DF㉪錖0ㄤ瓶8Nଷd?眡GLc陓\\_죌Vì°à¤²äºŒ?cë¦æ± \u0019JC\u0011b⤉zẒT볕\"绣蘨뚋cꡉkî« I\u001eé³´",
+ "ꃣI'{6u^㡃#཰Kq4逹y൒䧠䵮!㱙ï®/n??{Lí’“ZETã™ í¿X2᩟綳跠葿㚙w཮x캽扳B唕S|å°¾}ì´•%N?o䪨": null,
+ "ⰴFjà·Ÿì…ˆ[\u0018è¾·px?椯\\1<ﲻ栘á£ë´¢æ† ë‰´p": -5263694954586507640
+ }
+ ]
+ ]]
+ ]}
+ ]}]
+ ]
+ ],
+ "?#癘82禩鋆êŠty?&": -1.9419029518535086E-19
+ }
+ ]
+ ]
+ ]}
+ ]
+ ]
+ ],
+ "훊榲.|῕戄&.ãšZꛦ2\"䢥ሆ⤢fV_æ‘•å©”?â‰Fji冀탆꜕iã¬_ẑKᅢ꫄蔻XWc|饡Siẘ^㲦?羡2ã´1ç¸á™…?ì‰Ou": false
+ }]]
+ ]}}},
+ "æ…‚ë—„å“è“”á“åŒåš–/颹蘯/翻ㆼL?뇊,í…µ<\\ç·ã”Cボ": null
+ },
+ "p溉ᑟi짣z:䒤棇r^٫%G9缑r砌롧.물农g?0׼ሩ4ƸO㣥㯄쩞ጩ": null,
+ "껎繥YxK\"F젷쨹뤤1wq轫o?鱑뜀瘊?뎃hç‘\\ꛣ}Kå³^ኖâ¤ï§´ê‰“hy": null
+ }
+ ],
+ "á±€nè‚“ã„›\"å »2>mæ®®'1橌%êž´êµ°=Ӳ鯨9耛<\/n據0u彘8㬇៩fá¿è¯™]嚊": "䋯쪦S럶åŒã…›#î½)O`ሀX_éªæ¸²â›€ã¨»å®…闩➈ꢙஶDRâª"
+ },
+ "tAì“龇 â‹¥bj왎录r땽✒롰;羋^\\?툳*┎?ì€ma䵳넅U䳆૘〹䆀LQ0\bç–€U~u$M}(鵸gï­â³¾i抦뛹?䤈땚검.鹆?ê©¡tâ¶¥GÄ’;!ቹHïš©Så³»B츪ì¼f5≺": 2366175040075384032,
+ "ì „pJjleb]áž½": -7.5418493141528422E18,
+ "n.鎖ጲ\n?,$䪘": true
+ },
+ "欈Ar㉣螵᪚茩?O)": null
+ },
+ "쫸M#x}Dç§±æ¬K=侫们ä¸ï‡ª.KꕾxẠ\u001e㿯䣛FÜ캗ï¬qq8꟞ṢFD훎⵳簕꭛^鳜\u205cÙ«~⑟~冫ऊ2ì«°<\/戲윱o<\"": true
+ },
+ "ã·è¥/T뱂\u0010锕|内䞇xä¾â‰¦ã­–:M?iM᣿IJeç…œdG࣯尃⚩gPt*辂.{磼럾äª@a\\袛?}ᓺBç¼": true
+ }
+ }
+ ]]}]}},
+ "tn\"6î´ê«¤ìƒ¾ä„„;銞^%VBPwu묪`Y僑N.↺Ws?3C⤻9唩Sä ®á´m;sᇷ냞඘B/;툥B?lB∤)G+O9m裢0kC햪䪤": -4.5941249382502277E18,
+ "áš”t'\\æ„«?éµ€@\\ã³ê‚•Pí <<]ç…¹G-b!S?\nꖽ鼫,Ý›&é ºy踦?Eæ†î¬–릱H}햧캡b@手.p탻>췽㣬ꒅ`qeä½­P>á“‚&?u}毚ᜉ蟶頳졪áŽzl2wO": -2.53561440423275936E17
+ }]}
+ }
+ ]
+ ]],
+ "潈촒⿂å¡": 5495738871964062986
+ }
+ ]]
+ }
+ ]
+ ]}
+ ]]
+ ]]
+ ]}
+ ]
+ ]},
+ "á‚qí‚è“…R`謈èŸá¦î’³å„‚æ§åƒ»ï¹¶9å©Œî¬æ«žé‡ˆ~\"%匹躾ɢ뤥>࢟瀴愅?殕节/냔O✬H鲽엢?ᮈà©î“Žâ‹§dâ½ã«zCe*": 2.15062231586689536E17,
+ "ã¶µUi曚ç°é‹ªá¾¼è‡§P{ä䷪쨑̟A뼿T渠誈äšD1!ìž¶<\/ã¡7?)2l≣穷᛾ç¨{:;㡹nemיּ訊`Gî¹²": null,
+ "䀕\"飕辭påœf#뫆䶷뛮;â›´á©3çšëá°ìŽ“â¦·è©µ%᜖Մfs⇫(\u001e~P|ï­—CⲾផv湟W첋(텪બTî¾·<บSê‰à©—⋲X婵i ӵ⇮?L䬇|êˆ?졸": 1.548341247351782E-19
+ }
+ ]
+ },
+ "t;:N\u0015qé¦Rt缆{ê®C?஛㷱敪\\+鲊㉫㓪몗릙ç«(æ°µkYS": "Xá°‚T?൮ô",
+ "碕飦幑|+ 㚦é¶`é•¥ê© B<\/加륙": -4314053432419755959,
+ "秌孳(p!G?Vå‚«%8ሽ8w;5鲗㦙LI檸\u2098": "zG N볞䆭éŽí˜\\ONK3íš™<\/樚立圌Q튅k쩎Ffì‹aׂJK銆ઘì¦ç‹©6༥✙䩜篥CzP(è»é§‡HHퟲ讃%,ά{ë p而刲vy䦅ክ^톺M楒é¢ã¹³]Mdg2>䤉洞",
+ "踛M젧>忔芿㌜Zk": 2215369545966507819,
+ "ì”A`$æ§­é °í»^U覒\bG毲aᣴU;8!팲f꜇E⸃_åµ{å«ç¾ƒX쀳C7ë—®m(åš¼u NÜè°ŸD劯9]#": true,
+ "ﻩ!뵸-ç­šPá­›}á¼°å±¥lPh?౮ⶹꆛ穉뎃gè‘㑓溢CX뾇Gã–¬A錟]RKï’î´²aꄘ]Yo+@ä˜'s섎襠$^í™°}F": null
+ },
+ "粘ꪒ4HXᕘ蹵.$å€\r\u001dë¬77pPc^yî¶ç¬²Q<\/ê–¶ è¨äƒá¨•G?*": 1.73773035935040224E17
+ },
+ "婅拳?bkU;#D矠â´vVN쩆t㜷A풃갮娪a%é®çµª3dAv룒#tm쑬⌛qYwc4|L8KZ;xU⓭㳔밆拓EZ7襨eD|隰ऌ䧼u9Ô¢+]è´´Pè¿": 2.9628516456987075E18
+ }]}}]
+ ]}
+ }}
+ ]}]
+ ],
+ "|g翉F*湹̶\u0005â1脉̀eI쩓ᖂ㫱0碞l䴨ꑅ㵽7AtἈ턧yq䳥塑:z:é€ï¾¼X눔擉)`N3昛oQì…–y-ڨ⾶æ¢êˆµq^<\/": null,
+ "è¹\\ëž“G^璬x৴뭸ゆUSê²§ï®·Bꮤ ┉銜᯻0%N7}~fæ´‹å„Xꔼ<\/4妟Vꄟ9:౟곡t킅冩䧉笭裟炂4ë´‹â±³åºæ€Št+怯涗\"0ã–ˆHq": false,
+ "졬믟'ﺇফ圪쓬멤m邸QLà¦¬ä—æ„4jvsç¿™ à¾ê§€è‰³H-|": null,
+ "컮襱⣱뗠 R毪/鹙꾀%헳8&": -5770986448525107020
+ }
+ ],
+ "î½­B䔚bê»ë™å§“展槰T-똌鷺tcï§ç¿á«½^㓟ä€o3o$꘭趙è¬Ié¡©)뇭Ἑä“\f@{ᣨ`x3è”›": null
+ }
+ ]
+ ]
+ }],
+ "⦖扚vWꃱ꥙㾠壢輓{-⎳鹷è´ç’¿äœ‘bG倛â‹ç£Žc皇皩7a~ﳫUâ•£Q࠭ꎉS摅姽OW.홌ೞ.": null,
+ "蚪eVlH献r}á®ë¯ ï°©ê”„@ç‘„â²±": null,
+ "퀭$JWoê©¢gì—­ì䖔㑺h&à­¢tXX愰㱇?㾫I_6 OaB瑈q裿": null,
+ "꽦ﲼLyr纛ZduçB絟쬴糔?ã•‚ì§¹äµe": "ḱ\u2009cX9ë©€i䶛簆㳀k"
+ }
+ ]]]],
+ "(_ê®g່澮?ᩑyM<艷\u001aꪽ\\庼뙭Zë§·ã°©Vm\\lYç­º]3㋲2㌩㄀Eਟäµâ¨„ì¨á”ŸgङHné–⤇놋瓇Q탚單oY\"♆臾jHᶈå¾îž«á‰„??uㇰA?#1侓": null
+ },
+ "è§“^~ሢ&iIë†g륎ḱ캀.ᓡꀮ胙鈉": 1.0664523593012836E-19,
+ "yè©­GbᔶऽsëŒU:æœî „⤎ϲì—⮼D醄诿që™°I#즧v蔎xHᵿt᡽[**?崮耖p缫쿃Lè,ë´¬ï–ꤦC쯵#=X1çž»@OZc鱗CQTï‹„x": null
+ }
+ ]
+ }}],
+ "剘ç´\u0004\\Xn⊠6,á€×±;嵣崇}讃iႽ)d1\\䔓": null
+ },
+ "脨z\"{X,1u찜<'k&@?1}Yn$\u0015Rd輲ーa쮂굄+B$l": true,
+ "諳>*ì­®ê´äµŸÒ+<ç®}빀䅱⡔æªï€è‡’hIH脟ꩪCí•ଗP좕\"0i<\/C褻DÛžæ—+^5?'ꂱ䚫^7}ã¡ cq6\\쨪ꔞꥢ?纖䫀氮蒫侲빦敶q{Aç…²G": -6880961710038544266
+ }}]
+ },
+ "5s⨲JvಽῶꭂᄢI.a৊": null,
+ "?1qê½ì¿»ê›‹DR%Uå¨>DgNä¹­G": -1.2105047302732358E-19
+ }
+ ]
+ ]},
+ "qZz`撋뙹둣j碇ì\\ꆥ\u0018@ïœè—´ç–°Wz)O{Fä¶›l᷂绘訥$]ë®å¤»ä¢‹ä©‡è¿ç°æ¨§çŒµâ£­jè¶q)$꬚⵷0馢W:â°!Qoe": -1666634370862219540,
+ "t": "=î¹›wp|~碎Q鬳Ó\\l-<\/^ﳊhní–}ä”t碵ḛ혷?é»äŠ—",
+ "邙쇡㯇%#=,î‰E4勃驆V繚q[Y댻XV㡸[逹á°è‘¢B@u=JS5?bLRnì–®ã‰â…ï°³?a6[&íŸ!è—ˆ": 1.2722786745736667E-19
+ },
+ "X블땨4{ph鵋ꉯ웸 5p簂䦭s_E徔濧dç¨~No穔噕뽲)뉈c5M윅>âš‹[岦䲟懷æ?éŽê“†à¸¬çˆ‹ç äœ”s{\u001bméšå„¸ç…›%bﯿXT>ê—˜@8G": 1157841540507770724,
+ "媤娪Qæ¸ï‡\u0011SAyᡈ쿯": true,
+ "çš^ಸ%ê±<\/蛯<O\"-刷ã R(kO=䢊䅎l䰓팪A絫픧": "è­”\\ãš„ ?R7㔪G㋉⣰渆?\\#|gN⤴;Wì¹·A׫癮଼ೣã³ë’œ7dæ“ê¾²0扬S0ᆵi/贎ྡn䆋武",
+ "è‡ç ‡Gã“æœ¦ì¼‹Wq`㞲攊*å†î‘µî¨~霓L剢zI腧튴Tç¹™Cঅ뫬╈뮜ㄾ䦧촄椘B⊬츩r2f㶱厊8eϬ{挚â¯OM焄覤\\(KÓ¡>?\"祴å“\\\\'í": -3.4614808555942579E18,
+ "釴U:O湛㴑䀣렑縓\ta)<D8ï­³æ§é«­D.L|xsæ–‹æ• \"ë‹æ—©7wáŽ": true,
+ "쵈+쬎簨up䓬?q+~\u0019仇îŒëµˆá«¯3áµ£æ˜æž°åŠ«ãª¢uç˜-퀭:ì»™:u`⌿ï«A(9鄦!<çšnj3:Hà£¨å·‹ä€æ—¸ëŽˆë§»v\"\\(곘vO㤰aZe<\/W鹙鄜;l厮ë‘": null,
+ "î–·": -1.2019926774977002E-18,
+ "%者Oî–‹7.Nêªs梇接z蕜綛<\/䜭\"죊y<曋漵@Śâ¹sD⟓jݗᢜ?zî–†/9á²Ma쨮긗贎8ᔮ㦛;6p뾥໭䭊0B찛+)(Yã¿ é¸ä•’^옥": "鬃뫤&痽舎Jì½®è—󽸰ᨨMꈫ髿v<N\\î·.ì‚’ê»…Ñ1ê­¼5ä´·5쳬臨wjë¥"
+ }],
+ "é·Ž'ã³—@帚妇OAj' è°¬f94ǯ(횡ヒ%io쪖ì‚좛>(j:숾å´ä—ŒgCiB뽬Oyuqè¼¥åŽ/7)?今hY︺Q": null
+ }
+ ]
+ ]]]}]
+ ],
+ "I笔趠Ph!<ཛྷ㸞诘X$畉F\u0005笷èŸ.Esr릙!W☆ï›ä²–뗷莾뒭U\"䀸犜Uo3ï¯Gꯌx4r蔇᡹㧪쨢準<ä‚€%ࡡꟼç‘8ç‚Xs0ä€é”€?fi쥱ê†àª²BB": -8571484181158525797,
+ "Lâ¦o#J|\"⽩-ã±¢d㌛8d\\㶤傩儻E[Y熯)r噤὘勇 }": "e(濨쓌K䧚僒ã˜è ¤Vᛸ\"络QJL2,嬓ì™î¿‰ä¼¢ã‹’䴿考澰@(ã¾`kX$ë‘ÑE斡,èœ&~y",
+ "vj.|统圪ᵮPL?2oŶ`ë°§\"勃+0ue%⿥绬췈체$6:qaë Q;~晘3㙘鹑": true,
+ "à·Ø™4ç„â¶¿c︋iâš…:ã‚“é–Ⳙ苆籦kw{䙞셕pCì·ƒê¬âœêŸ¯êš“é…„bížhwkê­­M鬋8B耳쑘WQ\\å™ac'唀x᪌\u2048*hì§Ž#á‡é® ë¾áž¿ë€Œ": false,
+ "⎀jꄒ牺3Ⓝ컴~?親ꕽã¼Ü“å–瘘!@<튋ãŒê¿±â©¦{a?Yv%⪧笯Uܱ栅Eæši뚬:ꄃx7䙳ꦋ&䓹vq☶Iä˜á¾˜æ¶œ\\ì‰ëºŒLr%Bcãœ3?î¤ï…¨ê­ç ¿è£ž]": null,
+ "⭤뙓z(㡂%亳K䌽꫿AԾ岺㦦㼴輞낚Vꦴw냟鬓㹈뽈+o3譻K1잞": 2091209026076965894,
+ "ㇲ\t⋇轑ꠤ룫X긒\"zoYì‡í¬wjæ¢ì‘l侸`e%s": -9.9240075473576563E17,
+ "啸ꮑ㉰!áš“}éŠ": -4.0694813896301194E18,
+ "ï‰>]囋੽EK뇜>_ꀣ緳碖{ì裔[<ನ\"䇅\"5L?#îµ³xTwv#ç½\u0005래t应\\N?빗;": "v쮽瞭pë­ƒ"
+ }
+ ]],
+ "æ–´æ§¾?Zç¿\"~æ…弞ﻆ=꜡o5é‹ï’½dw\"?Kè ¡i샾ogDï²°_C*⬟iㇷ4nયèŸ[㟉U꽌娛苸 à§æ“贻洞펻)쿗૊許X⨪VY츚Zä¾ã¶­~튃ᵦ<\/E臭tve猑x嚢": null,
+ "锡⛩<\/칥ꈙᬙè€&êšç±¬â– 865?_>Lè©ì¿¨äˆŒæµ¿å¼¥ï©‰Ì«î¾½ï‘lj&zx<\/C쉾?覯n?": null,
+ "꾳鑤/꼩ï¨d=ᘈn挫ᑩ䰬ZC": "3錢爋6Ƹ䴗v⪿Wr益G韠[\u0010å±—9ì¡é’u?殢c䳀蓃樄욂NAq赟c튒ç˜ë ¶î‚³Aà«¡Éšæ"
+ }
+ ]
+ ]
+ ]}
+ ]
+ ]
+ }]]]}}
+ ]}],
+ "ï‚’Ejä—³U<\/Q=ç’샎䞦,å °é  @褙g_\u0003ꤾfâ¶½?퇋!łB〙ד3CC䌴鈌U:뭔咎(Qો臃䡬è‹BO7î¼§ã¢äŸ¸\"Yb": 2.36010731779814E-20,
+ "逸'0å²”j\u000e눘먷翌C츊秦=ꭣ棭ှ;鳸=麱$XP⩉駚橄A\\좱⛌jqvä°ž3Ь踌v㳆¹gT┌gvLBè³–ïžçƒ¡m?@E঳i": null
+ },
+ "曺vì°˜×?&绫OáŸ": 9107241066550187880
+ }
+ ]
+ ],
+ "(e屄\u0019昜훕ç–b蓘ᬄ0/۲묇Z蘮á€â¨è›˜èƒ¯ë¢ƒ@㘉8ሪWᨮ⦬ᅳ䅴HIá‡ì¨³z囕陻엣1赳o": true,
+ ",b刈Z,á æ™Tì†Å•B⩆ou'í¼â‰ƒç»—é›—dè­Š": null,
+ "a唥KB\"ï³è‚•$u\n^â…„P䟼냉䞸⩪u윗瀱ꔨ#yÅŸsî««ê’¬=ï‹•1ïš–|ﲤ爢`tà±íмî£ì³«_Az(Ṋ擬㦷좕耈6": 2099309172767331582,
+ "?ã´¸U<\/䢔ꯡ阽扆ã¤qé‹?f㔫wM嬙-;UV죫嚔픞G&\"Cá—äªí’ŠQ": "VM7ç–¹+陕枡툩窲}ç¿¡ä–¶8欞ÄsTë®}ç’¤:jﺋ鎴}HfAàµâ§»Zd#Qï¬u茅J髒皣Y-︴[?-~쉜vë”璮㹚䅊﩯<-#\u000eê±€h\u0004u抱﵊㼃U<㱷⊱IC進"
+ },
+ "숌dee節é½é‚ºp넱蹓+e罕U": true
+ }
+ ],
+ "b⧴ë£??á” 3ã±>%郿劃ç¿ê¬ê ›Wï¡°çž³á«ëˆ„躨狀ໄy੽\"ីuS=㨞馸k乆E": "トz݈^9R䬑<ﮛG<s~<\/?ⵆá¥è€ç†·uë“·"
+ }}
+ ]
+ }
+ ]}
+ }
+ }
+ }
+ }},
+ "宩j鬅쳜Qê–јyç”Zá­µï1væ“–}䨿F%cֲ᫺贴m塼딚NP亪\"ï¿‹sa뺯ꘓ2:9뛓ï à¼‚쌅䊈#>Rꨳ\u000fTT泠纷꽀MR<CBxPñ±’«X쇤": -2.22390568492330598E18,
+ "?䯣ᄽ@Z鸅->ᴱ纊:ã ­ë³®?%N56%鈕1ä—äœaä²—j陇=ë¿»å‚衋࿘ᓸ?ᕵZ+<\/}H耢bä€z^f$&ã’LkꢳI脚뙛u": 5.694374481577558E-20
+ }]
+ }
+ ]],
+ "obj": {"key": "wrong value"},
+ "퓲꽪m{ã¶©/뇿#â¼¢&᭙硞㪔E嚉c樱㬇1aç¶‘á–DḾä©": null
+ }
+} \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/data/webapp.json b/3rdparty/rapidjson/bin/data/webapp.json
new file mode 100644
index 00000000000..d540b57f0df
--- /dev/null
+++ b/3rdparty/rapidjson/bin/data/webapp.json
@@ -0,0 +1,88 @@
+{"web-app": {
+ "servlet": [
+ {
+ "servlet-name": "cofaxCDS",
+ "servlet-class": "org.cofax.cds.CDSServlet",
+ "init-param": {
+ "configGlossary:installationAt": "Philadelphia, PA",
+ "configGlossary:adminEmail": "ksm@pobox.com",
+ "configGlossary:poweredBy": "Cofax",
+ "configGlossary:poweredByIcon": "/images/cofax.gif",
+ "configGlossary:staticPath": "/content/static",
+ "templateProcessorClass": "org.cofax.WysiwygTemplate",
+ "templateLoaderClass": "org.cofax.FilesTemplateLoader",
+ "templatePath": "templates",
+ "templateOverridePath": "",
+ "defaultListTemplate": "listTemplate.htm",
+ "defaultFileTemplate": "articleTemplate.htm",
+ "useJSP": false,
+ "jspListTemplate": "listTemplate.jsp",
+ "jspFileTemplate": "articleTemplate.jsp",
+ "cachePackageTagsTrack": 200,
+ "cachePackageTagsStore": 200,
+ "cachePackageTagsRefresh": 60,
+ "cacheTemplatesTrack": 100,
+ "cacheTemplatesStore": 50,
+ "cacheTemplatesRefresh": 15,
+ "cachePagesTrack": 200,
+ "cachePagesStore": 100,
+ "cachePagesRefresh": 10,
+ "cachePagesDirtyRead": 10,
+ "searchEngineListTemplate": "forSearchEnginesList.htm",
+ "searchEngineFileTemplate": "forSearchEngines.htm",
+ "searchEngineRobotsDb": "WEB-INF/robots.db",
+ "useDataStore": true,
+ "dataStoreClass": "org.cofax.SqlDataStore",
+ "redirectionClass": "org.cofax.SqlRedirection",
+ "dataStoreName": "cofax",
+ "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
+ "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
+ "dataStoreUser": "sa",
+ "dataStorePassword": "dataStoreTestQuery",
+ "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",
+ "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
+ "dataStoreInitConns": 10,
+ "dataStoreMaxConns": 100,
+ "dataStoreConnUsageLimit": 100,
+ "dataStoreLogLevel": "debug",
+ "maxUrlLength": 500}},
+ {
+ "servlet-name": "cofaxEmail",
+ "servlet-class": "org.cofax.cds.EmailServlet",
+ "init-param": {
+ "mailHost": "mail1",
+ "mailHostOverride": "mail2"}},
+ {
+ "servlet-name": "cofaxAdmin",
+ "servlet-class": "org.cofax.cds.AdminServlet"},
+
+ {
+ "servlet-name": "fileServlet",
+ "servlet-class": "org.cofax.cds.FileServlet"},
+ {
+ "servlet-name": "cofaxTools",
+ "servlet-class": "org.cofax.cms.CofaxToolsServlet",
+ "init-param": {
+ "templatePath": "toolstemplates/",
+ "log": 1,
+ "logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
+ "logMaxSize": "",
+ "dataLog": 1,
+ "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
+ "dataLogMaxSize": "",
+ "removePageCache": "/content/admin/remove?cache=pages&id=",
+ "removeTemplateCache": "/content/admin/remove?cache=templates&id=",
+ "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
+ "lookInContext": 1,
+ "adminGroupID": 4,
+ "betaServer": true}}],
+ "servlet-mapping": {
+ "cofaxCDS": "/",
+ "cofaxEmail": "/cofaxutil/aemail/*",
+ "cofaxAdmin": "/admin/*",
+ "fileServlet": "/static/*",
+ "cofaxTools": "/tools/*"},
+
+ "taglib": {
+ "taglib-uri": "cofax.tld",
+ "taglib-location": "/WEB-INF/tlds/cofax.tld"}}} \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/data/widget.json b/3rdparty/rapidjson/bin/data/widget.json
new file mode 100644
index 00000000000..0449493a644
--- /dev/null
+++ b/3rdparty/rapidjson/bin/data/widget.json
@@ -0,0 +1,26 @@
+{"widget": {
+ "debug": "on",
+ "window": {
+ "title": "Sample Konfabulator Widget",
+ "name": "main_window",
+ "width": 500,
+ "height": 500
+ },
+ "image": {
+ "src": "Images/Sun.png",
+ "name": "sun1",
+ "hOffset": 250,
+ "vOffset": 250,
+ "alignment": "center"
+ },
+ "text": {
+ "data": "Click Here",
+ "size": 36,
+ "style": "bold",
+ "name": "text1",
+ "hOffset": 250,
+ "vOffset": 100,
+ "alignment": "center",
+ "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
+ }
+}} \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/encodings/utf16be.json b/3rdparty/rapidjson/bin/encodings/utf16be.json
new file mode 100644
index 00000000000..e46dbfb9ddc
--- /dev/null
+++ b/3rdparty/rapidjson/bin/encodings/utf16be.json
Binary files differ
diff --git a/3rdparty/rapidjson/bin/encodings/utf16bebom.json b/3rdparty/rapidjson/bin/encodings/utf16bebom.json
new file mode 100644
index 00000000000..0a23ae205cb
--- /dev/null
+++ b/3rdparty/rapidjson/bin/encodings/utf16bebom.json
Binary files differ
diff --git a/3rdparty/rapidjson/bin/encodings/utf16le.json b/3rdparty/rapidjson/bin/encodings/utf16le.json
new file mode 100644
index 00000000000..92d504530cd
--- /dev/null
+++ b/3rdparty/rapidjson/bin/encodings/utf16le.json
Binary files differ
diff --git a/3rdparty/rapidjson/bin/encodings/utf16lebom.json b/3rdparty/rapidjson/bin/encodings/utf16lebom.json
new file mode 100644
index 00000000000..eaba00132cd
--- /dev/null
+++ b/3rdparty/rapidjson/bin/encodings/utf16lebom.json
Binary files differ
diff --git a/3rdparty/rapidjson/bin/encodings/utf32be.json b/3rdparty/rapidjson/bin/encodings/utf32be.json
new file mode 100644
index 00000000000..9cbb522279d
--- /dev/null
+++ b/3rdparty/rapidjson/bin/encodings/utf32be.json
Binary files differ
diff --git a/3rdparty/rapidjson/bin/encodings/utf32bebom.json b/3rdparty/rapidjson/bin/encodings/utf32bebom.json
new file mode 100644
index 00000000000..bde6a99ab43
--- /dev/null
+++ b/3rdparty/rapidjson/bin/encodings/utf32bebom.json
Binary files differ
diff --git a/3rdparty/rapidjson/bin/encodings/utf32le.json b/3rdparty/rapidjson/bin/encodings/utf32le.json
new file mode 100644
index 00000000000..b00f290a64f
--- /dev/null
+++ b/3rdparty/rapidjson/bin/encodings/utf32le.json
Binary files differ
diff --git a/3rdparty/rapidjson/bin/encodings/utf32lebom.json b/3rdparty/rapidjson/bin/encodings/utf32lebom.json
new file mode 100644
index 00000000000..d3db39bf732
--- /dev/null
+++ b/3rdparty/rapidjson/bin/encodings/utf32lebom.json
Binary files differ
diff --git a/3rdparty/rapidjson/bin/encodings/utf8.json b/3rdparty/rapidjson/bin/encodings/utf8.json
new file mode 100644
index 00000000000..1e27ece50e4
--- /dev/null
+++ b/3rdparty/rapidjson/bin/encodings/utf8.json
@@ -0,0 +1,7 @@
+{
+ "en":"I can eat glass and it doesn't hurt me.",
+ "zh-Hant":"我能åžä¸‹çŽ»ç’ƒè€Œä¸å‚·èº«é«”。",
+ "zh-Hans":"我能åžä¸‹çŽ»ç’ƒè€Œä¸ä¼¤èº«ä½“。",
+ "ja":"ç§ã¯ã‚¬ãƒ©ã‚¹ã‚’食ã¹ã‚‰ã‚Œã¾ã™ã€‚ãれã¯ç§ã‚’å‚·ã¤ã‘ã¾ã›ã‚“。",
+ "ko":"나는 유리를 ë¨¹ì„ ìˆ˜ 있어요. ê·¸ëž˜ë„ ì•„í”„ì§€ 않아요"
+} \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/encodings/utf8bom.json b/3rdparty/rapidjson/bin/encodings/utf8bom.json
new file mode 100644
index 00000000000..07e81e10528
--- /dev/null
+++ b/3rdparty/rapidjson/bin/encodings/utf8bom.json
@@ -0,0 +1,7 @@
+{
+ "en":"I can eat glass and it doesn't hurt me.",
+ "zh-Hant":"我能åžä¸‹çŽ»ç’ƒè€Œä¸å‚·èº«é«”。",
+ "zh-Hans":"我能åžä¸‹çŽ»ç’ƒè€Œä¸ä¼¤èº«ä½“。",
+ "ja":"ç§ã¯ã‚¬ãƒ©ã‚¹ã‚’食ã¹ã‚‰ã‚Œã¾ã™ã€‚ãれã¯ç§ã‚’å‚·ã¤ã‘ã¾ã›ã‚“。",
+ "ko":"나는 유리를 ë¨¹ì„ ìˆ˜ 있어요. ê·¸ëž˜ë„ ì•„í”„ì§€ 않아요"
+} \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail1.json b/3rdparty/rapidjson/bin/jsonchecker/fail1.json
new file mode 100644
index 00000000000..6216b865f10
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail1.json
@@ -0,0 +1 @@
+"A JSON payload should be an object or array, not a string." \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail10.json b/3rdparty/rapidjson/bin/jsonchecker/fail10.json
new file mode 100644
index 00000000000..5d8c0047bd5
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail10.json
@@ -0,0 +1 @@
+{"Extra value after close": true} "misplaced quoted value" \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail11.json b/3rdparty/rapidjson/bin/jsonchecker/fail11.json
new file mode 100644
index 00000000000..76eb95b4583
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail11.json
@@ -0,0 +1 @@
+{"Illegal expression": 1 + 2} \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail12.json b/3rdparty/rapidjson/bin/jsonchecker/fail12.json
new file mode 100644
index 00000000000..77580a4522d
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail12.json
@@ -0,0 +1 @@
+{"Illegal invocation": alert()} \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail13.json b/3rdparty/rapidjson/bin/jsonchecker/fail13.json
new file mode 100644
index 00000000000..379406b59bd
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail13.json
@@ -0,0 +1 @@
+{"Numbers cannot have leading zeroes": 013} \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail14.json b/3rdparty/rapidjson/bin/jsonchecker/fail14.json
new file mode 100644
index 00000000000..0ed366b38a3
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail14.json
@@ -0,0 +1 @@
+{"Numbers cannot be hex": 0x14} \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail15.json b/3rdparty/rapidjson/bin/jsonchecker/fail15.json
new file mode 100644
index 00000000000..fc8376b605d
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail15.json
@@ -0,0 +1 @@
+["Illegal backslash escape: \x15"] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail16.json b/3rdparty/rapidjson/bin/jsonchecker/fail16.json
new file mode 100644
index 00000000000..3fe21d4b532
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail16.json
@@ -0,0 +1 @@
+[\naked] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail17.json b/3rdparty/rapidjson/bin/jsonchecker/fail17.json
new file mode 100644
index 00000000000..62b9214aeda
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail17.json
@@ -0,0 +1 @@
+["Illegal backslash escape: \017"] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail18.json b/3rdparty/rapidjson/bin/jsonchecker/fail18.json
new file mode 100644
index 00000000000..edac92716f1
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail18.json
@@ -0,0 +1 @@
+[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail19.json b/3rdparty/rapidjson/bin/jsonchecker/fail19.json
new file mode 100644
index 00000000000..3b9c46fa9a2
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail19.json
@@ -0,0 +1 @@
+{"Missing colon" null} \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail2.json b/3rdparty/rapidjson/bin/jsonchecker/fail2.json
new file mode 100644
index 00000000000..6b7c11e5a56
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail2.json
@@ -0,0 +1 @@
+["Unclosed array" \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail20.json b/3rdparty/rapidjson/bin/jsonchecker/fail20.json
new file mode 100644
index 00000000000..27c1af3e72e
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail20.json
@@ -0,0 +1 @@
+{"Double colon":: null} \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail21.json b/3rdparty/rapidjson/bin/jsonchecker/fail21.json
new file mode 100644
index 00000000000..62474573b21
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail21.json
@@ -0,0 +1 @@
+{"Comma instead of colon", null} \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail22.json b/3rdparty/rapidjson/bin/jsonchecker/fail22.json
new file mode 100644
index 00000000000..a7752581bcf
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail22.json
@@ -0,0 +1 @@
+["Colon instead of comma": false] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail23.json b/3rdparty/rapidjson/bin/jsonchecker/fail23.json
new file mode 100644
index 00000000000..494add1ca19
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail23.json
@@ -0,0 +1 @@
+["Bad value", truth] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail24.json b/3rdparty/rapidjson/bin/jsonchecker/fail24.json
new file mode 100644
index 00000000000..caff239bfc3
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail24.json
@@ -0,0 +1 @@
+['single quote'] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail25.json b/3rdparty/rapidjson/bin/jsonchecker/fail25.json
new file mode 100644
index 00000000000..8b7ad23e010
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail25.json
@@ -0,0 +1 @@
+[" tab character in string "] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail26.json b/3rdparty/rapidjson/bin/jsonchecker/fail26.json
new file mode 100644
index 00000000000..845d26a6a54
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail26.json
@@ -0,0 +1 @@
+["tab\ character\ in\ string\ "] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail27.json b/3rdparty/rapidjson/bin/jsonchecker/fail27.json
new file mode 100644
index 00000000000..6b01a2ca4a9
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail27.json
@@ -0,0 +1,2 @@
+["line
+break"] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail28.json b/3rdparty/rapidjson/bin/jsonchecker/fail28.json
new file mode 100644
index 00000000000..621a0101c66
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail28.json
@@ -0,0 +1,2 @@
+["line\
+break"] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail29.json b/3rdparty/rapidjson/bin/jsonchecker/fail29.json
new file mode 100644
index 00000000000..47ec421bb62
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail29.json
@@ -0,0 +1 @@
+[0e] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail3.json b/3rdparty/rapidjson/bin/jsonchecker/fail3.json
new file mode 100644
index 00000000000..168c81eb785
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail3.json
@@ -0,0 +1 @@
+{unquoted_key: "keys must be quoted"} \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail30.json b/3rdparty/rapidjson/bin/jsonchecker/fail30.json
new file mode 100644
index 00000000000..8ab0bc4b8b2
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail30.json
@@ -0,0 +1 @@
+[0e+] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail31.json b/3rdparty/rapidjson/bin/jsonchecker/fail31.json
new file mode 100644
index 00000000000..1cce602b518
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail31.json
@@ -0,0 +1 @@
+[0e+-1] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail32.json b/3rdparty/rapidjson/bin/jsonchecker/fail32.json
new file mode 100644
index 00000000000..45cba7396ff
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail32.json
@@ -0,0 +1 @@
+{"Comma instead if closing brace": true, \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail33.json b/3rdparty/rapidjson/bin/jsonchecker/fail33.json
new file mode 100644
index 00000000000..ca5eb19dc97
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail33.json
@@ -0,0 +1 @@
+["mismatch"} \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail4.json b/3rdparty/rapidjson/bin/jsonchecker/fail4.json
new file mode 100644
index 00000000000..9de168bf34e
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail4.json
@@ -0,0 +1 @@
+["extra comma",] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail5.json b/3rdparty/rapidjson/bin/jsonchecker/fail5.json
new file mode 100644
index 00000000000..ddf3ce3d240
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail5.json
@@ -0,0 +1 @@
+["double extra comma",,] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail6.json b/3rdparty/rapidjson/bin/jsonchecker/fail6.json
new file mode 100644
index 00000000000..ed91580e1b1
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail6.json
@@ -0,0 +1 @@
+[ , "<-- missing value"] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail7.json b/3rdparty/rapidjson/bin/jsonchecker/fail7.json
new file mode 100644
index 00000000000..8a96af3e4ee
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail7.json
@@ -0,0 +1 @@
+["Comma after the close"], \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail8.json b/3rdparty/rapidjson/bin/jsonchecker/fail8.json
new file mode 100644
index 00000000000..b28479c6ecb
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail8.json
@@ -0,0 +1 @@
+["Extra close"]] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/fail9.json b/3rdparty/rapidjson/bin/jsonchecker/fail9.json
new file mode 100644
index 00000000000..5815574f363
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/fail9.json
@@ -0,0 +1 @@
+{"Extra comma": true,} \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/pass1.json b/3rdparty/rapidjson/bin/jsonchecker/pass1.json
new file mode 100644
index 00000000000..70e26854369
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/pass1.json
@@ -0,0 +1,58 @@
+[
+ "JSON Test Pattern pass1",
+ {"object with 1 member":["array with 1 element"]},
+ {},
+ [],
+ -42,
+ true,
+ false,
+ null,
+ {
+ "integer": 1234567890,
+ "real": -9876.543210,
+ "e": 0.123456789e-12,
+ "E": 1.234567890E+34,
+ "": 23456789012E66,
+ "zero": 0,
+ "one": 1,
+ "space": " ",
+ "quote": "\"",
+ "backslash": "\\",
+ "controls": "\b\f\n\r\t",
+ "slash": "/ & \/",
+ "alpha": "abcdefghijklmnopqrstuvwyz",
+ "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
+ "digit": "0123456789",
+ "0123456789": "digit",
+ "special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
+ "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
+ "true": true,
+ "false": false,
+ "null": null,
+ "array":[ ],
+ "object":{ },
+ "address": "50 St. James Street",
+ "url": "http://www.JSON.org/",
+ "comment": "// /* <!-- --",
+ "# -- --> */": " ",
+ " s p a c e d " :[1,2 , 3
+
+,
+
+4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],
+ "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
+ "quotes": "&#34; \u0022 %22 0x22 034 &#x22;",
+ "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
+: "A key can be any string"
+ },
+ 0.5 ,98.6
+,
+99.44
+,
+
+1066,
+1e1,
+0.1e1,
+1e-1,
+1e00,2e+00,2e-00
+,"rosebud"] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/pass2.json b/3rdparty/rapidjson/bin/jsonchecker/pass2.json
new file mode 100644
index 00000000000..d3c63c7ad84
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/pass2.json
@@ -0,0 +1 @@
+[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/jsonchecker/pass3.json b/3rdparty/rapidjson/bin/jsonchecker/pass3.json
new file mode 100644
index 00000000000..4528d51f1ac
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/pass3.json
@@ -0,0 +1,6 @@
+{
+ "JSON Test Pattern pass3": {
+ "The outermost value": "must be an object or array.",
+ "In this test": "It is an object."
+ }
+}
diff --git a/3rdparty/rapidjson/bin/jsonchecker/readme.txt b/3rdparty/rapidjson/bin/jsonchecker/readme.txt
new file mode 100644
index 00000000000..321d89d998e
--- /dev/null
+++ b/3rdparty/rapidjson/bin/jsonchecker/readme.txt
@@ -0,0 +1,3 @@
+Test suite from http://json.org/JSON_checker/.
+
+If the JSON_checker is working correctly, it must accept all of the pass*.json files and reject all of the fail*.json files.
diff --git a/3rdparty/rapidjson/bin/types/booleans.json b/3rdparty/rapidjson/bin/types/booleans.json
new file mode 100644
index 00000000000..2dcbb5fe876
--- /dev/null
+++ b/3rdparty/rapidjson/bin/types/booleans.json
@@ -0,0 +1,102 @@
+[
+ true,
+ true,
+ false,
+ false,
+ true,
+ true,
+ true,
+ false,
+ false,
+ true,
+ false,
+ false,
+ true,
+ false,
+ false,
+ false,
+ true,
+ false,
+ false,
+ true,
+ true,
+ false,
+ true,
+ true,
+ true,
+ false,
+ false,
+ false,
+ true,
+ false,
+ true,
+ false,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ false,
+ false,
+ true,
+ false,
+ false,
+ false,
+ true,
+ true,
+ false,
+ true,
+ true,
+ false,
+ true,
+ false,
+ true,
+ true,
+ true,
+ false,
+ false,
+ false,
+ true,
+ false,
+ false,
+ false,
+ true,
+ true,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ false,
+ false,
+ false,
+ false,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ false,
+ false,
+ false,
+ true,
+ false,
+ false,
+ false,
+ true,
+ true,
+ true,
+ false,
+ false,
+ true,
+ false
+] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/types/floats.json b/3rdparty/rapidjson/bin/types/floats.json
new file mode 100644
index 00000000000..12b94a11dc4
--- /dev/null
+++ b/3rdparty/rapidjson/bin/types/floats.json
@@ -0,0 +1,102 @@
+[
+ 135.747111636,
+ 123.377054008,
+ 140.527504552,
+ -72.299143906,
+ -23.851678949,
+ 73.586193519,
+ -158.299382442,
+ 177.477876032,
+ 32.268518982,
+ -139.560009969,
+ 115.203105183,
+ -106.025823607,
+ 167.224138231,
+ 103.378383732,
+ -97.498486285,
+ 18.184723416,
+ 69.137075711,
+ 33.849002681,
+ -120.185228215,
+ -20.841408615,
+ -172.659492727,
+ -2.691464061,
+ 22.426164066,
+ -98.416909437,
+ -31.603082708,
+ -85.072296561,
+ 108.620987395,
+ -43.127078238,
+ -126.473562057,
+ -158.595489097,
+ -57.890678254,
+ -13.254016573,
+ -85.024504709,
+ 171.663552644,
+ -146.495558248,
+ -10.606748276,
+ -118.786969354,
+ 153.352057804,
+ -45.215545083,
+ 37.038725288,
+ 106.344071897,
+ -64.607402031,
+ 85.148030911,
+ 28.897784566,
+ 39.51082061,
+ 20.450382102,
+ -113.174943618,
+ 71.60785784,
+ -168.202648062,
+ -157.338200017,
+ 10.879588527,
+ -114.261694831,
+ -5.622927072,
+ -173.330830616,
+ -29.47002003,
+ -39.829034201,
+ 50.031545162,
+ 82.815735508,
+ -119.188760828,
+ -48.455928081,
+ 163.964263034,
+ 46.30378861,
+ -26.248889762,
+ -47.354615322,
+ 155.388677633,
+ -166.710356904,
+ 42.987233558,
+ 144.275297374,
+ 37.394383186,
+ -122.550388725,
+ 177.469945914,
+ 101.104677413,
+ 109.429869885,
+ -104.919625624,
+ 147.522756541,
+ -81.294703727,
+ 122.744731363,
+ 81.803603684,
+ 26.321556167,
+ 147.045441354,
+ 147.256895816,
+ -174.211095908,
+ 52.518769316,
+ -78.58250334,
+ -173.356685435,
+ -107.728209264,
+ -69.982325771,
+ -113.776095893,
+ -35.785267074,
+ -105.748545976,
+ -30.206523864,
+ -76.185311723,
+ -126.400112781,
+ -26.864958639,
+ 56.840053629,
+ 93.781553535,
+ -116.002949803,
+ -46.617140948,
+ 176.846840093,
+ -144.24821335
+]
diff --git a/3rdparty/rapidjson/bin/types/guids.json b/3rdparty/rapidjson/bin/types/guids.json
new file mode 100644
index 00000000000..9d7f5dbc8f9
--- /dev/null
+++ b/3rdparty/rapidjson/bin/types/guids.json
@@ -0,0 +1,102 @@
+[
+ "d35bf0d4-8d8f-4e17-a5c3-ad9bfd675266",
+ "db402774-eeb6-463b-9986-c458c44d8b5a",
+ "2a2e4101-b5f2-40b8-8750-e03f01661e60",
+ "76787cfa-f4eb-4d62-aaad-e1d588d00ad5",
+ "fd73894b-b500-4a7c-888c-06b5bd9cec65",
+ "cce1862a-cf31-4ef2-9e23-f1d23b4e6163",
+ "00a98bb0-2b6e-4368-8512-71c21aa87db7",
+ "ab9a8d69-cec7-4550-bd35-3ed678e22782",
+ "f18b48e1-5114-4fbe-9652-579e8d66950e",
+ "4efe3baa-7ac5-4d6a-a839-6b9cfe825764",
+ "b4aec119-5b0a-434c-b388-109816c482a5",
+ "e0ef0cbb-127a-4a28-9831-5741b4295275",
+ "d50286a5-cb7b-4c9e-be99-f214439bae8c",
+ "a981094c-f1ac-42ed-a9fa-86404c7210ff",
+ "2a34ee57-5815-4829-b77b-eeebaa8fe340",
+ "a0530d44-48f8-4eff-b9ea-8810c4308351",
+ "c6f91509-83e1-4ea1-9680-e667fbfd56ee",
+ "cab11402-dcdd-4454-b190-6da124947395",
+ "283d159c-2b18-4856-b4c7-5059252eaa15",
+ "146157c6-72a8-4051-9991-cb6ea6743d81",
+ "aef6f269-7306-4bd2-83f7-6d5605b5dc9a",
+ "37fe6027-d638-4017-80a9-e7b0567b278e",
+ "5003d731-33fb-4159-af61-d76348a44079",
+ "e0e06979-5f80-4713-9fe0-8a4d60dc89f8",
+ "7e85bdc3-0345-4cb6-9398-ccab06e79976",
+ "f2ebf5af-6568-4ffe-a46d-403863fd4b66",
+ "e0b5bb1c-b4dd-4535-9a9e-3c73f1167d46",
+ "c852d20b-6bcb-4b12-bd57-308296c64c5a",
+ "7ac3ae82-1818-49cd-a8a4-5ac77dfafd46",
+ "138004a9-76e2-4ad7-bd42-e74dabdbb803",
+ "ab25b5be-96be-45b0-b765-947b40ec36a6",
+ "08404734-fd57-499e-a4cf-71e9ec782ede",
+ "8dfdeb16-248b-4a21-bf89-2e22b11a4101",
+ "a0e44ef0-3b09-41e8-ad5d-ed8e6a1a2a67",
+ "a7981e49-188d-414a-9779-b1ad91e599d1",
+ "329186c0-bf27-4208-baf7-c0a0a5a2d5b7",
+ "cb5f3381-d33e-4b30-b1a9-f482623cad33",
+ "15031262-ca73-4e3c-bd0a-fcf89bdf0caf",
+ "6d7333d1-2e8c-4d78-bfde-5be47e70eb13",
+ "acaa160c-670a-4e8f-ac45-49416e77d5f9",
+ "228f87eb-cde4-4106-808b-2dbf3c7b6d2e",
+ "2ff830a3-5445-4d8e-b161-bddd30666697",
+ "f488bedd-ff6e-4108-b9a7-07f6da62f476",
+ "2e12b846-0a34-478e-adf7-a438493803e6",
+ "6686b8ef-7446-4d86-bd8c-df24119e3bfe",
+ "e474a5c5-5793-4d41-b4ab-5423acc56ef1",
+ "ac046573-e718-44dc-a0dc-9037eeaba6a9",
+ "6b0e9099-cf53-4d5a-8a71-977528628fcf",
+ "d51a3f22-0ff9-4087-ba9b-fcee2a2d8ade",
+ "bdc01286-3511-4d22-bfb8-76d01203d366",
+ "ca44eb84-17ff-4f27-8f1e-1bd25f4e8725",
+ "4e9a8c2f-be0b-4913-92d2-c801b9a50d04",
+ "7685d231-dadd-4041-9165-898397438ab7",
+ "86f0bf26-d66a-44d8-99f5-d6768addae3b",
+ "2ca1167c-72ba-45a0-aa42-faf033db0d0b",
+ "199a1182-ea55-49ff-ba51-71c29cdd0aac",
+ "be6a4dd2-c821-4aa0-8b83-d64d6644b5b2",
+ "4c5f4781-7f80-4daa-9c20-76b183000514",
+ "513b31bd-54fb-4d12-a427-42a7c13ff8e1",
+ "8e211bcb-d76c-4012-83ad-74dd7d23b687",
+ "44d5807e-0501-4f66-8779-e244d4fdca0a",
+ "db8cd555-0563-4b7b-b00c-eada300a7065",
+ "cb14d0c9-46cc-4797-bd3a-752b05629f07",
+ "4f68b3ef-ac9b-47a0-b6d7-57f398a5c6a5",
+ "77221aae-1bcf-471c-be45-7f31f733f9d6",
+ "42a7cac8-9e80-4c45-8c71-511d863c98ea",
+ "f9018d22-b82c-468c-bdb5-8864d5964801",
+ "75f4e9b8-62a2-4f21-ad8a-e19eff0419bc",
+ "9b7385c8-8653-4184-951c-b0ac1b36b42e",
+ "571018aa-ffbf-4b42-a16d-07b57a7f5f0e",
+ "35de4a2f-6bf1-45aa-b820-2a27ea833e44",
+ "0b8edb20-3bb4-4cb4-b089-31957466dbab",
+ "97da4778-9a7b-4140-a545-968148c81fb7",
+ "969f326c-8f2a-47c5-b41c-d9c2f06c9b9d",
+ "ae211037-8b53-4b17-bfc8-c06fc7774409",
+ "12c5c3c4-0bd5-45d3-bc1d-d04a3c65d3e6",
+ "ec02024f-ce43-4dd3-8169-a59f7baee043",
+ "5b6afe77-ce48-47ca-90a0-25cd10ca5ffd",
+ "2e3a61d4-6b8f-4d2f-ba86-878b4012efd8",
+ "19a88a67-a5d3-4647-898f-1cde07bce040",
+ "6db6f420-b5c8-48b9-bbb2-8864fe6fed65",
+ "5a45dbde-7b53-4f6b-b864-e3b63be3708a",
+ "c878321b-8a02-4239-9981-15760c2e7d15",
+ "4e36687f-8bf6-4b12-b496-3a8e382d067e",
+ "a59a63cd-43c0-4c6e-b208-6dbca86f8176",
+ "303308c4-2e4a-45b5-8bf3-3e66e9ad05a1",
+ "8b58fdf1-43a6-4c98-9547-6361b50791af",
+ "a3563591-72ed-42b5-8e41-bac1d76d70cf",
+ "38db8c78-3739-4f6e-8313-de4138082114",
+ "86615bea-7e73-4daf-95da-ae6b9eee1bbb",
+ "35d38e3e-076e-40dd-9aa8-05be2603bd59",
+ "9f84c62d-b454-4ba3-8c19-a01878985cdc",
+ "6721bbae-d765-4a06-8289-6fe46a1bf943",
+ "0837796f-d0dd-4e50-9b7c-1983e6cc7c48",
+ "021eb7d7-e869-49b9-80c3-9dd16ce2d981",
+ "819c56f8-e040-475d-aad5-c6d5e98b20aa",
+ "3a61ef02-735e-4229-937d-b3777a3f4e1f",
+ "79dfab84-12e6-4ec8-bfc8-460ae71e4eca",
+ "a106fabf-e149-476c-8053-b62388b6eb57",
+ "9a3900a5-bfb4-4de0-baa5-253a8bd0b634"
+] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/types/integers.json b/3rdparty/rapidjson/bin/types/integers.json
new file mode 100644
index 00000000000..5dd05e097a4
--- /dev/null
+++ b/3rdparty/rapidjson/bin/types/integers.json
@@ -0,0 +1,102 @@
+[
+ 8125686,
+ 8958709,
+ 5976222,
+ 1889524,
+ 7968493,
+ 1357486,
+ 118415,
+ 7081097,
+ 4635968,
+ 7555332,
+ 2270233,
+ 3428352,
+ 8699968,
+ 2087333,
+ 7861337,
+ 7554440,
+ 2017031,
+ 7981692,
+ 6060687,
+ 1877715,
+ 3297474,
+ 8373177,
+ 6158629,
+ 7853641,
+ 3004441,
+ 9650406,
+ 2695251,
+ 1180761,
+ 4988426,
+ 6043805,
+ 8063373,
+ 6103218,
+ 2848339,
+ 8188690,
+ 9235573,
+ 5949816,
+ 6116081,
+ 6471138,
+ 3354531,
+ 4787414,
+ 9660600,
+ 942529,
+ 7278535,
+ 7967399,
+ 554292,
+ 1436493,
+ 267319,
+ 2606657,
+ 7900601,
+ 4276634,
+ 7996757,
+ 8544466,
+ 7266469,
+ 3301373,
+ 4005350,
+ 6437652,
+ 7717672,
+ 7126292,
+ 8588394,
+ 2127902,
+ 7410190,
+ 1517806,
+ 4583602,
+ 3123440,
+ 7747613,
+ 5029464,
+ 9834390,
+ 3087227,
+ 4913822,
+ 7550487,
+ 4518144,
+ 5862588,
+ 1778599,
+ 9493290,
+ 5588455,
+ 3638706,
+ 7394293,
+ 4294719,
+ 3837830,
+ 6381878,
+ 7175866,
+ 8575492,
+ 1415229,
+ 1453733,
+ 6972404,
+ 9782571,
+ 4234063,
+ 7117418,
+ 7293130,
+ 8057071,
+ 9345285,
+ 7626648,
+ 3358911,
+ 4574537,
+ 9371826,
+ 7627107,
+ 6154093,
+ 5392367,
+ 5398105,
+ 6956377
+] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/types/mixed.json b/3rdparty/rapidjson/bin/types/mixed.json
new file mode 100644
index 00000000000..43e9a1d7be0
--- /dev/null
+++ b/3rdparty/rapidjson/bin/types/mixed.json
@@ -0,0 +1,592 @@
+[
+ {
+ "favoriteFruit": "banana",
+ "greeting": "Hello, Kim! You have 10 unread messages.",
+ "friends": [
+ {
+ "name": "Higgins Rodriquez",
+ "id": 0
+ },
+ {
+ "name": "James Floyd",
+ "id": 1
+ },
+ {
+ "name": "Gay Stewart",
+ "id": 2
+ }
+ ],
+ "range": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9
+ ],
+ "tags": [
+ "pariatur",
+ "ad",
+ "eiusmod",
+ "sit",
+ "et",
+ "velit",
+ "culpa"
+ ],
+ "longitude": -57.919246,
+ "latitude": -36.022812,
+ "registered": "Friday, March 21, 2014 9:13 PM",
+ "about": "Laborum nulla aliquip ullamco proident excepteur est officia ipsum. Eiusmod exercitation minim ex do labore reprehenderit aliqua minim qui excepteur reprehenderit cupidatat. Sint enim exercitation duis id consequat nisi enim magna. Commodo aliqua id ipsum sit magna enim. Veniam officia in labore fugiat veniam ea laboris ex veniam duis.\r\n",
+ "address": "323 Pulaski Street, Ronco, North Carolina, 7701",
+ "phone": "+1 (919) 438-2678",
+ "email": "kim.griffith@cipromox.biz",
+ "company": "CIPROMOX",
+ "name": {
+ "last": "Griffith",
+ "first": "Kim"
+ },
+ "eyeColor": "green",
+ "age": 26,
+ "picture": "http://placehold.it/32x32",
+ "balance": "$1,283.55",
+ "isActive": false,
+ "guid": "10ab0392-c5e2-48a3-9473-aa725bad892d",
+ "index": 0,
+ "_id": "551b91198238a0bcf9a41133"
+ },
+ {
+ "favoriteFruit": "banana",
+ "greeting": "Hello, Skinner! You have 9 unread messages.",
+ "friends": [
+ {
+ "name": "Rhonda Justice",
+ "id": 0
+ },
+ {
+ "name": "Audra Castaneda",
+ "id": 1
+ },
+ {
+ "name": "Vicky Chavez",
+ "id": 2
+ }
+ ],
+ "range": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9
+ ],
+ "tags": [
+ "dolore",
+ "enim",
+ "sit",
+ "non",
+ "exercitation",
+ "fugiat",
+ "adipisicing"
+ ],
+ "longitude": -60.291407,
+ "latitude": -84.619318,
+ "registered": "Friday, February 7, 2014 3:17 AM",
+ "about": "Consectetur eiusmod laboris dolore est ullamco nulla in velit quis esse Lorem. Amet aliqua sunt aute occaecat veniam officia in duis proident aliqua cupidatat mollit. Sint eu qui anim duis ut anim duis eu cillum. Cillum nostrud adipisicing tempor Lorem commodo sit in ad qui non et irure qui. Labore eu aliquip id duis eiusmod veniam.\r\n",
+ "address": "347 Autumn Avenue, Fidelis, Puerto Rico, 543",
+ "phone": "+1 (889) 457-2319",
+ "email": "skinner.maddox@moltonic.co.uk",
+ "company": "MOLTONIC",
+ "name": {
+ "last": "Maddox",
+ "first": "Skinner"
+ },
+ "eyeColor": "green",
+ "age": 22,
+ "picture": "http://placehold.it/32x32",
+ "balance": "$3,553.10",
+ "isActive": false,
+ "guid": "cfbc2fb6-2641-4388-b06d-ec0212cfac1e",
+ "index": 1,
+ "_id": "551b91197e0abe92d6642700"
+ },
+ {
+ "favoriteFruit": "strawberry",
+ "greeting": "Hello, Reynolds! You have 5 unread messages.",
+ "friends": [
+ {
+ "name": "Brady Valdez",
+ "id": 0
+ },
+ {
+ "name": "Boyer Golden",
+ "id": 1
+ },
+ {
+ "name": "Gladys Knapp",
+ "id": 2
+ }
+ ],
+ "range": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9
+ ],
+ "tags": [
+ "commodo",
+ "eiusmod",
+ "cupidatat",
+ "et",
+ "occaecat",
+ "proident",
+ "Lorem"
+ ],
+ "longitude": 140.866287,
+ "latitude": 1.401032,
+ "registered": "Monday, October 20, 2014 8:01 AM",
+ "about": "Deserunt elit consequat ea dolor pariatur aute consectetur et nulla ipsum ad. Laboris occaecat ipsum ad duis et esse ea ut voluptate. Ex magna consequat pariatur amet. Quis excepteur non mollit dolore cillum dolor ex esse veniam esse deserunt non occaecat veniam. Sit amet proident proident amet. Nisi est id ut ut adipisicing esse fugiat non dolor aute.\r\n",
+ "address": "872 Montague Terrace, Haena, Montana, 3106",
+ "phone": "+1 (974) 410-2655",
+ "email": "reynolds.sanford@combot.biz",
+ "company": "COMBOT",
+ "name": {
+ "last": "Sanford",
+ "first": "Reynolds"
+ },
+ "eyeColor": "green",
+ "age": 21,
+ "picture": "http://placehold.it/32x32",
+ "balance": "$3,664.47",
+ "isActive": true,
+ "guid": "f9933a9c-c41a-412f-a18d-e727c569870b",
+ "index": 2,
+ "_id": "551b91197f170b65413a06e3"
+ },
+ {
+ "favoriteFruit": "banana",
+ "greeting": "Hello, Neva! You have 7 unread messages.",
+ "friends": [
+ {
+ "name": "Clara Cotton",
+ "id": 0
+ },
+ {
+ "name": "Ray Gates",
+ "id": 1
+ },
+ {
+ "name": "Jacobs Reese",
+ "id": 2
+ }
+ ],
+ "range": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9
+ ],
+ "tags": [
+ "magna",
+ "labore",
+ "incididunt",
+ "velit",
+ "ea",
+ "et",
+ "eiusmod"
+ ],
+ "longitude": -133.058479,
+ "latitude": 87.803677,
+ "registered": "Friday, May 9, 2014 5:41 PM",
+ "about": "Do duis occaecat ut officia occaecat officia nostrud reprehenderit ex excepteur aute anim in reprehenderit. Cupidatat nulla eiusmod nulla non minim veniam aute nulla deserunt adipisicing consectetur veniam. Sit consequat ex laboris aliqua labore consectetur tempor proident consequat est. Fugiat quis esse culpa aliquip. Excepteur laborum aliquip sunt eu cupidatat magna eiusmod amet nisi labore aliquip. Ut consectetur esse aliquip exercitation nulla ex occaecat elit do ex eiusmod deserunt. Ex eu voluptate minim deserunt fugiat minim est occaecat ad Lorem nisi.\r\n",
+ "address": "480 Eagle Street, Fostoria, Oklahoma, 2614",
+ "phone": "+1 (983) 439-3000",
+ "email": "neva.barker@pushcart.us",
+ "company": "PUSHCART",
+ "name": {
+ "last": "Barker",
+ "first": "Neva"
+ },
+ "eyeColor": "brown",
+ "age": 36,
+ "picture": "http://placehold.it/32x32",
+ "balance": "$3,182.24",
+ "isActive": true,
+ "guid": "52489849-78e1-4b27-8b86-e3e5ab2b7dc8",
+ "index": 3,
+ "_id": "551b9119a13061c083c878d5"
+ },
+ {
+ "favoriteFruit": "banana",
+ "greeting": "Hello, Rodgers! You have 6 unread messages.",
+ "friends": [
+ {
+ "name": "Marguerite Conway",
+ "id": 0
+ },
+ {
+ "name": "Margarita Cunningham",
+ "id": 1
+ },
+ {
+ "name": "Carmela Gallagher",
+ "id": 2
+ }
+ ],
+ "range": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9
+ ],
+ "tags": [
+ "ipsum",
+ "magna",
+ "amet",
+ "elit",
+ "sit",
+ "occaecat",
+ "elit"
+ ],
+ "longitude": -125.436981,
+ "latitude": 19.868524,
+ "registered": "Tuesday, July 8, 2014 8:09 PM",
+ "about": "In cillum esse tempor do magna id ad excepteur ex nostrud mollit deserunt aliqua. Minim aliqua commodo commodo consectetur exercitation nulla nisi dolore aliqua in. Incididunt deserunt mollit nostrud excepteur. Ipsum fugiat anim deserunt Lorem aliquip nisi consequat eu minim in ex duis.\r\n",
+ "address": "989 Varanda Place, Duryea, Palau, 3972",
+ "phone": "+1 (968) 578-2974",
+ "email": "rodgers.conner@frenex.net",
+ "company": "FRENEX",
+ "name": {
+ "last": "Conner",
+ "first": "Rodgers"
+ },
+ "eyeColor": "blue",
+ "age": 23,
+ "picture": "http://placehold.it/32x32",
+ "balance": "$1,665.17",
+ "isActive": true,
+ "guid": "ed3b2374-5afe-4fca-9325-8a7bbc9f81a0",
+ "index": 4,
+ "_id": "551b91197bcedb1b56a241ce"
+ },
+ {
+ "favoriteFruit": "strawberry",
+ "greeting": "Hello, Mari! You have 10 unread messages.",
+ "friends": [
+ {
+ "name": "Irwin Boyd",
+ "id": 0
+ },
+ {
+ "name": "Dejesus Flores",
+ "id": 1
+ },
+ {
+ "name": "Lane Mcmahon",
+ "id": 2
+ }
+ ],
+ "range": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9
+ ],
+ "tags": [
+ "esse",
+ "aliquip",
+ "excepteur",
+ "dolor",
+ "ex",
+ "commodo",
+ "anim"
+ ],
+ "longitude": -17.038176,
+ "latitude": 17.154663,
+ "registered": "Sunday, April 6, 2014 4:46 AM",
+ "about": "Excepteur veniam occaecat sint nulla magna in in officia elit. Eiusmod qui dolor fugiat tempor in minim esse officia minim consequat. Lorem ullamco labore proident ipsum id pariatur fugiat consectetur anim cupidatat qui proident non ipsum.\r\n",
+ "address": "563 Hendrickson Street, Westwood, South Dakota, 4959",
+ "phone": "+1 (980) 434-3976",
+ "email": "mari.fleming@beadzza.org",
+ "company": "BEADZZA",
+ "name": {
+ "last": "Fleming",
+ "first": "Mari"
+ },
+ "eyeColor": "blue",
+ "age": 21,
+ "picture": "http://placehold.it/32x32",
+ "balance": "$1,948.04",
+ "isActive": true,
+ "guid": "6bd02166-3b1f-4ed8-84c9-ed96cbf12abc",
+ "index": 5,
+ "_id": "551b9119b359ff6d24846f77"
+ },
+ {
+ "favoriteFruit": "strawberry",
+ "greeting": "Hello, Maxine! You have 7 unread messages.",
+ "friends": [
+ {
+ "name": "Sullivan Stark",
+ "id": 0
+ },
+ {
+ "name": "Underwood Mclaughlin",
+ "id": 1
+ },
+ {
+ "name": "Kristy Carlson",
+ "id": 2
+ }
+ ],
+ "range": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9
+ ],
+ "tags": [
+ "commodo",
+ "ipsum",
+ "quis",
+ "non",
+ "est",
+ "mollit",
+ "exercitation"
+ ],
+ "longitude": -105.40635,
+ "latitude": 37.197993,
+ "registered": "Tuesday, January 20, 2015 12:30 AM",
+ "about": "Proident ullamco Lorem est consequat consectetur non eiusmod esse nostrud pariatur eiusmod enim exercitation eiusmod. Consequat duis elit elit minim ullamco et dolor eu minim do tempor esse consequat excepteur. Mollit dolor do voluptate nostrud quis anim cillum velit tempor eiusmod adipisicing tempor do culpa. Eu magna dolor sit amet nisi do laborum dolore nisi. Deserunt ipsum et deserunt non nisi.\r\n",
+ "address": "252 Boulevard Court, Brenton, Tennessee, 9444",
+ "phone": "+1 (950) 466-3377",
+ "email": "maxine.moreno@zentia.tv",
+ "company": "ZENTIA",
+ "name": {
+ "last": "Moreno",
+ "first": "Maxine"
+ },
+ "eyeColor": "brown",
+ "age": 24,
+ "picture": "http://placehold.it/32x32",
+ "balance": "$1,200.24",
+ "isActive": false,
+ "guid": "ce307a37-ca1f-43f5-b637-dca2605712be",
+ "index": 6,
+ "_id": "551b91195a6164b2e35f6dc8"
+ },
+ {
+ "favoriteFruit": "strawberry",
+ "greeting": "Hello, Helga! You have 5 unread messages.",
+ "friends": [
+ {
+ "name": "Alicia Vance",
+ "id": 0
+ },
+ {
+ "name": "Vinson Phelps",
+ "id": 1
+ },
+ {
+ "name": "Francisca Kelley",
+ "id": 2
+ }
+ ],
+ "range": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9
+ ],
+ "tags": [
+ "nostrud",
+ "eiusmod",
+ "dolore",
+ "officia",
+ "sint",
+ "non",
+ "qui"
+ ],
+ "longitude": -7.275151,
+ "latitude": 75.54202,
+ "registered": "Wednesday, October 1, 2014 6:35 PM",
+ "about": "Quis duis ullamco velit qui. Consectetur non adipisicing id magna anim. Deserunt est officia qui esse. Et do pariatur incididunt anim ad mollit non. Et eiusmod sunt fugiat elit mollit ad excepteur anim nisi laboris eiusmod aliquip aliquip.\r\n",
+ "address": "981 Bush Street, Beaulieu, Vermont, 3775",
+ "phone": "+1 (956) 506-3807",
+ "email": "helga.burch@synkgen.name",
+ "company": "SYNKGEN",
+ "name": {
+ "last": "Burch",
+ "first": "Helga"
+ },
+ "eyeColor": "blue",
+ "age": 22,
+ "picture": "http://placehold.it/32x32",
+ "balance": "$3,827.89",
+ "isActive": false,
+ "guid": "ff5dfea0-1052-4ef2-8b66-4dc1aad0a4fb",
+ "index": 7,
+ "_id": "551b911946be8358ae40e90e"
+ },
+ {
+ "favoriteFruit": "banana",
+ "greeting": "Hello, Shaw! You have 5 unread messages.",
+ "friends": [
+ {
+ "name": "Christian Cardenas",
+ "id": 0
+ },
+ {
+ "name": "Cohen Pennington",
+ "id": 1
+ },
+ {
+ "name": "Mary Lindsay",
+ "id": 2
+ }
+ ],
+ "range": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9
+ ],
+ "tags": [
+ "occaecat",
+ "ut",
+ "occaecat",
+ "magna",
+ "exercitation",
+ "incididunt",
+ "irure"
+ ],
+ "longitude": -89.102972,
+ "latitude": 89.489596,
+ "registered": "Thursday, August 21, 2014 5:00 PM",
+ "about": "Amet cupidatat quis velit aute Lorem consequat pariatur mollit deserunt et sint culpa excepteur duis. Enim proident duis qui ex tempor sunt nostrud occaecat. Officia sit veniam mollit eiusmod minim do aute eiusmod fugiat qui anim adipisicing in laboris. Do tempor reprehenderit sunt laborum esse irure dolor ad consectetur aute sit id ipsum. Commodo et voluptate anim consequat do. Minim laborum ad veniam ad minim incididunt excepteur excepteur aliqua.\r\n",
+ "address": "237 Pierrepont Street, Herbster, New York, 3490",
+ "phone": "+1 (976) 455-2880",
+ "email": "shaw.zamora@shadease.me",
+ "company": "SHADEASE",
+ "name": {
+ "last": "Zamora",
+ "first": "Shaw"
+ },
+ "eyeColor": "blue",
+ "age": 38,
+ "picture": "http://placehold.it/32x32",
+ "balance": "$3,440.82",
+ "isActive": false,
+ "guid": "ac5fdb0e-e1fb-427e-881d-da461be0d1ca",
+ "index": 8,
+ "_id": "551b9119af0077bc28a2de25"
+ },
+ {
+ "favoriteFruit": "apple",
+ "greeting": "Hello, Melissa! You have 5 unread messages.",
+ "friends": [
+ {
+ "name": "Marion Villarreal",
+ "id": 0
+ },
+ {
+ "name": "Kate Rose",
+ "id": 1
+ },
+ {
+ "name": "Hines Simon",
+ "id": 2
+ }
+ ],
+ "range": [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9
+ ],
+ "tags": [
+ "amet",
+ "veniam",
+ "mollit",
+ "ad",
+ "cupidatat",
+ "deserunt",
+ "Lorem"
+ ],
+ "longitude": -52.735052,
+ "latitude": 16.258838,
+ "registered": "Wednesday, April 16, 2014 7:56 PM",
+ "about": "Aute ut culpa eiusmod tempor duis dolor tempor incididunt. Nisi non proident excepteur eiusmod incididunt nisi minim irure sit. In veniam commodo deserunt proident reprehenderit et consectetur ullamco quis nulla cupidatat.\r\n",
+ "address": "642 Halsey Street, Blandburg, Kansas, 6761",
+ "phone": "+1 (941) 539-3851",
+ "email": "melissa.vaughn@memora.io",
+ "company": "MEMORA",
+ "name": {
+ "last": "Vaughn",
+ "first": "Melissa"
+ },
+ "eyeColor": "brown",
+ "age": 24,
+ "picture": "http://placehold.it/32x32",
+ "balance": "$2,399.44",
+ "isActive": true,
+ "guid": "1769f022-a7f1-4a69-bf4c-f5a5ebeab2d1",
+ "index": 9,
+ "_id": "551b9119b607c09c7ffc3b8a"
+ }
+] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/types/nulls.json b/3rdparty/rapidjson/bin/types/nulls.json
new file mode 100644
index 00000000000..7a636ec87cd
--- /dev/null
+++ b/3rdparty/rapidjson/bin/types/nulls.json
@@ -0,0 +1,102 @@
+[
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/types/paragraphs.json b/3rdparty/rapidjson/bin/types/paragraphs.json
new file mode 100644
index 00000000000..8ab3e1c561c
--- /dev/null
+++ b/3rdparty/rapidjson/bin/types/paragraphs.json
@@ -0,0 +1,102 @@
+[
+ "Commodo ullamco cupidatat nisi sit proident ex. Cillum pariatur occaecat in officia do commodo nisi cillum tempor minim. Ad dolor ut et aliquip fugiat eu officia cupidatat occaecat consectetur eiusmod veniam enim officia.\r\n",
+ "Adipisicing cillum laborum nisi irure. Cillum dolor proident duis nulla qui mollit dolore reprehenderit mollit. Irure nulla dolor ipsum irure nulla quis laboris do.\r\n",
+ "Est adipisicing consectetur incididunt in. Occaecat ea magna ex consequat irure sit laborum cillum officia magna sunt do exercitation aliquip. Laboris id aute in dolore reprehenderit voluptate non deserunt laborum.\r\n",
+ "Consectetur eu aute est est occaecat adipisicing sint enim dolor eu. Tempor amet id non mollit eu consectetur cillum duis. Eu labore velit nulla ipsum commodo consequat aliquip. Cupidatat commodo dolore mollit enim sit excepteur nisi duis laboris deserunt esse.\r\n",
+ "Incididunt ullamco est fugiat enim fugiat. Do sit mollit anim ad excepteur eu laboris exercitation officia labore nulla ut. Voluptate non voluptate cillum sit et voluptate anim duis velit consequat aliquip dolor. Elit et et esse laboris consectetur officia eiusmod aliquip nisi est. Qui labore dolore ad dolor.\r\n",
+ "Anim adipisicing est irure proident sit officia ullamco voluptate sunt consectetur duis mollit excepteur veniam. Nostrud ut duis aute exercitation officia et quis elit commodo elit tempor aute aliquip enim. Est officia non cillum consequat voluptate ipsum sit voluptate nulla id.\r\n",
+ "Ipsum enim consectetur aliquip nulla commodo ut ex aliqua elit duis do. Officia et sunt aliqua dolor minim voluptate veniam esse elit enim. Adipisicing reprehenderit duis ex magna non in fugiat sunt ipsum nostrud fugiat aliquip. Labore voluptate id officia voluptate eu. Magna do nostrud excepteur sunt aliqua adipisicing qui.\r\n",
+ "Est occaecat non non cupidatat laborum qui. Veniam sit est voluptate labore sit irure consectetur fugiat. Anim enim enim fugiat exercitation anim ad proident esse in aliqua. Laboris ut aute culpa ullamco.\r\n",
+ "Sit et aliquip cupidatat deserunt eiusmod sint aliquip occaecat nostrud aliqua elit commodo ut magna. Amet sit est deserunt id duis in officia pariatur cupidatat ex. Mollit duis est consequat nulla aute velit ipsum sit consectetur pariatur ut non ex ipsum. Tempor esse velit pariatur reprehenderit et nostrud commodo laborum mollit labore.\r\n",
+ "Aliquip irure quis esse aliquip. Ex non deserunt culpa aliqua ad anim occaecat ad. Lorem consectetur mollit eu consectetur est non nisi non ipsum. Qui veniam ullamco officia est ut excepteur. Nulla elit dolore cupidatat aliqua enim Lorem elit consequat eiusmod non aliqua eu in. Pariatur in culpa labore sint ipsum consectetur occaecat ad ex ipsum laboris aliquip officia. Non officia eiusmod nisi officia id id laboris deserunt sunt enim magna mollit sit.\r\n",
+ "Mollit velit laboris laborum nulla aliquip consequat Lorem non incididunt irure. Eu voluptate sint do consectetur tempor sit Lorem in. Laborum eiusmod nisi Lorem ipsum dolore do aute laborum occaecat aute sunt. Sit laborum in ea do ipsum officia irure cillum irure nisi laboris. Ad anim deserunt excepteur ea veniam eiusmod culpa velit veniam. Commodo incididunt ea Lorem eu enim esse nisi incididunt mollit.\r\n",
+ "Velit proident sunt aute dolore reprehenderit culpa. Pariatur reprehenderit commodo ad ea voluptate anim nulla ipsum eu irure fugiat aliqua et. Adipisicing incididunt anim excepteur voluptate minim qui culpa. Sunt veniam enim reprehenderit magna magna. Sit ad amet deserunt ut aute dolore ad minim.\r\n",
+ "Esse ullamco sunt mollit mollit. Eu enim dolore laboris cupidatat. Cupidatat adipisicing non aute exercitation fugiat. Non ut cillum labore fugiat aliquip ex duis quis consectetur ut nisi Lorem amet qui. Proident veniam amet qui reprehenderit duis qui. Nisi culpa sit occaecat ullamco occaecat laborum fugiat ut. Non duis deserunt culpa duis.\r\n",
+ "Id ipsum eiusmod laboris non est ipsum deserunt labore duis reprehenderit deserunt. Sint tempor fugiat eiusmod nostrud in ut laborum esse in nostrud sit deserunt nostrud reprehenderit. Cupidatat aliqua qui anim consequat eu quis consequat consequat elit ipsum pariatur. Cupidatat in dolore velit quis. Exercitation cillum ullamco ex consectetur commodo tempor incididunt exercitation labore ad dolore. Minim incididunt consequat adipisicing esse eu eu voluptate.\r\n",
+ "Anim sint eiusmod nisi anim do deserunt voluptate ut cillum eiusmod esse ex reprehenderit laborum. Dolore nulla excepteur duis excepteur. Magna nisi nostrud duis non commodo velit esse ipsum Lorem incididunt. Nulla enim consequat ad aliqua. Incididunt irure culpa nostrud ea aute ex sit non ad esse.\r\n",
+ "Ullamco nostrud cupidatat adipisicing anim fugiat mollit eu. Et ut eu in nulla consequat. Sunt do pariatur culpa non est.\r\n",
+ "Pariatur incididunt reprehenderit non qui excepteur cillum exercitation nisi occaecat ad. Lorem aliquip laborum commodo reprehenderit sint. Laboris qui ut veniam magna quis et et ullamco voluptate. Tempor reprehenderit deserunt consequat nisi. Esse duis sint in tempor. Amet aute cupidatat in sint et.\r\n",
+ "Est officia nisi dolore consequat irure et excepteur. Sit qui elit tempor magna qui cillum anim amet proident exercitation proident. Eu cupidatat laborum consectetur duis ullamco irure nulla. Adipisicing culpa non reprehenderit anim aute.\r\n",
+ "Eu est laborum culpa velit dolore non sunt. Tempor magna veniam ea sit non qui Lorem qui exercitation aliqua aliqua et excepteur eiusmod. Culpa aute anim proident culpa adipisicing duis tempor elit aliquip elit nulla laboris esse dolore. Sit adipisicing non dolor eiusmod occaecat cupidatat.\r\n",
+ "Culpa velit eu esse sunt. Laborum irure aliqua reprehenderit velit ipsum fugiat officia dolor ut aute officia deserunt. Ipsum sit quis fugiat nostrud aliqua cupidatat ex pariatur et. Cillum proident est irure nisi dolor aliqua deserunt esse occaecat velit dolor.\r\n",
+ "Exercitation nulla officia sit eiusmod cillum eu incididunt officia exercitation qui Lorem deserunt. Voluptate Lorem minim commodo laborum esse in duis excepteur do duis aliquip nisi voluptate consectetur. Amet tempor officia enim ex esse minim reprehenderit.\r\n",
+ "Laboris sint deserunt ad aute incididunt. Anim officia sunt elit qui laborum labore commodo irure non. Mollit adipisicing ullamco do aute nulla eu laborum et quis sint aute adipisicing amet. Aliqua officia irure nostrud duis ex.\r\n",
+ "Eiusmod ipsum aliqua reprehenderit esse est non aute id veniam eiusmod. Elit consequat ad sit tempor elit eu incididunt quis irure ad. Eu incididunt veniam consequat Lorem nostrud cillum officia ea consequat ad cillum. Non nisi irure cupidatat incididunt pariatur incididunt. Duis velit officia ad cillum qui. Aliquip consequat sint aute nisi cillum. Officia commodo nisi incididunt laborum nisi voluptate aliquip Lorem cupidatat anim consequat sit laboris.\r\n",
+ "Veniam cupidatat et incididunt mollit do ex voluptate veniam nostrud labore esse. Eiusmod irure sint fugiat esse. Aute irure consectetur ut mollit nulla sint esse. Lorem ut quis ex proident nostrud mollit nostrud ea duis duis in magna anim consectetur.\r\n",
+ "Irure culpa esse qui do dolor fugiat veniam ad. Elit commodo aute elit magna incididunt tempor pariatur velit irure pariatur cillum et ea ad. Ad consequat ea et ad minim ut sunt qui commodo voluptate. Laboris est aliquip anim reprehenderit eu officia et exercitation. Occaecat laboris cupidatat Lorem ullamco in nostrud commodo ipsum in quis esse ex.\r\n",
+ "Incididunt officia quis voluptate eiusmod esse nisi ipsum quis commodo. Eiusmod dolore tempor occaecat sit exercitation aliqua minim consequat minim mollit qui ad nisi. Aute quis irure adipisicing veniam nisi nisi velit deserunt incididunt anim nostrud.\r\n",
+ "Voluptate exercitation exercitation id minim excepteur excepteur mollit. Fugiat aute proident nulla ullamco ea. Nisi ea culpa duis dolore veniam anim tempor officia in dolore exercitation exercitation. Dolore quis cillum adipisicing sunt do nulla esse proident ad sint.\r\n",
+ "Laborum ut mollit sint commodo nulla laborum deserunt Lorem magna commodo mollit tempor deserunt ut. Qui aliquip commodo ea id. Consectetur dolor fugiat dolor excepteur eiusmod. Eu excepteur ex aute ex ex elit ex esse officia cillum exercitation. Duis ut labore ea nostrud excepteur. Reprehenderit labore aute sunt nisi quis Lorem officia. Ad aliquip cupidatat voluptate exercitation voluptate ad irure magna quis.\r\n",
+ "Tempor velit veniam sit labore elit minim do elit cillum eiusmod sunt excepteur nisi. Aliquip est deserunt excepteur duis fugiat incididunt veniam fugiat. Pariatur sit irure labore et minim non. Cillum quis aute anim sint laboris laboris ullamco exercitation nostrud. Nulla pariatur id laborum minim nisi est adipisicing irure.\r\n",
+ "Irure exercitation laboris nostrud in do consectetur ad. Magna aliqua Lorem culpa exercitation sint do culpa incididunt mollit eu exercitation. Elit tempor Lorem dolore enim deserunt. Anim et ullamco sint ullamco mollit cillum officia et. Proident incididunt laboris aliquip laborum sint veniam deserunt eu consequat deserunt voluptate laboris. Anim Lorem non laborum exercitation voluptate. Cupidatat reprehenderit culpa Lorem fugiat enim minim consectetur tempor quis ad reprehenderit laboris irure.\r\n",
+ "Deserunt elit mollit nostrud occaecat labore reprehenderit laboris ex. Esse reprehenderit adipisicing cillum minim in esse aliquip excepteur ex et nisi cillum quis. Cillum labore ut ex sunt. Occaecat proident et mollit magna consequat irure esse. Dolor do enim esse nisi ad.\r\n",
+ "Pariatur est anim cillum minim elit magna adipisicing quis tempor proident nisi laboris incididunt cupidatat. Nulla est adipisicing sit adipisicing id nostrud amet qui consequat eiusmod tempor voluptate ad. Adipisicing non magna sit occaecat magna mollit ad ex nulla velit ea pariatur. Irure labore ad ea exercitation ex cillum.\r\n",
+ "Lorem fugiat eu eu cillum nulla tempor sint. Lorem id officia nulla velit labore ut duis ad tempor non. Excepteur quis aute adipisicing nisi nisi consectetur aliquip enim Lorem id ullamco cillum sint voluptate. Qui aliquip incididunt tempor aliqua voluptate labore reprehenderit. Veniam eiusmod elit occaecat voluptate tempor culpa consectetur ea ut exercitation eiusmod exercitation qui.\r\n",
+ "Aliqua esse pariatur nulla veniam velit ea. Aliquip consectetur tempor ex magna sit aliquip exercitation veniam. Dolor ullamco minim commodo pariatur. Et amet reprehenderit dolore proident elit tempor eiusmod eu incididunt enim ullamco. Adipisicing id officia incididunt esse dolor sunt cupidatat do deserunt mollit do non. Magna ut officia fugiat adipisicing quis ea cillum laborum dolore ad nostrud magna minim est. Dolor voluptate officia proident enim ea deserunt eu voluptate dolore proident laborum officia ea.\r\n",
+ "Culpa aute consequat esse fugiat cupidatat minim voluptate voluptate eiusmod irure anim elit. Do eiusmod culpa laboris consequat incididunt minim nostrud eiusmod commodo velit ea ullamco proident. Culpa pariatur magna ut mollit nisi. Ea officia do magna deserunt minim nisi tempor ea deserunt veniam cillum exercitation esse.\r\n",
+ "Anim ullamco nostrud commodo Lorem. Do sunt laborum exercitation proident proident magna. Lorem officia laborum laborum dolor sunt duis commodo Lorem. Officia aute adipisicing ea cupidatat ea dolore. Aliquip adipisicing pariatur consectetur aliqua sit amet officia reprehenderit laborum culpa. Occaecat Lorem eu nisi do Lorem occaecat enim eiusmod laboris id quis. Ad mollit adipisicing sunt adipisicing esse.\r\n",
+ "Laborum quis sit adipisicing cupidatat. Veniam Lorem eiusmod esse esse sint nisi labore elit et. Deserunt aliqua mollit ut commodo aliqua non incididunt ipsum reprehenderit consectetur. Eiusmod nulla minim laboris Lorem ea Lorem aute tempor pariatur in sit. Incididunt culpa ut do irure amet irure cupidatat est anim anim culpa occaecat. Est velit consectetur eiusmod veniam reprehenderit officia sunt occaecat eiusmod ut sunt occaecat amet.\r\n",
+ "Elit minim aute fugiat nulla ex quis. Labore fugiat sint nostrud amet quis culpa excepteur in. Consectetur exercitation cupidatat laborum sit. Aute nisi eu aliqua est deserunt eiusmod commodo dolor id. Mollit laborum esse sint ipsum voluptate reprehenderit velit et. Veniam aliquip enim in veniam Lorem voluptate quis deserunt consequat qui commodo ut excepteur aute.\r\n",
+ "Dolore deserunt veniam aute nisi labore sunt et voluptate irure nisi anim ea. Magna nisi quis anim mollit nisi est dolor do ex aliquip elit aliquip ipsum minim. Dolore est officia nostrud eiusmod ex laborum ea amet est. Officia culpa non est et tempor consectetur exercitation tempor eiusmod enim. Ea tempor laboris qui amet ex nisi culpa dolore consectetur incididunt sunt sunt. Lorem aliquip incididunt magna do et ullamco ex elit aliqua eiusmod qui. Commodo amet dolor sint incididunt ex veniam non Lorem fugiat.\r\n",
+ "Officia culpa enim voluptate dolore commodo. Minim commodo aliqua minim ex sint excepteur cupidatat adipisicing eu irure. Anim magna deserunt anim Lorem non.\r\n",
+ "Cupidatat aliquip nulla excepteur sunt cupidatat cupidatat laborum cupidatat exercitation. Laboris minim ex cupidatat culpa elit. Amet enim reprehenderit aliqua laborum est tempor exercitation cupidatat ex dolore do. Do incididunt labore fugiat commodo consectetur nisi incididunt irure sit culpa sit. Elit aute occaecat qui excepteur velit proident cillum qui aliqua ex do ex. Dolore irure ex excepteur veniam id proident mollit Lorem.\r\n",
+ "Ad commodo cillum duis deserunt elit officia consectetur veniam eiusmod. Reprehenderit et veniam ad commodo reprehenderit magna elit laboris sunt non quis. Adipisicing dolor aute proident ea magna sunt et proident in consectetur.\r\n",
+ "Veniam exercitation esse esse veniam est nisi. Minim velit incididunt sint aute dolor anim. Fugiat cupidatat id ad nisi in voluptate dolor culpa eiusmod magna eiusmod amet id. Duis aliquip labore et ex amet amet aliquip laborum eiusmod ipsum. Quis qui ut duis duis. Minim in voluptate reprehenderit aliqua.\r\n",
+ "Elit ut pariatur dolor veniam ipsum consequat. Voluptate Lorem mollit et esse dolore mollit Lorem ad. Elit nostrud eu Lorem labore mollit minim cupidatat officia quis minim dolore incididunt. In cillum aute cillum ut.\r\n",
+ "Commodo laborum deserunt ut cupidatat pariatur ullamco in esse anim exercitation cillum duis. Consectetur incididunt sit esse Lorem in aute. Eiusmod mollit Lorem consequat minim reprehenderit laborum enim excepteur irure nisi elit. Laborum esse proident aute aute proident adipisicing laborum. Pariatur tempor duis incididunt qui velit pariatur ut officia ea mollit labore dolore. Cillum pariatur minim ullamco sunt incididunt culpa id ullamco exercitation consectetur. Ea exercitation consequat reprehenderit ut ullamco velit eu ad velit magna excepteur eiusmod.\r\n",
+ "Eu deserunt magna laboris laborum laborum in consequat dolore. Officia proident consectetur proident do occaecat minim pariatur officia ipsum sit non velit officia cillum. Laborum excepteur labore eu minim eiusmod. Sit anim dolore cillum ad do minim culpa sit est ad.\r\n",
+ "Cupidatat dolor nostrud Lorem sint consequat quis. Quis labore sint incididunt officia tempor. Fugiat nostrud in elit reprehenderit dolor. Nisi sit enim officia minim est adipisicing nulla aute labore nulla nostrud cupidatat est. Deserunt dolore qui irure Lorem esse voluptate velit qui nostrud.\r\n",
+ "Fugiat Lorem amet nulla nisi qui amet laboris enim cillum. Dolore occaecat exercitation id labore velit do commodo ut cupidatat laborum velit fugiat mollit. Ut et aliqua pariatur occaecat. Lorem occaecat dolore quis esse enim cupidatat exercitation ut tempor sit laboris fugiat adipisicing. Est tempor ex irure consectetur ipsum magna labore. Lorem non quis qui minim nisi magna amet aliquip ex cillum fugiat tempor.\r\n",
+ "Aliquip eiusmod laborum ipsum deserunt velit esse do magna excepteur consectetur exercitation sit. Minim ullamco reprehenderit commodo nostrud exercitation id irure ex qui ullamco sit esse laboris. Nulla cillum non minim qui cillum nisi aute proident. Dolor anim culpa elit quis excepteur aliqua eiusmod. Elit ea est excepteur consectetur sunt eiusmod enim id commodo irure amet et pariatur laboris. Voluptate magna ad magna dolore cillum cillum irure laboris ipsum officia id Lorem veniam.\r\n",
+ "Esse sunt elit est aliquip cupidatat commodo deserunt. Deserunt pariatur ipsum qui ad esse esse magna qui cillum laborum. Exercitation veniam pariatur elit amet enim.\r\n",
+ "Esse quis in id elit nulla occaecat incididunt. Et amet Lorem mollit in veniam do. Velit mollit Lorem consequat commodo Lorem aliquip cupidatat. Minim consequat nostrud nulla in nostrud.\r\n",
+ "Cillum nulla et eu est nostrud quis elit cupidatat dolor enim excepteur exercitation nisi voluptate. Nulla dolore non ex velit et qui tempor proident id deserunt nisi eu. Tempor ad Lorem ipsum reprehenderit in anim. Anim dolore ullamco enim deserunt quis ex id exercitation velit. Magna exercitation fugiat mollit pariatur ipsum ex consectetur nostrud. Id dolore officia nostrud excepteur laborum. Magna incididunt elit ipsum pariatur adipisicing enim duis est qui commodo velit aute.\r\n",
+ "Quis esse ex qui nisi dolor. Ullamco laborum dolor esse laboris eiusmod ea magna laboris ea esse ut. Dolore ipsum pariatur veniam sint mollit. Lorem ea proident fugiat ullamco ut nisi culpa eu exercitation exercitation aliquip veniam laborum consectetur.\r\n",
+ "Pariatur veniam laboris sit aliquip pariatur tempor aute sunt id et ut. Laboris excepteur eiusmod nisi qui quis elit enim ut cupidatat. Et et laborum in fugiat veniam consectetur ipsum laboris duis excepteur ullamco aliqua dolor Lorem. Aliqua ex amet sint anim cupidatat nisi ipsum anim et sunt deserunt. Occaecat culpa ut tempor cillum pariatur ex tempor.\r\n",
+ "Dolor deserunt eiusmod magna do officia voluptate excepteur est cupidatat. Veniam qui cupidatat amet anim est qui consectetur sit commodo commodo ea ad. Enim ad adipisicing qui nostrud. Non nulla esse ullamco nulla et ex.\r\n",
+ "Id ullamco ea consectetur est incididunt deserunt et esse. Elit nostrud voluptate eiusmod ut. Excepteur adipisicing qui cupidatat consequat labore id. Qui dolor aliqua do dolore do cupidatat labore ex consectetur ea sit cillum. Sint veniam eiusmod in consectetur consequat fugiat et mollit ut fugiat esse dolor adipisicing.\r\n",
+ "Ea magna proident labore duis pariatur. Esse cillum aliquip dolor duis fugiat ea ex officia ea irure. Sint elit nisi pariatur sunt nostrud exercitation ullamco culpa magna do.\r\n",
+ "Minim aliqua voluptate dolor consequat sint tempor deserunt amet magna excepteur. Irure do voluptate magna velit. Nostrud in reprehenderit magna officia nostrud. Cupidatat nulla irure laboris non fugiat ex ex est cupidatat excepteur officia aute velit duis. Sit voluptate id ea exercitation deserunt culpa voluptate nostrud est adipisicing incididunt. Amet proident laborum commodo magna ipsum quis.\r\n",
+ "Ipsum consectetur consectetur excepteur tempor eiusmod ea fugiat aute velit magna in officia sunt. Sit ut sunt dolore cupidatat dolor adipisicing. Veniam nisi adipisicing esse reprehenderit amet aliqua voluptate ex commodo occaecat est voluptate mollit sunt. Pariatur aliqua qui qui in dolor. Fugiat reprehenderit sit nostrud do sint esse. Tempor sit irure adipisicing ea pariatur duis est sit est incididunt laboris quis do. Et voluptate anim minim aliquip excepteur consequat nisi anim pariatur aliquip ut ipsum dolor magna.\r\n",
+ "Cillum sit labore excepteur magna id aliqua exercitation consequat laborum Lorem id pariatur nostrud. Lorem qui est labore sint cupidatat sint excepteur nulla in eu aliqua et. Adipisicing velit do enim occaecat laboris quis excepteur ipsum dolor occaecat Lorem dolore id exercitation.\r\n",
+ "Incididunt in laborum reprehenderit eiusmod irure ex. Elit duis consequat minim magna. Esse consectetur aliquip cillum excepteur excepteur fugiat. Sint tempor consequat minim reprehenderit consectetur adipisicing dolor id Lorem elit non. Occaecat esse quis mollit ea et sint aute fugiat qui tempor. Adipisicing tempor duis non dolore irure elit deserunt qui do.\r\n",
+ "Labore fugiat eiusmod sint laborum sit duis occaecat. Magna in laborum non cillum excepteur nostrud sit proident pariatur voluptate voluptate adipisicing exercitation occaecat. Ad non dolor aute ex sint do do minim exercitation veniam laborum irure magna ea. Magna do non quis sit consequat Lorem aliquip.\r\n",
+ "Velit anim do laborum laboris laborum Lorem. Sunt do Lorem amet ipsum est sint velit sit do voluptate mollit veniam enim. Commodo do deserunt in pariatur ut elit sint elit deserunt ea. Ad dolor anim consequat aliquip ut mollit nostrud tempor sunt mollit elit. Reprehenderit laboris labore excepteur occaecat veniam adipisicing cupidatat esse. Ad enim aliquip ea minim excepteur magna. Sint velit veniam pariatur qui dolor est adipisicing ex laboris.\r\n",
+ "Ea cupidatat ex nulla in sunt est sit dolor enim ad. Eu tempor consequat cupidatat consequat ex incididunt sint culpa. Est Lorem Lorem non cupidatat sunt ut aliqua non nostrud do ullamco. Reprehenderit ad ad nulla nostrud do nulla in. Ipsum adipisicing commodo mollit ipsum exercitation. Aliqua ea anim anim est elit. Ea incididunt consequat minim ad sunt eu cillum.\r\n",
+ "Tempor quis excepteur eiusmod cupidatat ipsum occaecat id et occaecat. Eiusmod magna aliquip excepteur id amet elit. Ullamco dolore amet anim dolor enim ea magna magna elit. Occaecat magna pariatur in deserunt consectetur officia aliquip ullamco ex aute anim. Minim laborum eu sit elit officia esse do irure pariatur tempor et reprehenderit ullamco labore.\r\n",
+ "Sit tempor eu minim dolore velit pariatur magna duis reprehenderit ea nulla in. Amet est do consectetur commodo do adipisicing adipisicing in amet. Cillum id ut commodo do pariatur duis aliqua nisi sint ad irure officia reprehenderit. Mollit labore id enim fugiat ullamco irure mollit cupidatat. Quis nisi amet labore eu dolor occaecat commodo aliqua laboris deserunt excepteur deserunt officia. Aliqua non ut sit ad. Laborum veniam ad velit minim dolore ea id magna dolor qui in.\r\n",
+ "Dolore nostrud ipsum aliqua pariatur id reprehenderit enim ad eiusmod qui. Deserunt anim commodo pariatur excepteur velit eu irure nulla ex labore ipsum aliqua minim aute. Id consequat amet tempor aliquip ex elit adipisicing est do. Eu enim Lorem consectetur minim id irure nulla culpa. Consectetur do consequat aute tempor anim. Qui ad non elit dolor est adipisicing nisi amet cillum sunt quis anim laboris incididunt. Incididunt proident adipisicing labore Lorem.\r\n",
+ "Et reprehenderit ea officia veniam. Aliquip ullamco consequat elit nisi magna mollit id elit. Amet amet sint velit labore ad nisi. Consectetur tempor id dolor aliqua esse deserunt amet. Qui laborum enim proident voluptate aute eu aute aute sit sit incididunt eu. Sunt ullamco nisi nostrud labore commodo non consectetur quis do duis minim irure. Tempor sint dolor sint aliquip dolore nostrud fugiat.\r\n",
+ "Aute ullamco quis nisi ut excepteur nostrud duis elit. Veniam ex ad incididunt veniam voluptate. Commodo dolore ullamco sit sint adipisicing proident amet aute duis deserunt.\r\n",
+ "Labore velit eu cillum nisi. Laboris do cupidatat et non duis cillum. Ullamco dolor tempor cupidatat voluptate laborum ullamco ea duis.\r\n",
+ "Deserunt consequat aliqua duis aliquip nostrud nostrud dolore nisi. Culpa do sint laborum consectetur ipsum quis laborum laborum pariatur eiusmod. Consectetur laboris ad ad ut quis. Ullamco laboris qui velit id laborum voluptate qui aute nostrud aliquip ea.\r\n",
+ "Ad cillum anim ex est consectetur mollit id in. Non enim aliquip consequat qui deserunt commodo cillum ad laborum fugiat. Dolor deserunt amet laborum tempor adipisicing voluptate dolor pariatur dolor cillum. Eu mollit ex sunt officia veniam qui est sunt proident. Non aliqua qui elit eu cupidatat ex enim ex proident. Lorem sit minim ullamco officia cupidatat duis minim. Exercitation laborum deserunt voluptate culpa tempor quis nulla id pariatur.\r\n",
+ "Nostrud quis consectetur ut aliqua excepteur elit consectetur occaecat. Occaecat voluptate Lorem pariatur consequat ullamco fugiat minim. Anim voluptate eu eu cillum tempor dolore aliquip aliqua. Fugiat incididunt ut tempor amet minim. Voluptate nostrud minim pariatur non excepteur ullamco.\r\n",
+ "Dolore nulla velit officia exercitation irure laboris incididunt anim in laborum in fugiat ut proident. Fugiat aute id consequat fugiat officia ut. Labore sint amet proident amet sint nisi laboris amet id ullamco culpa quis consequat proident. Magna do fugiat veniam dolore elit irure minim. Esse ullamco excepteur labore tempor labore fugiat dolore nisi cupidatat irure dolor pariatur. Magna excepteur laboris nisi eiusmod sit pariatur mollit.\r\n",
+ "In enim aliquip officia ea ad exercitation cillum culpa occaecat dolore Lorem. Irure cillum commodo adipisicing sunt pariatur ea duis fugiat exercitation laboris culpa ullamco aute. Ut voluptate exercitation qui dolor. Irure et duis elit consequat deserunt proident.\r\n",
+ "Officia ea Lorem sunt culpa id et tempor excepteur enim deserunt proident. Dolore aliquip dolor laboris cillum proident velit. Et culpa occaecat exercitation cupidatat irure sint adipisicing excepteur pariatur incididunt ad occaecat. Qui proident ipsum cillum minim. Quis ut culpa irure aliqua minim fugiat. In voluptate cupidatat fugiat est laborum dolor esse in pariatur voluptate.\r\n",
+ "Voluptate enim ipsum officia aute ea adipisicing nisi ut ex do aliquip amet. Reprehenderit enim voluptate tempor ex adipisicing culpa. Culpa occaecat voluptate dolor mollit ipsum exercitation labore et tempor sit ea consectetur aliqua. Elit elit sit minim ea ea commodo do tempor cupidatat irure dolore. Occaecat esse adipisicing anim eiusmod commodo fugiat mollit amet. Incididunt tempor tempor qui occaecat cupidatat in.\r\n",
+ "Ut qui anim velit enim aliquip do ut nulla labore. Mollit ut commodo ut eiusmod consectetur laboris aliqua qui voluptate culpa fugiat incididunt elit. Lorem ullamco esse elit elit. Labore amet incididunt ea nulla aliquip eiusmod. Sit nulla est voluptate officia ipsum aute aute cillum tempor deserunt. Laboris commodo eiusmod labore sunt aute excepteur ea consectetur reprehenderit veniam nisi. Culpa nisi sint sunt sint tempor laboris dolore cupidatat.\r\n",
+ "Duis cillum qui nisi duis amet velit ad cillum ut elit aute sint ad. Amet laboris pariatur excepteur ipsum Lorem aliqua veniam Lorem quis mollit cupidatat aliqua exercitation. Pariatur ex ullamco sit commodo cillum eiusmod ut proident elit cillum. Commodo ut ipsum excepteur occaecat sint elit consequat ex dolor adipisicing consectetur id ut ad. Velit sit eiusmod est esse tempor incididunt consectetur eiusmod duis commodo veniam.\r\n",
+ "Ut sunt qui officia anim laboris exercitation Lorem quis laborum do eiusmod officia. Enim consectetur occaecat fugiat cillum cillum. Dolore dolore nostrud in commodo fugiat mollit consequat occaecat non et et elit ullamco. Sit voluptate minim ut est culpa velit nulla fugiat reprehenderit eu aliquip adipisicing labore. Sit minim minim do dolor dolor. Lorem Lorem labore exercitation magna veniam eiusmod do.\r\n",
+ "Fugiat dolor adipisicing quis aliquip aute dolore. Qui proident anim elit veniam ex aliquip eiusmod ipsum sunt pariatur est. Non fugiat duis do est officia adipisicing.\r\n",
+ "Nulla deserunt do laboris cupidatat veniam do consectetur ipsum elit veniam in mollit eu. Ea in consequat cupidatat laboris sint fugiat irure. In commodo esse reprehenderit deserunt minim velit ullamco enim eu cupidatat tempor ex. Ullamco in non id culpa amet occaecat culpa nostrud id. Non occaecat culpa magna incididunt.\r\n",
+ "Enim laboris ex mollit reprehenderit eiusmod exercitation magna. Exercitation Lorem ex mollit non non culpa labore enim. Adipisicing labore dolore incididunt do amet aliquip excepteur ad et nostrud officia aute veniam voluptate. Fugiat enim eiusmod Lorem esse. Minim ullamco commodo consequat ex commodo aliqua eu nulla eu. Veniam non enim nulla ut Lorem nostrud minim sint duis.\r\n",
+ "Enim duis consectetur in ullamco cillum veniam nulla amet. Exercitation nisi sunt sunt duis in culpa nisi magna ex id ipsum laboris reprehenderit qui. Officia pariatur qui ex fugiat veniam et sunt sit nostrud. Veniam ullamco tempor fugiat minim Lorem proident velit in eiusmod elit. Enim minim excepteur aute aliquip ex magna commodo dolore qui et labore. Proident eu aliquip cillum dolor. Nostrud ipsum ut irure consequat fugiat nulla proident occaecat laborum.\r\n",
+ "Amet duis eiusmod sunt adipisicing esse ex nostrud consectetur voluptate cillum. Ipsum occaecat sit et anim velit irure ea incididunt cupidatat ullamco in nisi quis. Esse officia ipsum commodo qui quis qui do. Commodo aliquip amet aute sit sit ut cupidatat elit nostrud.\r\n",
+ "Laboris laboris sit mollit cillum nulla deserunt commodo culpa est commodo anim id anim sit. Officia id consectetur velit incididunt est dolor sunt ipsum magna aliqua consectetur. Eiusmod pariatur minim deserunt cupidatat veniam Lorem aliquip sunt proident eu Lorem sit dolor fugiat. Proident qui ut ex in incididunt nulla nulla dolor ex laboris ea ad.\r\n",
+ "Ex incididunt enim labore nulla cupidatat elit. Quis ut incididunt incididunt non irure commodo do mollit cillum anim excepteur. Qui consequat laborum dolore elit tempor aute ut nulla pariatur eu ullamco veniam. Nisi non velit labore in commodo excepteur culpa nulla tempor cillum. Ipsum qui sit sint reprehenderit ut labore incididunt dolor aliquip sunt. Reprehenderit occaecat tempor nisi laborum.\r\n",
+ "Lorem officia ullamco eu occaecat in magna eiusmod consectetur nisi aliqua mollit esse. Ullamco ex aute nostrud pariatur do enim cillum sint do fugiat nostrud culpa tempor. Do aliquip excepteur nostrud culpa eu pariatur eiusmod cillum excepteur do. Est sunt non quis cillum voluptate ex.\r\n",
+ "Deserunt consectetur tempor irure mollit qui tempor et. Labore enim eu irure laboris in. Nisi in tempor ex occaecat amet cupidatat laboris occaecat amet minim ut magna incididunt id. Consequat cillum laborum commodo mollit. Et magna culpa sunt dolore consequat laboris et sit. Deserunt qui voluptate excepteur dolor. Eu qui amet est proident.\r\n",
+ "Eu elit minim eiusmod occaecat eu nostrud dolor qui ut elit. Sunt dolore proident ea eu do eiusmod fugiat incididunt pariatur duis amet Lorem nisi ut. Adipisicing quis veniam cupidatat Lorem sint culpa sunt veniam sint. Excepteur eu exercitation est magna pariatur veniam dolore qui fugiat labore proident eiusmod cillum. Commodo reprehenderit elit proident duis sint magna.\r\n",
+ "Ut aliquip pariatur deserunt nostrud commodo ad proident est exercitation. Sit minim do ea enim sint officia nisi incididunt laborum. Ex amet duis commodo fugiat. Ut aute tempor deserunt irure occaecat aliquip voluptate cillum aute elit qui nostrud.\r\n",
+ "Irure et quis consectetur sit est do sunt aliquip eu. Cupidatat pariatur consequat dolore consectetur. Adipisicing magna velit mollit occaecat do id. Nisi pariatur cupidatat cillum incididunt excepteur consectetur excepteur do laborum deserunt irure pariatur cillum.\r\n",
+ "Adipisicing esse incididunt cillum est irure consequat irure ad aute voluptate. Incididunt do occaecat nostrud do ipsum pariatur Lorem qui laboris et pariatur. Est exercitation dolor culpa ad velit ut et.\r\n",
+ "Sit eiusmod id enim ad ex dolor pariatur do. Ullamco occaecat quis dolor minim non elit labore amet est. Commodo velit eu nulla eiusmod ullamco. Incididunt anim pariatur aute eiusmod veniam tempor enim officia elit id. Elit Lorem est commodo dolore nostrud. Labore et consectetur do exercitation veniam laboris incididunt aliqua proident dolore ea officia cupidatat. Velit laboris aliquip deserunt labore commodo.\r\n",
+ "Proident nostrud labore eu nostrud. Excepteur ut in velit labore ea proident labore ea sint cillum. Incididunt ipsum consectetur officia irure sit pariatur veniam id velit officia mollit. Adipisicing magna voluptate velit excepteur enim consectetur incididunt voluptate tempor occaecat fugiat velit excepteur labore. Do do incididunt qui nisi voluptate enim. Laboris aute sit voluptate cillum pariatur minim excepteur ullamco mollit deserunt.\r\n",
+ "Excepteur laborum adipisicing nisi elit fugiat tempor. Elit laboris qui enim labore duis. Proident tempor in consectetur proident excepteur do ex laboris sit.\r\n",
+ "Dolore do ea incididunt do duis dolore eu labore nisi cupidatat voluptate amet incididunt minim. Nulla pariatur mollit cupidatat adipisicing nulla et. Dolor aliquip in ex magna excepteur. Nulla consequat minim consequat ullamco dolor laboris ullamco eu reprehenderit duis nostrud pariatur.\r\n",
+ "Id nisi labore duis qui. Incididunt laboris tempor aute do sit. Occaecat excepteur est mollit ea in mollit ullamco est amet reprehenderit.\r\n",
+ "Aute labore ipsum velit non voluptate eiusmod et reprehenderit cupidatat occaecat. Lorem tempor tempor consectetur exercitation qui nostrud sunt cillum quis ut non dolore. Reprehenderit consequat reprehenderit laborum qui pariatur anim et officia est cupidatat enim velit velit.\r\n",
+ "Commodo ex et fugiat cupidatat non adipisicing commodo. Minim ad dolore fugiat mollit cupidatat aliqua sunt dolor sit. Labore esse labore velit aute enim. Nulla duis incididunt est aliquip consectetur elit qui incididunt minim minim labore amet sit cillum.\r\n"
+] \ No newline at end of file
diff --git a/3rdparty/rapidjson/bin/types/readme.txt b/3rdparty/rapidjson/bin/types/readme.txt
new file mode 100644
index 00000000000..da1dae675e9
--- /dev/null
+++ b/3rdparty/rapidjson/bin/types/readme.txt
@@ -0,0 +1 @@
+Test data obtained from https://github.com/xpol/lua-rapidjson/tree/master/performance
diff --git a/3rdparty/rapidjson/doc/CMakeLists.txt b/3rdparty/rapidjson/doc/CMakeLists.txt
new file mode 100644
index 00000000000..c1f165a37ad
--- /dev/null
+++ b/3rdparty/rapidjson/doc/CMakeLists.txt
@@ -0,0 +1,25 @@
+find_package(Doxygen)
+
+IF(NOT DOXYGEN_FOUND)
+ MESSAGE(STATUS "No Doxygen found. Documentation won't be built")
+ELSE()
+ file(GLOB SOURCES ${CMAKE_CURRENT_LIST_DIR}/../include/*)
+ file(GLOB MARKDOWN_DOC ${CMAKE_CURRENT_LIST_DIR}/../doc/*.md)
+ list(APPEND MARKDOWN_DOC ${CMAKE_CURRENT_LIST_DIR}/../readme.md)
+
+ CONFIGURE_FILE(Doxyfile.in Doxyfile @ONLY)
+ CONFIGURE_FILE(Doxyfile.zh-cn.in Doxyfile.zh-cn @ONLY)
+
+ add_custom_command(OUTPUT html
+ COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
+ COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile.zh-cn
+ COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/html
+ DEPENDS ${MARKDOWN_DOC} ${SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile*
+ WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../
+ )
+
+ add_custom_target(doc ALL DEPENDS html)
+ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html
+ DESTINATION ${DOC_INSTALL_DIR}
+ COMPONENT doc)
+ENDIF()
diff --git a/3rdparty/rapidjson/doc/Doxyfile.in b/3rdparty/rapidjson/doc/Doxyfile.in
new file mode 100644
index 00000000000..fcb09266097
--- /dev/null
+++ b/3rdparty/rapidjson/doc/Doxyfile.in
@@ -0,0 +1,2368 @@
+# Doxyfile 1.8.7
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = RapidJSON
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "A fast JSON parser/generator for C++ with both SAX/DOM style API"
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = YES
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS = $(RAPIDJSON_SECTIONS)
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. Do not use file names with spaces, bibtex cannot handle them. See
+# also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = readme.md \
+ include/rapidjson/rapidjson.h \
+ include/ \
+ doc/features.md \
+ doc/tutorial.md \
+ doc/pointer.md \
+ doc/stream.md \
+ doc/encoding.md \
+ doc/dom.md \
+ doc/sax.md \
+ doc/schema.md \
+ doc/performance.md \
+ doc/internals.md \
+ doc/faq.md
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.inc \
+ *.md
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE = ./include/rapidjson/msinttypes/
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS = internal
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH = ./doc
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = readme.md
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# compiled with the --with-libclang option.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = NO
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER = ./doc/misc/header.html
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER = ./doc/misc/footer.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
+# defined cascading style sheet that is included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet file to the output directory. For an example
+# see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET = ./doc/misc/doxygenextra.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = YES
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://www.mathjax.org/mathjax
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
+# replace them by respectively the title of the page, the current date and time,
+# only the current date, the version number of doxygen, the project name (see
+# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = YES
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED = \
+ RAPIDJSON_DOXYGEN_RUNNING \
+ RAPIDJSON_NAMESPACE_BEGIN="namespace rapidjson {" \
+ RAPIDJSON_NAMESPACE_END="}" \
+ RAPIDJSON_REMOVEFPTR_(x)=x \
+ RAPIDJSON_ENABLEIF_RETURN(cond,returntype)="RAPIDJSON_REMOVEFPTR_ returntype" \
+ RAPIDJSON_DISABLEIF_RETURN(cond,returntype)="RAPIDJSON_REMOVEFPTR_ returntype"
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED = \
+ RAPIDJSON_NOEXCEPT
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font n the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/3rdparty/rapidjson/doc/Doxyfile.zh-cn.in b/3rdparty/rapidjson/doc/Doxyfile.zh-cn.in
new file mode 100644
index 00000000000..76d828b5e69
--- /dev/null
+++ b/3rdparty/rapidjson/doc/Doxyfile.zh-cn.in
@@ -0,0 +1,2368 @@
+# Doxyfile 1.8.7
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = RapidJSON
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "一个C++快速JSONè§£æžå™¨åŠç”Ÿæˆå™¨ï¼ŒåŒ…å«SAX/DOM风格API"
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = Chinese
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = YES
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS = $(RAPIDJSON_SECTIONS)
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. Do not use file names with spaces, bibtex cannot handle them. See
+# also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = readme.zh-cn.md \
+ include/rapidjson/rapidjson.h \
+ include/ \
+ doc/features.zh-cn.md \
+ doc/tutorial.zh-cn.md \
+ doc/pointer.zh-cn.md \
+ doc/stream.zh-cn.md \
+ doc/encoding.zh-cn.md \
+ doc/dom.zh-cn.md \
+ doc/sax.zh-cn.md \
+ doc/schema.zh-cn.md \
+ doc/performance.zh-cn.md \
+ doc/internals.md \
+ doc/faq.zh-cn.md
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.inc \
+ *.md
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE = ./include/rapidjson/msinttypes/
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS = internal
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH = ./doc
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = readme.zh-cn.md
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# compiled with the --with-libclang option.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = NO
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html/zh-cn
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER = ./doc/misc/header.html
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER = ./doc/misc/footer.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
+# defined cascading style sheet that is included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet file to the output directory. For an example
+# see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET = ./doc/misc/doxygenextra.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = YES
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://www.mathjax.org/mathjax
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
+# replace them by respectively the title of the page, the current date and time,
+# only the current date, the version number of doxygen, the project name (see
+# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = YES
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED = \
+ RAPIDJSON_DOXYGEN_RUNNING \
+ RAPIDJSON_NAMESPACE_BEGIN="namespace rapidjson {" \
+ RAPIDJSON_NAMESPACE_END="}" \
+ RAPIDJSON_REMOVEFPTR_(x)=x \
+ RAPIDJSON_ENABLEIF_RETURN(cond,returntype)="RAPIDJSON_REMOVEFPTR_ returntype" \
+ RAPIDJSON_DISABLEIF_RETURN(cond,returntype)="RAPIDJSON_REMOVEFPTR_ returntype"
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED = \
+ RAPIDJSON_NOEXCEPT
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font n the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/3rdparty/rapidjson/doc/diagram/architecture.dot b/3rdparty/rapidjson/doc/diagram/architecture.dot
new file mode 100644
index 00000000000..c816c871834
--- /dev/null
+++ b/3rdparty/rapidjson/doc/diagram/architecture.dot
@@ -0,0 +1,50 @@
+digraph {
+ compound=true
+ fontname="Inconsolata, Consolas"
+ fontsize=10
+ margin="0,0"
+ ranksep=0.2
+ nodesep=0.5
+ penwidth=0.5
+ colorscheme=spectral7
+
+ node [shape=box, fontname="Inconsolata, Consolas", fontsize=10, penwidth=0.5, style=filled, fillcolor=white]
+ edge [fontname="Inconsolata, Consolas", fontsize=10, penwidth=0.5]
+
+ subgraph cluster1 {
+ margin="10,10"
+ labeljust="left"
+ label = "SAX"
+ style=filled
+ fillcolor=6
+
+ Reader -> Writer [style=invis]
+ }
+
+ subgraph cluster2 {
+ margin="10,10"
+ labeljust="left"
+ label = "DOM"
+ style=filled
+ fillcolor=7
+
+ Value
+ Document
+ }
+
+ Handler [label="<<concept>>\nHandler"]
+
+ {
+ edge [arrowtail=onormal, dir=back]
+ Value -> Document
+ Handler -> Document
+ Handler -> Writer
+ }
+
+ {
+ edge [arrowhead=vee, style=dashed, constraint=false]
+ Reader -> Handler [label="calls"]
+ Value -> Handler [label="calls"]
+ Document -> Reader [label="uses"]
+ }
+} \ No newline at end of file
diff --git a/3rdparty/rapidjson/doc/diagram/architecture.png b/3rdparty/rapidjson/doc/diagram/architecture.png
new file mode 100644
index 00000000000..556c7e72914
--- /dev/null
+++ b/3rdparty/rapidjson/doc/diagram/architecture.png
Binary files differ
diff --git a/3rdparty/rapidjson/doc/diagram/insituparsing.dot b/3rdparty/rapidjson/doc/diagram/insituparsing.dot
new file mode 100644
index 00000000000..eca0e3854f4
--- /dev/null
+++ b/3rdparty/rapidjson/doc/diagram/insituparsing.dot
@@ -0,0 +1,65 @@
+digraph {
+ compound=true
+ fontname="Inconsolata, Consolas"
+ fontsize=10
+ margin="0,0"
+ ranksep=0.2
+ penwidth=0.5
+
+ node [fontname="Inconsolata, Consolas", fontsize=10, penwidth=0.5]
+ edge [fontname="Inconsolata, Consolas", fontsize=10, arrowhead=normal]
+
+ {
+ node [shape=record, fontsize="8", margin="0.04", height=0.2, color=gray]
+ oldjson [label="\{|\"|m|s|g|\"|:|\"|H|e|l|l|o|\\|n|W|o|r|l|d|!|\"|,|\"|\\|u|0|0|7|3|t|a|r|s|\"|:|1|0|\}", xlabel="Before Parsing"]
+ //newjson [label="\{|\"|<a>m|s|g|\\0|:|\"|<b>H|e|l|l|o|\\n|W|o|r|l|d|!|\\0|\"|,|\"|<c>s|t|a|r|s|\\0|t|a|r|s|:|1|0|\}", xlabel="After Parsing"]
+ newjson [shape=plaintext, label=<
+<table BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="2"><tr>
+<td>{</td>
+<td>"</td><td port="a">m</td><td>s</td><td>g</td><td bgcolor="yellow">\\0</td>
+<td>:</td>
+<td>"</td><td port="b">H</td><td>e</td><td>l</td><td>l</td><td>o</td><td bgcolor="yellow">\\n</td><td bgcolor="yellow">W</td><td bgcolor="yellow">o</td><td bgcolor="yellow">r</td><td bgcolor="yellow">l</td><td bgcolor="yellow">d</td><td bgcolor="yellow">!</td><td bgcolor="yellow">\\0</td><td>"</td>
+<td>,</td>
+<td>"</td><td port="c" bgcolor="yellow">s</td><td bgcolor="yellow">t</td><td bgcolor="yellow">a</td><td bgcolor="yellow">r</td><td bgcolor="yellow">s</td><td bgcolor="yellow">\\0</td><td>t</td><td>a</td><td>r</td><td>s</td>
+<td>:</td>
+<td>1</td><td>0</td>
+<td>}</td>
+</tr></table>
+>, xlabel="After Parsing"]
+ }
+
+ subgraph cluster1 {
+ margin="10,10"
+ labeljust="left"
+ label = "Document by In situ Parsing"
+ style=filled
+ fillcolor=gray95
+ node [shape=Mrecord, style=filled, colorscheme=spectral7]
+
+ root [label="{object|}", fillcolor=3]
+
+ {
+ msg [label="{string|<a>}", fillcolor=5]
+ helloworld [label="{string|<a>}", fillcolor=5]
+ stars [label="{string|<a>}", fillcolor=5]
+ ten [label="{number|10}", fillcolor=6]
+ }
+ }
+
+ oldjson -> root [label=" ParseInsitu()" lhead="cluster1"]
+ edge [arrowhead=vee]
+ root -> { msg; stars }
+
+ edge [arrowhead="none"]
+ msg -> helloworld
+ stars -> ten
+
+ {
+ edge [arrowhead=vee, arrowtail=dot, arrowsize=0.5, dir=both, tailclip=false]
+ msg:a:c -> newjson:a
+ helloworld:a:c -> newjson:b
+ stars:a:c -> newjson:c
+ }
+
+ //oldjson -> newjson [style=invis]
+} \ No newline at end of file
diff --git a/3rdparty/rapidjson/doc/diagram/insituparsing.png b/3rdparty/rapidjson/doc/diagram/insituparsing.png
new file mode 100644
index 00000000000..4400c88466a
--- /dev/null
+++ b/3rdparty/rapidjson/doc/diagram/insituparsing.png
Binary files differ
diff --git a/3rdparty/rapidjson/doc/diagram/iterative-parser-states-diagram.dot b/3rdparty/rapidjson/doc/diagram/iterative-parser-states-diagram.dot
new file mode 100644
index 00000000000..82ebfe1f095
--- /dev/null
+++ b/3rdparty/rapidjson/doc/diagram/iterative-parser-states-diagram.dot
@@ -0,0 +1,62 @@
+digraph {
+ fontname="Inconsolata, Consolas"
+ fontsize=10
+ margin="0,0"
+ penwidth=0.0
+
+ node [fontname="Inconsolata, Consolas", fontsize=10, penwidth=0.5]
+ edge [fontname="Inconsolata, Consolas", fontsize=10, penwidth=0.5]
+
+ node [shape = doublecircle]; Start; Finish;
+ node [shape = box; style = "rounded, filled"; fillcolor=white ];
+
+ Start -> ArrayInitial [label=" ["];
+ Start -> ObjectInitial [label=" {"];
+
+ subgraph clusterArray {
+ margin="10,10"
+ style=filled
+ fillcolor=gray95
+ label = "Array"
+
+ ArrayInitial; Element; ElementDelimiter; ArrayFinish;
+ }
+
+ subgraph clusterObject {
+ margin="10,10"
+ style=filled
+ fillcolor=gray95
+ label = "Object"
+
+ ObjectInitial; MemberKey; KeyValueDelimiter; MemberValue; MemberDelimiter; ObjectFinish;
+ }
+
+ ArrayInitial -> ArrayInitial [label="["];
+ ArrayInitial -> ArrayFinish [label=" ]"];
+ ArrayInitial -> ObjectInitial [label="{", constraint=false];
+ ArrayInitial -> Element [label="string\nfalse\ntrue\nnull\nnumber"];
+
+ Element -> ArrayFinish [label="]"];
+ Element -> ElementDelimiter [label=","];
+
+ ElementDelimiter -> ArrayInitial [label=" ["];
+ ElementDelimiter -> ObjectInitial [label="{"];
+ ElementDelimiter -> Element [label="string\nfalse\ntrue\nnull\nnumber"];
+
+ ObjectInitial -> ObjectFinish [label=" }"];
+ ObjectInitial -> MemberKey [label=" string "];
+
+ MemberKey -> KeyValueDelimiter [label=":"];
+
+ KeyValueDelimiter -> ArrayInitial [label="["];
+ KeyValueDelimiter -> ObjectInitial [label=" {"];
+ KeyValueDelimiter -> MemberValue [label=" string\n false\n true\n null\n number"];
+
+ MemberValue -> ObjectFinish [label="}"];
+ MemberValue -> MemberDelimiter [label=","];
+
+ MemberDelimiter -> MemberKey [label=" string "];
+
+ ArrayFinish -> Finish;
+ ObjectFinish -> Finish;
+}
diff --git a/3rdparty/rapidjson/doc/diagram/iterative-parser-states-diagram.png b/3rdparty/rapidjson/doc/diagram/iterative-parser-states-diagram.png
new file mode 100644
index 00000000000..f315494db1d
--- /dev/null
+++ b/3rdparty/rapidjson/doc/diagram/iterative-parser-states-diagram.png
Binary files differ
diff --git a/3rdparty/rapidjson/doc/diagram/move1.dot b/3rdparty/rapidjson/doc/diagram/move1.dot
new file mode 100644
index 00000000000..a7c1464ad06
--- /dev/null
+++ b/3rdparty/rapidjson/doc/diagram/move1.dot
@@ -0,0 +1,47 @@
+digraph {
+ compound=true
+ fontname="Inconsolata, Consolas"
+ fontsize=10
+ margin="0,0"
+ ranksep=0.2
+ penwidth=0.5
+
+ node [fontname="Inconsolata, Consolas", fontsize=10, penwidth=0.5]
+ edge [fontname="Inconsolata, Consolas", fontsize=10, arrowhead=normal]
+
+ subgraph cluster1 {
+ margin="10,10"
+ labeljust="left"
+ label = "Before"
+ style=filled
+ fillcolor=gray95
+
+ node [shape=Mrecord, style=filled, colorscheme=spectral7]
+
+ {
+ rank = same
+ b1 [label="{b:number|456}", fillcolor=6]
+ a1 [label="{a:number|123}", fillcolor=6]
+ }
+
+ a1 -> b1 [style="dashed", label="Move", dir=back]
+ }
+
+ subgraph cluster2 {
+ margin="10,10"
+ labeljust="left"
+ label = "After"
+ style=filled
+ fillcolor=gray95
+
+ node [shape=Mrecord, style=filled, colorscheme=spectral7]
+
+ {
+ rank = same
+ b2 [label="{b:null|}", fillcolor=1]
+ a2 [label="{a:number|456}", fillcolor=6]
+ }
+ a2 -> b2 [style=invis, dir=back]
+ }
+ b1 -> b2 [style=invis]
+} \ No newline at end of file
diff --git a/3rdparty/rapidjson/doc/diagram/move1.png b/3rdparty/rapidjson/doc/diagram/move1.png
new file mode 100644
index 00000000000..ab322d084bd
--- /dev/null
+++ b/3rdparty/rapidjson/doc/diagram/move1.png
Binary files differ
diff --git a/3rdparty/rapidjson/doc/diagram/move2.dot b/3rdparty/rapidjson/doc/diagram/move2.dot
new file mode 100644
index 00000000000..7037ea6cbb2
--- /dev/null
+++ b/3rdparty/rapidjson/doc/diagram/move2.dot
@@ -0,0 +1,62 @@
+digraph {
+ compound=true
+ fontname="Inconsolata, Consolas"
+ fontsize=10
+ margin="0,0"
+ ranksep=0.2
+ penwidth=0.5
+
+ node [fontname="Inconsolata, Consolas", fontsize=10, penwidth=0.5]
+ edge [fontname="Inconsolata, Consolas", fontsize=10, arrowhead=normal]
+
+ subgraph cluster1 {
+ margin="10,10"
+ labeljust="left"
+ label = "Before Copying (Hypothetic)"
+ style=filled
+ fillcolor=gray95
+
+ node [shape=Mrecord, style=filled, colorscheme=spectral7]
+
+ c1 [label="{contact:array|}", fillcolor=4]
+ c11 [label="{|}"]
+ c12 [label="{|}"]
+ c13 [shape="none", label="...", style="solid"]
+ o1 [label="{o:object|}", fillcolor=3]
+ ghost [label="{o:object|}", style=invis]
+
+ c1 -> o1 [style="dashed", label="AddMember", constraint=false]
+
+ edge [arrowhead=vee]
+ c1 -> { c11; c12; c13 }
+ o1 -> ghost [style=invis]
+ }
+
+ subgraph cluster2 {
+ margin="10,10"
+ labeljust="left"
+ label = "After Copying (Hypothetic)"
+ style=filled
+ fillcolor=gray95
+
+ node [shape=Mrecord, style=filled, colorscheme=spectral7]
+
+ c2 [label="{contact:array|}", fillcolor=4]
+ c3 [label="{array|}", fillcolor=4]
+ c21 [label="{|}"]
+ c22 [label="{|}"]
+ c23 [shape=none, label="...", style="solid"]
+ o2 [label="{o:object|}", fillcolor=3]
+ cs [label="{string|\"contact\"}", fillcolor=5]
+ c31 [label="{|}"]
+ c32 [label="{|}"]
+ c33 [shape="none", label="...", style="solid"]
+
+ edge [arrowhead=vee]
+ c2 -> { c21; c22; c23 }
+ o2 -> cs
+ cs -> c3 [arrowhead=none]
+ c3 -> { c31; c32; c33 }
+ }
+ ghost -> o2 [style=invis]
+} \ No newline at end of file
diff --git a/3rdparty/rapidjson/doc/diagram/move2.png b/3rdparty/rapidjson/doc/diagram/move2.png
new file mode 100644
index 00000000000..8d4fc5bcc22
--- /dev/null
+++ b/3rdparty/rapidjson/doc/diagram/move2.png
Binary files differ
diff --git a/3rdparty/rapidjson/doc/diagram/move3.dot b/3rdparty/rapidjson/doc/diagram/move3.dot
new file mode 100644
index 00000000000..c197b99df59
--- /dev/null
+++ b/3rdparty/rapidjson/doc/diagram/move3.dot
@@ -0,0 +1,60 @@
+digraph {
+ compound=true
+ fontname="Inconsolata, Consolas"
+ fontsize=10
+ margin="0,0"
+ ranksep=0.2
+ penwidth=0.5
+ forcelabels=true
+
+ node [fontname="Inconsolata, Consolas", fontsize=10, penwidth=0.5]
+ edge [fontname="Inconsolata, Consolas", fontsize=10, arrowhead=normal]
+
+ subgraph cluster1 {
+ margin="10,10"
+ labeljust="left"
+ label = "Before Moving"
+ style=filled
+ fillcolor=gray95
+
+ node [shape=Mrecord, style=filled, colorscheme=spectral7]
+
+ c1 [label="{contact:array|}", fillcolor=4]
+ c11 [label="{|}"]
+ c12 [label="{|}"]
+ c13 [shape=none, label="...", style="solid"]
+ o1 [label="{o:object|}", fillcolor=3]
+ ghost [label="{o:object|}", style=invis]
+
+ c1 -> o1 [style="dashed", constraint=false, label="AddMember"]
+
+ edge [arrowhead=vee]
+ c1 -> { c11; c12; c13 }
+ o1 -> ghost [style=invis]
+ }
+
+ subgraph cluster2 {
+ margin="10,10"
+ labeljust="left"
+ label = "After Moving"
+ style=filled
+ fillcolor=gray95
+
+ node [shape=Mrecord, style=filled, colorscheme=spectral7]
+
+ c2 [label="{contact:null|}", fillcolor=1]
+ c3 [label="{array|}", fillcolor=4]
+ c21 [label="{|}"]
+ c22 [label="{|}"]
+ c23 [shape="none", label="...", style="solid"]
+ o2 [label="{o:object|}", fillcolor=3]
+ cs [label="{string|\"contact\"}", fillcolor=5]
+ c2 -> o2 [style="dashed", constraint=false, label="AddMember", style=invis]
+
+ edge [arrowhead=vee]
+ c3 -> { c21; c22; c23 }
+ o2 -> cs
+ cs -> c3 [arrowhead=none]
+ }
+ ghost -> o2 [style=invis]
+} \ No newline at end of file
diff --git a/3rdparty/rapidjson/doc/diagram/move3.png b/3rdparty/rapidjson/doc/diagram/move3.png
new file mode 100644
index 00000000000..558470f1fab
--- /dev/null
+++ b/3rdparty/rapidjson/doc/diagram/move3.png
Binary files differ
diff --git a/3rdparty/rapidjson/doc/diagram/normalparsing.dot b/3rdparty/rapidjson/doc/diagram/normalparsing.dot
new file mode 100644
index 00000000000..b15941ba0fc
--- /dev/null
+++ b/3rdparty/rapidjson/doc/diagram/normalparsing.dot
@@ -0,0 +1,56 @@
+digraph {
+ compound=true
+ fontname="Inconsolata, Consolas"
+ fontsize=10
+ margin="0,0"
+ ranksep=0.2
+ penwidth=0.5
+
+ node [fontname="Inconsolata, Consolas", fontsize=10, penwidth=0.5]
+ edge [fontname="Inconsolata, Consolas", fontsize=10, arrowhead=normal]
+
+ {
+ node [shape=record, fontsize="8", margin="0.04", height=0.2, color=gray]
+ normaljson [label="\{|\"|m|s|g|\"|:|\"|H|e|l|l|o|\\|n|W|o|r|l|d|!|\"|,|\"|\\|u|0|0|7|3|t|a|r|s\"|:|1|0|\}"]
+
+ {
+ rank = same
+ msgstring [label="m|s|g|\\0"]
+ helloworldstring [label="H|e|l|l|o|\\n|W|o|r|l|d|!|\\0"]
+ starsstring [label="s|t|a|r|s\\0"]
+ }
+ }
+
+ subgraph cluster1 {
+ margin="10,10"
+ labeljust="left"
+ label = "Document by Normal Parsing"
+ style=filled
+ fillcolor=gray95
+ node [shape=Mrecord, style=filled, colorscheme=spectral7]
+
+ root [label="{object|}", fillcolor=3]
+
+ {
+ msg [label="{string|<a>}", fillcolor=5]
+ helloworld [label="{string|<a>}", fillcolor=5]
+ stars [label="{string|<a>}", fillcolor=5]
+ ten [label="{number|10}", fillcolor=6]
+ }
+ }
+
+ normaljson -> root [label=" Parse()" lhead="cluster1"]
+ edge [arrowhead=vee]
+ root -> { msg; stars }
+
+ edge [arrowhead="none"]
+ msg -> helloworld
+ stars -> ten
+
+ edge [arrowhead=vee, arrowtail=dot, arrowsize=0.5, dir=both, tailclip=false]
+ msg:a:c -> msgstring:w
+ helloworld:a:c -> helloworldstring:w
+ stars:a:c -> starsstring:w
+
+ msgstring -> helloworldstring -> starsstring [style=invis]
+} \ No newline at end of file
diff --git a/3rdparty/rapidjson/doc/diagram/normalparsing.png b/3rdparty/rapidjson/doc/diagram/normalparsing.png
new file mode 100644
index 00000000000..702512ca367
--- /dev/null
+++ b/3rdparty/rapidjson/doc/diagram/normalparsing.png
Binary files differ
diff --git a/3rdparty/rapidjson/doc/diagram/simpledom.dot b/3rdparty/rapidjson/doc/diagram/simpledom.dot
new file mode 100644
index 00000000000..959cdbb417a
--- /dev/null
+++ b/3rdparty/rapidjson/doc/diagram/simpledom.dot
@@ -0,0 +1,54 @@
+digraph {
+ compound=true
+ fontname="Inconsolata, Consolas"
+ fontsize=10
+ margin="0,0"
+ ranksep=0.2
+ penwidth=0.5
+
+ node [fontname="Inconsolata, Consolas", fontsize=10, penwidth=0.5]
+ edge [fontname="Inconsolata, Consolas", fontsize=10, arrowhead=normal]
+
+ {
+ node [shape=record, fontsize="8", margin="0.04", height=0.2, color=gray]
+ srcjson [label="\{|\"|p|r|o|j|e|c|t|\"|:|\"|r|a|p|i|d|j|s|o|n|\"|,|\"|s|t|a|r|s|\"|:|1|0|\}"]
+ dstjson [label="\{|\"|p|r|o|j|e|c|t|\"|:|\"|r|a|p|i|d|j|s|o|n|\"|,|\"|s|t|a|r|s|\"|:|1|1|\}"]
+ }
+
+ {
+ node [shape="box", style="filled", fillcolor="gray95"]
+ Document2 [label="(Modified) Document"]
+ Writer
+ }
+
+ subgraph cluster1 {
+ margin="10,10"
+ labeljust="left"
+ label = "Document"
+ style=filled
+ fillcolor=gray95
+ node [shape=Mrecord, style=filled, colorscheme=spectral7]
+
+ root [label="{object|}", fillcolor=3]
+
+ {
+ project [label="{string|\"project\"}", fillcolor=5]
+ rapidjson [label="{string|\"rapidjson\"}", fillcolor=5]
+ stars [label="{string|\"stars\"}", fillcolor=5]
+ ten [label="{number|10}", fillcolor=6]
+ }
+
+ edge [arrowhead=vee]
+ root -> { project; stars }
+
+ edge [arrowhead="none"]
+ project -> rapidjson
+ stars -> ten
+ }
+
+ srcjson -> root [label=" Parse()", lhead="cluster1"]
+
+ ten -> Document2 [label=" Increase \"stars\"", ltail="cluster1" ]
+ Document2 -> Writer [label=" Traverse DOM by Accept()"]
+ Writer -> dstjson [label=" Output to StringBuffer"]
+} \ No newline at end of file
diff --git a/3rdparty/rapidjson/doc/diagram/simpledom.png b/3rdparty/rapidjson/doc/diagram/simpledom.png
new file mode 100644
index 00000000000..38d9c5dc126
--- /dev/null
+++ b/3rdparty/rapidjson/doc/diagram/simpledom.png
Binary files differ
diff --git a/3rdparty/rapidjson/doc/diagram/tutorial.dot b/3rdparty/rapidjson/doc/diagram/tutorial.dot
new file mode 100644
index 00000000000..138ddc381d4
--- /dev/null
+++ b/3rdparty/rapidjson/doc/diagram/tutorial.dot
@@ -0,0 +1,58 @@
+digraph {
+ compound=true
+ fontname="Inconsolata, Consolas"
+ fontsize=10
+ margin="0,0"
+ ranksep=0.2
+ penwidth=0.5
+
+ node [fontname="Inconsolata, Consolas", fontsize=10, penwidth=0.5]
+ edge [fontname="Inconsolata, Consolas", fontsize=10]
+
+ subgraph cluster1 {
+ margin="10,10"
+ labeljust="left"
+ label = "Document"
+ style=filled
+ fillcolor=gray95
+ node [shape=Mrecord, style=filled, colorscheme=spectral7]
+
+ root [label="{object|}", fillcolor=3]
+
+ {
+ hello [label="{string|\"hello\"}", fillcolor=5]
+ t [label="{string|\"t\"}", fillcolor=5]
+ f [label="{string|\"f\"}", fillcolor=5]
+ n [label="{string|\"n\"}", fillcolor=5]
+ i [label="{string|\"i\"}", fillcolor=5]
+ pi [label="{string|\"pi\"}", fillcolor=5]
+ a [label="{string|\"a\"}", fillcolor=5]
+
+ world [label="{string|\"world\"}", fillcolor=5]
+ true [label="{true|}", fillcolor=7]
+ false [label="{false|}", fillcolor=2]
+ null [label="{null|}", fillcolor=1]
+ i1 [label="{number|123}", fillcolor=6]
+ pi1 [label="{number|3.1416}", fillcolor=6]
+ array [label="{array|size=4}", fillcolor=4]
+
+ a1 [label="{number|1}", fillcolor=6]
+ a2 [label="{number|2}", fillcolor=6]
+ a3 [label="{number|3}", fillcolor=6]
+ a4 [label="{number|4}", fillcolor=6]
+ }
+
+ edge [arrowhead=vee]
+ root -> { hello; t; f; n; i; pi; a }
+ array -> { a1; a2; a3; a4 }
+
+ edge [arrowhead=none]
+ hello -> world
+ t -> true
+ f -> false
+ n -> null
+ i -> i1
+ pi -> pi1
+ a -> array
+ }
+} \ No newline at end of file
diff --git a/3rdparty/rapidjson/doc/diagram/tutorial.png b/3rdparty/rapidjson/doc/diagram/tutorial.png
new file mode 100644
index 00000000000..8a12924acdd
--- /dev/null
+++ b/3rdparty/rapidjson/doc/diagram/tutorial.png
Binary files differ
diff --git a/3rdparty/rapidjson/doc/diagram/utilityclass.dot b/3rdparty/rapidjson/doc/diagram/utilityclass.dot
new file mode 100644
index 00000000000..1492a8a7af6
--- /dev/null
+++ b/3rdparty/rapidjson/doc/diagram/utilityclass.dot
@@ -0,0 +1,73 @@
+digraph {
+ rankdir=LR
+ compound=true
+ fontname="Inconsolata, Consolas"
+ fontsize=10
+ margin="0,0"
+ ranksep=0.3
+ nodesep=0.15
+ penwidth=0.5
+ colorscheme=spectral7
+
+ node [shape=box, fontname="Inconsolata, Consolas", fontsize=10, penwidth=0.5, style=filled, fillcolor=white]
+ edge [fontname="Inconsolata, Consolas", fontsize=10, penwidth=0.5]
+
+ subgraph cluster0 {
+ style=filled
+ fillcolor=4
+
+ Encoding [label="<<concept>>\nEncoding"]
+
+ edge [arrowtail=onormal, dir=back]
+ Encoding -> { UTF8; UTF16; UTF32; ASCII; AutoUTF }
+ UTF16 -> { UTF16LE; UTF16BE }
+ UTF32 -> { UTF32LE; UTF32BE }
+ }
+
+ subgraph cluster1 {
+ style=filled
+ fillcolor=5
+
+ Stream [label="<<concept>>\nStream"]
+ InputByteStream [label="<<concept>>\nInputByteStream"]
+ OutputByteStream [label="<<concept>>\nOutputByteStream"]
+
+ edge [arrowtail=onormal, dir=back]
+ Stream -> {
+ StringStream; InsituStringStream; StringBuffer;
+ EncodedInputStream; EncodedOutputStream;
+ AutoUTFInputStream; AutoUTFOutputStream
+ InputByteStream; OutputByteStream
+ }
+
+ InputByteStream -> { MemoryStream; FlieReadStream }
+ OutputByteStream -> { MemoryBuffer; FileWriteStream }
+ }
+
+ subgraph cluster2 {
+ style=filled
+ fillcolor=3
+
+ Allocator [label="<<concept>>\nAllocator"]
+
+ edge [arrowtail=onormal, dir=back]
+ Allocator -> { CrtAllocator; MemoryPoolAllocator }
+ }
+
+ {
+ edge [arrowtail=odiamond, arrowhead=vee, dir=both]
+ EncodedInputStream -> InputByteStream
+ EncodedOutputStream -> OutputByteStream
+ AutoUTFInputStream -> InputByteStream
+ AutoUTFOutputStream -> OutputByteStream
+ MemoryPoolAllocator -> Allocator [label="base", tailport=s]
+ }
+
+ {
+ edge [arrowhead=vee, style=dashed]
+ AutoUTFInputStream -> AutoUTF
+ AutoUTFOutputStream -> AutoUTF
+ }
+
+ //UTF32LE -> Stream [style=invis]
+} \ No newline at end of file
diff --git a/3rdparty/rapidjson/doc/diagram/utilityclass.png b/3rdparty/rapidjson/doc/diagram/utilityclass.png
new file mode 100644
index 00000000000..ce029a4d067
--- /dev/null
+++ b/3rdparty/rapidjson/doc/diagram/utilityclass.png
Binary files differ
diff --git a/3rdparty/rapidjson/doc/dom.md b/3rdparty/rapidjson/doc/dom.md
new file mode 100644
index 00000000000..cb25fc4f3af
--- /dev/null
+++ b/3rdparty/rapidjson/doc/dom.md
@@ -0,0 +1,277 @@
+# DOM
+
+Document Object Model(DOM) is an in-memory representation of JSON for query and manipulation. The basic usage of DOM is described in [Tutorial](doc/tutorial.md). This section will describe some details and more advanced usages.
+
+[TOC]
+
+# Template {#Template}
+
+In the tutorial, `Value` and `Document` was used. Similarly to `std::string`, these are actually `typedef` of template classes:
+
+~~~~~~~~~~cpp
+namespace rapidjson {
+
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
+class GenericValue {
+ // ...
+};
+
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
+class GenericDocument : public GenericValue<Encoding, Allocator> {
+ // ...
+};
+
+typedef GenericValue<UTF8<> > Value;
+typedef GenericDocument<UTF8<> > Document;
+
+} // namespace rapidjson
+~~~~~~~~~~
+
+User can customize these template parameters.
+
+## Encoding {#Encoding}
+
+The `Encoding` parameter specifies the encoding of JSON String value in memory. Possible options are `UTF8`, `UTF16`, `UTF32`. Note that, these 3 types are also template class. `UTF8<>` is `UTF8<char>`, which means using char to store the characters. You may refer to [Encoding](doc/encoding.md) for details.
+
+Suppose a Windows application would query localization strings stored in JSON files. Unicode-enabled functions in Windows use UTF-16 (wide character) encoding. No matter what encoding was used in JSON files, we can store the strings in UTF-16 in memory.
+
+~~~~~~~~~~cpp
+using namespace rapidjson;
+
+typedef GenericDocument<UTF16<> > WDocument;
+typedef GenericValue<UTF16<> > WValue;
+
+FILE* fp = fopen("localization.json", "rb"); // non-Windows use "r"
+
+char readBuffer[256];
+FileReadStream bis(fp, readBuffer, sizeof(readBuffer));
+
+AutoUTFInputStream<unsigned, FileReadStream> eis(bis); // wraps bis into eis
+
+WDocument d;
+d.ParseStream<0, AutoUTF<unsigned> >(eis);
+
+const WValue locale(L"ja"); // Japanese
+
+MessageBoxW(hWnd, d[locale].GetString(), L"Test", MB_OK);
+~~~~~~~~~~
+
+## Allocator {#Allocator}
+
+The `Allocator` defines which allocator class is used when allocating/deallocating memory for `Document`/`Value`. `Document` owns, or references to an `Allocator` instance. On the other hand, `Value` does not do so, in order to reduce memory consumption.
+
+The default allocator used in `GenericDocument` is `MemoryPoolAllocator`. This allocator actually allocate memory sequentially, and cannot deallocate one by one. This is very suitable when parsing a JSON into a DOM tree.
+
+Another allocator is `CrtAllocator`, of which CRT is short for C RunTime library. This allocator simply calls the standard `malloc()`/`realloc()`/`free()`. When there is a lot of add and remove operations, this allocator may be preferred. But this allocator is far less efficient than `MemoryPoolAllocator`.
+
+# Parsing {#Parsing}
+
+`Document` provides several functions for parsing. In below, (1) is the fundamental function, while the others are helpers which call (1).
+
+~~~~~~~~~~cpp
+using namespace rapidjson;
+
+// (1) Fundamental
+template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
+GenericDocument& GenericDocument::ParseStream(InputStream& is);
+
+// (2) Using the same Encoding for stream
+template <unsigned parseFlags, typename InputStream>
+GenericDocument& GenericDocument::ParseStream(InputStream& is);
+
+// (3) Using default parse flags
+template <typename InputStream>
+GenericDocument& GenericDocument::ParseStream(InputStream& is);
+
+// (4) In situ parsing
+template <unsigned parseFlags>
+GenericDocument& GenericDocument::ParseInsitu(Ch* str);
+
+// (5) In situ parsing, using default parse flags
+GenericDocument& GenericDocument::ParseInsitu(Ch* str);
+
+// (6) Normal parsing of a string
+template <unsigned parseFlags, typename SourceEncoding>
+GenericDocument& GenericDocument::Parse(const Ch* str);
+
+// (7) Normal parsing of a string, using same Encoding of Document
+template <unsigned parseFlags>
+GenericDocument& GenericDocument::Parse(const Ch* str);
+
+// (8) Normal parsing of a string, using default parse flags
+GenericDocument& GenericDocument::Parse(const Ch* str);
+~~~~~~~~~~
+
+The examples of [tutorial](doc/tutorial.md) uses (8) for normal parsing of string. The examples of [stream](doc/stream.md) uses the first three. *In situ* parsing will be described soon.
+
+The `parseFlags` are combination of the following bit-flags:
+
+Parse flags | Meaning
+------------------------------|-----------------------------------
+`kParseNoFlags` | No flag is set.
+`kParseDefaultFlags` | Default parse flags. It is equal to macro `RAPIDJSON_PARSE_DEFAULT_FLAGS`, which is defined as `kParseNoFlags`.
+`kParseInsituFlag` | In-situ(destructive) parsing.
+`kParseValidateEncodingFlag` | Validate encoding of JSON strings.
+`kParseIterativeFlag` | Iterative(constant complexity in terms of function call stack size) parsing.
+`kParseStopWhenDoneFlag` | After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate `kParseErrorDocumentRootNotSingular` error. Using this flag for parsing multiple JSONs in the same stream.
+`kParseFullPrecisionFlag` | Parse number in full precision (slower). If this flag is not set, the normal precision (faster) is used. Normal precision has maximum 3 [ULP](http://en.wikipedia.org/wiki/Unit_in_the_last_place) error.
+`kParseCommentsFlag` | Allow one-line `// ...` and multi-line `/* ... */` comments (relaxed JSON syntax).
+
+By using a non-type template parameter, instead of a function parameter, C++ compiler can generate code which is optimized for specified combinations, improving speed, and reducing code size (if only using a single specialization). The downside is the flags needed to be determined in compile-time.
+
+The `SourceEncoding` parameter defines what encoding is in the stream. This can be differed to the `Encoding` of the `Document`. See [Transcoding and Validation](#TranscodingAndValidation) section for details.
+
+And the `InputStream` is type of input stream.
+
+## Parse Error {#ParseError}
+
+When the parse processing succeeded, the `Document` contains the parse results. When there is an error, the original DOM is *unchanged*. And the error state of parsing can be obtained by `bool HasParseError()`, `ParseErrorCode GetParseError()` and `size_t GetParseOffset()`.
+
+Parse Error Code | Description
+--------------------------------------------|---------------------------------------------------
+`kParseErrorNone` | No error.
+`kParseErrorDocumentEmpty` | The document is empty.
+`kParseErrorDocumentRootNotSingular` | The document root must not follow by other values.
+`kParseErrorValueInvalid` | Invalid value.
+`kParseErrorObjectMissName` | Missing a name for object member.
+`kParseErrorObjectMissColon` | Missing a colon after a name of object member.
+`kParseErrorObjectMissCommaOrCurlyBracket` | Missing a comma or `}` after an object member.
+`kParseErrorArrayMissCommaOrSquareBracket` | Missing a comma or `]` after an array element.
+`kParseErrorStringUnicodeEscapeInvalidHex` | Incorrect hex digit after `\\u` escape in string.
+`kParseErrorStringUnicodeSurrogateInvalid` | The surrogate pair in string is invalid.
+`kParseErrorStringEscapeInvalid` | Invalid escape character in string.
+`kParseErrorStringMissQuotationMark` | Missing a closing quotation mark in string.
+`kParseErrorStringInvalidEncoding` | Invalid encoding in string.
+`kParseErrorNumberTooBig` | Number too big to be stored in `double`.
+`kParseErrorNumberMissFraction` | Miss fraction part in number.
+`kParseErrorNumberMissExponent` | Miss exponent in number.
+
+The offset of error is defined as the character number from beginning of stream. Currently RapidJSON does not keep track of line number.
+
+To get an error message, RapidJSON provided a English messages in `rapidjson/error/en.h`. User can customize it for other locales, or use a custom localization system.
+
+Here shows an example of parse error handling.
+
+~~~~~~~~~~cpp
+#include "rapidjson/document.h"
+#include "rapidjson/error/en.h"
+
+// ...
+Document d;
+if (d.Parse(json).HasParseError()) {
+ fprintf(stderr, "\nError(offset %u): %s\n",
+ (unsigned)d.GetErrorOffset(),
+ GetParseError_En(d.GetParseErrorCode()));
+ // ...
+}
+~~~~~~~~~~
+
+## In Situ Parsing {#InSituParsing}
+
+From [Wikipedia](http://en.wikipedia.org/wiki/In_situ):
+
+> *In situ* ... is a Latin phrase that translates literally to "on site" or "in position". It means "locally", "on site", "on the premises" or "in place" to describe an event where it takes place, and is used in many different contexts.
+> ...
+> (In computer science) An algorithm is said to be an in situ algorithm, or in-place algorithm, if the extra amount of memory required to execute the algorithm is O(1), that is, does not exceed a constant no matter how large the input. For example, heapsort is an in situ sorting algorithm.
+
+In normal parsing process, a large overhead is to decode JSON strings and copy them to other buffers. *In situ* parsing decodes those JSON string at the place where it is stored. It is possible in JSON because the length of decoded string is always shorter than or equal to the one in JSON. In this context, decoding a JSON string means to process the escapes, such as `"\n"`, `"\u1234"`, etc., and add a null terminator (`'\0'`)at the end of string.
+
+The following diagrams compare normal and *in situ* parsing. The JSON string values contain pointers to the decoded string.
+
+![normal parsing](diagram/normalparsing.png)
+
+In normal parsing, the decoded string are copied to freshly allocated buffers. `"\\n"` (2 characters) is decoded as `"\n"` (1 character). `"\\u0073"` (6 characters) is decoded as `"s"` (1 character).
+
+![instiu parsing](diagram/insituparsing.png)
+
+*In situ* parsing just modified the original JSON. Updated characters are highlighted in the diagram. If the JSON string does not contain escape character, such as `"msg"`, the parsing process merely replace the closing double quotation mark with a null character.
+
+Since *in situ* parsing modify the input, the parsing API needs `char*` instead of `const char*`.
+
+~~~~~~~~~~cpp
+// Read whole file into a buffer
+FILE* fp = fopen("test.json", "r");
+fseek(fp, 0, SEEK_END);
+size_t filesize = (size_t)ftell(fp);
+fseek(fp, 0, SEEK_SET);
+char* buffer = (char*)malloc(filesize + 1);
+size_t readLength = fread(buffer, 1, filesize, fp);
+buffer[readLength] = '\0';
+fclose(fp);
+
+// In situ parsing the buffer into d, buffer will also be modified
+Document d;
+d.ParseInsitu(buffer);
+
+// Query/manipulate the DOM here...
+
+free(buffer);
+// Note: At this point, d may have dangling pointers pointed to the deallocated buffer.
+~~~~~~~~~~
+
+The JSON strings are marked as const-string. But they may not be really "constant". The life cycle of it depends on the JSON buffer.
+
+In situ parsing minimizes allocation overheads and memory copying. Generally this improves cache coherence, which is an important factor of performance in modern computer.
+
+There are some limitations of *in situ* parsing:
+
+1. The whole JSON is in memory.
+2. The source encoding in stream and target encoding in document must be the same.
+3. The buffer need to be retained until the document is no longer used.
+4. If the DOM need to be used for long period after parsing, and there are few JSON strings in the DOM, retaining the buffer may be a memory waste.
+
+*In situ* parsing is mostly suitable for short-term JSON that only need to be processed once, and then be released from memory. In practice, these situation is very common, for example, deserializing JSON to C++ objects, processing web requests represented in JSON, etc.
+
+## Transcoding and Validation {#TranscodingAndValidation}
+
+RapidJSON supports conversion between Unicode formats (officially termed UCS Transformation Format) internally. During DOM parsing, the source encoding of the stream can be different from the encoding of the DOM. For example, the source stream contains a UTF-8 JSON, while the DOM is using UTF-16 encoding. There is an example code in [EncodedInputStream](doc/stream.md).
+
+When writing a JSON from DOM to output stream, transcoding can also be used. An example is in [EncodedOutputStream](doc/stream.md).
+
+During transcoding, the source string is decoded to into Unicode code points, and then the code points are encoded in the target format. During decoding, it will validate the byte sequence in the source string. If it is not a valid sequence, the parser will be stopped with `kParseErrorStringInvalidEncoding` error.
+
+When the source encoding of stream is the same as encoding of DOM, by default, the parser will *not* validate the sequence. User may use `kParseValidateEncodingFlag` to force validation.
+
+# Techniques {#Techniques}
+
+Some techniques about using DOM API is discussed here.
+
+## DOM as SAX Event Publisher
+
+In RapidJSON, stringifying a DOM with `Writer` may be look a little bit weired.
+
+~~~~~~~~~~cpp
+// ...
+Writer<StringBuffer> writer(buffer);
+d.Accept(writer);
+~~~~~~~~~~
+
+Actually, `Value::Accept()` is responsible for publishing SAX events about the value to the handler. With this design, `Value` and `Writer` are decoupled. `Value` can generate SAX events, and `Writer` can handle those events.
+
+User may create custom handlers for transforming the DOM into other formats. For example, a handler which converts the DOM into XML.
+
+For more about SAX events and handler, please refer to [SAX](doc/sax.md).
+
+## User Buffer {#UserBuffer}
+
+Some applications may try to avoid memory allocations whenever possible.
+
+`MemoryPoolAllocator` can support this by letting user to provide a buffer. The buffer can be on the program stack, or a "scratch buffer" which is statically allocated (a static/global array) for storing temporary data.
+
+`MemoryPoolAllocator` will use the user buffer to satisfy allocations. When the user buffer is used up, it will allocate a chunk of memory from the base allocator (by default the `CrtAllocator`).
+
+Here is an example of using stack memory. The first allocator is for storing values, while the second allocator is for storing temporary data during parsing.
+
+~~~~~~~~~~cpp
+typedef GenericDocument<UTF8<>, MemoryPoolAllocator<>, MemoryPoolAllocator<>> DocumentType;
+char valueBuffer[4096];
+char parseBuffer[1024];
+MemoryPoolAllocator<> valueAllocator(valueBuffer, sizeof(valueBuffer));
+MemoryPoolAllocator<> parseAllocator(parseBuffer, sizeof(parseBuffer));
+DocumentType d(&valueAllocator, sizeof(parseBuffer), &parseAllocator);
+d.Parse(json);
+~~~~~~~~~~
+
+If the total size of allocation is less than 4096+1024 bytes during parsing, this code does not invoke any heap allocation (via `new` or `malloc()`) at all.
+
+User can query the current memory consumption in bytes via `MemoryPoolAllocator::Size()`. And then user can determine a suitable size of user buffer.
diff --git a/3rdparty/rapidjson/doc/dom.zh-cn.md b/3rdparty/rapidjson/doc/dom.zh-cn.md
new file mode 100644
index 00000000000..2adf34354b5
--- /dev/null
+++ b/3rdparty/rapidjson/doc/dom.zh-cn.md
@@ -0,0 +1,281 @@
+# DOM
+
+文档对象模型(Document Object Model, DOM)是一ç§ç½äºŽå†…存中的JSON表示方å¼ï¼Œä»¥ä¾›æŸ¥è¯¢åŠæ“作。我们己于[教程](doc/tutorial.md)中介ç»äº†DOM的基本用法,本节将讲述一些细节åŠé«˜çº§ç”¨æ³•。
+
+[TOC]
+
+# æ¨¡æ¿ {#Template}
+
+教程中使用了`Value`å’Œ`Document`类型。与`std::string`相似,这些类型其实是两个模æ¿ç±»çš„`typedef`:
+
+~~~~~~~~~~cpp
+namespace rapidjson {
+
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
+class GenericValue {
+ // ...
+};
+
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
+class GenericDocument : public GenericValue<Encoding, Allocator> {
+ // ...
+};
+
+typedef GenericValue<UTF8<> > Value;
+typedef GenericDocument<UTF8<> > Document;
+
+} // namespace rapidjson
+~~~~~~~~~~
+
+使用者å¯ä»¥è‡ªå®šä¹‰è¿™äº›æ¨¡æ¿å‚数。
+
+## ç¼–ç  {#Encoding}
+
+`Encoding`傿•°æŒ‡æ˜Žåœ¨å†…存中的JSON String使用哪ç§ç¼–ç ã€‚å¯è¡Œçš„选项有`UTF8`ã€`UTF16`ã€`UTF32`ã€‚è¦æ³¨æ„è¿™3个类型其实也是模æ¿ç±»ã€‚`UTF8<>`ç­‰åŒ`UTF8<char>`,这代表它使用`char`æ¥å­˜å‚¨å­—符串。更多细节å¯ä»¥å‚考[ç¼–ç ](encoding.md)。
+
+这里是一个例å­ã€‚å‡è®¾ä¸€ä¸ªWindows应用软件希望查询存储于JSON中的本地化字符串。Windows中å«Unicode的函数使用UTF-16(宽字符)编ç ã€‚无论JSON文件使用哪ç§ç¼–ç ï¼Œæˆ‘们都å¯ä»¥æŠŠå­—符串以UTF-16å½¢å¼å­˜å‚¨åœ¨å†…存。
+
+~~~~~~~~~~cpp
+using namespace rapidjson;
+
+typedef GenericDocument<UTF16<> > WDocument;
+typedef GenericValue<UTF16<> > WValue;
+
+FILE* fp = fopen("localization.json", "rb"); // éžWindowså¹³å°ä½¿ç”¨"r"
+
+char readBuffer[256];
+FileReadStream bis(fp, readBuffer, sizeof(readBuffer));
+
+AutoUTFInputStream<unsigned, FileReadStream> eis(bis); // 包装bisæˆeis
+
+WDocument d;
+d.ParseStream<0, AutoUTF<unsigned> >(eis);
+
+const WValue locale(L"ja"); // Japanese
+
+MessageBoxW(hWnd, d[locale].GetString(), L"Test", MB_OK);
+~~~~~~~~~~
+
+## 分é…器 {#Allocator}
+
+`Allocator`定义当`Document`/`Value`åˆ†é…æˆ–释放内存时使用那个分é…类。`Document`拥有或引用到一个`Allocator`实例。而为了节çœå†…存,`Value`没有这么åšã€‚
+
+`GenericDocument`的缺çœåˆ†é…器是`MemoryPoolAllocator`。此分é…器实际上会顺åºåœ°åˆ†é…内存,并且ä¸èƒ½é€ä¸€é‡Šæ”¾ã€‚当è¦è§£æžä¸€ä¸ªJSON并生æˆDOM,这ç§åˆ†é…器是éžå¸¸åˆé€‚的。
+
+RapidJSON还æä¾›å¦ä¸€ä¸ªåˆ†é…器`CrtAllocator`,当中CRT是Cè¿è¡Œåº“(C RunTime library)的缩写。此分é…器简å•地读用标准的`malloc()`/`realloc()`/`free()`。当我们需è¦è®¸å¤šå¢žå‡æ“作,这ç§åˆ†é…器会更为适åˆã€‚然而这ç§åˆ†é…器远远比`MemoryPoolAllocator`低效。
+
+# è§£æž {#Parsing}
+
+`Document`æä¾›å‡ ä¸ªè§£æžå‡½æ•°ã€‚以下的(1)是根本的函数,其他都是调用(1)çš„å助函数。
+
+~~~~~~~~~~cpp
+using namespace rapidjson;
+
+// (1) 根本
+template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
+GenericDocument& GenericDocument::ParseStream(InputStream& is);
+
+// (2) 使用æµçš„ç¼–ç 
+template <unsigned parseFlags, typename InputStream>
+GenericDocument& GenericDocument::ParseStream(InputStream& is);
+
+// (3) ä½¿ç”¨ç¼ºçœæ ‡å¿—
+template <typename InputStream>
+GenericDocument& GenericDocument::ParseStream(InputStream& is);
+
+// (4) 原ä½è§£æž
+template <unsigned parseFlags>
+GenericDocument& GenericDocument::ParseInsitu(Ch* str);
+
+// (5) 原ä½è§£æžï¼Œä½¿ç”¨ç¼ºçœæ ‡å¿—
+GenericDocument& GenericDocument::ParseInsitu(Ch* str);
+
+// (6) 正常解æžä¸€ä¸ªå­—符串
+template <unsigned parseFlags, typename SourceEncoding>
+GenericDocument& GenericDocument::Parse(const Ch* str);
+
+// (7) 正常解æžä¸€ä¸ªå­—符串,使用Document的编ç 
+template <unsigned parseFlags>
+GenericDocument& GenericDocument::Parse(const Ch* str);
+
+// (8) 正常解æžä¸€ä¸ªå­—ç¬¦ä¸²ï¼Œä½¿ç”¨ç¼ºçœæ ‡å¿—
+GenericDocument& GenericDocument::Parse(const Ch* str);
+~~~~~~~~~~
+
+[教程](tutorial.md)中的例使用(8)去正常解æžå­—符串。而[æµ](stream.md)的例å­ä½¿ç”¨å‰3个函数。我们将ç¨åŽä»‹ç»åŽŸä½ï¼ˆ*In situ*) è§£æžã€‚
+
+`parseFlags`æ˜¯ä»¥ä¸‹ä½æ ‡ç½®çš„组åˆï¼š
+
+è§£æžä½æ ‡å¿— | æ„义
+------------------------------|-----------------------------------
+`kParseNoFlags` | 没有任何标志。
+`kParseDefaultFlags` | 缺çœçš„è§£æžé€‰é¡¹ã€‚它等于`RAPIDJSON_PARSE_DEFAULT_FLAGS`å®ï¼Œæ­¤å®å®šä¹‰ä¸º`kParseNoFlags`。
+`kParseInsituFlag` | 原ä½ï¼ˆç ´å性)解æžã€‚
+`kParseValidateEncodingFlag` | 校验JSON字符串的编ç ã€‚
+`kParseIterativeFlag` | 迭代å¼ï¼ˆè°ƒç”¨å †æ ˆå¤§å°ä¸ºå¸¸æ•°å¤æ‚度)解æžã€‚
+`kParseStopWhenDoneFlag` | 当从æµè§£æžäº†ä¸€ä¸ªå®Œæ•´çš„JSON根节点之åŽï¼Œåœæ­¢ç»§ç»­å¤„ç†ä½™ä¸‹çš„æµã€‚å½“ä½¿ç”¨äº†æ­¤æ ‡å¿—ï¼Œè§£æžå™¨ä¾¿ä¸ä¼šäº§ç”Ÿ`kParseErrorDocumentRootNotSingular`错误。å¯ä½¿ç”¨æœ¬æ ‡å¿—去解æžåŒä¸€ä¸ªæµé‡Œçš„多个JSON。
+`kParseFullPrecisionFlag` | ä½¿ç”¨å®Œæ•´çš„ç²¾ç¡®åº¦åŽ»è§£æžæ•°å­—(较慢)。如ä¸è®¾ç½®æ­¤æ ‡èŠ‚ï¼Œåˆ™ä¼šä½¿ç”¨æ­£å¸¸çš„ç²¾ç¡®åº¦ï¼ˆè¾ƒå¿«ï¼‰ã€‚æ­£å¸¸ç²¾ç¡®åº¦ä¼šæœ‰æœ€å¤š3个[ULP](http://en.wikipedia.org/wiki/Unit_in_the_last_place)的误差。
+`kParseCommentsFlag` | 容许å•行 `// ...` åŠå¤šè¡Œ `/* ... */` 注释(放宽的JSON语法)。
+
+由于使用了éžç±»åž‹æ¨¡æ¿å‚æ•°ï¼Œè€Œä¸æ˜¯å‡½æ•°å‚数,C++编译器能为个别组åˆç”Ÿæˆä»£ç ï¼Œä»¥æ”¹å–„性能åŠå‡å°‘代ç å°ºå¯¸ï¼ˆå½“åªç”¨å•ç§ç‰¹åŒ–)。缺点是需è¦åœ¨ç¼–译期决定标志。
+
+`SourceEncoding`傿•°å®šä¹‰æµä½¿ç”¨äº†ä»€ä¹ˆç¼–ç ã€‚这与`Document`çš„`Encoding`ä¸ç›¸åŒã€‚细节å¯å‚考[转ç å’Œæ ¡éªŒ](#TranscodingAndValidation)一节。
+
+此外`InputStream`是输入æµçš„类型。
+
+## è§£æžé”™è¯¯ {#ParseError}
+
+当解æžè¿‡ç¨‹é¡ºåˆ©å®Œæˆï¼Œ`Document`ä¾¿ä¼šå«æœ‰è§£æžç»“果。当过程出现错误,原æ¥çš„DOM会*ç»´æŒä¸ä¾¿*。å¯ä½¿ç”¨`bool HasParseError()`ã€`ParseErrorCode GetParseError()`åŠ`size_t GetParseOffset()`获å–è§£æžçš„错误状æ€ã€‚
+
+è§£æžé”™è¯¯ä»£å· | æè¿°
+--------------------------------------------|---------------------------------------------------
+`kParseErrorNone` | 无错误。
+`kParseErrorDocumentEmpty` | 文档是空的。
+`kParseErrorDocumentRootNotSingular` | 文档的根åŽé¢ä¸èƒ½æœ‰å…¶å®ƒå€¼ã€‚
+`kParseErrorValueInvalid` | ä¸åˆæ³•的值。
+`kParseErrorObjectMissName` | Objectæˆå‘˜ç¼ºå°‘å字。
+`kParseErrorObjectMissColon` | Objectæˆå‘˜åå­—åŽç¼ºå°‘冒å·ã€‚
+`kParseErrorObjectMissCommaOrCurlyBracket` | Objectæˆå‘˜åŽç¼ºå°‘逗巿ˆ–`}`。
+`kParseErrorArrayMissCommaOrSquareBracket` | Array元素åŽç¼ºå°‘逗巿ˆ–`]` 。
+`kParseErrorStringUnicodeEscapeInvalidHex` | String中的`\\u`转义符åŽå«éžåå…­è¿›ä½æ•°å­—。
+`kParseErrorStringUnicodeSurrogateInvalid` | String中的代ç†å¯¹ï¼ˆsurrogate pair)ä¸åˆæ³•。
+`kParseErrorStringEscapeInvalid` | Stringå«éžæ³•转义字符。
+`kParseErrorStringMissQuotationMark` | String缺少关闭引å·ã€‚
+`kParseErrorStringInvalidEncoding` | Stringå«éžæ³•ç¼–ç ã€‚
+`kParseErrorNumberTooBig` | Number的值太大,ä¸èƒ½å­˜å‚¨äºŽ`double`。
+`kParseErrorNumberMissFraction` | Numberç¼ºå°‘äº†å°æ•°éƒ¨åˆ†ã€‚
+`kParseErrorNumberMissExponent` | Number缺少了指数。
+
+错误的åç§»é‡å®šä¹‰ä¸ºä»Žæµå¼€å§‹è‡³é”™è¯¯å¤„的字符数é‡ã€‚ç›®å‰RapidJSONä¸è®°å½•错误行å·ã€‚
+
+è¦å–得错误讯æ¯ï¼ŒRapidJSON在`rapidjson/error/en.h`中æä¾›äº†è‹±æ–‡é”™è¯¯è®¯æ¯ã€‚使用者å¯ä»¥ä¿®æ”¹å®ƒç”¨äºŽå…¶ä»–语言环境,或使用一个自定义的本地化系统。
+
+以下是一个处ç†é”™è¯¯çš„例å­ã€‚
+
+~~~~~~~~~~cpp
+#include "rapidjson/document.h"
+#include "rapidjson/error/en.h"
+
+// ...
+Document d;
+if (d.Parse(json).HasParseError()) {
+ fprintf(stderr, "\nError(offset %u): %s\n",
+ (unsigned)d.GetErrorOffset(),
+ GetParseError_En(d.GetParseErrorCode()));
+ // ...
+}
+~~~~~~~~~~
+
+## 原ä½è§£æž {#InSituParsing}
+
+æ ¹æ®[维基百科](http://en.wikipedia.org/wiki/In_situ):
+
+> *In situ* ... is a Latin phrase that translates literally to "on site" or "in position". It means "locally", "on site", "on the premises" or "in place" to describe an event where it takes place, and is used in many different contexts.
+> ...
+> (In computer science) An algorithm is said to be an in situ algorithm, or in-place algorithm, if the extra amount of memory required to execute the algorithm is O(1), that is, does not exceed a constant no matter how large the input. For example, heapsort is an in situ sorting algorithm.
+
+> 翻译:*In situ*â€¦â€¦æ˜¯ä¸€ä¸ªæ‹‰ä¸æ–‡ç‰‡è¯­ï¼Œå­—é¢ä¸Šçš„æ„æ€æ˜¯æŒ‡ã€ŒçŽ°åœºã€ã€ã€Œåœ¨ä½ç½®ã€ã€‚在许多ä¸åŒè¯­å¢ƒä¸­ï¼Œå®ƒæè¿°ä¸€ä¸ªäº‹ä»¶å‘生的ä½ç½®ï¼Œæ„指「本地ã€ã€ã€ŒçŽ°åœºã€ã€ã€Œåœ¨å¤„所ã€ã€ã€Œå°±ä½ã€ã€‚
+> ……
+> (在计算机科学中)一个算法若称为原ä½ç®—法,或在ä½ç®—法,是指执行该算法所需的é¢å¤–内存空间是O(1)的,æ¢å¥è¯è¯´ï¼Œæ— è®ºè¾“入大å°éƒ½åªéœ€è¦å¸¸æ•°ç©ºé—´ã€‚ä¾‹å¦‚ï¼Œå †æŽ’åºæ˜¯ä¸€ä¸ªåŽŸä½æŽ’åºç®—法。
+
+在正常的解æžè¿‡ç¨‹ä¸­ï¼Œå¯¹JSON stringè§£ç å¹¶å¤åˆ¶è‡³å…¶ä»–缓冲区是一个很大的开销。原ä½è§£æžï¼ˆ*in situ* parsing)把这些JSON string直接解ç äºŽå®ƒåŽŸæ¥å­˜å‚¨çš„地方。由于解ç åŽçš„string长度总是短于或等于原æ¥å‚¨å­˜äºŽJSONçš„string,所以这是å¯è¡Œçš„。在这个语境下,对JSON stringè¿›è¡Œè§£ç æ˜¯æŒ‡å¤„ç†è½¬ä¹‰ç¬¦ï¼Œå¦‚`"\n"`ã€`"\u1234"`等,以åŠåœ¨string末端加入空终止符å·(`'\0'`)。
+
+以下的图比较正常åŠåŽŸä½è§£æžã€‚JSON stringå€¼åŒ…å«æŒ‡å‘è§£ç åŽçš„字符串。
+
+![正常解æž](diagram/normalparsing.png)
+
+在正常解æžä¸­ï¼Œè§£ç åŽçš„字符串被å¤åˆ¶è‡³å…¨æ–°åˆ†é…的缓冲区中。`"\\n"`(2ä¸ªå­—ç¬¦ï¼‰è¢«è§£ç æˆ`"\n"`(1个字符)。`"\\u0073"`(6ä¸ªå­—ç¬¦ï¼‰è¢«è§£ç æˆ`"s"`(1个字符)。
+
+![原ä½è§£æž](diagram/insituparsing.png)
+
+原ä½è§£æžç›´æŽ¥ä¿®æ”¹äº†åŽŸæ¥çš„JSON。图中高亮了被更新的字符。若JSON stringä¸å«è½¬ä¹‰ç¬¦ï¼Œä¾‹å¦‚`"msg"`,那么解æžè¿‡ç¨‹ä»…仅是以空字符代替结æŸåŒå¼•å·ã€‚
+
+由于原ä½è§£æžä¿®æ”¹äº†è¾“入,其解æžAPI需è¦`char*`而éž`const char*`。
+
+~~~~~~~~~~cpp
+// 把整个文件读入buffer
+FILE* fp = fopen("test.json", "r");
+fseek(fp, 0, SEEK_END);
+size_t filesize = (size_t)ftell(fp);
+fseek(fp, 0, SEEK_SET);
+char* buffer = (char*)malloc(filesize + 1);
+size_t readLength = fread(buffer, 1, filesize, fp);
+buffer[readLength] = '\0';
+fclose(fp);
+
+// 原ä½è§£æžbuffer至d,buffer内容会被修改。
+Document d;
+d.ParseInsitu(buffer);
+
+// 在此查询ã€ä¿®æ”¹DOM……
+
+free(buffer);
+// 注æ„:在这个ä½ç½®ï¼Œdå¯èƒ½å«æœ‰æŒ‡å‘已被释放的buffer的悬空指针
+~~~~~~~~~~
+
+JSON string会被打上const-string的标志。但它们å¯èƒ½å¹¶éžçœŸæ­£çš„「常数ã€ã€‚它的生命周期å–决于存储JSON的缓冲区。
+
+原ä½è§£æžæŠŠåˆ†é…开销åŠå†…å­˜å¤åˆ¶å‡è‡³æœ€å°ã€‚通常这样åšèƒ½æ”¹å–„缓存一致性,而这对现代计算机æ¥è¯´æ˜¯ä¸€ä¸ªé‡è¦çš„æ€§èƒ½å› ç´ ã€‚
+
+原ä½è§£æžæœ‰ä»¥ä¸‹é™åˆ¶ï¼š
+
+1. 整个JSON须存储在内存之中。
+2. æµçš„æ¥æºç¼“ç ä¸Žæ–‡æ¡£çš„目标编ç å¿…须相åŒã€‚
+3. 需è¦ä¿ç•™ç¼“冲区,直至文档ä¸å†è¢«ä½¿ç”¨ã€‚
+4. è‹¥DOM需è¦åœ¨è§£æžåŽè¢«é•¿æœŸä½¿ç”¨ï¼Œè€ŒDOMå†…åªæœ‰å¾ˆå°‘JSON string,ä¿ç•™ç¼“冲区å¯èƒ½é€ æˆå†…存浪费。
+
+原ä½è§£æžæœ€é€‚åˆç”¨äºŽçŸ­æœŸçš„ã€ç”¨å®Œå³å¼ƒçš„JSONã€‚å®žé™…åº”ç”¨ä¸­ï¼Œè¿™äº›åœºåˆæ˜¯éžå¸¸æ™®é的,例如ååºåˆ—化JSON至C++对象ã€å¤„ç†ä»¥JSON表示的web请求等。
+
+## 转ç ä¸Žæ ¡éªŒ {#TranscodingAndValidation}
+
+RapidJSON内部支æŒä¸åŒUnicodeæ ¼å¼ï¼ˆæ­£å¼çš„æœ¯è¯­æ˜¯UCSå˜æ¢æ ¼å¼ï¼‰é—´çš„转æ¢ã€‚在DOMè§£æžæ—¶ï¼Œæµçš„æ¥æºç¼–ç ä¸ŽDOM的编ç å¯ä»¥ä¸åŒã€‚ä¾‹å¦‚ï¼Œæ¥æºæµå¯èƒ½å«æœ‰UTF-8çš„JSON,而DOM则使用UTF-16ç¼–ç ã€‚在[EncodedInputStream](doc/stream.md)一节里有一个例å­ã€‚
+
+当从DOM输出一个JSON至输出æµä¹‹æ—¶ï¼Œä¹Ÿå¯ä»¥ä½¿ç”¨è½¬ç åŠŸèƒ½ã€‚åœ¨[EncodedOutputStream](doc/stream.md)一节里有一个例å­ã€‚
+
+在转ç è¿‡ç¨‹ä¸­ï¼Œä¼šæŠŠæ¥æºstringè§£ç æˆUnicodeç ç‚¹ï¼Œç„¶åŽæŠŠç ç‚¹ç¼–ç æˆç›®æ ‡æ ¼å¼ã€‚åœ¨è§£ç æ—¶ï¼Œå®ƒä¼šæ ¡éªŒæ¥æºstring的字节åºåˆ—是å¦åˆæ³•。若é‡ä¸Šéžåˆæ³•åºåˆ—,解æžå™¨ä¼šåœæ­¢å¹¶è¿”回`kParseErrorStringInvalidEncoding`错误。
+
+å½“æ¥æºç¼–ç ä¸ŽDOM的编ç ç›¸åŒï¼Œè§£æžå™¨ç¼ºçœåœ°*ä¸ä¼š*校验åºåˆ—。使用者å¯å¼€å¯`kParseValidateEncodingFlag`去强制校验。
+
+# 技巧 {#Techniques}
+
+这里讨论一些DOM API的使用技巧。
+
+## 把DOM作为SAX事件å‘表者
+
+在RapidJSON中,利用`Writer`把DOM生æˆJSONçš„åšæ³•ï¼Œçœ‹æ¥æœ‰ç‚¹å¥‡æ€ªã€‚
+
+~~~~~~~~~~cpp
+// ...
+Writer<StringBuffer> writer(buffer);
+d.Accept(writer);
+~~~~~~~~~~
+
+实际上,`Value::Accept()`是负责å‘布该值相关的SAX事件至处ç†å™¨çš„。通过这个设计,`Value`åŠ`Writer`解除了å¶åˆã€‚`Value`å¯ç”ŸæˆSAX事件,而`Writer`则å¯ä»¥å¤„ç†è¿™äº›äº‹ä»¶ã€‚
+
+使用者å¯ä»¥åˆ›å»ºè‡ªå®šä¹‰çš„处ç†å™¨ï¼ŒåŽ»æŠŠDOMè½¬æ¢æˆå…¶å®ƒæ ¼å¼ã€‚例如,一个把DOMè½¬æ¢æˆXML的处ç†å™¨ã€‚
+
+è¦çŸ¥é“更多关于SAX事件与处ç†å™¨ï¼Œå¯å‚阅[SAX](doc/sax.md)。
+
+## 使用者缓冲区{ #UserBuffer}
+
+许多应用软件å¯èƒ½éœ€è¦å°½é‡å‡å°‘内存分é…。
+
+`MemoryPoolAllocator`å¯ä»¥å¸®åŠ©è¿™æ–¹é¢ï¼Œå®ƒå®¹è®¸ä½¿ç”¨è€…æä¾›ä¸€ä¸ªç¼“冲区。该缓冲区å¯èƒ½ç½®äºŽç¨‹åºå †æ ˆï¼Œæˆ–æ˜¯ä¸€ä¸ªé™æ€åˆ†é…的「è‰ç¨¿ç¼“冲区(scratch buffer)ã€ï¼ˆä¸€ä¸ªé™æ€ï¼å…¨å±€çš„æ•°ç»„),用于储存临时数æ®ã€‚
+
+`MemoryPoolAllocator`会先用使用者缓冲区去解决分é…请求。当使用者缓冲区用完,就会从基础分é…器(缺çœä¸º`CrtAllocator`)分é…一å—内存。
+
+以下是使用堆栈内存的例å­ï¼Œç¬¬ä¸€ä¸ªåˆ†é…å™¨ç”¨äºŽå­˜å‚¨å€¼ï¼Œç¬¬äºŒä¸ªç”¨äºŽè§£æžæ—¶çš„临时缓冲。
+
+~~~~~~~~~~cpp
+typedef GenericDocument<UTF8<>, MemoryPoolAllocator<>, MemoryPoolAllocator<>> DocumentType;
+char valueBuffer[4096];
+char parseBuffer[1024];
+MemoryPoolAllocator<> valueAllocator(valueBuffer, sizeof(valueBuffer));
+MemoryPoolAllocator<> parseAllocator(parseBuffer, sizeof(parseBuffer));
+DocumentType d(&valueAllocator, sizeof(parseBuffer), &parseAllocator);
+d.Parse(json);
+~~~~~~~~~~
+
+è‹¥è§£æžæ—¶åˆ†é…总é‡å°‘于4096+1024字节时,这段代ç ä¸ä¼šé€ æˆä»»ä½•堆内存分é…(ç»`new`或`malloc()`)。
+
+使用者å¯ä»¥é€šè¿‡`MemoryPoolAllocator::Size()`查询当å‰å·²åˆ†çš„内存大å°ã€‚那么使用者å¯ä»¥æ‹Ÿå®šä½¿ç”¨è€…缓冲区的åˆé€‚大å°ã€‚
diff --git a/3rdparty/rapidjson/doc/encoding.md b/3rdparty/rapidjson/doc/encoding.md
new file mode 100644
index 00000000000..e9ebe8f2149
--- /dev/null
+++ b/3rdparty/rapidjson/doc/encoding.md
@@ -0,0 +1,146 @@
+# Encoding
+
+According to [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf),
+
+> (in Introduction) JSON text is a sequence of Unicode code points.
+
+The earlier [RFC4627](http://www.ietf.org/rfc/rfc4627.txt) stated that,
+
+> (in §3) JSON text SHALL be encoded in Unicode. The default encoding is UTF-8.
+
+> (in §6) JSON may be represented using UTF-8, UTF-16, or UTF-32. When JSON is written in UTF-8, JSON is 8bit compatible. When JSON is written in UTF-16 or UTF-32, the binary content-transfer-encoding must be used.
+
+RapidJSON supports various encodings. It can also validate the encodings of JSON, and transconding JSON among encodings. All these features are implemented internally, without the need for external libraries (e.g. [ICU](http://site.icu-project.org/)).
+
+[TOC]
+
+# Unicode {#Unicode}
+From [Unicode's official website](http://www.unicode.org/standard/WhatIsUnicode.html):
+> Unicode provides a unique number for every character,
+> no matter what the platform,
+> no matter what the program,
+> no matter what the language.
+
+Those unique numbers are called code points, which is in the range `0x0` to `0x10FFFF`.
+
+## Unicode Transformation Format {#UTF}
+
+There are various encodings for storing Unicode code points. These are called Unicode Transformation Format (UTF). RapidJSON supports the most commonly used UTFs, including
+
+* UTF-8: 8-bit variable-width encoding. It maps a code point to 1–4 bytes.
+* UTF-16: 16-bit variable-width encoding. It maps a code point to 1–2 16-bit code units (i.e., 2–4 bytes).
+* UTF-32: 32-bit fixed-width encoding. It directly maps a code point to a single 32-bit code unit (i.e. 4 bytes).
+
+For UTF-16 and UTF-32, the byte order (endianness) does matter. Within computer memory, they are often stored in the computer's endianness. However, when it is stored in file or transferred over network, we need to state the byte order of the byte sequence, either little-endian (LE) or big-endian (BE).
+
+RapidJSON provide these encodings via the structs in `rapidjson/encodings.h`:
+
+~~~~~~~~~~cpp
+namespace rapidjson {
+
+template<typename CharType = char>
+struct UTF8;
+
+template<typename CharType = wchar_t>
+struct UTF16;
+
+template<typename CharType = wchar_t>
+struct UTF16LE;
+
+template<typename CharType = wchar_t>
+struct UTF16BE;
+
+template<typename CharType = unsigned>
+struct UTF32;
+
+template<typename CharType = unsigned>
+struct UTF32LE;
+
+template<typename CharType = unsigned>
+struct UTF32BE;
+
+} // namespace rapidjson
+~~~~~~~~~~
+
+For processing text in memory, we normally use `UTF8`, `UTF16` or `UTF32`. For processing text via I/O, we may use `UTF8`, `UTF16LE`, `UTF16BE`, `UTF32LE` or `UTF32BE`.
+
+When using the DOM-style API, the `Encoding` template parameter in `GenericValue<Encoding>` and `GenericDocument<Encoding>` indicates the encoding to be used to represent JSON string in memory. So normally we will use `UTF8`, `UTF16` or `UTF32` for this template parameter. The choice depends on operating systems and other libraries that the application is using. For example, Windows API represents Unicode characters in UTF-16, while most Linux distributions and applications prefer UTF-8.
+
+Example of UTF-16 DOM declaration:
+
+~~~~~~~~~~cpp
+typedef GenericDocument<UTF16<> > WDocument;
+typedef GenericValue<UTF16<> > WValue;
+~~~~~~~~~~
+
+For a detail example, please check the example in [DOM's Encoding](doc/stream.md) section.
+
+## Character Type {#CharacterType}
+
+As shown in the declaration, each encoding has a `CharType` template parameter. Actually, it may be a little bit confusing, but each `CharType` stores a code unit, not a character (code point). As mentioned in previous section, a code point may be encoded to 1–4 code units for UTF-8.
+
+For `UTF16(LE|BE)`, `UTF32(LE|BE)`, the `CharType` must be integer type of at least 2 and 4 bytes respectively.
+
+Note that C++11 introduces `char16_t` and `char32_t`, which can be used for `UTF16` and `UTF32` respectively.
+
+## AutoUTF {#AutoUTF}
+
+Previous encodings are statically bound in compile-time. In other words, user must know exactly which encodings will be used in the memory or streams. However, sometimes we may need to read/write files of different encodings. The encoding needed to be decided in runtime.
+
+`AutoUTF` is an encoding designed for this purpose. It chooses which encoding to be used according to the input or output stream. Currently, it should be used with `EncodedInputStream` and `EncodedOutputStream`.
+
+## ASCII {#ASCII}
+
+Although the JSON standards did not mention about [ASCII](http://en.wikipedia.org/wiki/ASCII), sometimes we would like to write 7-bit ASCII JSON for applications that cannot handle UTF-8. Since any JSON can represent unicode characters in escaped sequence `\uXXXX`, JSON can always be encoded in ASCII.
+
+Here is an example for writing a UTF-8 DOM into ASCII:
+
+~~~~~~~~~~cpp
+using namespace rapidjson;
+Document d; // UTF8<>
+// ...
+StringBuffer buffer;
+Writer<StringBuffer, Document::EncodingType, ASCII<> > writer(buffer);
+d.Accept(writer);
+std::cout << buffer.GetString();
+~~~~~~~~~~
+
+ASCII can be used in input stream. If the input stream contains bytes with values above 127, it will cause `kParseErrorStringInvalidEncoding` error.
+
+ASCII *cannot* be used in memory (encoding of `Document` or target encoding of `Reader`), as it cannot represent Unicode code points.
+
+# Validation & Transcoding {#ValidationTranscoding}
+
+When RapidJSON parses a JSON, it can validate the input JSON, whether it is a valid sequence of a specified encoding. This option can be turned on by adding `kParseValidateEncodingFlag` in `parseFlags` template parameter.
+
+If the input encoding and output encoding is different, `Reader` and `Writer` will automatically transcode (convert) the text. In this case, `kParseValidateEncodingFlag` is not necessary, as it must decode the input sequence. And if the sequence was unable to be decoded, it must be invalid.
+
+## Transcoder {#Transcoder}
+
+Although the encoding functions in RapidJSON are designed for JSON parsing/generation, user may abuse them for transcoding of non-JSON strings.
+
+Here is an example for transcoding a string from UTF-8 to UTF-16:
+
+~~~~~~~~~~cpp
+#include "rapidjson/encodings.h"
+
+using namespace rapidjson;
+
+const char* s = "..."; // UTF-8 string
+StringStream source(s);
+GenericStringBuffer<UTF16<> > target;
+
+bool hasError = false;
+while (source.Peak() != '\0')
+ if (!Transcoder::Transcode<UTF8<>, UTF16<> >(source, target)) {
+ hasError = true;
+ break;
+ }
+
+if (!hasError) {
+ const wchar_t* t = target.GetString();
+ // ...
+}
+~~~~~~~~~~
+
+You may also use `AutoUTF` and the associated streams for setting source/target encoding in runtime.
diff --git a/3rdparty/rapidjson/doc/encoding.zh-cn.md b/3rdparty/rapidjson/doc/encoding.zh-cn.md
new file mode 100644
index 00000000000..3435c3ab942
--- /dev/null
+++ b/3rdparty/rapidjson/doc/encoding.zh-cn.md
@@ -0,0 +1,152 @@
+# ç¼–ç 
+
+æ ¹æ®[ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf):
+
+> (in Introduction) JSON text is a sequence of Unicode code points.
+>
+> 翻译:JSON文本是Unicodeç ç‚¹çš„åºåˆ—。
+
+较早的[RFC4627](http://www.ietf.org/rfc/rfc4627.txt)申明:
+
+> (in §3) JSON text SHALL be encoded in Unicode. The default encoding is UTF-8.
+>
+> 翻译:JSON文本应该以Unicodeç¼–ç ã€‚缺çœçš„ç¼–ç ä¸ºUTF-8。
+
+> (in §6) JSON may be represented using UTF-8, UTF-16, or UTF-32. When JSON is written in UTF-8, JSON is 8bit compatible. When JSON is written in UTF-16 or UTF-32, the binary content-transfer-encoding must be used.
+>
+> 翻译:JSONå¯ä½¿ç”¨UTF-8ã€UTF-16或UTF-18表示。当JSON以UTF-8写入,该JSON是8ä½å…¼å®¹çš„。当JSON以UTF-16或UTF-32写入,就必须使用二进制的内容传é€ç¼–ç ã€‚
+
+RapidJSON支æŒå¤šç§ç¼–ç ã€‚它也能检查JSON的编ç ï¼Œä»¥åŠåœ¨ä¸åŒç¼–ç ä¸­è¿›è¡Œè½¬ç ã€‚所有这些功能都是在内部实现,无需使用外部的程åºåº“(如[ICU](http://site.icu-project.org/))。
+
+[TOC]
+
+# Unicode {#Unicode}
+æ ¹æ® [Unicode的官方网站](http://www.unicode.org/standard/translations/t-chinese.html):
+>Unicodeç»™æ¯ä¸ªå­—符æä¾›äº†ä¸€ä¸ªå”¯ä¸€çš„æ•°å­—,
+ä¸è®ºæ˜¯ä»€ä¹ˆå¹³å°ã€
+ä¸è®ºæ˜¯ä»€ä¹ˆç¨‹åºã€
+ä¸è®ºæ˜¯ä»€ä¹ˆè¯­è¨€ã€‚
+
+这些唯一数字称为ç ç‚¹ï¼ˆcode point),其范围介乎`0x0`至`0x10FFFF`之间。
+
+## Unicodeè½¬æ¢æ ¼å¼ {#UTF}
+
+存储Unicodeç ç‚¹æœ‰å¤šç§ç¼–ç æ–¹å¼ã€‚这些称为Unicodeè½¬æ¢æ ¼å¼ï¼ˆUnicode Transformation Format, UTF)。RapidJSONæ”¯æŒæœ€å¸¸ç”¨çš„UTF,包括:
+
+* UTF-8:8ä½å¯å˜é•¿åº¦ç¼–ç ã€‚它把一个ç ç‚¹æ˜ å°„至1至4个字节。
+* UTF-16:16ä½å¯å˜é•¿åº¦ç¼–ç ã€‚它把一个ç ç‚¹æ˜ å°„至1至2个16ä½ç¼–ç å•元(å³2至4个字节)。
+* UTF-32:32ä½å›ºå®šé•¿åº¦ç¼–ç ã€‚它直接把ç ç‚¹æ˜ å°„至å•个32ä½ç¼–ç å•元(å³4字节)。
+
+对于UTF-16åŠUTF-32æ¥è¯´ï¼Œå­—节åºï¼ˆendianness)是有影å“çš„ã€‚åœ¨å†…å­˜ä¸­ï¼Œå®ƒä»¬é€šå¸¸éƒ½æ˜¯ä»¥è¯¥è®¡ç®—æœºçš„å­—èŠ‚åºæ¥å­˜å‚¨ã€‚然而,当è¦å‚¨å­˜åœ¨æ–‡ä»¶ä¸­æˆ–åœ¨ç½‘ä¸Šä¼ è¾“ï¼Œæˆ‘ä»¬éœ€è¦æŒ‡æ˜Žå­—节åºåˆ—的字节åºï¼Œæ˜¯å°ç«¯ï¼ˆlittle endian, LE)还是大端(big-endian, BE)。
+
+RapidJSON通过`rapidjson/encodings.h`中的struct去æä¾›å„ç§ç¼–ç ï¼š
+
+~~~~~~~~~~cpp
+namespace rapidjson {
+
+template<typename CharType = char>
+struct UTF8;
+
+template<typename CharType = wchar_t>
+struct UTF16;
+
+template<typename CharType = wchar_t>
+struct UTF16LE;
+
+template<typename CharType = wchar_t>
+struct UTF16BE;
+
+template<typename CharType = unsigned>
+struct UTF32;
+
+template<typename CharType = unsigned>
+struct UTF32LE;
+
+template<typename CharType = unsigned>
+struct UTF32BE;
+
+} // namespace rapidjson
+~~~~~~~~~~
+
+对于在内存中的文本,我们正常会使用`UTF8`ã€`UTF16`或`UTF32`。对于处ç†ç»è¿‡I/O的文本,我们å¯ä½¿ç”¨`UTF8`ã€`UTF16LE`ã€`UTF16BE`ã€`UTF32LE`或`UTF32BE`。
+
+当使用DOM风格的API,`GenericValue<Encoding>`åŠ`GenericDocument<Encoding>`里的`Encoding`模æ¿å‚数是用于指明内存中存储的JSON字符串使用哪ç§ç¼–ç ã€‚å› æ­¤é€šå¸¸æˆ‘ä»¬ä¼šåœ¨æ­¤å‚æ•°ä¸­ä½¿ç”¨`UTF8`ã€`UTF16`或`UTF32`。如何选择,视乎应用软件所使用的æ“作系统åŠå…¶ä»–程åºåº“。例如,Windows API使用UTF-16表示Unicode字符,而多数的Linuxå‘行版本åŠåº”用软件则更喜欢UTF-8。
+
+使用UTF-16çš„DOM声明例å­ï¼š
+
+~~~~~~~~~~cpp
+typedef GenericDocument<UTF16<> > WDocument;
+typedef GenericValue<UTF16<> > WValue;
+~~~~~~~~~~
+
+å¯ä»¥åœ¨[DOM's Encoding](doc/stream.md)一节看到更详细的使用例å­ã€‚
+
+## 字符类型 {#CharacterType}
+
+从之å‰çš„声明中å¯ä»¥çœ‹åˆ°ï¼Œæ¯ä¸ªç¼–ç éƒ½æœ‰ä¸€ä¸ª`CharType`模æ¿å‚数。这å¯èƒ½æ¯”较容易混淆,实际上,æ¯ä¸ª`CharType`存储一个编ç å•å…ƒï¼Œè€Œä¸æ˜¯ä¸€ä¸ªå­—符(ç ç‚¹ï¼‰ã€‚如之剿‰€è°ˆåŠï¼Œåœ¨UTF-8中一个ç ç‚¹å¯èƒ½ä¼šç¼–ç æˆ1至4个编ç å•元。
+
+对于`UTF16(LE|BE)`åŠ`UTF32(LE|BE)`æ¥è¯´ï¼Œ`CharType`必须分别是一个至少2åŠ4字节的整数类型。
+
+注æ„C++11新添了`char16_t`åŠ`char32_t`类型,也å¯åˆ†åˆ«ç”¨äºŽ`UTF16`åŠ`UTF32`。
+
+## AutoUTF {#AutoUTF}
+
+上述所介ç»çš„ç¼–ç éƒ½æ˜¯åœ¨ç¼–è¯‘æœŸé™æ€æŒ·å®šçš„。æ¢å¥è¯è¯´ï¼Œä½¿ç”¨è€…必须知é“内存或æµä¹‹ä¸­ä½¿ç”¨äº†å“ªç§ç¼–ç ã€‚然而,有时候我们å¯èƒ½éœ€è¦è¯»å†™ä¸åŒç¼–ç çš„æ–‡ä»¶ï¼Œè€Œä¸”这些编ç éœ€è¦åœ¨è¿è¡Œæ—¶æ‰èƒ½å†³å®šã€‚
+
+`AutoUTF`是为此而设计的编ç ã€‚它根æ®è¾“å…¥æˆ–è¾“å‡ºæµæ¥é€‰æ‹©ä½¿ç”¨å“ªç§ç¼–ç ã€‚ç›®å‰å®ƒåº”该与`EncodedInputStream`åŠ`EncodedOutputStream`结åˆä½¿ç”¨ã€‚
+
+## ASCII {#ASCII}
+
+虽然JSON标准并未æåŠ[ASCII](http://en.wikipedia.org/wiki/ASCII),有时候我们希望写入7ä½çš„ASCII JSON,以供未能处ç†UTF-8的应用程åºä½¿ç”¨ã€‚由于任JSON都å¯ä»¥æŠŠUnicode字符表示为`\uXXXX`转义åºåˆ—,JSON总是å¯ç”¨ASCIIæ¥ç¼–ç ã€‚
+
+ä»¥ä¸‹çš„ä¾‹å­æŠŠUTF-8çš„DOM写æˆASCIIçš„JSON:
+
+~~~~~~~~~~cpp
+using namespace rapidjson;
+Document d; // UTF8<>
+// ...
+StringBuffer buffer;
+Writer<StringBuffer, Document::EncodingType, ASCII<> > writer(buffer);
+d.Accept(writer);
+std::cout << buffer.GetString();
+~~~~~~~~~~
+
+ASCIIå¯ç”¨äºŽè¾“å…¥æµã€‚当输入æµåŒ…å«å¤§äºŽ127的字节,就会导致`kParseErrorStringInvalidEncoding`错误。
+
+ASCII *ä¸èƒ½* 用于内存(`Document`的编ç ï¼Œæˆ–`Reader`的目标编ç ),因为它ä¸èƒ½è¡¨ç¤ºUnicodeç ç‚¹ã€‚
+
+# 校验åŠè½¬ç  {#ValidationTranscoding}
+
+当RapidJSONè§£æžä¸€ä¸ªJSON时,它能校验输入JSONï¼Œåˆ¤æ–­å®ƒæ˜¯å¦æ‰€æ ‡æ˜Žç¼–ç çš„åˆæ³•åºåˆ—。è¦å¼€å¯æ­¤é€‰é¡¹ï¼Œè¯·æŠŠ`kParseValidateEncodingFlag`加入`parseFlags`模æ¿å‚数。
+
+若输入编ç å’Œè¾“出编ç å¹¶ä¸ç›¸åŒï¼Œ`Reader`åŠ`Writer`会算把文本转ç ã€‚åœ¨è¿™ç§æƒ…况下,并ä¸éœ€è¦`kParseValidateEncodingFlag`,因为它必须解ç è¾“å…¥åºåˆ—。若åºåˆ—ä¸èƒ½è¢«è§£ç ï¼Œå®ƒå¿…然是ä¸åˆæ³•的。
+
+## 转ç å™¨ {#Transcoder}
+
+虽然RapidJSON的编ç åŠŸèƒ½æ˜¯ä¸ºJSONè§£æžï¼ç”Ÿæˆè€Œè®¾è®¡ï¼Œä½¿ç”¨è€…也å¯ä»¥â€œæ»¥ç”¨â€å®ƒä»¬æ¥ä¸ºéžJSON字符串转ç ã€‚
+
+ä»¥ä¸‹çš„ä¾‹å­æŠŠUTF-8å­—ç¬¦ä¸²è½¬ç æˆUTF-16:
+
+~~~~~~~~~~cpp
+#include "rapidjson/encodings.h"
+
+using namespace rapidjson;
+
+const char* s = "..."; // UTF-8 string
+StringStream source(s);
+GenericStringBuffer<UTF16<> > target;
+
+bool hasError = false;
+while (source.Peak() != '\0')
+ if (!Transcoder::Transcode<UTF8<>, UTF16<> >(source, target)) {
+ hasError = true;
+ break;
+ }
+
+if (!hasError) {
+ const wchar_t* t = target.GetString();
+ // ...
+}
+~~~~~~~~~~
+
+你也å¯ä»¥ç”¨`AutoUTF`åŠå¯¹åº”çš„æµæ¥åœ¨è¿è¡Œæ—¶è®¾ç½®å†…æºï¼ç›®çš„之编ç ã€‚
diff --git a/3rdparty/rapidjson/doc/faq.md b/3rdparty/rapidjson/doc/faq.md
new file mode 100644
index 00000000000..1b0541c27a9
--- /dev/null
+++ b/3rdparty/rapidjson/doc/faq.md
@@ -0,0 +1,289 @@
+# FAQ
+
+[TOC]
+
+## General
+
+1. What is RapidJSON?
+
+ RapidJSON is a C++ library for parsing and generating JSON. You may check all [features](doc/features.md) of it.
+
+2. Why is RapidJSON named so?
+
+ It is inspired by [RapidXML](http://rapidxml.sourceforge.net/), which is a fast XML DOM parser.
+
+3. Is RapidJSON similar to RapidXML?
+
+ RapidJSON borrowed some designs of RapidXML, including *in situ* parsing, header-only library. But the two APIs are completely different. Also RapidJSON provide many features that are not in RapidXML.
+
+4. Is RapidJSON free?
+
+ Yes, it is free under MIT license. It can be used in commercial applications. Please check the details in [license.txt](https://github.com/miloyip/rapidjson/blob/master/license.txt).
+
+5. Is RapidJSON small? What are its dependencies?
+
+ Yes. A simple executable which parses a JSON and prints its statistics is less than 30KB on Windows.
+
+ RapidJSON depends on C++ standard library only.
+
+6. How to install RapidJSON?
+
+ Check [Installation section](https://miloyip.github.io/rapidjson/).
+
+7. Can RapidJSON run on my platform?
+
+ RapidJSON has been tested in many combinations of operating systems, compilers and CPU architecture by the community. But we cannot ensure that it can be run on your particular platform. Building and running the unit test suite will give you the answer.
+
+8. Does RapidJSON support C++03? C++11?
+
+ RapidJSON was firstly implemented for C++03. Later it added optional support of some C++11 features (e.g., move constructor, `noexcept`). RapidJSON shall be compatible with C++03 or C++11 compliant compilers.
+
+9. Does RapidJSON really work in real applications?
+
+ Yes. It is deployed in both client and server real applications. A community member reported that RapidJSON in their system parses 50 million JSONs daily.
+
+10. How RapidJSON is tested?
+
+ RapidJSON contains a unit test suite for automatic testing. [Travis](https://travis-ci.org/miloyip/rapidjson/)(for Linux) and [AppVeyor](https://ci.appveyor.com/project/miloyip/rapidjson/)(for Windows) will compile and run the unit test suite for all modifications. The test process also uses Valgrind (in Linux) to detect memory leaks.
+
+11. Is RapidJSON well documented?
+
+ RapidJSON provides user guide and API documentationn.
+
+12. Are there alternatives?
+
+ Yes, there are a lot alternatives. For example, [nativejson-benchmark](https://github.com/miloyip/nativejson-benchmark) has a listing of open-source C/C++ JSON libraries. [json.org](http://www.json.org/) also has a list.
+
+## JSON
+
+1. What is JSON?
+
+ JSON (JavaScript Object Notation) is a lightweight data-interchange format. It uses human readable text format. More details of JSON can be referred to [RFC7159](http://www.ietf.org/rfc/rfc7159.txt) and [ECMA-404](http://www.ecma-international.org/publications/standards/Ecma-404.htm).
+
+2. What are applications of JSON?
+
+ JSON are commonly used in web applications for transferring structured data. It is also used as a file format for data persistence.
+
+2. Does RapidJSON conform to the JSON standard?
+
+ Yes. RapidJSON is fully compliance with [RFC7159](http://www.ietf.org/rfc/rfc7159.txt) and [ECMA-404](http://www.ecma-international.org/publications/standards/Ecma-404.htm). It can handle corner cases, such as supporting null character and surrogate pairs in JSON strings.
+
+3. Does RapidJSON support relaxed syntax?
+
+ Currently no. RapidJSON only support the strict standardized format. Support on related syntax is under discussion in this [issue](https://github.com/miloyip/rapidjson/issues/36).
+
+## DOM and SAX
+
+1. What is DOM style API?
+
+ Document Object Model (DOM) is an in-memory representation of JSON for query and manipulation.
+
+2. What is SAX style API?
+
+ SAX is an event-driven API for parsing and generation.
+
+3. Should I choose DOM or SAX?
+
+ DOM is easy for query and manipulation. SAX is very fast and memory-saving but often more difficult to be applied.
+
+4. What is *in situ* parsing?
+
+ *in situ* parsing decodes the JSON strings directly into the input JSON. This is an optimization which can reduce memory consumption and improve performance, but the input JSON will be modified. Check [in-situ parsing](doc/dom.md) for details.
+
+5. When does parsing generate an error?
+
+ The parser generates an error when the input JSON contains invalid syntax, or a value can not be represented (a number is too big), or the handler of parsers terminate the parsing. Check [parse error](doc/dom.md) for details.
+
+6. What error information is provided?
+
+ The error is stored in `ParseResult`, which includes the error code and offset (number of characters from the beginning of JSON). The error code can be translated into human-readable error message.
+
+7. Why not just using `double` to represent JSON number?
+
+ Some applications use 64-bit unsigned/signed integers. And these integers cannot be converted into `double` without loss of precision. So the parsers detects whether a JSON number is convertible to different types of integers and/or `double`.
+
+8. How to clear-and-minimize a document or value?
+
+ Call one of the `SetXXX()` methods - they call destructor which deallocates DOM data:
+
+ ~~~~~~~~~~cpp
+ Document d;
+ ...
+ d.SetObject(); // clear and minimize
+ ~~~~~~~~~~
+
+ Alternatively, use equivalent of the [C++ swap with temporary idiom](https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Clear-and-minimize):
+ ~~~~~~~~~~cpp
+ Value(kObjectType).Swap(d);
+ ~~~~~~~~~~
+ or equivalent, but sightly longer to type:
+ ~~~~~~~~~~cpp
+ d.Swap(Value(kObjectType).Move());
+ ~~~~~~~~~~
+
+9. How to insert a document node into another document?
+
+ Let's take the following two DOM trees represented as JSON documents:
+ ~~~~~~~~~~cpp
+ Document person;
+ person.Parse("{\"person\":{\"name\":{\"first\":\"Adam\",\"last\":\"Thomas\"}}}");
+
+ Document address;
+ address.Parse("{\"address\":{\"city\":\"Moscow\",\"street\":\"Quiet\"}}");
+ ~~~~~~~~~~
+ Let's assume we want to merge them in such way that the whole `address` document becomes a node of the `person`:
+ ~~~~~~~~~~js
+ { "person": {
+ "name": { "first": "Adam", "last": "Thomas" },
+ "address": { "city": "Moscow", "street": "Quiet" }
+ }
+ }
+ ~~~~~~~~~~
+
+ The most important requirement to take care of document and value life-cycle as well as consistent memory managent using the right allocator during the value transfer.
+
+ Simple yet most efficient way to achieve that is to modify the `address` definition above to initialize it with allocator of the `person` document, then we just add the root member of the value:
+ ~~~~~~~~~~cpp
+ Documnet address(person.GetAllocator());
+ ...
+ person["person"].AddMember("address", address["address"], person.GetAllocator());
+ ~~~~~~~~~~
+Alternatively, if we don't want to explicitly refer to the root value of `address` by name, we can refer to it via iterator:
+ ~~~~~~~~~~cpp
+ auto addressRoot = address.MemberBegin();
+ person["person"].AddMember(addressRoot->name, addressRoot->value, person.GetAllocator());
+ ~~~~~~~~~~
+
+ Second way is to deep-clone the value from the address document:
+ ~~~~~~~~~~cpp
+ Value addressValue = Value(address["address"], person.GetAllocator());
+ person["person"].AddMember("address", addressValue, person.GetAllocator());
+ ~~~~~~~~~~
+
+## Document/Value (DOM)
+
+1. What is move semantics? Why?
+
+ Instead of copy semantics, move semantics is used in `Value`. That means, when assigning a source value to a target value, the ownership of source value is moved to the target value.
+
+ Since moving is faster than copying, this design decision forces user to aware of the copying overhead.
+
+2. How to copy a value?
+
+ There are two APIs: constructor with allocator, and `CopyFrom()`. See [Deep Copy Value](doc/tutorial.md) for an example.
+
+3. Why do I need to provide the length of string?
+
+ Since C string is null-terminated, the length of string needs to be computed via `strlen()`, with linear runtime complexity. This incurs an unncessary overhead of many operations, if the user already knows the length of string.
+
+ Also, RapidJSON can handle `\u0000` (null character) within a string. If a string contains null characters, `strlen()` cannot return the true length of it. In such case user must provide the length of string explicitly.
+
+4. Why do I need to provide allocator parameter in many DOM manipulation API?
+
+ Since the APIs are member functions of `Value`, we do not want to save an allocator pointer in every `Value`.
+
+5. Does it convert between numerical types?
+
+ When using `GetInt()`, `GetUint()`, ... conversion may occur. For integer-to-integer conversion, it only convert when it is safe (otherwise it will assert). However, when converting a 64-bit signed/unsigned integer to double, it will convert but be aware that it may lose precision. A number with fraction, or an integer larger than 64-bit, can only be obtained by `GetDouble()`.
+
+## Reader/Writer (SAX)
+
+1. Why don't we just `printf` a JSON? Why do we need a `Writer`?
+
+ Most importantly, `Writer` will ensure the output JSON is well-formed. Calling SAX events incorrectly (e.g. `StartObject()` pairing with `EndArray()`) will assert. Besides, `Writer` will escapes strings (e.g., `\n`). Finally, the numeric output of `printf()` may not be a valid JSON number, especially in some locale with digit delimiters. And the number-to-string conversion in `Writer` is implemented with very fast algorithms, which outperforms than `printf()` or `iostream`.
+
+2. Can I pause the parsing process and resume it later?
+
+ This is not directly supported in the current version due to performance consideration. However, if the execution environment supports multi-threading, user can parse a JSON in a separate thread, and pause it by blocking in the input stream.
+
+## Unicode
+
+1. Does it support UTF-8, UTF-16 and other format?
+
+ Yes. It fully support UTF-8, UTF-16 (LE/BE), UTF-32 (LE/BE) and ASCII.
+
+2. Can it validate the encoding?
+
+ Yes, just pass `kParseValidateEncodingFlag` to `Parse()`. If there is invalid encoding in the stream, it wil generate `kParseErrorStringInvalidEncoding` error.
+
+3. What is surrogate pair? Does RapidJSON support it?
+
+ JSON uses UTF-16 encoding when escaping unicode character, e.g. `\u5927` representing Chinese character "big". To handle characters other than those in basic multilingual plane (BMP), UTF-16 encodes those characters with two 16-bit values, which is called UTF-16 surrogate pair. For example, the Emoji character U+1F602 can be encoded as `\uD83D\uDE02` in JSON.
+
+ RapidJSON fully support parsing/generating UTF-16 surrogates.
+
+4. Can it handle `\u0000` (null character) in JSON string?
+
+ Yes. RapidJSON fully support null character in JSON string. However, user need to be aware of it and using `GetStringLength()` and related APIs to obtain the true length of string.
+
+5. Can I output `\uxxxx` for all non-ASCII character?
+
+ Yes, use `ASCII<>` as output encoding template parameter in `Writer` can enforce escaping those characters.
+
+## Stream
+
+1. I have a big JSON file. Should I load the whole file to memory?
+
+ User can use `FileReadStream` to read the file chunk-by-chunk. But for *in situ* parsing, the whole file must be loaded.
+
+2. Can I parse JSON while it is streamed from network?
+
+ Yes. User can implement a custom stream for this. Please refer to the implementation of `FileReadStream`.
+
+3. I don't know what encoding will the JSON be. How to handle them?
+
+ You may use `AutoUTFInputStream` which detects the encoding of input stream automatically. However, it will incur some performance overhead.
+
+4. What is BOM? How RapidJSON handle it?
+
+ [Byte order mark (BOM)](http://en.wikipedia.org/wiki/Byte_order_mark) sometimes reside at the beginning of file/stream to indiciate the UTF encoding type of it.
+
+ RapidJSON's `EncodedInputStream` can detect/consume BOM. `EncodedOutputStream` can optionally write a BOM. See [Encoded Streams](doc/stream.md) for example.
+
+5. Why little/big endian is related?
+
+ little/big endian of stream is an issue for UTF-16 and UTF-32 streams, but not UTF-8 stream.
+
+## Performance
+
+1. Is RapidJSON really fast?
+
+ Yes. It may be the fastest open source JSON library. There is a [benchmark](https://github.com/miloyip/nativejson-benchmark) for evaluating performance of C/C++ JSON libaries.
+
+2. Why is it fast?
+
+ Many design decisions of RapidJSON is aimed at time/space performance. These may reduce user-friendliness of APIs. Besides, it also employs low-level optimizations (intrinsics, SIMD) and special algorithms (custom double-to-string, string-to-double conversions).
+
+3. What is SIMD? How it is applied in RapidJSON?
+
+ [SIMD](http://en.wikipedia.org/wiki/SIMD) instructions can perform parallel computation in modern CPUs. RapidJSON support Intel's SSE2/SSE4.2 to accelerate whitespace skipping. This improves performance of parsing indent formatted JSON. Define `RAPIDJSON_SSE2` or `RAPIDJSON_SSE42` macro to enable this feature. However, running the executable on a machine without such instruction set support will make it crash.
+
+4. Does it consume a lot of memory?
+
+ The design of RapidJSON aims at reducing memory footprint.
+
+ In the SAX API, `Reader` consumes memory portional to maximum depth of JSON tree, plus maximum length of JSON string.
+
+ In the DOM API, each `Value` consumes exactly 16/24 bytes for 32/64-bit architecture respectively. RapidJSON also uses a special memory allocator to minimize overhead of allocations.
+
+5. What is the purpose of being high performance?
+
+ Some applications need to process very large JSON files. Some server-side applications need to process huge amount of JSONs. Being high performance can improve both latency and throuput. In a broad sense, it will also save energy.
+
+## Gossip
+
+1. Who are the developers of RapidJSON?
+
+ Milo Yip ([miloyip](https://github.com/miloyip)) is the original author of RapidJSON. Many contributors from the world have improved RapidJSON. Philipp A. Hartmann ([pah](https://github.com/pah)) has implemented a lot of improvements, setting up automatic testing and also involves in a lot of discussions for the community. Don Ding ([thebusytypist](https://github.com/thebusytypist)) implemented the iterative parser. Andrii Senkovych ([jollyroger](https://github.com/jollyroger)) completed the CMake migration. Kosta ([Kosta-Github](https://github.com/Kosta-Github)) provided a very neat short-string optimization. Thank you for all other contributors and community members as well.
+
+2. Why do you develop RapidJSON?
+
+ It was just a hobby project initially in 2011. Milo Yip is a game programmer and he just knew about JSON at that time and would like to apply JSON in future projects. As JSON seems very simple he would like to write a header-only and fast library.
+
+3. Why there is a long empty period of development?
+
+ It is basically due to personal issues, such as getting new family members. Also, Milo Yip has spent a lot of spare time on translating "Game Engine Architecture" by Jason Gregory into Chinese.
+
+4. Why did the repository move from Google Code to GitHub?
+
+ This is the trend. And GitHub is much more powerful and convenient.
diff --git a/3rdparty/rapidjson/doc/faq.zh-cn.md b/3rdparty/rapidjson/doc/faq.zh-cn.md
new file mode 100644
index 00000000000..7127283b243
--- /dev/null
+++ b/3rdparty/rapidjson/doc/faq.zh-cn.md
@@ -0,0 +1,290 @@
+# 常è§é—®é¢˜
+
+[TOC]
+
+## 一般问题
+
+1. RapidJSON是什么?
+
+ RapidJSON是一个C++库,用于解æžåŠç”ŸæˆJSON。读者å¯å‚考它的所有[特点](doc/features.zh-cn.md)。
+
+2. 为什么称作RapidJSON?
+
+ å®ƒçš„çµæ„Ÿæ¥è‡ªäºŽ[RapidXML](http://rapidxml.sourceforge.net/),RapidXML是一个高速的XML DOMè§£æžå™¨ã€‚
+
+3. RapidJSON与RapidXML相似么?
+
+ RapidJSON借镜了RapidXML的一些设计, 包括原ä½ï¼ˆ*in situ*)解æžã€åªæœ‰å¤´æ–‡ä»¶çš„库。但两者的API是完全ä¸åŒçš„。此外RapidJSON也æä¾›è®¸å¤šRapidXML没有的特点。
+
+4. RapidJSON是å…费的么?
+
+ 是的,它在MITç‰¹è¨±æ¢æ¬¾ä¸‹å…费。它å¯ç”¨äºŽå•†ä¸šè½¯ä»¶ã€‚详情请å‚看[license.txt](https://github.com/miloyip/rapidjson/blob/master/license.txt)。
+
+5. RapidJSON很å°ä¹ˆï¼Ÿå®ƒæœ‰ä½•ä¾èµ–?
+
+ 是的。在Windows上,一个解æžJSON并打å°å‡ºç»Ÿè®¡çš„坿‰§è¡Œæ–‡ä»¶å°‘于30KB。
+
+ RapidJSONä»…ä¾èµ–于C++标准库。
+
+6. 怎样安装RapidJSON?
+
+ è§[安装一节](../readme.zh-cn.md#安装)。
+
+7. RapidJSON能å¦è¿è¡ŒäºŽæˆ‘的平å°ï¼Ÿ
+
+ 社区已在多个æ“作系统ï¼ç¼–译器ï¼CPU架构的组åˆä¸Šæµ‹è¯•RapidJSON。但我们无法确ä¿å®ƒèƒ½è¿è¡ŒäºŽä½ ç‰¹å®šçš„å¹³å°ä¸Šã€‚åªéœ€è¦ç”ŸæˆåŠæ‰§è¡Œå•元测试便能获å–答案。
+
+8. RapidJSON支æŒC++03么?C++11呢?
+
+ RapidJSON开始时在C++03ä¸Šå®žçŽ°ã€‚åŽæ¥åŠ å…¥äº†å¯é€‰çš„C++11特性支æŒï¼ˆå¦‚转移构造函数ã€`noexcept`)。RapidJSON应该兼容所有éµä»ŽC++03或C++11的编译器。
+
+9. RapidJSON是å¦çœŸçš„用于实际应用?
+
+ 是的。它被é…置于å‰å°åŠåŽå°çš„真实应用中。一个社区æˆå‘˜è¯´RapidJSONåœ¨ä»–ä»¬çš„ç³»ç»Ÿä¸­æ¯æ—¥è§£æž5åƒä¸‡ä¸ªJSON。
+
+10. RapidJSON是如何被测试的?
+
+ RapidJSON包å«ä¸€ç»„å•元测试去执行自动测试。[Travis](https://travis-ci.org/miloyip/rapidjson/)(供Linuxå¹³å°ï¼‰åŠ[AppVeyor](https://ci.appveyor.com/project/miloyip/rapidjson/)(供Windowså¹³å°ï¼‰ä¼šå¯¹æ‰€æœ‰ä¿®æ”¹è¿›è¡Œç¼–è¯‘åŠæ‰§è¡Œå•元测试。在Linux下还会使用Valgrind去检测内存泄æ¼ã€‚
+
+11. RapidJSONæ˜¯å¦æœ‰å®Œæ•´çš„æ–‡æ¡£ï¼Ÿ
+
+ RapidJSONæä¾›äº†ä½¿ç”¨æ‰‹å†ŒåŠAPI说明文档。
+
+12. 有没有其他替代å“?
+
+ 有许多替代å“。例如[nativejson-benchmark](https://github.com/miloyip/nativejson-benchmark)列出了一些开æºçš„C/C++ JSON库。[json.org](http://www.json.org/)也有一个列表。
+
+## JSON
+
+1. 什么是JSON?
+
+ JSON (JavaScript Object Notation)是一个轻é‡çš„æ•°æ®äº¤æ¢æ ¼å¼ã€‚它使用人类å¯è¯»çš„æ–‡æœ¬æ ¼å¼ã€‚更多关于JSON的细节å¯è€ƒ[RFC7159](http://www.ietf.org/rfc/rfc7159.txt)åŠ[ECMA-404](http://www.ecma-international.org/publications/standards/Ecma-404.htm)。
+
+2. JSON有什么应用场åˆï¼Ÿ
+
+ JSON常用于网页应用程åºï¼Œä»¥ä¼ é€ç»“构化数æ®ã€‚它也å¯ä½œä¸ºæ–‡ä»¶æ ¼å¼ç”¨äºŽæ•°æ®æŒä¹…化。
+
+2. RapidJSON是å¦ç¬¦åˆJSON标准?
+
+ 是。RapidJSON完全符åˆ[RFC7159](http://www.ietf.org/rfc/rfc7159.txt)åŠ[ECMA-404](http://www.ecma-international.org/publications/standards/Ecma-404.htm)。它能处ç†ä¸€äº›ç‰¹æ®Šæƒ…况,例如支æŒJSONå­—ç¬¦ä¸²ä¸­å«æœ‰ç©ºå­—符åŠä»£ç†å¯¹ï¼ˆsurrogate pair)。
+
+3. RapidJSONæ˜¯å¦æ”¯æŒå®½æ¾çš„语法?
+
+ çŽ°æ—¶ä¸æ”¯æŒã€‚RapidJSONåªæ”¯æŒä¸¥æ ¼çš„æ ‡å‡†æ ¼å¼ã€‚宽æ¾è¯­æ³•现时在这[issue](https://github.com/miloyip/rapidjson/issues/36)中进行讨论。
+
+## DOM与SAX
+
+1. 什么是DOM风格API?
+
+ Document Object Model(DOM)是一个储存于内存的JSON表示方å¼ï¼Œç”¨äºŽæŸ¥è¯¢åŠä¿®æ”¹JSON。
+
+2. 什么是SAX风格API?
+
+ SAX是一个事件驱动的API,用于解æžåŠç”ŸæˆJSON。
+
+3. 我应用DOM还是SAX?
+
+ DOM易于查询åŠä¿®æ”¹ã€‚SAX则是éžå¸¸å¿«åŠçœå†…存的,但通常较难使用。
+
+4. 什么是原ä½ï¼ˆ*in situ*)解æžï¼Ÿ
+
+ 原ä½è§£æžä¼šæŠŠJSON字符串直接解ç è‡³è¾“入的JSON中。这是一个优化,å¯å‡å°‘å†…å­˜æ¶ˆè€—åŠæå‡æ€§èƒ½ï¼Œä½†è¾“入的JSON会被更改。进一步细节请å‚考[原ä½è§£æž](doc/dom.md) 。
+
+5. 什么时候会产生解æžé”™è¯¯ï¼Ÿ
+
+ 当输入的JSON包å«éžæ³•语法,或ä¸èƒ½è¡¨ç¤ºä¸€ä¸ªå€¼ï¼ˆå¦‚Number太大),或解æžå™¨çš„处ç†å™¨ä¸­æ–­è§£æžè¿‡ç¨‹ï¼Œè§£æžå™¨éƒ½ä¼šäº§ç”Ÿä¸€ä¸ªé”™è¯¯ã€‚详情请å‚考[è§£æžé”™è¯¯](doc/dom.md)。
+
+6. 有什么错误信æ¯ï¼Ÿ
+
+ 错误信æ¯å­˜å‚¨åœ¨`ParseResult`,它包å«é”™è¯¯ä»£å·åŠå移值(从JSON开始至错误处的字符数目)。å¯ä»¥æŠŠé”™è¯¯ä»£å·ç¿»è¯‘为人类å¯è¯»çš„错误讯æ¯ã€‚
+
+7. 为何ä¸åªä½¿ç”¨`double`去表示JSON number?
+
+ 一些应用需è¦ä½¿ç”¨64使— å·ï¼æœ‰å·æ•´æ•°ã€‚这些整数ä¸èƒ½æ— æŸåœ°è½¬æ¢æˆ`double`。因此解æžå™¨ä¼šæ£€æµ‹ä¸€ä¸ªJSON number是å¦èƒ½è½¬æ¢è‡³å„ç§æ•´æ•°ç±»åž‹åŠ`double`。
+
+8. 如何清空并最å°åŒ–`document`或`value`的容é‡ï¼Ÿ
+
+ 调用 `SetXXX()` 方法 - è¿™äº›æ–¹æ³•ä¼šè°ƒç”¨æžæž„函数,并é‡å»ºç©ºçš„Object或Array:
+
+ ~~~~~~~~~~cpp
+ Document d;
+ ...
+ d.SetObject(); // clear and minimize
+ ~~~~~~~~~~
+
+ å¦å¤–,也å¯ä»¥å‚考在 [C++ swap with temporary idiom](https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Clear-and-minimize)中的一ç§ç­‰ä»·çš„æ–¹æ³•:
+ ~~~~~~~~~~cpp
+ Value(kObjectType).Swap(d);
+ ~~~~~~~~~~
+ 或者,使用这个ç¨å¾®é•¿ä¸€ç‚¹çš„代ç ä¹Ÿèƒ½å®ŒæˆåŒæ ·çš„事情:
+ ~~~~~~~~~~cpp
+ d.Swap(Value(kObjectType).Move());
+ ~~~~~~~~~~
+
+9. 如何将一个`document`节点æ’入到å¦ä¸€ä¸ª`document`中?
+
+ 比如有以下两个document(DOM):
+ ~~~~~~~~~~cpp
+ Document person;
+ person.Parse("{\"person\":{\"name\":{\"first\":\"Adam\",\"last\":\"Thomas\"}}}");
+
+ Document address;
+ address.Parse("{\"address\":{\"city\":\"Moscow\",\"street\":\"Quiet\"}}");
+ ~~~~~~~~~~
+ å‡è®¾æˆ‘们希望将整个 `address` æ’入到`person`中,作为其的一个å­èŠ‚ç‚¹:
+ ~~~~~~~~~~js
+ { "person": {
+ "name": { "first": "Adam", "last": "Thomas" },
+ "address": { "city": "Moscow", "street": "Quiet" }
+ }
+ }
+ ~~~~~~~~~~
+
+ 在æ’å…¥èŠ‚ç‚¹çš„è¿‡ç¨‹ä¸­éœ€è¦æ³¨æ„`document`å’Œ`value`的生命周期并且正确地使用allocator进行内存分é…和管ç†ã€‚
+
+ ä¸€ä¸ªç®€å•æœ‰æ•ˆçš„æ–¹æ³•就是修改上述`address`å˜é‡çš„定义,让其使用`person`çš„allocatoråˆå§‹åŒ–,然åŽå°†å…¶æ·»åŠ åˆ°æ ¹èŠ‚ç‚¹ã€‚
+
+ ~~~~~~~~~~cpp
+ Documnet address(person.GetAllocator());
+ ...
+ person["person"].AddMember("address", address["address"], person.GetAllocator());
+ ~~~~~~~~~~
+ å½“ç„¶ï¼Œå¦‚æžœä½ ä¸æƒ³é€šè¿‡æ˜¾å¼åœ°å†™å‡º`address`çš„keyæ¥å¾—到其值,å¯ä»¥ä½¿ç”¨è¿­ä»£å™¨æ¥å®žçް:
+ ~~~~~~~~~~cpp
+ auto addressRoot = address.MemberBegin();
+ person["person"].AddMember(addressRoot->name, addressRoot->value, person.GetAllocator());
+ ~~~~~~~~~~
+
+ 此外,还å¯ä»¥é€šè¿‡æ·±æ‹·è´address documentæ¥å®žçް:
+ ~~~~~~~~~~cpp
+ Value addressValue = Value(address["address"], person.GetAllocator());
+ person["person"].AddMember("address", addressValue, person.GetAllocator());
+ ~~~~~~~~~~
+
+## Document/Value (DOM)
+
+1. 什么是转移语æ„?为什么?
+
+ `Value`ä¸ç”¨å¤åˆ¶è¯­æ„,而使用了转移语æ„ã€‚è¿™æ˜¯æŒ‡ï¼Œå½“æŠŠæ¥æºå€¼èµ‹å€¼äºŽç›®æ ‡å€¼æ—¶ï¼Œæ¥æºå€¼çš„æ‰€æœ‰æƒä¼šè½¬ç§»è‡³ç›®æ ‡å€¼ã€‚
+
+ 由于转移快于å¤åˆ¶ï¼Œæ­¤è®¾è®¡å†³å®šå¼ºè¿«ä½¿ç”¨è€…注æ„到å¤åˆ¶çš„æ¶ˆè€—。
+
+2. 怎样去å¤åˆ¶ä¸€ä¸ªå€¼ï¼Ÿ
+
+ 有两个APIå¯ç”¨ï¼šå«allocator的构造函数,以åŠ`CopyFrom()`。å¯å‚考[æ·±å¤åˆ¶Value](doc/tutorial.md)里的用例。
+
+3. ä¸ºä»€ä¹ˆæˆ‘éœ€è¦æä¾›å­—ç¬¦ä¸²çš„é•¿åº¦ï¼Ÿ
+
+ 由于C字符串是空字符结尾的,需è¦ä½¿ç”¨`strlen()`åŽ»è®¡ç®—å…¶é•¿åº¦ï¼Œè¿™æ˜¯çº¿æ€§å¤æ‚度的æ“作。若使用者已知字符串的长度,对很多æ“作æ¥è¯´ä¼šé€ æˆä¸å¿…è¦çš„æ¶ˆè€—。
+
+ 此外,RapidJSONå¯å¤„ç†å«æœ‰`\u0000`ï¼ˆç©ºå­—ç¬¦ï¼‰çš„å­—ç¬¦ä¸²ã€‚è‹¥ä¸€ä¸ªå­—ç¬¦ä¸²å«æœ‰ç©ºå­—符,`strlen()`便ä¸èƒ½è¿”å›žçœŸæ­£çš„å­—ç¬¦ä¸²é•¿åº¦ã€‚åœ¨è¿™ç§æƒ…况下使用者必须明确地æä¾›å­—符串长度。
+
+4. 为什么在许多DOMæ“作APIä¸­è¦æä¾›åˆ†é…å™¨ä½œä¸ºå‚æ•°ï¼Ÿ
+
+ 由于这些API是`Value`çš„æˆå‘˜å‡½æ•°ï¼Œæˆ‘们ä¸å¸Œæœ›ä¸ºæ¯ä¸ª`Value`储存一个分é…器指针。
+
+5. 它会转æ¢å„ç§æ•°å€¼ç±»åž‹ä¹ˆï¼Ÿ
+
+ 当使用`GetInt()`ã€`GetUint()`ç­‰API时,å¯èƒ½ä¼šå‘生转æ¢ã€‚对于整数至整数转æ¢ï¼Œä»…当ä¿è¯è½¬æ¢å®‰å…¨æ‰ä¼šè½¬æ¢ï¼ˆå¦åˆ™ä¼šæ–­è¨€å¤±è´¥ï¼‰ã€‚然而,当把一个64使œ‰å·ï¼æ— å·æ•´æ•°è½¬æ¢è‡³double时,它会转æ¢ï¼Œä½†æœ‰å¯èƒ½ä¼šæŸå¤±ç²¾åº¦ã€‚嫿œ‰å°æ•°çš„æ•°å­—ã€æˆ–大于64ä½çš„æ•´æ•°ï¼Œéƒ½åªèƒ½ä½¿ç”¨`GetDouble()`获å–其值。
+
+## Reader/Writer (SAX)
+
+1. 为什么ä¸ä»…仅用`printf`输出一个JSON?为什么需è¦`Writer`?
+
+ 最é‡è¦çš„æ˜¯ï¼Œ`Writer`能确ä¿è¾“出的JSONæ˜¯æ ¼å¼æ­£ç¡®çš„。错误地调用SAX事件(如`StartObject()`é”™é…`EndArray()`ï¼‰ä¼šé€ æˆæ–­è¨€å¤±è´¥ã€‚此外,`Writer`会把字符串进行转义(如`\n`)。最åŽï¼Œ`printf()`的数值输出å¯èƒ½å¹¶ä¸æ˜¯ä¸€ä¸ªåˆæ³•çš„JSON number,特别是æŸäº›locale会有数字分隔符。而且`Writer`çš„æ•°å€¼å­—ç¬¦ä¸²è½¬æ¢æ˜¯ä½¿ç”¨éžå¸¸å¿«çš„算法æ¥å®žçŽ°çš„ï¼Œèƒœè¿‡`printf()`åŠ`iostream`。
+
+2. æˆ‘èƒ½å¦æš‚åœè§£æžè¿‡ç¨‹ï¼Œå¹¶åœ¨ç¨åŽç»§ç»­ï¼Ÿ
+
+ 基于性能考虑,目å‰ç‰ˆæœ¬å¹¶ä¸ç›´æŽ¥æ”¯æŒæ­¤åŠŸèƒ½ã€‚ç„¶è€Œï¼Œè‹¥æ‰§è¡ŒçŽ¯å¢ƒæ”¯æŒå¤šçº¿ç¨‹ï¼Œä½¿ç”¨è€…å¯ä»¥åœ¨å¦ä¸€çº¿ç¨‹è§£æžJSON,并通过阻塞输入æµåŽ»æš‚åœã€‚
+
+## Unicode
+
+1. å®ƒæ˜¯å¦æ”¯æŒUTF-8ã€UTF-16åŠå…¶ä»–æ ¼å¼ï¼Ÿ
+
+ 是。它完全支æŒUTF-8ã€UTF-16(大端ï¼å°ç«¯ï¼‰ã€UTF-32(大端ï¼å°ç«¯ï¼‰åŠASCII。
+
+2. å®ƒèƒ½å¦æ£€æµ‹ç¼–ç çš„åˆæ³•性?
+
+ 能。åªéœ€æŠŠ`kParseValidateEncodingFlag`å‚考传给`Parse()`。若å‘现在输入æµä¸­æœ‰éžæ³•的编ç ï¼Œå®ƒå°±ä¼šäº§ç”Ÿ`kParseErrorStringInvalidEncoding`错误。
+
+3. 什么是代ç†å¯¹ï¼ˆsurrogate pair)?RapidJSONæ˜¯å¦æ”¯æŒï¼Ÿ
+
+ JSON使用UTF-16ç¼–ç åŽ»è½¬ä¹‰Unicode字符,例如`\u5927`表示中文字“大â€ã€‚è¦å¤„ç†åŸºæœ¬å¤šæ–‡ç§å¹³é¢ï¼ˆbasic multilingual plane,BMP)以外的字符时,UTF-16ä¼šæŠŠé‚£äº›å­—ç¬¦ç¼–ç æˆä¸¤ä¸ª16ä½å€¼ï¼Œè¿™ç§°ä¸ºUTF-16代ç†å¯¹ã€‚例如,绘文字字符U+1F602在JSON中å¯è¢«ç¼–ç æˆ`\uD83D\uDE02`。
+
+ RapidJSON完全支æŒè§£æžåŠç”ŸæˆUTF-16代ç†å¯¹ã€‚
+
+4. 它能å¦å¤„ç†JSON字符串中的`\u0000`(空字符)?
+
+ 能。RapidJSON完全支æŒJSONå­—ç¬¦ä¸²ä¸­çš„ç©ºå­—ç¬¦ã€‚ç„¶è€Œï¼Œä½¿ç”¨è€…éœ€è¦æ³¨æ„到这件事,并使用`GetStringLength()`åŠç›¸å…³API去å–得字符串真正长度。
+
+5. 能å¦å¯¹æ‰€æœ‰éžASCII字符输出æˆ`\uxxxx`å½¢å¼ï¼Ÿ
+
+ å¯ä»¥ã€‚åªè¦åœ¨`Writer`中使用`ASCII<>`作为输出编ç å‚数,就å¯ä»¥å¼ºé€¼è½¬ä¹‰é‚£äº›å­—符。
+
+## æµ
+
+1. 我有一个很大的JSONæ–‡ä»¶ã€‚æˆ‘åº”å¦æŠŠå®ƒæ•´ä¸ªè½½å…¥å†…å­˜ä¸­ï¼Ÿ
+
+ 使用者å¯ä½¿ç”¨`FileReadStream`去é€å—读入文件。但若使用于原ä½è§£æžï¼Œå¿…须载入整个文件。
+
+2. 我能å¦è§£æžä¸€ä¸ªä»Žç½‘络上串æµè¿›æ¥çš„JSON?
+
+ å¯ä»¥ã€‚ä½¿ç”¨è€…å¯æ ¹æ®`FileReadStream`的实现,去实现一个自定义的æµã€‚
+
+3. 我ä¸çŸ¥é“一些JSON将会使用哪ç§ç¼–ç ã€‚怎样处ç†å®ƒä»¬ï¼Ÿ
+
+ ä½ å¯ä»¥ä½¿ç”¨`AutoUTFInputStream`,它能自动检测输入æµçš„ç¼–ç ã€‚然而,它会带æ¥ä¸€äº›æ€§èƒ½å¼€é”€ã€‚
+
+4. 什么是BOM?RapidJSON怎样处ç†å®ƒï¼Ÿ
+
+ [å­—èŠ‚é¡ºåºæ ‡è®°ï¼ˆbyte order mark, BOM)](http://en.wikipedia.org/wiki/Byte_order_mark)æœ‰æ—¶ä¼šå‡ºçŽ°äºŽæ–‡ä»¶ï¼æµçš„开始,以表示其UTFç¼–ç ç±»åž‹ã€‚
+
+ RapidJSONçš„`EncodedInputStream`坿£€æµ‹ï¼è·³è¿‡BOM。`EncodedOutputStream`å¯é€‰æ‹©æ˜¯å¦å†™å…¥BOM。å¯å‚考[ç¼–ç æµ](doc/stream.md)中的例å­ã€‚
+
+5. 为什么会涉åŠå¤§ç«¯ï¼å°ç«¯ï¼Ÿ
+
+ æµçš„大端ï¼å°ç«¯æ˜¯UTF-16åŠUTF-32æµè¦å¤„ç†çš„问题,而UTF-8ä¸éœ€è¦å¤„ç†ã€‚
+
+## 性能
+
+1. RapidJSON是å¦çœŸçš„快?
+
+ 是。它å¯èƒ½æ˜¯æœ€å¿«çš„å¼€æºJSON库。有一个[评测](https://github.com/miloyip/nativejson-benchmark)评估C/C++ JSON库的性能。
+
+2. 为什么它会快?
+
+ RapidJSON的许多设计是针对时间ï¼ç©ºé—´æ€§èƒ½æ¥è®¾è®¡çš„,这些决定å¯èƒ½ä¼šå½±å“API的易用性。此外,它也使用了许多底层优化(内部函数ï¼intrinsicã€SIMD)åŠç‰¹åˆ«çš„算法(自定义的double至字符串转æ¢ã€å­—符串至double的转æ¢ï¼‰ã€‚
+
+3. 什是是SIMD?它如何用于RapidJSON?
+
+ [SIMD](http://en.wikipedia.org/wiki/SIMD)指令å¯ä»¥åœ¨çް代CPU中执行并行è¿ç®—。RapidJSON支æŒäº†Intelçš„SSE2/SSE4.2去加速跳过空白字符。在解æžå«ç¼©è¿›çš„JSON时,这能æå‡æ€§èƒ½ã€‚åªè¦å®šä¹‰å为`RAPIDJSON_SSE2`或`RAPIDJSON_SSE42`çš„å®ï¼Œå°±èƒ½å¯åŠ¨è¿™ä¸ªåŠŸèƒ½ã€‚ç„¶è€Œï¼Œè‹¥åœ¨ä¸æ”¯æŒè¿™äº›æŒ‡ä»¤é›†çš„æœºå™¨ä¸Šæ‰§è¡Œè¿™äº›å¯æ‰§è¡Œæ–‡ä»¶ï¼Œä¼šå¯¼è‡´å´©æºƒã€‚
+
+4. 它会消耗许多内存么?
+
+ RapidJSON的设计目标是å‡ä½Žå†…å­˜å ç”¨ã€‚
+
+ 在SAX API中,`Reader`消耗的内存与JSON树深度加上最长JSONå­—ç¬¦æˆæ­£æ¯”。
+
+ 在DOM API中,æ¯ä¸ª`Value`在32/64使ž¶æž„下分别消耗16/24字节。RapidJSON也使用一个特殊的内存分é…器去å‡å°‘分é…çš„é¢å¤–开销。
+
+5. 高性能的æ„义何在?
+
+ 有些应用程åºéœ€è¦å¤„ç†éžå¸¸å¤§çš„JSON文件。而有些åŽå°åº”用程åºéœ€è¦å¤„ç†å¤§é‡çš„JSONã€‚è¾¾åˆ°é«˜æ€§èƒ½åŒæ—¶æ”¹å–„å»¶æ—¶åŠåžåé‡ã€‚更广义æ¥è¯´ï¼Œè¿™ä¹Ÿå¯ä»¥èŠ‚çœèƒ½æºã€‚
+
+## 八挂
+
+1. è°æ˜¯RapidJSON的开å‘者?
+
+ å¶åŠ²å³°ï¼ˆMilo Yip,[miloyip](https://github.com/miloyip))是RapidJSON的原作者。全世界许多贡献者一直在改善RapidJSON。Philipp A. Hartmann([pah](https://github.com/pah))实现了许多改进,也设置了自动化测试,而且还å‚ä¸Žè®¸å¤šç¤¾åŒºè®¨è®ºã€‚ä¸æ¬§å—(Don Ding,[thebusytypist](https://github.com/thebusytypist))实现了迭代å¼è§£æžå™¨ã€‚Andrii Senkovych([jollyroger](https://github.com/jollyroger))完æˆäº†å‘CMakeçš„è¿ç§»ã€‚Kosta([Kosta-Github](https://github.com/Kosta-Github))æä¾›äº†ä¸€ä¸ªéžå¸¸çµå·§çš„çŸ­å­—ç¬¦ä¸²ä¼˜åŒ–ã€‚ä¹Ÿéœ€è¦æ„Ÿè°¢å…¶ä»–献者åŠç¤¾åŒºæˆå‘˜ã€‚
+
+2. 为何你è¦å¼€å‘RapidJSON?
+
+ 在2011年开始这项目是,它仅一个兴趣项目。Milo Yip是一个游æˆç¨‹åºå‘˜ï¼Œä»–在那时候认识到JSON并希望在未æ¥çš„项目中使用。由于JSON好åƒå¾ˆç®€å•,他希望写一个仅有头文件并且快速的程åºåº“。
+
+3. 为什么开å‘中段有一段长期空档?
+
+ ä¸»è¦æ˜¯ä¸ªäººå› ç´ ï¼Œä¾‹å¦‚加入新家庭æˆå‘˜ã€‚å¦å¤–,Milo Yip也花了许多业馀时间去翻译Jason Gregory的《Game Engine Architecture》至中文版《游æˆå¼•擎架构》。
+
+4. 为什么这个项目从Google Codeæ¬åˆ°GitHub?
+
+ 这是大势所趋,而且GitHubæ›´ä¸ºå¼ºå¤§åŠæ–¹ä¾¿ã€‚
diff --git a/3rdparty/rapidjson/doc/features.md b/3rdparty/rapidjson/doc/features.md
new file mode 100644
index 00000000000..6b529a77646
--- /dev/null
+++ b/3rdparty/rapidjson/doc/features.md
@@ -0,0 +1,98 @@
+# Features
+
+## General
+
+* Cross-platform
+ * Compilers: Visual Studio, gcc, clang, etc.
+ * Architectures: x86, x64, ARM, etc.
+ * Operating systems: Windows, Mac OS X, Linux, iOS, Android, etc.
+* Easy installation
+ * Header files only library. Just copy the headers to your project.
+* Self-contained, minimal dependences
+ * No STL, BOOST, etc.
+ * Only included `<cstdio>`, `<cstdlib>`, `<cstring>`, `<inttypes.h>`, `<new>`, `<stdint.h>`.
+* Without C++ exception, RTTI
+* High performance
+ * Use template and inline functions to reduce function call overheads.
+ * Internal optimized Grisu2 and floating point parsing implementations.
+ * Optional SSE2/SSE4.2 support.
+
+## Standard compliance
+
+* RapidJSON should be fully RFC4627/ECMA-404 compliance.
+* Support Unicode surrogate.
+* Support null character (`"\u0000"`)
+ * For example, `["Hello\u0000World"]` can be parsed and handled gracefully. There is API for getting/setting lengths of string.
+* Support optional relaxed syntax.
+ * Single line (`// ...`) and multiple line (`/* ... */`) comments.
+
+## Unicode
+
+* Support UTF-8, UTF-16, UTF-32 encodings, including little endian and big endian.
+ * These encodings are used in input/output streams and in-memory representation.
+* Support automatic detection of encodings in input stream.
+* Support transcoding between encodings internally.
+ * For example, you can read a UTF-8 file and let RapidJSON transcode the JSON strings into UTF-16 in the DOM.
+* Support encoding validation internally.
+ * For example, you can read a UTF-8 file, and let RapidJSON check whether all JSON strings are valid UTF-8 byte sequence.
+* Support custom character types.
+ * By default the character types are `char` for UTF8, `wchar_t` for UTF16, `uint32_t` for UTF32.
+* Support custom encodings.
+
+## API styles
+
+* SAX (Simple API for XML) style API
+ * Similar to [SAX](http://en.wikipedia.org/wiki/Simple_API_for_XML), RapidJSON provides a event sequential access parser API (`rapidjson::GenericReader`). It also provides a generator API (`rapidjson::Writer`) which consumes the same set of events.
+* DOM (Document Object Model) style API
+ * Similar to [DOM](http://en.wikipedia.org/wiki/Document_Object_Model) for HTML/XML, RapidJSON can parse JSON into a DOM representation (`rapidjson::GenericDocument`), for easy manipulation, and finally stringify back to JSON if needed.
+ * The DOM style API (`rapidjson::GenericDocument`) is actually implemented with SAX style API (`rapidjson::GenericReader`). SAX is faster but sometimes DOM is easier. Users can pick their choices according to scenarios.
+
+## Parsing
+
+* Recursive (default) and iterative parser
+ * Recursive parser is faster but prone to stack overflow in extreme cases.
+ * Iterative parser use custom stack to keep parsing state.
+* Support *in situ* parsing.
+ * Parse JSON string values in-place at the source JSON, and then the DOM points to addresses of those strings.
+ * Faster than convention parsing: no allocation for strings, no copy (if string does not contain escapes), cache-friendly.
+* Support 32-bit/64-bit signed/unsigned integer and `double` for JSON number type.
+* Support parsing multiple JSONs in input stream (`kParseStopWhenDoneFlag`).
+* Error Handling
+ * Support comprehensive error code if parsing failed.
+ * Support error message localization.
+
+## DOM (Document)
+
+* RapidJSON checks range of numerical values for conversions.
+* Optimization for string literal
+ * Only store pointer instead of copying
+* Optimization for "short" strings
+ * Store short string in `Value` internally without additional allocation.
+ * For UTF-8 string: maximum 11 characters in 32-bit, 15 characters in 64-bit.
+* Optionally support `std::string` (define `RAPIDJSON_HAS_STDSTRING=1`)
+
+## Generation
+
+* Support `rapidjson::PrettyWriter` for adding newlines and indentations.
+
+## Stream
+
+* Support `rapidjson::GenericStringBuffer` for storing the output JSON as string.
+* Support `rapidjson::FileReadStream` and `rapidjson::FileWriteStream` for input/output `FILE` object.
+* Support custom streams.
+
+## Memory
+
+* Minimize memory overheads for DOM.
+ * Each JSON value occupies exactly 16/20 bytes for most 32/64-bit machines (excluding text string).
+* Support fast default allocator.
+ * A stack-based allocator (allocate sequentially, prohibit to free individual allocations, suitable for parsing).
+ * User can provide a pre-allocated buffer. (Possible to parse a number of JSONs without any CRT allocation)
+* Support standard CRT(C-runtime) allocator.
+* Support custom allocators.
+
+## Miscellaneous
+
+* Some C++11 support (optional)
+ * Rvalue reference
+ * `noexcept` specifier
diff --git a/3rdparty/rapidjson/doc/features.zh-cn.md b/3rdparty/rapidjson/doc/features.zh-cn.md
new file mode 100644
index 00000000000..85a7db16274
--- /dev/null
+++ b/3rdparty/rapidjson/doc/features.zh-cn.md
@@ -0,0 +1,97 @@
+# 特点
+
+## 总体
+
+* 跨平å°
+ * 编译器:Visual Studioã€gccã€clangç­‰
+ * 架构:x86ã€x64ã€ARMç­‰
+ * æ“作系统:Windowsã€Mac OS Xã€Linuxã€iOSã€Androidç­‰
+* 容易安装
+ * åªæœ‰å¤´æ–‡ä»¶çš„库。åªéœ€æŠŠå¤´æ–‡ä»¶å¤åˆ¶è‡³ä½ çš„项目中。
+* ç‹¬ç«‹ã€æœ€å°ä¾èµ–
+ * ä¸éœ€ä¾èµ–STLã€BOOST等。
+ * åªåŒ…å«`<cstdio>`, `<cstdlib>`, `<cstring>`, `<inttypes.h>`, `<new>`, `<stdint.h>`。
+* 没使用C++异常ã€RTTI
+* 高性能
+ * 使用模版åŠå†…è”函数去é™ä½Žå‡½æ•°è°ƒç”¨å¼€é”€ã€‚
+ * 内部ç»ä¼˜åŒ–çš„Grisu2åŠæµ®ç‚¹æ•°è§£æžå®žçŽ°ã€‚
+ * å¯é€‰çš„SSE2/SSE4.2支æŒã€‚
+
+## ç¬¦åˆæ ‡å‡†
+
+* RapidJSON应完全符åˆRFC4627/ECMA-404标准。
+* 支æŒUnicod代ç†å¯¹ï¼ˆsurrogate pair)。
+* 支æŒç©ºå­—符(`"\u0000"`)。
+ * 例如,å¯ä»¥ä¼˜é›…地解æžåŠå¤„ç†`["Hello\u0000World"]`。å«è¯»å†™å­—符串长度的API。
+* æ”¯æŒæ”¾å®½çš„å¯é€‰è¯­æ³•
+ * å•行(`// ...`)åŠå¤šè¡Œï¼ˆ`/* ... */`) 注释。
+
+## Unicode
+
+* 支æŒUTF-8ã€UTF-16ã€UTF-32ç¼–ç ï¼ŒåŒ…括å°ç«¯åºå’Œå¤§ç«¯åºã€‚
+ * 这些编ç ç”¨äºŽè¾“入输出æµï¼Œä»¥åŠå†…存中的表示。
+* 支æŒä»Žè¾“å…¥æµè‡ªåŠ¨æ£€æµ‹ç¼–ç ã€‚
+* 内部支æŒç¼–ç çš„转æ¢ã€‚
+ * 例如,你å¯ä»¥è¯»å–一个UTF-8文件,让RapidJSON把JSON字符串转æ¢è‡³UTF-16çš„DOM。
+* 内部支æŒç¼–ç æ ¡éªŒã€‚
+ * 例如,你å¯ä»¥è¯»å–一个UTF-8文件,让RapidJSONæ£€æŸ¥æ˜¯å¦æ‰€æœ‰JSONå­—ç¬¦ä¸²æ˜¯åˆæ³•çš„UTF-8字节åºåˆ—。
+* 支æŒè‡ªå®šä¹‰çš„字符类型。
+ * 预设的字符类型是:UTF-8为`char`,UTF-16为`wchar_t`,UTF32为`uint32_t`。
+* 支æŒè‡ªå®šä¹‰çš„ç¼–ç ã€‚
+
+## API风格
+
+* SAX(Simple API for XML)风格API
+ * 类似于[SAX](http://en.wikipedia.org/wiki/Simple_API_for_XML), RapidJSONæä¾›ä¸€ä¸ªäº‹ä»¶å¾ªåºè®¿é—®çš„è§£æžå™¨API(`rapidjson::GenericReader`)。RapidJSON也æä¾›ä¸€ä¸ªç”Ÿæˆå™¨API(`rapidjson::Writer`),å¯ä»¥å¤„ç†ç›¸åŒçš„事件集åˆã€‚
+* DOM(Document Object Model)风格API
+ * 类似于HTMLï¼XMLçš„[DOM](http://en.wikipedia.org/wiki/Document_Object_Model),RapidJSONå¯æŠŠJSONè§£æžè‡³ä¸€ä¸ªDOM表示方å¼ï¼ˆ`rapidjson::GenericDocument`),以方便æ“作。如有需è¦ï¼Œå¯æŠŠDOM转æ¢ï¼ˆstringify)回JSON。
+ * DOM风格API(`rapidjson::GenericDocument`)实际上是由SAX风格API(`rapidjson::GenericReader`)实现的。SAX更快,但有时DOMæ›´æ˜“ç”¨ã€‚ç”¨æˆ·å¯æ ¹æ®æƒ…况作出选择。
+
+## è§£æž
+
+* 递归å¼ï¼ˆé¢„设)åŠè¿­ä»£å¼è§£æžå™¨
+ * 递归å¼è§£æžå™¨è¾ƒå¿«ï¼Œä½†åœ¨æžç«¯æƒ…况下å¯å‡ºçŽ°å †æ ˆæº¢å‡ºã€‚
+ * 迭代å¼è§£æžå™¨ä½¿ç”¨è‡ªå®šä¹‰çš„堆栈去维æŒè§£æžçжæ€ã€‚
+* 支æŒåŽŸä½ï¼ˆ*in situ*)解æžã€‚
+ * 把JSON字符串的值解æžè‡³åŽŸJSON之中,然åŽè®©DOM指å‘那些字符串。
+ * æ¯”å¸¸è§„åˆ†æžæ›´å¿«ï¼šä¸éœ€å­—符串的内存分é…ã€ä¸éœ€å¤åˆ¶ï¼ˆå¦‚字符串ä¸å«è½¬ä¹‰ç¬¦ï¼‰ã€ç¼“å­˜å‹å¥½ã€‚
+* 对于JSON数字类型,支æŒ32-bit/64-bit的有å·ï¼æ— å·æ•´æ•°ï¼Œä»¥åŠ`double`。
+* 错误处ç†
+ * 支æŒè¯¦å°½çš„è§£æžé”™è¯¯ä»£å·ã€‚
+ * æ”¯æŒæœ¬åœ°åŒ–错误信æ¯ã€‚
+
+## DOM (Document)
+
+* RapidJSONåœ¨ç±»åž‹è½¬æ¢æ—¶ä¼šæ£€æŸ¥æ•°å€¼çš„范围。
+* 字符串字é¢é‡çš„优化
+ * åªå‚¨å­˜æŒ‡é’ˆï¼Œä¸ä½œå¤åˆ¶
+* 优化“短â€å­—符串
+ * 在`Value`内储存短字符串,无需é¢å¤–分é…。
+ * 对UTF-8字符串æ¥è¯´ï¼Œ32使ž¶æž„下å¯å­˜å‚¨æœ€å¤š11字符,64ä½ä¸‹15字符。
+* å¯é€‰åœ°æ”¯æŒ`std::string`(定义`RAPIDJSON_HAS_STDSTRING=1`)
+
+## 生æˆ
+
+* 支æŒ`rapidjson::PrettyWriter`去加入æ¢è¡ŒåŠç¼©è¿›ã€‚
+
+## 输入输出æµ
+
+* 支æŒ`rapidjson::GenericStringBuffer`,把输出的JSON储存于字符串内。
+* 支æŒ`rapidjson::FileReadStream`åŠ`rapidjson::FileWriteStream`,使用`FILE`对象作输入输出。
+* 支æŒè‡ªå®šä¹‰è¾“入输出æµã€‚
+
+## 内存
+
+* 最å°åŒ–DOM的内存开销。
+ * 对大部分32ï¼64使œºå™¨è€Œè¨€ï¼Œæ¯ä¸ªJSON值åªå 16或20字节(ä¸åŒ…å«å­—符串)。
+* 支æŒå¿«é€Ÿçš„预设分é…器。
+ * 它是一个堆栈形å¼çš„分é…器(顺åºåˆ†é…,ä¸å®¹è®¸å•独释放,适åˆè§£æžè¿‡ç¨‹ä¹‹ç”¨ï¼‰ã€‚
+ * ä½¿ç”¨è€…ä¹Ÿå¯æä¾›ä¸€ä¸ªé¢„åˆ†é…的缓冲区。(有å¯èƒ½è¾¾è‡³æ— éœ€CRT分é…就能解æžå¤šä¸ªJSON)
+* æ”¯æŒæ ‡å‡†CRT(C-runtime)分é…器。
+* 支æŒè‡ªå®šä¹‰åˆ†é…器。
+
+## å…¶ä»–
+
+* 一些C++11的支æŒï¼ˆå¯é€‰ï¼‰
+ * å³å€¼å¼•用(rvalue reference)
+ * `noexcept`修饰符
diff --git a/3rdparty/rapidjson/doc/internals.md b/3rdparty/rapidjson/doc/internals.md
new file mode 100644
index 00000000000..174a03a2477
--- /dev/null
+++ b/3rdparty/rapidjson/doc/internals.md
@@ -0,0 +1,365 @@
+# Internals
+
+This section records some design and implementation details.
+
+[TOC]
+
+# Architecture {#Architecture}
+
+## SAX and DOM
+
+The basic relationships of SAX and DOM is shown in the following UML diagram.
+
+![Architecture UML class diagram](diagram/architecture.png)
+
+The core of the relationship is the `Handler` concept. From the SAX side, `Reader` parses a JSON from a stream and publish events to a `Handler`. `Writer` implements the `Handler` concept to handle the same set of events. From the DOM side, `Document` implements the `Handler` concept to build a DOM according to the events. `Value` supports a `Value::Accept(Handler&)` function, which traverses the DOM to publish events.
+
+With this design, SAX is not dependent on DOM. Even `Reader` and `Writer` have no dependencies between them. This provides flexibility to chain event publisher and handlers. Besides, `Value` does not depends on SAX as well. So, in addition to stringify a DOM to JSON, user may also stringify it to a XML writer, or do anything else.
+
+## Utility Classes
+
+Both SAX and DOM APIs depends on 3 additional concepts: `Allocator`, `Encoding` and `Stream`. Their inheritance hierarchy is shown as below.
+
+![Utility classes UML class diagram](diagram/utilityclass.png)
+
+# Value {#Value}
+
+`Value` (actually a typedef of `GenericValue<UTF8<>>`) is the core of DOM API. This section describes the design of it.
+
+## Data Layout {#DataLayout}
+
+`Value` is a [variant type](http://en.wikipedia.org/wiki/Variant_type). In RapidJSON's context, an instance of `Value` can contain 1 of 6 JSON value types. This is possible by using `union`. Each `Value` contains two members: `union Data data_` and a`unsigned flags_`. The `flags_` indiciates the JSON type, and also additional information.
+
+The following tables show the data layout of each type. The 32-bit/64-bit columns indicates the size of the field in bytes.
+
+| Null | |32-bit|64-bit|
+|-------------------|----------------------------------|:----:|:----:|
+| (unused) | |4 |8 |
+| (unused) | |4 |4 |
+| (unused) | |4 |4 |
+| `unsigned flags_` | `kNullType kNullFlag` |4 |4 |
+
+| Bool | |32-bit|64-bit|
+|-------------------|----------------------------------------------------|:----:|:----:|
+| (unused) | |4 |8 |
+| (unused) | |4 |4 |
+| (unused) | |4 |4 |
+| `unsigned flags_` | `kBoolType` (either `kTrueFlag` or `kFalseFlag`) |4 |4 |
+
+| String | |32-bit|64-bit|
+|---------------------|-------------------------------------|:----:|:----:|
+| `Ch* str` | Pointer to the string (may own) |4 |8 |
+| `SizeType length` | Length of string |4 |4 |
+| (unused) | |4 |4 |
+| `unsigned flags_` | `kStringType kStringFlag ...` |4 |4 |
+
+| Object | |32-bit|64-bit|
+|---------------------|-------------------------------------|:----:|:----:|
+| `Member* members` | Pointer to array of members (owned) |4 |8 |
+| `SizeType size` | Number of members |4 |4 |
+| `SizeType capacity` | Capacity of members |4 |4 |
+| `unsigned flags_` | `kObjectType kObjectFlag` |4 |4 |
+
+| Array | |32-bit|64-bit|
+|---------------------|-------------------------------------|:----:|:----:|
+| `Value* values` | Pointer to array of values (owned) |4 |8 |
+| `SizeType size` | Number of values |4 |4 |
+| `SizeType capacity` | Capacity of values |4 |4 |
+| `unsigned flags_` | `kArrayType kArrayFlag` |4 |4 |
+
+| Number (Int) | |32-bit|64-bit|
+|---------------------|-------------------------------------|:----:|:----:|
+| `int i` | 32-bit signed integer |4 |4 |
+| (zero padding) | 0 |4 |4 |
+| (unused) | |4 |8 |
+| `unsigned flags_` | `kNumberType kNumberFlag kIntFlag kInt64Flag ...` |4 |4 |
+
+| Number (UInt) | |32-bit|64-bit|
+|---------------------|-------------------------------------|:----:|:----:|
+| `unsigned u` | 32-bit unsigned integer |4 |4 |
+| (zero padding) | 0 |4 |4 |
+| (unused) | |4 |8 |
+| `unsigned flags_` | `kNumberType kNumberFlag kUIntFlag kUInt64Flag ...` |4 |4 |
+
+| Number (Int64) | |32-bit|64-bit|
+|---------------------|-------------------------------------|:----:|:----:|
+| `int64_t i64` | 64-bit signed integer |8 |8 |
+| (unused) | |4 |8 |
+| `unsigned flags_` | `kNumberType kNumberFlag kInt64Flag ...` |4 |4 |
+
+| Number (Uint64) | |32-bit|64-bit|
+|---------------------|-------------------------------------|:----:|:----:|
+| `uint64_t i64` | 64-bit unsigned integer |8 |8 |
+| (unused) | |4 |8 |
+| `unsigned flags_` | `kNumberType kNumberFlag kInt64Flag ...` |4 |4 |
+
+| Number (Double) | |32-bit|64-bit|
+|---------------------|-------------------------------------|:----:|:----:|
+| `uint64_t i64` | Double precision floating-point |8 |8 |
+| (unused) | |4 |8 |
+| `unsigned flags_` | `kNumberType kNumberFlag kDoubleFlag` |4 |4 |
+
+Here are some notes:
+* To reduce memory consumption for 64-bit architecture, `SizeType` is typedef as `unsigned` instead of `size_t`.
+* Zero padding for 32-bit number may be placed after or before the actual type, according to the endianess. This makes possible for interpreting a 32-bit integer as a 64-bit integer, without any conversion.
+* An `Int` is always an `Int64`, but the converse is not always true.
+
+## Flags {#Flags}
+
+The 32-bit `flags_` contains both JSON type and other additional information. As shown in the above tables, each JSON type contains redundant `kXXXType` and `kXXXFlag`. This design is for optimizing the operation of testing bit-flags (`IsNumber()`) and obtaining a sequential number for each type (`GetType()`).
+
+String has two optional flags. `kCopyFlag` means that the string owns a copy of the string. `kInlineStrFlag` means using [Short-String Optimization](#ShortString).
+
+Number is a bit more complicated. For normal integer values, it can contains `kIntFlag`, `kUintFlag`, `kInt64Flag` and/or `kUint64Flag`, according to the range of the integer. For numbers with fraction, and integers larger than 64-bit range, they will be stored as `double` with `kDoubleFlag`.
+
+## Short-String Optimization {#ShortString}
+
+ Kosta (@Kosta-Github) provided a very neat short-string optimization. The optimization idea is given as follow. Excluding the `flags_`, a `Value` has 12 or 16 bytes (32-bit or 64-bit) for storing actual data. Instead of storing a pointer to a string, it is possible to store short strings in these space internally. For encoding with 1-byte character type (e.g. `char`), it can store maximum 11 or 15 characters string inside the `Value` type.
+
+| ShortString (Ch=char) | |32-bit|64-bit|
+|---------------------|-------------------------------------|:----:|:----:|
+| `Ch str[MaxChars]` | String buffer |11 |15 |
+| `Ch invLength` | MaxChars - Length |1 |1 |
+| `unsigned flags_` | `kStringType kStringFlag ...` |4 |4 |
+
+A special technique is applied. Instead of storing the length of string directly, it stores (MaxChars - length). This make it possible to store 11 characters with trailing `\0`.
+
+This optimization can reduce memory usage for copy-string. It can also improve cache-coherence thus improve runtime performance.
+
+# Allocator {#Allocator}
+
+`Allocator` is a concept in RapidJSON:
+~~~cpp
+concept Allocator {
+ static const bool kNeedFree; //!< Whether this allocator needs to call Free().
+
+ // Allocate a memory block.
+ // \param size of the memory block in bytes.
+ // \returns pointer to the memory block.
+ void* Malloc(size_t size);
+
+ // Resize a memory block.
+ // \param originalPtr The pointer to current memory block. Null pointer is permitted.
+ // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
+ // \param newSize the new size in bytes.
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
+
+ // Free a memory block.
+ // \param pointer to the memory block. Null pointer is permitted.
+ static void Free(void *ptr);
+};
+~~~
+
+Note that `Malloc()` and `Realloc()` are member functions but `Free()` is static member function.
+
+## MemoryPoolAllocator {#MemoryPoolAllocator}
+
+`MemoryPoolAllocator` is the default allocator for DOM. It allocate but do not free memory. This is suitable for building a DOM tree.
+
+Internally, it allocates chunks of memory from the base allocator (by default `CrtAllocator`) and stores the chunks as a singly linked list. When user requests an allocation, it allocates memory from the following order:
+
+1. User supplied buffer if it is available. (See [User Buffer section in DOM](dom.md))
+2. If user supplied buffer is full, use the current memory chunk.
+3. If the current block is full, allocate a new block of memory.
+
+# Parsing Optimization {#ParsingOptimization}
+
+## Skip Whitespaces with SIMD {#SkipwhitespaceWithSIMD}
+
+When parsing JSON from a stream, the parser need to skip 4 whitespace characters:
+
+1. Space (`U+0020`)
+2. Character Tabulation (`U+000B`)
+3. Line Feed (`U+000A`)
+4. Carriage Return (`U+000D`)
+
+A simple implementation will be simply:
+~~~cpp
+void SkipWhitespace(InputStream& s) {
+ while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
+ s.Take();
+}
+~~~
+
+However, this requires 4 comparisons and a few branching for each character. This was found to be a hot spot.
+
+To accelerate this process, SIMD was applied to compare 16 characters with 4 white spaces for each iteration. Currently RapidJSON only supports SSE2 and SSE4.2 instructions for this. And it is only activated for UTF-8 memory streams, including string stream or *in situ* parsing.
+
+To enable this optimization, need to define `RAPIDJSON_SSE2` or `RAPIDJSON_SSE42` before including `rapidjson.h`. Some compilers can detect the setting, as in `perftest.h`:
+
+~~~cpp
+// __SSE2__ and __SSE4_2__ are recognized by gcc, clang, and the Intel compiler.
+// We use -march=native with gmake to enable -msse2 and -msse4.2, if supported.
+#if defined(__SSE4_2__)
+# define RAPIDJSON_SSE42
+#elif defined(__SSE2__)
+# define RAPIDJSON_SSE2
+#endif
+~~~
+
+Note that, these are compile-time settings. Running the executable on a machine without such instruction set support will make it crash.
+
+### Page boundary issue
+
+In an early version of RapidJSON, [an issue](https://code.google.com/archive/p/rapidjson/issues/104) reported that the `SkipWhitespace_SIMD()` causes crash very rarely (around 1 in 500,000). After investigation, it is suspected that `_mm_loadu_si128()` accessed bytes after `'\0'`, and across a protected page boundary.
+
+In [Intel® 64 and IA-32 Architectures Optimization Reference Manual
+](http://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-optimization-manual.html), section 10.2.1:
+
+> To support algorithms requiring unaligned 128-bit SIMD memory accesses, memory buffer allocation by a caller function should consider adding some pad space so that a callee function can safely use the address pointer safely with unaligned 128-bit SIMD memory operations.
+> The minimal padding size should be the width of the SIMD register that might be used in conjunction with unaligned SIMD memory access.
+
+This is not feasible as RapidJSON should not enforce such requirement.
+
+To fix this issue, currently the routine process bytes up to the next aligned address. After tha, use aligned read to perform SIMD processing. Also see [#85](https://github.com/miloyip/rapidjson/issues/85).
+
+## Local Stream Copy {#LocalStreamCopy}
+
+During optimization, it is found that some compilers cannot localize some member data access of streams into local variables or registers. Experimental results show that for some stream types, making a copy of the stream and used it in inner-loop can improve performance. For example, the actual (non-SIMD) implementation of `SkipWhitespace()` is implemented as:
+
+~~~cpp
+template<typename InputStream>
+void SkipWhitespace(InputStream& is) {
+ internal::StreamLocalCopy<InputStream> copy(is);
+ InputStream& s(copy.s);
+
+ while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
+ s.Take();
+}
+~~~
+
+Depending on the traits of stream, `StreamLocalCopy` will make (or not make) a copy of the stream object, use it locally and copy the states of stream back to the original stream.
+
+## Parsing to Double {#ParsingDouble}
+
+Parsing string into `double` is difficult. The standard library function `strtod()` can do the job but it is slow. By default, the parsers use normal precision setting. This has has maximum 3 [ULP](http://en.wikipedia.org/wiki/Unit_in_the_last_place) error and implemented in `internal::StrtodNormalPrecision()`.
+
+When using `kParseFullPrecisionFlag`, the parsers calls `internal::StrtodFullPrecision()` instead, and this function actually implemented 3 versions of conversion methods.
+1. [Fast-Path](http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/).
+2. Custom DIY-FP implementation as in [double-conversion](https://github.com/floitsch/double-conversion).
+3. Big Integer Method as in (Clinger, William D. How to read floating point numbers accurately. Vol. 25. No. 6. ACM, 1990).
+
+If the first conversion methods fail, it will try the second, and so on.
+
+# Generation Optimization {#GenerationOptimization}
+
+## Integer-to-String conversion {#itoa}
+
+The naive algorithm for integer-to-string conversion involves division per each decimal digit. We have implemented various implementations and evaluated them in [itoa-benchmark](https://github.com/miloyip/itoa-benchmark).
+
+Although SSE2 version is the fastest but the difference is minor by comparing to the first running-up `branchlut`. And `branchlut` is pure C++ implementation so we adopt `branchlut` in RapidJSON.
+
+## Double-to-String conversion {#dtoa}
+
+Originally RapidJSON uses `snprintf(..., ..., "%g")` to achieve double-to-string conversion. This is not accurate as the default precision is 6. Later we also find that this is slow and there is an alternative.
+
+Google's V8 [double-conversion](https://github.com/floitsch/double-conversion
+) implemented a newer, fast algorithm called Grisu3 (Loitsch, Florian. "Printing floating-point numbers quickly and accurately with integers." ACM Sigplan Notices 45.6 (2010): 233-243.).
+
+However, since it is not header-only so that we implemented a header-only version of Grisu2. This algorithm guarantees that the result is always accurate. And in most of cases it produces the shortest (optimal) string representation.
+
+The header-only conversion function has been evaluated in [dtoa-benchmark](https://github.com/miloyip/dtoa-benchmark).
+
+# Parser {#Parser}
+
+## Iterative Parser {#IterativeParser}
+
+The iterative parser is a recursive descent LL(1) parser
+implemented in a non-recursive manner.
+
+### Grammar {#IterativeParserGrammar}
+
+The grammar used for this parser is based on strict JSON syntax:
+~~~~~~~~~~
+S -> array | object
+array -> [ values ]
+object -> { members }
+values -> non-empty-values | ε
+non-empty-values -> value addition-values
+addition-values -> ε | , non-empty-values
+members -> non-empty-members | ε
+non-empty-members -> member addition-members
+addition-members -> ε | , non-empty-members
+member -> STRING : value
+value -> STRING | NUMBER | NULL | BOOLEAN | object | array
+~~~~~~~~~~
+
+Note that left factoring is applied to non-terminals `values` and `members`
+to make the grammar be LL(1).
+
+### Parsing Table {#IterativeParserParsingTable}
+
+Based on the grammar, we can construct the FIRST and FOLLOW set.
+
+The FIRST set of non-terminals is listed below:
+
+| NON-TERMINAL | FIRST |
+|:-----------------:|:--------------------------------:|
+| array | [ |
+| object | { |
+| values | ε STRING NUMBER NULL BOOLEAN { [ |
+| addition-values | ε COMMA |
+| members | ε STRING |
+| addition-members | ε COMMA |
+| member | STRING |
+| value | STRING NUMBER NULL BOOLEAN { [ |
+| S | [ { |
+| non-empty-members | STRING |
+| non-empty-values | STRING NUMBER NULL BOOLEAN { [ |
+
+The FOLLOW set is listed below:
+
+| NON-TERMINAL | FOLLOW |
+|:-----------------:|:-------:|
+| S | $ |
+| array | , $ } ] |
+| object | , $ } ] |
+| values | ] |
+| non-empty-values | ] |
+| addition-values | ] |
+| members | } |
+| non-empty-members | } |
+| addition-members | } |
+| member | , } |
+| value | , } ] |
+
+Finally the parsing table can be constructed from FIRST and FOLLOW set:
+
+| NON-TERMINAL | [ | { | , | : | ] | } | STRING | NUMBER | NULL | BOOLEAN |
+|:-----------------:|:---------------------:|:---------------------:|:-------------------:|:-:|:-:|:-:|:-----------------------:|:---------------------:|:---------------------:|:---------------------:|
+| S | array | object | | | | | | | | |
+| array | [ values ] | | | | | | | | | |
+| object | | { members } | | | | | | | | |
+| values | non-empty-values | non-empty-values | | | ε | | non-empty-values | non-empty-values | non-empty-values | non-empty-values |
+| non-empty-values | value addition-values | value addition-values | | | | | value addition-values | value addition-values | value addition-values | value addition-values |
+| addition-values | | | , non-empty-values | | ε | | | | | |
+| members | | | | | | ε | non-empty-members | | | |
+| non-empty-members | | | | | | | member addition-members | | | |
+| addition-members | | | , non-empty-members | | | ε | | | | |
+| member | | | | | | | STRING : value | | | |
+| value | array | object | | | | | STRING | NUMBER | NULL | BOOLEAN |
+
+There is a great [tool](http://hackingoff.com/compilers/predict-first-follow-set) for above grammar analysis.
+
+### Implementation {#IterativeParserImplementation}
+
+Based on the parsing table, a direct(or conventional) implementation
+that pushes the production body in reverse order
+while generating a production could work.
+
+In RapidJSON, several modifications(or adaptations to current design) are made to a direct implementation.
+
+First, the parsing table is encoded in a state machine in RapidJSON.
+States are constructed by the head and body of production.
+State transitions are constructed by production rules.
+Besides, extra states are added for productions involved with `array` and `object`.
+In this way the generation of array values or object members would be a single state transition,
+rather than several pop/push operations in the direct implementation.
+This also makes the estimation of stack size more easier.
+
+The state diagram is shown as follows:
+
+![State Diagram](diagram/iterative-parser-states-diagram.png)
+
+Second, the iterative parser also keeps track of array's value count and object's member count
+in its internal stack, which may be different from a conventional implementation.
diff --git a/3rdparty/rapidjson/doc/logo/rapidjson.png b/3rdparty/rapidjson/doc/logo/rapidjson.png
new file mode 100644
index 00000000000..b3b2f80ccb9
--- /dev/null
+++ b/3rdparty/rapidjson/doc/logo/rapidjson.png
Binary files differ
diff --git a/3rdparty/rapidjson/doc/logo/rapidjson.svg b/3rdparty/rapidjson/doc/logo/rapidjson.svg
new file mode 100644
index 00000000000..9708d5a06f3
--- /dev/null
+++ b/3rdparty/rapidjson/doc/logo/rapidjson.svg
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="217.15039"
+ height="60.831055"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="rapidjson.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3801">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop3803" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop3805" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3801"
+ id="linearGradient3807"
+ x1="81.25"
+ y1="52.737183"
+ x2="122.25"
+ y2="52.737183"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.2378503,0,0,1.1662045,-226.99279,64.427324)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3801"
+ id="linearGradient3935"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-1.4768835,0,0,2.2904698,246.48785,81.630301)"
+ x1="81.25"
+ y1="52.737183"
+ x2="115.96579"
+ y2="48.439766" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3801"
+ id="linearGradient3947"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.2378503,0,0,1.1662045,-226.99279,-10.072676)"
+ x1="81.25"
+ y1="52.737183"
+ x2="122.25"
+ y2="52.737183" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="2"
+ inkscape:cx="207.8959"
+ inkscape:cy="-3.2283687"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1137"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:window-maximized="1"
+ fit-margin-top="10"
+ fit-margin-left="10"
+ fit-margin-right="10"
+ fit-margin-bottom="10" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-39.132812,-38.772339)">
+ <text
+ sodipodi:linespacing="125%"
+ id="text3939"
+ y="79.862183"
+ x="147.5"
+ style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Microsoft JhengHei;-inkscape-font-specification:Microsoft JhengHei"
+ xml:space="preserve"><tspan
+ style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Inconsolata;-inkscape-font-specification:Inconsolata"
+ y="79.862183"
+ x="147.5"
+ id="tspan3941"
+ sodipodi:role="line"><tspan
+ id="tspan3943"
+ style="font-size:42px;font-style:oblique;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Segoe UI;-inkscape-font-specification:Segoe UI Oblique">Rapid</tspan><tspan
+ id="tspan3945"
+ style="font-weight:bold;-inkscape-font-specification:Inconsolata Bold">JSON</tspan></tspan></text>
+ </g>
+</svg>
diff --git a/3rdparty/rapidjson/doc/misc/DoxygenLayout.xml b/3rdparty/rapidjson/doc/misc/DoxygenLayout.xml
new file mode 100644
index 00000000000..b7c958665b4
--- /dev/null
+++ b/3rdparty/rapidjson/doc/misc/DoxygenLayout.xml
@@ -0,0 +1,194 @@
+<doxygenlayout version="1.0">
+ <!-- Generated by doxygen 1.8.7 -->
+ <!-- Navigation index tabs for HTML output -->
+ <navindex>
+ <tab type="mainpage" visible="yes" title=""/>
+ <tab type="pages" visible="yes" title="" intro=""/>
+ <tab type="modules" visible="yes" title="" intro=""/>
+ <tab type="namespaces" visible="yes" title="">
+ <tab type="namespacelist" visible="yes" title="" intro=""/>
+ <tab type="namespacemembers" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="classes" visible="yes" title="">
+ <tab type="classlist" visible="yes" title="" intro=""/>
+ <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
+ <tab type="hierarchy" visible="yes" title="" intro=""/>
+ <tab type="classmembers" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="files" visible="yes" title="">
+ <tab type="filelist" visible="yes" title="" intro=""/>
+ <tab type="globals" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="examples" visible="yes" title="" intro=""/>
+ </navindex>
+
+ <!-- Layout definition for a class page -->
+ <class>
+ <briefdescription visible="yes"/>
+ <includes visible="$SHOW_INCLUDE_FILES"/>
+ <inheritancegraph visible="$CLASS_GRAPH"/>
+ <collaborationgraph visible="$COLLABORATION_GRAPH"/>
+ <memberdecl>
+ <nestedclasses visible="yes" title=""/>
+ <publictypes title=""/>
+ <services title=""/>
+ <interfaces title=""/>
+ <publicslots title=""/>
+ <signals title=""/>
+ <publicmethods title=""/>
+ <publicstaticmethods title=""/>
+ <publicattributes title=""/>
+ <publicstaticattributes title=""/>
+ <protectedtypes title=""/>
+ <protectedslots title=""/>
+ <protectedmethods title=""/>
+ <protectedstaticmethods title=""/>
+ <protectedattributes title=""/>
+ <protectedstaticattributes title=""/>
+ <packagetypes title=""/>
+ <packagemethods title=""/>
+ <packagestaticmethods title=""/>
+ <packageattributes title=""/>
+ <packagestaticattributes title=""/>
+ <properties title=""/>
+ <events title=""/>
+ <privatetypes title=""/>
+ <privateslots title=""/>
+ <privatemethods title=""/>
+ <privatestaticmethods title=""/>
+ <privateattributes title=""/>
+ <privatestaticattributes title=""/>
+ <friends title=""/>
+ <related title="" subtitle=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ <memberdef>
+ <inlineclasses title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <services title=""/>
+ <interfaces title=""/>
+ <constructors title=""/>
+ <functions title=""/>
+ <related title=""/>
+ <variables title=""/>
+ <properties title=""/>
+ <events title=""/>
+ </memberdef>
+ <allmemberslink visible="yes"/>
+ <usedfiles visible="$SHOW_USED_FILES"/>
+ <authorsection visible="yes"/>
+ </class>
+
+ <!-- Layout definition for a namespace page -->
+ <namespace>
+ <briefdescription visible="yes"/>
+ <memberdecl>
+ <nestednamespaces visible="yes" title=""/>
+ <constantgroups visible="yes" title=""/>
+ <classes visible="yes" title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ <memberdef>
+ <inlineclasses title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ </memberdef>
+ <authorsection visible="yes"/>
+ </namespace>
+
+ <!-- Layout definition for a file page -->
+ <file>
+ <briefdescription visible="yes"/>
+ <includes visible="$SHOW_INCLUDE_FILES"/>
+ <includegraph visible="$INCLUDE_GRAPH"/>
+ <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
+ <sourcelink visible="yes"/>
+ <memberdecl>
+ <classes visible="yes" title=""/>
+ <namespaces visible="yes" title=""/>
+ <constantgroups visible="yes" title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ <memberdef>
+ <inlineclasses title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ </memberdef>
+ <authorsection/>
+ </file>
+
+ <!-- Layout definition for a group page -->
+ <group>
+ <briefdescription visible="yes"/>
+ <groupgraph visible="$GROUP_GRAPHS"/>
+ <memberdecl>
+ <nestedgroups visible="yes" title=""/>
+ <dirs visible="yes" title=""/>
+ <files visible="yes" title=""/>
+ <namespaces visible="yes" title=""/>
+ <classes visible="yes" title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <enumvalues title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <signals title=""/>
+ <publicslots title=""/>
+ <protectedslots title=""/>
+ <privateslots title=""/>
+ <events title=""/>
+ <properties title=""/>
+ <friends title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ <memberdef>
+ <pagedocs/>
+ <inlineclasses title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <enumvalues title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <signals title=""/>
+ <publicslots title=""/>
+ <protectedslots title=""/>
+ <privateslots title=""/>
+ <events title=""/>
+ <properties title=""/>
+ <friends title=""/>
+ </memberdef>
+ <authorsection visible="yes"/>
+ </group>
+
+ <!-- Layout definition for a directory page -->
+ <directory>
+ <briefdescription visible="yes"/>
+ <directorygraph visible="yes"/>
+ <memberdecl>
+ <dirs visible="yes"/>
+ <files visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ </directory>
+</doxygenlayout>
diff --git a/3rdparty/rapidjson/doc/misc/doxygenextra.css b/3rdparty/rapidjson/doc/misc/doxygenextra.css
new file mode 100644
index 00000000000..bd6737585b6
--- /dev/null
+++ b/3rdparty/rapidjson/doc/misc/doxygenextra.css
@@ -0,0 +1,274 @@
+body code {
+ margin: 0;
+ border: 1px solid #ddd;
+ background-color: #f8f8f8;
+ border-radius: 3px;
+ padding: 0;
+}
+
+a {
+ color: #4183c4;
+}
+
+a.el {
+ font-weight: normal;
+}
+
+body, table, div, p, dl {
+ color: #333333;
+ font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol';
+ font-size: 15px;
+ font-style: normal;
+ font-variant: normal;
+ font-weight: normal;
+ line-height: 25.5px;
+}
+
+body {
+ background-color: #eee;
+}
+
+div.header {
+ background-image: none;
+ background-color: white;
+ margin: 0px;
+ border: 0px;
+}
+
+div.headertitle {
+ width: 858px;
+ margin: 30px;
+ padding: 0px;
+}
+
+div.toc {
+ background-color: #f8f8f8;
+ border-color: #ddd;
+ margin-right: 10px;
+ margin-left: 20px;
+}
+div.toc h3 {
+ color: #333333;
+ font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol';
+ font-size: 18px;
+ font-style: normal;
+ font-variant: normal;
+ font-weight: normal;
+}
+div.toc li {
+ color: #333333;
+ font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol';
+ font-size: 12px;
+ font-style: normal;
+ font-variant: normal;
+ font-weight: normal;
+}
+
+.title {
+ font-size: 2.5em;
+ line-height: 63.75px;
+ border-bottom: 1px solid #ddd;
+ margin-bottom: 15px;
+ margin-left: 0px;
+ margin-right: 0px;
+ margin-top: 0px;
+}
+
+.summary {
+ float: none !important;
+ width: auto !important;
+ padding-top: 10px;
+ padding-right: 10px !important;
+}
+
+.summary + .headertitle .title {
+ font-size: 1.5em;
+ line-height: 2.0em;
+}
+
+body h1 {
+ font-size: 2em;
+ line-height: 1.7;
+ border-bottom: 1px solid #eee;
+ margin: 1em 0 15px;
+ padding: 0;
+ overflow: hidden;
+}
+
+body h2 {
+ font-size: 1.5em;
+ line-height: 1.7;
+ margin: 1em 0 15px;
+ padding: 0;
+}
+
+pre.fragment {
+ font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
+ font-size: 13px;
+ font-style: normal;
+ font-variant: normal;
+ font-weight: normal;
+ line-height: 19px;
+}
+
+table.doxtable th {
+ background-color: #f8f8f8;
+ color: #333333;
+ font-size: 15px;
+}
+
+table.doxtable td, table.doxtable th {
+ border: 1px solid #ddd;
+}
+
+#doc-content {
+ background-color: #fff;
+ width: 918px;
+ height: auto !important;
+ margin-left: 270px !important;
+}
+
+div.contents {
+ width: 858px;
+ margin: 30px;
+}
+
+div.line {
+ font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
+ font-size: 13px;
+ font-style: normal;
+ font-variant: normal;
+ font-weight: normal;
+ line-height: 19px;
+}
+
+tt, code, pre {
+ font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-size: 12px;
+}
+
+div.fragment {
+ background-color: #f8f8f8;
+ border: 1px solid #ddd;
+ font-size: 13px;
+ line-height: 19px;
+ overflow: auto;
+ padding: 6px 10px;
+ border-radius: 3px;
+}
+
+#topbanner {
+ position: fixed;
+ margin: 15px;
+ z-index: 101;
+}
+
+#projectname
+{
+ font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol';
+ font-size: 38px;
+ font-weight: bold;
+ line-height: 63.75px;
+ margin: 0px;
+ padding: 2px 0px;
+}
+
+#projectbrief
+{
+ font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol';
+ font-size: 16px;
+ line-height: 22.4px;
+ margin: 0px 0px 13px 0px;
+ padding: 2px;
+}
+
+/* side bar and search */
+
+#side-nav
+{
+ padding: 10px 0px 20px 20px;
+ border-top: 60px solid #2980b9;
+ background-color: #343131;
+ width: 250px !important;
+ height: 100% !important;
+ position: fixed;
+}
+
+#nav-tree
+{
+ background-color: transparent;
+ background-image: none;
+ height: 100% !important;
+}
+
+#nav-tree .label
+{
+ font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol';
+ line-height: 25.5px;
+ font-size: 15px;
+}
+
+#nav-tree
+{
+ color: #b3b3b3;
+}
+
+#nav-tree .selected {
+ background-image: none;
+}
+
+#nav-tree a
+{
+ color: #b3b3b3;
+}
+
+#github
+{
+ position: fixed;
+ left: auto;
+ right: auto;
+ width: 250px;
+}
+
+#MSearchBox
+{
+ margin: 20px;
+ left: 40px;
+ right: auto;
+ position: fixed;
+ width: 180px;
+}
+
+#MSearchField
+{
+ width: 121px;
+}
+
+#MSearchResultsWindow
+{
+ left: 45px !important;
+}
+
+#nav-sync
+{
+ display: none;
+}
+
+.ui-resizable .ui-resizable-handle
+{
+ width: 0px;
+}
+
+#nav-path
+{
+ display: none;
+}
+
+/* external link icon */
+div.contents a[href ^= "http"]:after {
+ content: " " url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAVklEQVR4Xn3PgQkAMQhDUXfqTu7kTtkpd5RA8AInfArtQ2iRXFWT2QedAfttj2FsPIOE1eCOlEuoWWjgzYaB/IkeGOrxXhqB+uA9Bfcm0lAZuh+YIeAD+cAqSz4kCMUAAAAASUVORK5CYII=);
+}
+
+.githublogo {
+ content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RERCMUIwOUY4NkNFMTFFM0FBNTJFRTMzNTJEMUJDNDYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RERCMUIwOUU4NkNFMTFFM0FBNTJFRTMzNTJEMUJDNDYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkU1MTc4QTJBOTlBMDExRTI5QTE1QkMxMDQ2QTg5MDREIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkU1MTc4QTJCOTlBMDExRTI5QTE1QkMxMDQ2QTg5MDREIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+jUqS1wAAApVJREFUeNq0l89rE1EQx3e3gVJoSPzZeNEWPKgHoa0HBak0iHiy/4C3WvDmoZ56qJ7txVsPQu8qlqqHIhRKJZceesmhioQEfxTEtsoSpdJg1u/ABJ7Pmc1m8zLwgWTmzcw3L+/te+tHUeQltONgCkyCi2AEDHLsJ6iBMlgHL8FeoqokoA2j4CloRMmtwTmj7erHBXPgCWhG6a3JNXKdCiDl1cidVbXZkJoXQRi5t5BrxwoY71FzU8S4JuAIqFkJ2+BFSlEh525b/hr3+k/AklDkNsf6wTT4yv46KIMNpsy+iMdMc47HNWxbsgVcUn7FmLAzzoFAWDsBx+wVP6bUpp5ewI+DOeUx0Wd9D8F70BTGNjkWtqnhmT1JQAHcUgZd8Lo3rQb1LAT8eJVUfgGvHQigGp+V2Z0iAUUl8QH47kAA1XioxIo+bRN8OG8F/oBjwv+Z1nJgX5jpdzQDw0LCjsPmrcW7I/iHScCAEDj03FtD8A0EyuChHgg4KTlJQF3wZ7WELppnBX+dBFSVpJsOBWi1qiRgSwnOgoyD5hmuJdkWCVhTgnTvW3AgYIFrSbZGh0UW/Io5Vp+DQoK7o80pztWMemZbgxeNwCNwDbw1fIfgGZjhU6xPaJgBV8BdsMw5cbZoHsenwYFxkZzl83xTSKTiviCAfCsJLysH3POfC8m8NegyGAGfLP/VmGmfSChgXroR0RSWjEFv2J/nG84cuKFMf4sTCZqXuJd4KaXFVjEG3+tw4eXbNK/YC9oXXs3O8NY8y99L4BXY5cvLY/Bb2VZ58EOJVcB18DHJq9lRsKr8inyKGVjlmh29mtHs3AHfuhCwy1vXT/Nu2GKQt+UHsGdctyX6eQyNvc+5sfX9Dl7Pe2J/BRgAl2CpwmrsHR0AAAAASUVORK5CYII=);
+} \ No newline at end of file
diff --git a/3rdparty/rapidjson/doc/misc/footer.html b/3rdparty/rapidjson/doc/misc/footer.html
new file mode 100644
index 00000000000..843aa110448
--- /dev/null
+++ b/3rdparty/rapidjson/doc/misc/footer.html
@@ -0,0 +1,27 @@
+<!-- HTML footer for doxygen 1.8.7-->
+<!-- start footer part -->
+<!--BEGIN GENERATE_TREEVIEW-->
+<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
+ <ul>
+ $navpath
+ </ul>
+</div>
+<!--END GENERATE_TREEVIEW-->
+<script type="text/javascript">
+ /* * * CONFIGURATION VARIABLES * * */
+ var disqus_shortname = 'rapidjson-doc';
+
+ /* * * DON'T EDIT BELOW THIS LINE * * */
+ (function() {
+ var dt = document.createElement('div');
+ dt.id = "disqus_thread";
+ (document.getElementsByClassName('contents')[0]).appendChild(dt);
+
+ var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
+ dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
+ (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
+ })();
+</script>
+
+</body>
+</html>
diff --git a/3rdparty/rapidjson/doc/misc/header.html b/3rdparty/rapidjson/doc/misc/header.html
new file mode 100644
index 00000000000..d43f2aaff9a
--- /dev/null
+++ b/3rdparty/rapidjson/doc/misc/header.html
@@ -0,0 +1,33 @@
+<!-- HTML header for doxygen 1.8.7-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<meta http-equiv="X-UA-Compatible" content="IE=9"/>
+<meta name="generator" content="Doxygen $doxygenversion"/>
+<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
+<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
+<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
+<script type="text/javascript" src="$relpath^jquery.js"></script>
+<script type="text/javascript" src="$relpath^dynsections.js"></script>
+$treeview
+$search
+$mathjax
+<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
+$extrastylesheet
+</head>
+<script>
+ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+ })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+ ga('create', 'UA-63929386-1', 'auto');
+ ga('send', 'pageview');
+</script>
+<body>
+<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
+<div id="topbanner"><a href="https://github.com/miloyip/rapidjson" title="RapidJSON GitHub"><i class="githublogo"></i></a></div>
+$searchbox
+<!--END TITLEAREA-->
+<!-- end header part -->
diff --git a/3rdparty/rapidjson/doc/performance.md b/3rdparty/rapidjson/doc/performance.md
new file mode 100644
index 00000000000..702ca7230b5
--- /dev/null
+++ b/3rdparty/rapidjson/doc/performance.md
@@ -0,0 +1,26 @@
+# Performance
+
+There is a [native JSON benchmark collection] [1] which evaluates speed, memory usage and code size of various operations among 20 JSON libaries.
+
+[1]: https://github.com/miloyip/nativejson-benchmark
+
+The old performance article for RapidJSON 0.1 is provided [here](https://code.google.com/p/rapidjson/wiki/Performance).
+
+Additionally, you may refer to the following third-party benchmarks.
+
+## Third-party benchmarks
+
+* [Basic benchmarks for miscellaneous C++ JSON parsers and generators](https://github.com/mloskot/json_benchmark) by Mateusz Loskot (Jun 2013)
+ * [casablanca](https://casablanca.codeplex.com/)
+ * [json_spirit](https://github.com/cierelabs/json_spirit)
+ * [jsoncpp](http://jsoncpp.sourceforge.net/)
+ * [libjson](http://sourceforge.net/projects/libjson/)
+ * [rapidjson](https://github.com/miloyip/rapidjson/)
+ * [QJsonDocument](http://qt-project.org/doc/qt-5.0/qtcore/qjsondocument.html)
+
+* [JSON Parser Benchmarking](http://chadaustin.me/2013/01/json-parser-benchmarking/) by Chad Austin (Jan 2013)
+ * [sajson](https://github.com/chadaustin/sajson)
+ * [rapidjson](https://github.com/miloyip/rapidjson/)
+ * [vjson](https://code.google.com/p/vjson/)
+ * [YAJL](http://lloyd.github.com/yajl/)
+ * [Jansson](http://www.digip.org/jansson/)
diff --git a/3rdparty/rapidjson/doc/performance.zh-cn.md b/3rdparty/rapidjson/doc/performance.zh-cn.md
new file mode 100644
index 00000000000..b590fe0c617
--- /dev/null
+++ b/3rdparty/rapidjson/doc/performance.zh-cn.md
@@ -0,0 +1,26 @@
+# 性能
+
+有一个[native JSON benchmark collection][1]项目,能评估20个JSON库在ä¸åŒæ“作下的速度ã€å…§å­˜ç”¨é‡åŠä»£ç å¤§å°ã€‚
+
+[1]: https://github.com/miloyip/nativejson-benchmark
+
+RapidJSON 0.1版本的性能测试文章ä½äºŽ[这里](https://code.google.com/p/rapidjson/wiki/Performance).
+
+此外,你也å¯ä»¥å‚考以下这些第三方的评测。
+
+## 第三方评测
+
+* [Basic benchmarks for miscellaneous C++ JSON parsers and generators](https://github.com/mloskot/json_benchmark) by Mateusz Loskot (Jun 2013)
+ * [casablanca](https://casablanca.codeplex.com/)
+ * [json_spirit](https://github.com/cierelabs/json_spirit)
+ * [jsoncpp](http://jsoncpp.sourceforge.net/)
+ * [libjson](http://sourceforge.net/projects/libjson/)
+ * [rapidjson](https://github.com/miloyip/rapidjson/)
+ * [QJsonDocument](http://qt-project.org/doc/qt-5.0/qtcore/qjsondocument.html)
+
+* [JSON Parser Benchmarking](http://chadaustin.me/2013/01/json-parser-benchmarking/) by Chad Austin (Jan 2013)
+ * [sajson](https://github.com/chadaustin/sajson)
+ * [rapidjson](https://github.com/miloyip/rapidjson/)
+ * [vjson](https://code.google.com/p/vjson/)
+ * [YAJL](http://lloyd.github.com/yajl/)
+ * [Jansson](http://www.digip.org/jansson/)
diff --git a/3rdparty/rapidjson/doc/pointer.md b/3rdparty/rapidjson/doc/pointer.md
new file mode 100644
index 00000000000..3927a12ec6e
--- /dev/null
+++ b/3rdparty/rapidjson/doc/pointer.md
@@ -0,0 +1,234 @@
+# Pointer
+
+## Status: experimental, shall be included in v1.1
+
+JSON Pointer is a standardized ([RFC6901]) way to select a value inside a JSON Document (DOM). This can be analogous to XPath for XML document. However, JSON Pointer is much simpler, and a single JSON Pointer only pointed to a single value.
+
+Using RapidJSON's implementation of JSON Pointer can simplify some manipulations of the DOM.
+
+[TOC]
+
+# JSON Pointer {#JsonPointer}
+
+A JSON Pointer is a list of zero-to-many tokens, each prefixed by `/`. Each token can be a string or a number. For example, given a JSON:
+~~~javascript
+{
+ "foo" : ["bar", "baz"],
+ "pi" : 3.1416
+}
+~~~
+
+The following JSON Pointers resolve this JSON as:
+
+1. `"/foo"` → `[ "bar", "baz" ]`
+2. `"/foo/0"` → `"bar"`
+3. `"/foo/1"` → `"baz"`
+4. `"/pi"` → `3.1416`
+
+Note that, an empty JSON Pointer `""` (zero token) resolves to the whole JSON.
+
+# Basic Usage {#BasicUsage}
+
+The following example code is self-explanatory.
+
+~~~cpp
+#include "rapidjson/pointer.h"
+
+// ...
+Document d;
+
+// Create DOM by Set()
+Pointer("/project").Set(d, "RapidJSON");
+Pointer("/stars").Set(d, 10);
+
+// { "project" : "RapidJSON", "stars" : 10 }
+
+// Access DOM by Get(). It return nullptr if the value does not exist.
+if (Value* stars = Pointer("/stars").Get(d))
+ stars->SetInt(stars->GetInt() + 1);
+
+// { "project" : "RapidJSON", "stars" : 11 }
+
+// Set() and Create() automatically generate parents if not exist.
+Pointer("/a/b/0").Create(d);
+
+// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] } }
+
+// GetWithDefault() returns reference. And it deep clones the default value.
+Value& hello = Pointer("/hello").GetWithDefault(d, "world");
+
+// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] }, "hello" : "world" }
+
+// Swap() is similar to Set()
+Value x("C++");
+Pointer("/hello").Swap(d, x);
+
+// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] }, "hello" : "C++" }
+// x becomes "world"
+
+// Erase a member or element, return true if the value exists
+bool success = Pointer("/a").Erase(d);
+assert(success);
+
+// { "project" : "RapidJSON", "stars" : 10 }
+~~~
+
+# Helper Functions {#HelperFunctions}
+
+Since object-oriented calling convention may be non-intuitive, RapidJSON also provides helper functions, which just wrap the member functions with free-functions.
+
+The following example does exactly the same as the above one.
+
+~~~cpp
+Document d;
+
+SetValueByPointer(d, "/project", "RapidJSON");
+SetValueByPointer(d, "/stars", 10);
+
+if (Value* stars = GetValueByPointer(d, "/stars"))
+ stars->SetInt(stars->GetInt() + 1);
+
+CreateValueByPointer(d, "/a/b/0");
+
+Value& hello = GetValueByPointerWithDefault(d, "/hello", "world");
+
+Value x("C++");
+SwapValueByPointer(d, "/hello", x);
+
+bool success = EraseValueByPointer(d, "/a");
+assert(success);
+~~~
+
+The conventions are shown here for comparison:
+
+1. `Pointer(source).<Method>(root, ...)`
+2. `<Method>ValueByPointer(root, Pointer(source), ...)`
+3. `<Method>ValueByPointer(root, source, ...)`
+
+# Resolving Pointer {#ResolvingPointer}
+
+`Pointer::Get()` or `GetValueByPointer()` function does not modify the DOM. If the tokens cannot match a value in the DOM, it returns `nullptr`. User can use this to check whether a value exists.
+
+Note that, numerical tokens can represent an array index or member name. The resolving process will match the values according to the types of value.
+
+~~~javascript
+{
+ "0" : 123,
+ "1" : [456]
+}
+~~~
+
+1. `"/0"` → `123`
+2. `"/1/0"` → `456`
+
+The token `"0"` is treated as member name in the first pointer. It is treated as an array index in the second pointer.
+
+The other functions, including `Create()`, `GetWithDefault()`, `Set()` and `Swap()`, will change the DOM. These functions will always succeed. They will create the parent values if they do not exist. If the parent values do not match the tokens, they will also be forced to change their type. Changing the type also mean fully removal of that DOM subtree.
+
+Parsing the above JSON into `d`,
+
+~~~cpp
+SetValueByPointer(d, "1/a", 789); // { "0" : 123, "1" : { "a" : 789 } }
+~~~
+
+## Resolving Minus Sign Token
+
+Besides, [RFC6901] defines a special token `-` (single minus sign), which represents the pass-the-end element of an array. `Get()` only treats this token as a member name '"-"'. Yet the other functions can resolve this for array, equivalent to calling `Value::PushBack()` to the array.
+
+~~~cpp
+Document d;
+d.Parse("{\"foo\":[123]}");
+SetValueByPointer(d, "/foo/-", 456); // { "foo" : [123, 456] }
+SetValueByPointer(d, "/-", 789); // { "foo" : [123, 456], "-" : 789 }
+~~~
+
+## Resolving Document and Value
+
+When using `p.Get(root)` or `GetValueByPointer(root, p)`, `root` is a (const) `Value&`. That means, it can be a subtree of the DOM.
+
+The other functions have two groups of signature. One group uses `Document& document` as parameter, another one uses `Value& root`. The first group uses `document.GetAllocator()` for creating values. And the second group needs user to supply an allocator, like the functions in DOM.
+
+All examples above do not require an allocator parameter, because the first parameter is a `Document&`. But if you want to resolve a pointer to a subtree, you need to supply the allocator as in the following example:
+
+~~~cpp
+class Person {
+public:
+ Person() {
+ document_ = new Document();
+ // CreateValueByPointer() here no need allocator
+ SetLocation(CreateValueByPointer(*document_, "/residence"), ...);
+ SetLocation(CreateValueByPointer(*document_, "/office"), ...);
+ };
+
+private:
+ void SetLocation(Value& location, const char* country, const char* addresses[2]) {
+ Value::Allocator& a = document_->GetAllocator();
+ // SetValueByPointer() here need allocator
+ SetValueByPointer(location, "/country", country, a);
+ SetValueByPointer(location, "/address/0", address[0], a);
+ SetValueByPointer(location, "/address/1", address[1], a);
+ }
+
+ // ...
+
+ Document* document_;
+};
+~~~
+
+`Erase()` or `EraseValueByPointer()` does not need allocator. And they return `true` if the value is erased successfully.
+
+# Error Handling {#ErrorHandling}
+
+A `Pointer` parses a source string in its constructor. If there is parsing error, `Pointer::IsValid()` returns `false`. And you can use `Pointer::GetParseErrorCode()` and `GetParseErrorOffset()` to retrieve the error information.
+
+Note that, all resolving functions assumes valid pointer. Resolving with an invalid pointer causes assertion failure.
+
+# URI Fragment Representation {#URIFragment}
+
+In addition to the string representation of JSON pointer that we are using till now, [RFC6901] also defines the URI fragment representation of JSON pointer. URI fragment is specified in [RFC3986] "Uniform Resource Identifier (URI): Generic Syntax".
+
+The main differences are that a the URI fragment always has a `#` (pound sign) in the beginning, and some characters are encoded by percent-encoding in UTF-8 sequence. For example, the following table shows different C/C++ string literals of different representations.
+
+String Representation | URI Fragment Representation | Pointer Tokens (UTF-8)
+----------------------|-----------------------------|------------------------
+`"/foo/0"` | `"#/foo/0"` | `{"foo", 0}`
+`"/a~1b"` | `"#/a~1b"` | `{"a/b"}`
+`"/m~0n"` | `"#/m~0n"` | `{"m~n"}`
+`"/ "` | `"#/%20"` | `{" "}`
+`"/\0"` | `"#/%00"` | `{"\0"}`
+`"/€"` | `"#/%E2%82%AC"` | `{"€"}`
+
+RapidJSON fully support URI fragment representation. It automatically detects the pound sign during parsing.
+
+# Stringify
+
+You may also stringify a `Pointer` to a string or other output streams. This can be done by:
+
+~~~
+Pointer p(...);
+StringBuffer sb;
+p.Stringify(sb);
+std::cout << sb.GetString() << std::endl;
+~~~
+
+It can also stringify to URI fragment reprsentation by `StringifyUriFragment()`.
+
+# User-Supplied Tokens {#UserSuppliedTokens}
+
+If a pointer will be resolved multiple times, it should be constructed once, and then apply it to different DOMs or in different times. This reduce time and memory allocation for constructing `Pointer` multiple times.
+
+We can go one step further, to completely eliminate the parsing process and dynamic memory allocation, we can establish the token array directly:
+
+~~~cpp
+#define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex }
+#define INDEX(i) { #i, sizeof(#i) - 1, i }
+
+static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) };
+static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
+// Equivalent to static const Pointer p("/foo/123");
+~~~
+
+This may be useful for memory constrained systems.
+
+[RFC3986]: https://tools.ietf.org/html/rfc3986
+[RFC6901]: https://tools.ietf.org/html/rfc6901
diff --git a/3rdparty/rapidjson/doc/pointer.zh-cn.md b/3rdparty/rapidjson/doc/pointer.zh-cn.md
new file mode 100644
index 00000000000..b340debf033
--- /dev/null
+++ b/3rdparty/rapidjson/doc/pointer.zh-cn.md
@@ -0,0 +1,234 @@
+# Pointer
+
+## 状æ€: 实验性,应该会åˆè¿› v1.1
+
+JSON Pointer 是一个标准化([RFC6901])的方å¼å޻选å–一个 JSON Document(DOM)中的值。这类似于 XML çš„ XPath。然而,JSON Pointer 简å•得多,而且æ¯ä¸ª JSON Pointer 仅指å‘å•个值。
+
+使用 RapidJSON çš„ JSON Pointer 实现能简化一些 DOM çš„æ“作。
+
+[TOC]
+
+# JSON Pointer {#JsonPointer}
+
+一个 JSON Pointer 由一串(零至多个)token 所组æˆï¼Œæ¯ä¸ª token 都有 `/` å‰ç¼€ã€‚æ¯ä¸ª token å¯ä»¥æ˜¯ä¸€ä¸ªå­—符串或数字。例如,给定一个 JSON:
+~~~javascript
+{
+ "foo" : ["bar", "baz"],
+ "pi" : 3.1416
+}
+~~~
+
+以下的 JSON Pointer è§£æžä¸ºï¼š
+
+1. `"/foo"` → `[ "bar", "baz" ]`
+2. `"/foo/0"` → `"bar"`
+3. `"/foo/1"` → `"baz"`
+4. `"/pi"` → `3.1416`
+
+è¦æ³¨æ„,一个空 JSON Pointer `""` (零个token)解æžä¸ºæ•´ä¸ª JSON。
+
+# 基本使用方法 {#BasicUsage}
+
+以下的代ç èŒƒä¾‹ä¸è§£è‡ªæ˜Žã€‚
+
+~~~cpp
+#include "rapidjson/pointer.h"
+
+// ...
+Document d;
+
+// 使用 Set() 创建 DOM
+Pointer("/project").Set(d, "RapidJSON");
+Pointer("/stars").Set(d, 10);
+
+// { "project" : "RapidJSON", "stars" : 10 }
+
+// 使用 Get() 访问 DOM。若该值ä¸å­˜åœ¨åˆ™è¿”回 nullptr。
+if (Value* stars = Pointer("/stars").Get(d))
+ stars->SetInt(stars->GetInt() + 1);
+
+// { "project" : "RapidJSON", "stars" : 11 }
+
+// Set() å’Œ Create() 自动生æˆçˆ¶å€¼ï¼ˆå¦‚果它们ä¸å­˜åœ¨ï¼‰ã€‚
+Pointer("/a/b/0").Create(d);
+
+// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] } }
+
+// GetWithDefault() 返回引用。若该值ä¸å­˜åœ¨åˆ™ä¼šæ·±æ‹·è´ç¼ºçœå€¼ã€‚
+Value& hello = Pointer("/hello").GetWithDefault(d, "world");
+
+// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] }, "hello" : "world" }
+
+// Swap() 和 Set() 相似
+Value x("C++");
+Pointer("/hello").Swap(d, x);
+
+// { "project" : "RapidJSON", "stars" : 11, "a" : { "b" : [ null ] }, "hello" : "C++" }
+// x å˜æˆ "world"
+
+// 删去一个æˆå‘˜æˆ–元素,若值存在返回 true
+bool success = Pointer("/a").Erase(d);
+assert(success);
+
+// { "project" : "RapidJSON", "stars" : 10 }
+~~~
+
+# 辅助函数 {#HelperFunctions}
+
+由于é¢å‘对象的调用习惯å¯èƒ½ä¸ç¬¦ç›´è§‰ï¼ŒRapidJSON 也æä¾›äº†ä¸€äº›è¾…助函数,它们把æˆå‘˜å‡½æ•°åŒ…装æˆè‡ªç”±å‡½æ•°ã€‚
+
+以下的例å­ä¸Žä¸Šé¢ä¾‹å­æ‰€åšçš„事情完全相åŒã€‚
+
+~~~cpp
+Document d;
+
+SetValueByPointer(d, "/project", "RapidJSON");
+SetValueByPointer(d, "/stars", 10);
+
+if (Value* stars = GetValueByPointer(d, "/stars"))
+ stars->SetInt(stars->GetInt() + 1);
+
+CreateValueByPointer(d, "/a/b/0");
+
+Value& hello = GetValueByPointerWithDefault(d, "/hello", "world");
+
+Value x("C++");
+SwapValueByPointer(d, "/hello", x);
+
+bool success = EraseValueByPointer(d, "/a");
+assert(success);
+~~~
+
+以下对比 3 ç§è°ƒç”¨æ–¹å¼ï¼š
+
+1. `Pointer(source).<Method>(root, ...)`
+2. `<Method>ValueByPointer(root, Pointer(source), ...)`
+3. `<Method>ValueByPointer(root, source, ...)`
+
+# è§£æž Pointer {#ResolvingPointer}
+
+`Pointer::Get()` 或 `GetValueByPointer()` 函数并ä¸ä¿®æ”¹ DOM。若那些 token ä¸èƒ½åŒ¹é… DOM 里的值,这些函数便返回 `nullptr`。使用者å¯åˆ©ç”¨è¿™ä¸ªæ–¹æ³•æ¥æ£€æŸ¥ä¸€ä¸ªå€¼æ˜¯å¦å­˜åœ¨ã€‚
+
+注æ„,数值 token å¯è¡¨ç¤ºæ•°ç»„索引或æˆå‘˜å字。解æžè¿‡ç¨‹ä¸­ä¼šæŒ‰å€¼çš„类型æ¥åŒ¹é…。
+
+~~~javascript
+{
+ "0" : 123,
+ "1" : [456]
+}
+~~~
+
+1. `"/0"` → `123`
+2. `"/1/0"` → `456`
+
+Token `"0"` 在第一个 pointer 中被当作æˆå‘˜å字。它在第二个 pointer ä¸­è¢«å½“ä½œæˆæ•°ç»„索引。
+
+å…¶ä»–å‡½æ•°ä¼šæ”¹å˜ DOM,包括`Create()`ã€`GetWithDefault()`ã€`Set()`ã€`Swap()`。这些函数总是æˆåŠŸçš„ã€‚è‹¥ä¸€äº›çˆ¶å€¼ä¸å­˜åœ¨ï¼Œå°±ä¼šåˆ›å»ºå®ƒä»¬ã€‚若父值类型ä¸åŒ¹é… token,也会强行改å˜å…¶ç±»åž‹ã€‚改å˜ç±»åž‹ä¹Ÿæ„味ç€å®Œå…¨ç§»é™¤å…¶ DOM å­æ ‘的内容。
+
+例如,把上é¢çš„ JSON 解译至 `d` 之åŽï¼Œ
+
+~~~cpp
+SetValueByPointer(d, "1/a", 789); // { "0" : 123, "1" : { "a" : 789 } }
+~~~
+
+## è§£æžè´Ÿå· token
+
+å¦å¤–,[RFC6901] 定义了一个特殊 token `-` (å•个负å·ï¼‰ï¼Œç”¨äºŽè¡¨ç¤ºæ•°ç»„最åŽå…ƒç´ çš„下一个元素。 `Get()` åªä¼šæŠŠæ­¤ token 当作æˆå‘˜åå­— '"-"'ã€‚è€Œå…¶ä»–å‡½æ•°åˆ™ä¼šä»¥æ­¤è§£æžæ•°ç»„,等åŒäºŽå¯¹æ•°ç»„调用 `Value::PushBack()` 。
+
+~~~cpp
+Document d;
+d.Parse("{\"foo\":[123]}");
+SetValueByPointer(d, "/foo/-", 456); // { "foo" : [123, 456] }
+SetValueByPointer(d, "/-", 789); // { "foo" : [123, 456], "-" : 789 }
+~~~
+
+## è§£æž Document åŠ Value
+
+当使用 `p.Get(root)` 或 `GetValueByPointer(root, p)`,`root` 是一个(常数) `Value&`。这æ„味ç€ï¼Œå®ƒä¹Ÿå¯ä»¥æ˜¯ DOM é‡Œçš„ä¸€ä¸ªå­æ ‘。
+
+其他函数有两组签å。一组使用 `Document& document` ä½œä¸ºå‚æ•°ï¼Œå¦ä¸€ç»„使用 `Value& root`。第一组使用 `document.GetAllocator()` 去创建值,而第二组则需è¦ä½¿ç”¨è€…æä¾›ä¸€ä¸ª allocatorï¼Œå¦‚åŒ DOM 里的函数。
+
+以上例å­éƒ½ä¸éœ€è¦ allocator 傿•°ï¼Œå› ä¸ºå®ƒçš„ç¬¬ä¸€ä¸ªå‚æ•°æ˜¯ `Document&`。但如果你需è¦å¯¹ä¸€ä¸ªå­æ ‘进行解æžï¼Œå°±éœ€è¦å¦‚下é¢çš„例å­èˆ¬æä¾› allocator:
+
+~~~cpp
+class Person {
+public:
+ Person() {
+ document_ = new Document();
+ // CreateValueByPointer() here no need allocator
+ SetLocation(CreateValueByPointer(*document_, "/residence"), ...);
+ SetLocation(CreateValueByPointer(*document_, "/office"), ...);
+ };
+
+private:
+ void SetLocation(Value& location, const char* country, const char* addresses[2]) {
+ Value::Allocator& a = document_->GetAllocator();
+ // SetValueByPointer() here need allocator
+ SetValueByPointer(location, "/country", country, a);
+ SetValueByPointer(location, "/address/0", address[0], a);
+ SetValueByPointer(location, "/address/1", address[1], a);
+ }
+
+ // ...
+
+ Document* document_;
+};
+~~~
+
+`Erase()` 或 `EraseValueByPointer()` ä¸éœ€è¦ allocator。而且它们æˆåŠŸåˆ é™¤å€¼ä¹‹åŽä¼šè¿”回 `true`。
+
+# é”™è¯¯å¤„ç† {#ErrorHandling}
+
+`Pointer` 在其建构函数里会解译æºå­—符串。若有解æžé”™è¯¯ï¼Œ`Pointer::IsValid()` 返回 `false`。你å¯ä½¿ç”¨ `Pointer::GetParseErrorCode()` å’Œ `GetParseErrorOffset()` 去获å–错信æ¯ã€‚
+
+è¦æ³¨æ„的是,所有解æžå‡½æ•°éƒ½å‡è®¾ pointer æ˜¯åˆæ³•çš„ã€‚å¯¹ä¸€ä¸ªéžæ³• pointer è§£æžä¼šåšæˆæ–­è¨€å¤±è´¥ã€‚
+
+# URI ç‰‡æ®µè¡¨ç¤ºæ–¹å¼ {#URIFragment}
+
+除了我们一直在使用的字符串方å¼è¡¨ç¤º JSON pointer,[RFC6901]也定义了一个 JSON Pointer çš„ URI 片段(fragment)表示方å¼ã€‚URI 片段是定义于 [RFC3986] "Uniform Resource Identifier (URI): Generic Syntax"。
+
+URI 片段的主è¦åˆ†åˆ«æ˜¯å¿…然以 `#` (pound signï¼‰å¼€å¤´ï¼Œè€Œä¸€äº›å­—ç¬¦ä¹Ÿä¼šä»¥ç™¾åˆ†æ¯”ç¼–ç æˆ UTF-8 åºåˆ—。例如,以下的表展示了ä¸åŒè¡¨ç¤ºæ³•下的 C/C++ 字符串常数。
+
+å­—ç¬¦ä¸²è¡¨ç¤ºæ–¹å¼ | URI ç‰‡æ®µè¡¨ç¤ºæ–¹å¼ | Pointer Tokens (UTF-8)
+----------------------|-----------------------------|------------------------
+`"/foo/0"` | `"#/foo/0"` | `{"foo", 0}`
+`"/a~1b"` | `"#/a~1b"` | `{"a/b"}`
+`"/m~0n"` | `"#/m~0n"` | `{"m~n"}`
+`"/ "` | `"#/%20"` | `{" "}`
+`"/\0"` | `"#/%00"` | `{"\0"}`
+`"/€"` | `"#/%E2%82%AC"` | `{"€"}`
+
+RapidJSON å®Œå…¨æ”¯æŒ URI 片段表示方å¼ã€‚它在解译时会自动检测 `#` å·ã€‚
+
+# 字符串化
+
+你也å¯ä»¥æŠŠä¸€ä¸ª `Pointer` 字符串化,储存于字符串或其他输出æµã€‚例如:
+
+~~~
+Pointer p(...);
+StringBuffer sb;
+p.Stringify(sb);
+std::cout << sb.GetString() << std::endl;
+~~~
+
+使用 `StringifyUriFragment()` å¯ä»¥æŠŠ pointer 字符串化为 URI 片段表示法。
+
+# 使用者æä¾›çš„ tokens {#UserSuppliedTokens}
+
+若一个 pointer 会用于多次解æžï¼Œå®ƒåº”该åªè¢«åˆ›å»ºä¸€æ¬¡ï¼Œç„¶åŽå†æ–½äºŽä¸åŒçš„ DOM ,或在ä¸åŒæ—¶é—´åšè§£æžã€‚这样å¯ä»¥é¿å…多次创键 `Pointer`ï¼ŒèŠ‚çœæ—¶é—´å’Œå†…存分é…。
+
+我们甚至å¯ä»¥å†æ›´è¿›ä¸€æ­¥ï¼Œå®Œå…¨æ¶ˆåŽ»è§£æžè¿‡ç¨‹åŠåЍæ€å†…存分é…。我们å¯ä»¥ç›´æŽ¥ç”Ÿæˆ token 数组:
+
+~~~cpp
+#define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex }
+#define INDEX(i) { #i, sizeof(#i) - 1, i }
+
+static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) };
+static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
+// Equivalent to static const Pointer p("/foo/123");
+~~~
+
+è¿™ç§å𿳕å¯èƒ½é€‚åˆå†…å­˜å—é™çš„系统。
+
+[RFC3986]: https://tools.ietf.org/html/rfc3986
+[RFC6901]: https://tools.ietf.org/html/rfc6901
diff --git a/3rdparty/rapidjson/doc/sax.md b/3rdparty/rapidjson/doc/sax.md
new file mode 100644
index 00000000000..9a6d8148031
--- /dev/null
+++ b/3rdparty/rapidjson/doc/sax.md
@@ -0,0 +1,475 @@
+# SAX
+
+The term "SAX" originated from [Simple API for XML](http://en.wikipedia.org/wiki/Simple_API_for_XML). We borrowed this term for JSON parsing and generation.
+
+In RapidJSON, `Reader` (typedef of `GenericReader<...>`) is the SAX-style parser for JSON, and `Writer` (typedef of `GenericWriter<...>`) is the SAX-style generator for JSON.
+
+[TOC]
+
+# Reader {#Reader}
+
+`Reader` parses a JSON from a stream. While it reads characters from the stream, it analyze the characters according to the syntax of JSON, and publish events to a handler.
+
+For example, here is a JSON.
+
+~~~~~~~~~~js
+{
+ "hello": "world",
+ "t": true ,
+ "f": false,
+ "n": null,
+ "i": 123,
+ "pi": 3.1416,
+ "a": [1, 2, 3, 4]
+}
+~~~~~~~~~~
+
+While a `Reader` parses this JSON, it publishes the following events to the handler sequentially:
+
+~~~~~~~~~~
+StartObject()
+Key("hello", 5, true)
+String("world", 5, true)
+Key("t", 1, true)
+Bool(true)
+Key("f", 1, true)
+Bool(false)
+Key("n", 1, true)
+Null()
+Key("i")
+UInt(123)
+Key("pi")
+Double(3.1416)
+Key("a")
+StartArray()
+Uint(1)
+Uint(2)
+Uint(3)
+Uint(4)
+EndArray(4)
+EndObject(7)
+~~~~~~~~~~
+
+These events can be easily matched with the JSON, except some event parameters need further explanation. Let's see the `simplereader` example which produces exactly the same output as above:
+
+~~~~~~~~~~cpp
+#include "rapidjson/reader.h"
+#include <iostream>
+
+using namespace rapidjson;
+using namespace std;
+
+struct MyHandler {
+ bool Null() { cout << "Null()" << endl; return true; }
+ bool Bool(bool b) { cout << "Bool(" << boolalpha << b << ")" << endl; return true; }
+ bool Int(int i) { cout << "Int(" << i << ")" << endl; return true; }
+ bool Uint(unsigned u) { cout << "Uint(" << u << ")" << endl; return true; }
+ bool Int64(int64_t i) { cout << "Int64(" << i << ")" << endl; return true; }
+ bool Uint64(uint64_t u) { cout << "Uint64(" << u << ")" << endl; return true; }
+ bool Double(double d) { cout << "Double(" << d << ")" << endl; return true; }
+ bool String(const char* str, SizeType length, bool copy) {
+ cout << "String(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
+ return true;
+ }
+ bool StartObject() { cout << "StartObject()" << endl; return true; }
+ bool Key(const char* str, SizeType length, bool copy) {
+ cout << "Key(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
+ return true;
+ }
+ bool EndObject(SizeType memberCount) { cout << "EndObject(" << memberCount << ")" << endl; return true; }
+ bool StartArray() { cout << "StartArray()" << endl; return true; }
+ bool EndArray(SizeType elementCount) { cout << "EndArray(" << elementCount << ")" << endl; return true; }
+};
+
+void main() {
+ const char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";
+
+ MyHandler handler;
+ Reader reader;
+ StringStream ss(json);
+ reader.Parse(ss, handler);
+}
+~~~~~~~~~~
+
+Note that, RapidJSON uses template to statically bind the `Reader` type and the handler type, instead of using class with virtual functions. This paradigm can improve the performance by inlining functions.
+
+## Handler {#Handler}
+
+As the previous example showed, user needs to implement a handler, which consumes the events (function calls) from `Reader`. The handler must contain the following member functions.
+
+~~~~~~~~~~cpp
+class Handler {
+ bool Null();
+ bool Bool(bool b);
+ bool Int(int i);
+ bool Uint(unsigned i);
+ bool Int64(int64_t i);
+ bool Uint64(uint64_t i);
+ bool Double(double d);
+ bool String(const Ch* str, SizeType length, bool copy);
+ bool StartObject();
+ bool Key(const Ch* str, SizeType length, bool copy);
+ bool EndObject(SizeType memberCount);
+ bool StartArray();
+ bool EndArray(SizeType elementCount);
+};
+~~~~~~~~~~
+
+`Null()` is called when the `Reader` encounters a JSON null value.
+
+`Bool(bool)` is called when the `Reader` encounters a JSON true or false value.
+
+When the `Reader` encounters a JSON number, it chooses a suitable C++ type mapping. And then it calls *one* function out of `Int(int)`, `Uint(unsigned)`, `Int64(int64_t)`, `Uint64(uint64_t)` and `Double(double)`.
+
+`String(const char* str, SizeType length, bool copy)` is called when the `Reader` encounters a string. The first parameter is pointer to the string. The second parameter is the length of the string (excluding the null terminator). Note that RapidJSON supports null character `'\0'` inside a string. If such situation happens, `strlen(str) < length`. The last `copy` indicates whether the handler needs to make a copy of the string. For normal parsing, `copy = true`. Only when *insitu* parsing is used, `copy = false`. And beware that, the character type depends on the target encoding, which will be explained later.
+
+When the `Reader` encounters the beginning of an object, it calls `StartObject()`. An object in JSON is a set of name-value pairs. If the object contains members it first calls `Key()` for the name of member, and then calls functions depending on the type of the value. These calls of name-value pairs repeats until calling `EndObject(SizeType memberCount)`. Note that the `memberCount` parameter is just an aid for the handler, user may not need this parameter.
+
+Array is similar to object but simpler. At the beginning of an array, the `Reader` calls `BeginArary()`. If there is elements, it calls functions according to the types of element. Similarly, in the last call `EndArray(SizeType elementCount)`, the parameter `elementCount` is just an aid for the handler.
+
+Every handler functions returns a `bool`. Normally it should returns `true`. If the handler encounters an error, it can return `false` to notify event publisher to stop further processing.
+
+For example, when we parse a JSON with `Reader` and the handler detected that the JSON does not conform to the required schema, then the handler can return `false` and let the `Reader` stop further parsing. And the `Reader` will be in error state with error code `kParseErrorTermination`.
+
+## GenericReader {#GenericReader}
+
+As mentioned before, `Reader` is a typedef of a template class `GenericReader`:
+
+~~~~~~~~~~cpp
+namespace rapidjson {
+
+template <typename SourceEncoding, typename TargetEncoding, typename Allocator = MemoryPoolAllocator<> >
+class GenericReader {
+ // ...
+};
+
+typedef GenericReader<UTF8<>, UTF8<> > Reader;
+
+} // namespace rapidjson
+~~~~~~~~~~
+
+The `Reader` uses UTF-8 as both source and target encoding. The source encoding means the encoding in the JSON stream. The target encoding means the encoding of the `str` parameter in `String()` calls. For example, to parse a UTF-8 stream and outputs UTF-16 string events, you can define a reader by:
+
+~~~~~~~~~~cpp
+GenericReader<UTF8<>, UTF16<> > reader;
+~~~~~~~~~~
+
+Note that, the default character type of `UTF16` is `wchar_t`. So this `reader`needs to call `String(const wchar_t*, SizeType, bool)` of the handler.
+
+The third template parameter `Allocator` is the allocator type for internal data structure (actually a stack).
+
+## Parsing {#Parsing}
+
+The one and only one function of `Reader` is to parse JSON.
+
+~~~~~~~~~~cpp
+template <unsigned parseFlags, typename InputStream, typename Handler>
+bool Parse(InputStream& is, Handler& handler);
+
+// with parseFlags = kDefaultParseFlags
+template <typename InputStream, typename Handler>
+bool Parse(InputStream& is, Handler& handler);
+~~~~~~~~~~
+
+If an error occurs during parsing, it will return `false`. User can also calls `bool HasParseEror()`, `ParseErrorCode GetParseErrorCode()` and `size_t GetErrorOffset()` to obtain the error states. Actually `Document` uses these `Reader` functions to obtain parse errors. Please refer to [DOM](doc/dom.md) for details about parse error.
+
+# Writer {#Writer}
+
+`Reader` converts (parses) JSON into events. `Writer` does exactly the opposite. It converts events into JSON.
+
+`Writer` is very easy to use. If your application only need to converts some data into JSON, it may be a good choice to use `Writer` directly, instead of building a `Document` and then stringifying it with a `Writer`.
+
+In `simplewriter` example, we do exactly the reverse of `simplereader`.
+
+~~~~~~~~~~cpp
+#include "rapidjson/writer.h"
+#include "rapidjson/stringbuffer.h"
+#include <iostream>
+
+using namespace rapidjson;
+using namespace std;
+
+void main() {
+ StringBuffer s;
+ Writer<StringBuffer> writer(s);
+
+ writer.StartObject();
+ writer.Key("hello");
+ writer.String("world");
+ writer.Key("t");
+ writer.Bool(true);
+ writer.Key("f");
+ writer.Bool(false);
+ writer.Key("n");
+ writer.Null();
+ writer.Key("i");
+ writer.Uint(123);
+ writer.Key("pi");
+ writer.Double(3.1416);
+ writer.Key("a");
+ writer.StartArray();
+ for (unsigned i = 0; i < 4; i++)
+ writer.Uint(i);
+ writer.EndArray();
+ writer.EndObject();
+
+ cout << s.GetString() << endl;
+}
+~~~~~~~~~~
+
+~~~~~~~~~~
+{"hello":"world","t":true,"f":false,"n":null,"i":123,"pi":3.1416,"a":[0,1,2,3]}
+~~~~~~~~~~
+
+There are two `String()` and `Key()` overloads. One is the same as defined in handler concept with 3 parameters. It can handle string with null characters. Another one is the simpler version used in the above example.
+
+Note that, the example code does not pass any parameters in `EndArray()` and `EndObject()`. An `SizeType` can be passed but it will be simply ignored by `Writer`.
+
+You may doubt that, why not just using `sprintf()` or `std::stringstream` to build a JSON?
+
+There are various reasons:
+1. `Writer` must output a well-formed JSON. If there is incorrect event sequence (e.g. `Int()` just after `StartObject()`), it generates assertion fail in debug mode.
+2. `Writer::String()` can handle string escaping (e.g. converting code point `U+000A` to `\n`) and Unicode transcoding.
+3. `Writer` handles number output consistently.
+4. `Writer` implements the event handler concept. It can be used to handle events from `Reader`, `Document` or other event publisher.
+5. `Writer` can be optimized for different platforms.
+
+Anyway, using `Writer` API is even simpler than generating a JSON by ad hoc methods.
+
+## Template {#WriterTemplate}
+
+`Writer` has a minor design difference to `Reader`. `Writer` is a template class, not a typedef. There is no `GenericWriter`. The following is the declaration.
+
+~~~~~~~~~~cpp
+namespace rapidjson {
+
+template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename Allocator = CrtAllocator<> >
+class Writer {
+public:
+ Writer(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth)
+// ...
+};
+
+} // namespace rapidjson
+~~~~~~~~~~
+
+The `OutputStream` template parameter is the type of output stream. It cannot be deduced and must be specified by user.
+
+The `SourceEncoding` template parameter specifies the encoding to be used in `String(const Ch*, ...)`.
+
+The `TargetEncoding` template parameter specifies the encoding in the output stream.
+
+The last one, `Allocator` is the type of allocator, which is used for allocating internal data structure (a stack).
+
+Besides, the constructor of `Writer` has a `levelDepth` parameter. This parameter affects the initial memory allocated for storing information per hierarchy level.
+
+## PrettyWriter {#PrettyWriter}
+
+While the output of `Writer` is the most condensed JSON without white-spaces, suitable for network transfer or storage, it is not easily readable by human.
+
+Therefore, RapidJSON provides a `PrettyWriter`, which adds indentation and line feeds in the output.
+
+The usage of `PrettyWriter` is exactly the same as `Writer`, expect that `PrettyWriter` provides a `SetIndent(Ch indentChar, unsigned indentCharCount)` function. The default is 4 spaces.
+
+## Completeness and Reset {#CompletenessReset}
+
+A `Writer` can only output a single JSON, which can be any JSON type at the root. Once the singular event for root (e.g. `String()`), or the last matching `EndObject()` or `EndArray()` event, is handled, the output JSON is well-formed and complete. User can detect this state by calling `Writer::IsComplete()`.
+
+When a JSON is complete, the `Writer` cannot accept any new events. Otherwise the output will be invalid (i.e. having more than one root). To reuse the `Writer` object, user can call `Writer::Reset(OutputStream& os)` to reset all internal states of the `Writer` with a new output stream.
+
+# Techniques {#Techniques}
+
+## Parsing JSON to Custom Data Structure {#CustomDataStructure}
+
+`Document`'s parsing capability is completely based on `Reader`. Actually `Document` is a handler which receives events from a reader to build a DOM during parsing.
+
+User may uses `Reader` to build other data structures directly. This eliminates building of DOM, thus reducing memory and improving performance.
+
+In the following `messagereader` example, `ParseMessages()` parses a JSON which should be an object with key-string pairs.
+
+~~~~~~~~~~cpp
+#include "rapidjson/reader.h"
+#include "rapidjson/error/en.h"
+#include <iostream>
+#include <string>
+#include <map>
+
+using namespace std;
+using namespace rapidjson;
+
+typedef map<string, string> MessageMap;
+
+struct MessageHandler
+ : public BaseReaderHandler<UTF8<>, MessageHandler> {
+ MessageHandler() : state_(kExpectObjectStart) {
+ }
+
+ bool StartObject() {
+ switch (state_) {
+ case kExpectObjectStart:
+ state_ = kExpectNameOrObjectEnd;
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool String(const char* str, SizeType length, bool) {
+ switch (state_) {
+ case kExpectNameOrObjectEnd:
+ name_ = string(str, length);
+ state_ = kExpectValue;
+ return true;
+ case kExpectValue:
+ messages_.insert(MessageMap::value_type(name_, string(str, length)));
+ state_ = kExpectNameOrObjectEnd;
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool EndObject(SizeType) { return state_ == kExpectNameOrObjectEnd; }
+
+ bool Default() { return false; } // All other events are invalid.
+
+ MessageMap messages_;
+ enum State {
+ kExpectObjectStart,
+ kExpectNameOrObjectEnd,
+ kExpectValue,
+ }state_;
+ std::string name_;
+};
+
+void ParseMessages(const char* json, MessageMap& messages) {
+ Reader reader;
+ MessageHandler handler;
+ StringStream ss(json);
+ if (reader.Parse(ss, handler))
+ messages.swap(handler.messages_); // Only change it if success.
+ else {
+ ParseErrorCode e = reader.GetParseErrorCode();
+ size_t o = reader.GetErrorOffset();
+ cout << "Error: " << GetParseError_En(e) << endl;;
+ cout << " at offset " << o << " near '" << string(json).substr(o, 10) << "...'" << endl;
+ }
+}
+
+int main() {
+ MessageMap messages;
+
+ const char* json1 = "{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\" }";
+ cout << json1 << endl;
+ ParseMessages(json1, messages);
+
+ for (MessageMap::const_iterator itr = messages.begin(); itr != messages.end(); ++itr)
+ cout << itr->first << ": " << itr->second << endl;
+
+ cout << endl << "Parse a JSON with invalid schema." << endl;
+ const char* json2 = "{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\", \"foo\" : {} }";
+ cout << json2 << endl;
+ ParseMessages(json2, messages);
+
+ return 0;
+}
+~~~~~~~~~~
+
+~~~~~~~~~~
+{ "greeting" : "Hello!", "farewell" : "bye-bye!" }
+farewell: bye-bye!
+greeting: Hello!
+
+Parse a JSON with invalid schema.
+{ "greeting" : "Hello!", "farewell" : "bye-bye!", "foo" : {} }
+Error: Terminate parsing due to Handler error.
+ at offset 59 near '} }...'
+~~~~~~~~~~
+
+The first JSON (`json1`) was successfully parsed into `MessageMap`. Since `MessageMap` is a `std::map`, the printing order are sorted by the key. This order is different from the JSON's order.
+
+In the second JSON (`json2`), `foo`'s value is an empty object. As it is an object, `MessageHandler::StartObject()` will be called. However, at that moment `state_ = kExpectValue`, so that function returns `false` and cause the parsing process be terminated. The error code is `kParseErrorTermination`.
+
+## Filtering of JSON {#Filtering}
+
+As mentioned earlier, `Writer` can handle the events published by `Reader`. `condense` example simply set a `Writer` as handler of a `Reader`, so it can remove all white-spaces in JSON. `pretty` example uses the same relationship, but replacing `Writer` by `PrettyWriter`. So `pretty` can be used to reformat a JSON with indentation and line feed.
+
+Actually, we can add intermediate layer(s) to filter the contents of JSON via these SAX-style API. For example, `capitalize` example capitalize all strings in a JSON.
+
+~~~~~~~~~~cpp
+#include "rapidjson/reader.h"
+#include "rapidjson/writer.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/filewritestream.h"
+#include "rapidjson/error/en.h"
+#include <vector>
+#include <cctype>
+
+using namespace rapidjson;
+
+template<typename OutputHandler>
+struct CapitalizeFilter {
+ CapitalizeFilter(OutputHandler& out) : out_(out), buffer_() {
+ }
+
+ bool Null() { return out_.Null(); }
+ bool Bool(bool b) { return out_.Bool(b); }
+ bool Int(int i) { return out_.Int(i); }
+ bool Uint(unsigned u) { return out_.Uint(u); }
+ bool Int64(int64_t i) { return out_.Int64(i); }
+ bool Uint64(uint64_t u) { return out_.Uint64(u); }
+ bool Double(double d) { return out_.Double(d); }
+ bool String(const char* str, SizeType length, bool) {
+ buffer_.clear();
+ for (SizeType i = 0; i < length; i++)
+ buffer_.push_back(std::toupper(str[i]));
+ return out_.String(&buffer_.front(), length, true); // true = output handler need to copy the string
+ }
+ bool StartObject() { return out_.StartObject(); }
+ bool Key(const char* str, SizeType length, bool copy) { return String(str, length, copy); }
+ bool EndObject(SizeType memberCount) { return out_.EndObject(memberCount); }
+ bool StartArray() { return out_.StartArray(); }
+ bool EndArray(SizeType elementCount) { return out_.EndArray(elementCount); }
+
+ OutputHandler& out_;
+ std::vector<char> buffer_;
+};
+
+int main(int, char*[]) {
+ // Prepare JSON reader and input stream.
+ Reader reader;
+ char readBuffer[65536];
+ FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
+
+ // Prepare JSON writer and output stream.
+ char writeBuffer[65536];
+ FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
+ Writer<FileWriteStream> writer(os);
+
+ // JSON reader parse from the input stream and let writer generate the output.
+ CapitalizeFilter<Writer<FileWriteStream> > filter(writer);
+ if (!reader.Parse(is, filter)) {
+ fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode()));
+ return 1;
+ }
+
+ return 0;
+}
+~~~~~~~~~~
+
+Note that, it is incorrect to simply capitalize the JSON as a string. For example:
+~~~~~~~~~~
+["Hello\nWorld"]
+~~~~~~~~~~
+
+Simply capitalizing the whole JSON would contain incorrect escape character:
+~~~~~~~~~~
+["HELLO\NWORLD"]
+~~~~~~~~~~
+
+The correct result by `capitalize`:
+~~~~~~~~~~
+["HELLO\nWORLD"]
+~~~~~~~~~~
+
+More complicated filters can be developed. However, since SAX-style API can only provide information about a single event at a time, user may need to book-keeping the contextual information (e.g. the path from root value, storage of other related values). Some processing may be easier to be implemented in DOM than SAX.
diff --git a/3rdparty/rapidjson/doc/sax.zh-cn.md b/3rdparty/rapidjson/doc/sax.zh-cn.md
new file mode 100644
index 00000000000..f8dc7b9aea7
--- /dev/null
+++ b/3rdparty/rapidjson/doc/sax.zh-cn.md
@@ -0,0 +1,476 @@
+# SAX
+
+"SAX"此术语æºäºŽ[Simple API for XML](http://en.wikipedia.org/wiki/Simple_API_for_XML)。我们借了此术语去套用在JSON的解æžåŠç”Ÿæˆã€‚
+
+在RapidJSON中,`Reader`(`GenericReader<...>`çš„typedef)是JSONçš„SAX风格解æžå™¨ï¼Œè€Œ`Writer`(`GenericWriter<...>`çš„typedef)则是JSONçš„SAX风格生æˆå™¨ã€‚
+
+[TOC]
+
+# Reader {#Reader}
+
+`Reader`从输入æµè§£æžä¸€ä¸ªJSON。当它从æµä¸­è¯»å–字符时,它会基于JSON的语法去分æžå­—符,并å‘处ç†å™¨å‘é€äº‹ä»¶ã€‚
+
+例如,以下是一个JSON。
+
+~~~~~~~~~~js
+{
+ "hello": "world",
+ "t": true ,
+ "f": false,
+ "n": null,
+ "i": 123,
+ "pi": 3.1416,
+ "a": [1, 2, 3, 4]
+}
+~~~~~~~~~~
+
+当一个`Reader`è§£æžæ­¤JSON时,它会顺åºåœ°å‘处ç†å™¨å‘é€ä»¥ä¸‹çš„事件:
+
+~~~~~~~~~~
+StartObject()
+Key("hello", 5, true)
+String("world", 5, true)
+Key("t", 1, true)
+Bool(true)
+Key("f", 1, true)
+Bool(false)
+Key("n", 1, true)
+Null()
+Key("i")
+UInt(123)
+Key("pi")
+Double(3.1416)
+Key("a")
+StartArray()
+Uint(1)
+Uint(2)
+Uint(3)
+Uint(4)
+EndArray(4)
+EndObject(7)
+~~~~~~~~~~
+
+é™¤äº†ä¸€äº›äº‹ä»¶å‚æ•°éœ€è¦å†ä½œè§£é‡Šï¼Œè¿™äº›äº‹ä»¶å¯ä»¥è½»æ¾åœ°ä¸ŽJSON对上。我们å¯ä»¥çœ‹çœ‹`simplereader`例孿€Žæ ·äº§ç”Ÿå’Œä»¥ä¸Šå®Œå…¨ç›¸åŒçš„结果:
+
+~~~~~~~~~~cpp
+#include "rapidjson/reader.h"
+#include <iostream>
+
+using namespace rapidjson;
+using namespace std;
+
+struct MyHandler {
+ bool Null() { cout << "Null()" << endl; return true; }
+ bool Bool(bool b) { cout << "Bool(" << boolalpha << b << ")" << endl; return true; }
+ bool Int(int i) { cout << "Int(" << i << ")" << endl; return true; }
+ bool Uint(unsigned u) { cout << "Uint(" << u << ")" << endl; return true; }
+ bool Int64(int64_t i) { cout << "Int64(" << i << ")" << endl; return true; }
+ bool Uint64(uint64_t u) { cout << "Uint64(" << u << ")" << endl; return true; }
+ bool Double(double d) { cout << "Double(" << d << ")" << endl; return true; }
+ bool String(const char* str, SizeType length, bool copy) {
+ cout << "String(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
+ return true;
+ }
+ bool StartObject() { cout << "StartObject()" << endl; return true; }
+ bool Key(const char* str, SizeType length, bool copy) {
+ cout << "Key(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
+ return true;
+ }
+ bool EndObject(SizeType memberCount) { cout << "EndObject(" << memberCount << ")" << endl; return true; }
+ bool StartArray() { cout << "StartArray()" << endl; return true; }
+ bool EndArray(SizeType elementCount) { cout << "EndArray(" << elementCount << ")" << endl; return true; }
+};
+
+void main() {
+ const char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";
+
+ MyHandler handler;
+ Reader reader;
+ StringStream ss(json);
+ reader.Parse(ss, handler);
+}
+~~~~~~~~~~
+
+注æ„RapidJSON使用模æ¿å޻陿€æŒ·å®š`Reader`类型åŠå¤„ç†å™¨çš„ç±»å½¢ï¼Œè€Œä¸æ˜¯ä½¿ç”¨å«è™šå‡½æ•°çš„类。这个范å¼å¯ä»¥é€šè¿‡æŠŠå‡½æ•°å†…è”而改善性能。
+
+## 处ç†å™¨ {#Handler}
+
+如å‰ä¾‹æ‰€ç¤ºï¼Œä½¿ç”¨è€…需è¦å®žçŽ°ä¸€ä¸ªå¤„ç†å™¨ï¼ˆhandlerï¼‰ï¼Œç”¨äºŽå¤„ç†æ¥è‡ª`Reader`的事件(函数调用)。处ç†å™¨å¿…须包å«ä»¥ä¸‹çš„æˆå‘˜å‡½æ•°ã€‚
+
+~~~~~~~~~~cpp
+class Handler {
+ bool Null();
+ bool Bool(bool b);
+ bool Int(int i);
+ bool Uint(unsigned i);
+ bool Int64(int64_t i);
+ bool Uint64(uint64_t i);
+ bool Double(double d);
+ bool String(const Ch* str, SizeType length, bool copy);
+ bool StartObject();
+ bool Key(const Ch* str, SizeType length, bool copy);
+ bool EndObject(SizeType memberCount);
+ bool StartArray();
+ bool EndArray(SizeType elementCount);
+};
+~~~~~~~~~~
+
+当`Reader`é‡åˆ°JSON null值时会调用`Null()`。
+
+当`Reader`é‡åˆ°JSON true或false值时会调用`Bool(bool)`。
+
+当`Reader`é‡åˆ°JSON number,它会选择一个åˆé€‚çš„C++类型映射,然åŽè°ƒç”¨`Int(int)`ã€`Uint(unsigned)`ã€`Int64(int64_t)`ã€`Uint64(uint64_t)`åŠ`Double(double)`çš„*其中之一个*。
+
+当`Reader`é‡åˆ°JSON string,它会调用`String(const char* str, SizeType length, bool copy)`ã€‚ç¬¬ä¸€ä¸ªå‚æ•°æ˜¯å­—ç¬¦ä¸²çš„æŒ‡é’ˆã€‚ç¬¬äºŒä¸ªå‚æ•°æ˜¯å­—符串的长度(ä¸åŒ…å«ç©ºç»ˆæ­¢ç¬¦å·ï¼‰ã€‚注æ„RapidJSON支æŒå­—䏲䏭嫿œ‰ç©ºå­—符`'\0'`ã€‚è‹¥å‡ºçŽ°è¿™ç§æƒ…况,便会有`strlen(str) < length`。最åŽçš„`copy`傿•°è¡¨ç¤ºå¤„ç†å™¨æ˜¯å¦éœ€è¦å¤åˆ¶è¯¥å­—ç¬¦ä¸²ã€‚åœ¨æ­£å¸¸è§£æžæ—¶ï¼Œ`copy = true`。仅当使用原ä½è§£æžæ—¶ï¼Œ`copy = false`ã€‚æ­¤å¤–ï¼Œè¿˜è¦æ³¨æ„字符的类型与目标编ç ç›¸å…³ï¼Œæˆ‘们ç¨åŽä¼šå†è°ˆè¿™ä¸€ç‚¹ã€‚
+
+当`Reader`é‡åˆ°JSON object的开始之时,它会调用`StartObject()`。JSONçš„object是一个键值对(æˆå‘˜ï¼‰çš„集åˆã€‚è‹¥objectåŒ…å«æˆå‘˜ï¼Œå®ƒä¼šå…ˆä¸ºæˆå‘˜çš„å字调用`Key()`,然åŽå†æŒ‰å€¼çš„ç±»åž‹è°ƒç”¨å‡½æ•°ã€‚å®ƒä¸æ–­è°ƒç”¨è¿™äº›é”®å€¼å¯¹ï¼Œç›´è‡³æœ€ç»ˆè°ƒç”¨`EndObject(SizeType memberCount)`。注æ„`memberCount`傿•°å¯¹å¤„ç†å™¨æ¥è¯´åªæ˜¯å助性质,使用者å¯èƒ½ä¸éœ€è¦æ­¤å‚数。
+
+JSON array与object相似,但更简å•。在array开始时,`Reader`会调用`BeginArary()`。若array嫿œ‰å…ƒç´ ï¼Œå®ƒä¼šæŒ‰å…ƒç´ çš„类型æ¥è¯»ç”¨å‡½æ•°ã€‚相似地,最åŽå®ƒä¼šè°ƒç”¨`EndArray(SizeType elementCount)`,其中`elementCount`傿•°å¯¹å¤„ç†å™¨æ¥è¯´åªæ˜¯å助性质。
+
+æ¯ä¸ªå¤„ç†å™¨å‡½æ•°éƒ½è¿”回一个`bool`。正常它们应返回`true`。若处ç†å™¨é‡åˆ°é”™è¯¯ï¼Œå®ƒå¯ä»¥è¿”回`false`去通知事件å‘逿–¹åœæ­¢ç»§ç»­å¤„ç†ã€‚
+
+例如,当我们用`Reader`è§£æžä¸€ä¸ªJSON时,处ç†å™¨æ£€æµ‹åˆ°è¯¥JSONå¹¶ä¸ç¬¦åˆæ‰€éœ€çš„schema,那么处ç†å™¨å¯ä»¥è¿”回`false`,令`Reader`åœæ­¢ä¹‹åŽçš„è§£æžå·¥ä½œã€‚而`Reader`会进入一个错误状æ€ï¼Œå¹¶ä»¥`kParseErrorTermination`é”™è¯¯ç æ ‡è¯†ã€‚
+
+## GenericReader {#GenericReader}
+
+å‰é¢æåŠï¼Œ`Reader`是`GenericReader`模æ¿ç±»çš„typedef:
+
+~~~~~~~~~~cpp
+namespace rapidjson {
+
+template <typename SourceEncoding, typename TargetEncoding, typename Allocator = MemoryPoolAllocator<> >
+class GenericReader {
+ // ...
+};
+
+typedef GenericReader<UTF8<>, UTF8<> > Reader;
+
+} // namespace rapidjson
+~~~~~~~~~~
+
+`Reader`使用UTF-8ä½œä¸ºæ¥æºåŠç›®æ ‡ç¼–ç ã€‚æ¥æºç¼–ç æ˜¯æŒ‡JSONæµçš„ç¼–ç ã€‚ç›®æ ‡ç¼–ç æ˜¯æŒ‡`String()`çš„`str`傿•°æ‰€ç”¨çš„ç¼–ç ã€‚例如,è¦è§£æžä¸€ä¸ªUTF-8æµå¹¶è¾“出至UTF-16 string事件,你需è¦è¿™ä¹ˆå®šä¹‰ä¸€ä¸ªreader:
+
+~~~~~~~~~~cpp
+GenericReader<UTF8<>, UTF16<> > reader;
+~~~~~~~~~~
+
+注æ„到`UTF16`的缺çœç±»åž‹æ˜¯`wchar_t`。因此这个`reader`需è¦è°ƒç”¨å¤„ç†å™¨çš„`String(const wchar_t*, SizeType, bool)`。
+
+第三个模æ¿å‚æ•°`Allocator`是内部数æ®ç»“构(实际上是一个堆栈)的分é…器类型。
+
+## è§£æž {#Parsing}
+
+`Reader`的唯一功能就是解æžJSON。
+
+~~~~~~~~~~cpp
+template <unsigned parseFlags, typename InputStream, typename Handler>
+bool Parse(InputStream& is, Handler& handler);
+
+// 使用 parseFlags = kDefaultParseFlags
+template <typename InputStream, typename Handler>
+bool Parse(InputStream& is, Handler& handler);
+~~~~~~~~~~
+
+若在解æžä¸­å‡ºçŽ°é”™è¯¯ï¼Œå®ƒä¼šè¿”å›ž`false`。使用者å¯è°ƒç”¨`bool HasParseEror()`, `ParseErrorCode GetParseErrorCode()`åŠ`size_t GetErrorOffset()`获å–错误状æ€ã€‚实际上`Document`使用这些`Reader`函数去获å–è§£æžé”™è¯¯ã€‚请å‚考[DOM](doc/dom.md)去了解有关解æžé”™è¯¯çš„细节。
+
+# Writer {#Writer}
+
+`Reader`把JSON转æ¢ï¼ˆè§£æžï¼‰æˆä¸ºäº‹ä»¶ã€‚`Writer`åšå®Œå…¨ç›¸åçš„äº‹æƒ…ã€‚å®ƒæŠŠäº‹ä»¶è½¬æ¢æˆJSON。
+
+`Writer`是éžå¸¸å®¹æ˜“使用的。若你的应用程åºåªéœ€æŠŠä¸€äº›æ•°æ®è½¬æ¢æˆJSON,å¯èƒ½ç›´æŽ¥ä½¿ç”¨`Writer`,会比建立一个`Document`ç„¶åŽç”¨`Writer`æŠŠå®ƒè½¬æ¢æˆJSON更加方便。
+
+在`simplewriter`例å­é‡Œï¼Œæˆ‘们åš`simplereader`完全相å的事情。
+
+~~~~~~~~~~cpp
+#include "rapidjson/writer.h"
+#include "rapidjson/stringbuffer.h"
+#include <iostream>
+
+using namespace rapidjson;
+using namespace std;
+
+void main() {
+ StringBuffer s;
+ Writer<StringBuffer> writer(s);
+
+ writer.StartObject();
+ writer.Key("hello");
+ writer.String("world");
+ writer.Key("t");
+ writer.Bool(true);
+ writer.Key("f");
+ writer.Bool(false);
+ writer.Key("n");
+ writer.Null();
+ writer.Key("i");
+ writer.Uint(123);
+ writer.Key("pi");
+ writer.Double(3.1416);
+ writer.Key("a");
+ writer.StartArray();
+ for (unsigned i = 0; i < 4; i++)
+ writer.Uint(i);
+ writer.EndArray();
+ writer.EndObject();
+
+ cout << s.GetString() << endl;
+}
+~~~~~~~~~~
+
+~~~~~~~~~~
+{"hello":"world","t":true,"f":false,"n":null,"i":123,"pi":3.1416,"a":[0,1,2,3]}
+~~~~~~~~~~
+
+`String()`åŠ`Key()`儿œ‰ä¸¤ä¸ªé‡è½½ã€‚一个是如处ç†å™¨concept般,有3ä¸ªå‚æ•°ã€‚它能处ç†å«ç©ºå­—符的字符串。å¦ä¸€ä¸ªæ˜¯å¦‚上中使用的较简å•版本。
+
+注æ„到,例å­ä»£ç ä¸­çš„`EndArray()`åŠ`EndObject()`å¹¶æ²¡æœ‰å‚æ•°ã€‚å¯ä»¥ä¼ é€’一个`SizeType`çš„å‚æ•°ï¼Œä½†å®ƒä¼šè¢«`Writer`忽略。
+
+ä½ å¯èƒ½ä¼šæ€€ç–‘,为什么ä¸ä½¿ç”¨`sprintf()`或`std::stringstream`去建立一个JSON?
+
+这有几个原因:
+1. `Writer`必然会输出一个结构良好(well-formed)的JSON。若然有错误的事件次åºï¼ˆå¦‚`Int()`ç´§éš`StartObject()`出现),它会在调试模å¼ä¸­äº§ç”Ÿæ–­è¨€å¤±è´¥ã€‚
+2. `Writer::String()`å¯å¤„ç†å­—符串转义(如把ç ç‚¹`U+000A`è½¬æ¢æˆ`\n`)åŠè¿›è¡ŒUnicode转ç ã€‚
+3. `Writer`一致地处ç†number的输出。
+4. `Writer`实现了事件处ç†å™¨concept。å¯ç”¨äºŽå¤„ç†æ¥è‡ª`Reader`ã€`Document`或其他事件å‘生器。
+5. `Writer`å¯å¯¹ä¸åŒå¹³å°è¿›è¡Œä¼˜åŒ–。
+
+无论如何,使用`Writer` API去生æˆJSON甚至乎比这些临时方法更简å•。
+
+## æ¨¡æ¿ {#WriterTemplate}
+
+`Writer`与`Reader`有少许设计区别。`Writer`是一个模æ¿ç±»ï¼Œè€Œä¸æ˜¯ä¸€ä¸ªtypedef。 并没有`GenericWriter`。以下是`Writer`的声明。
+
+~~~~~~~~~~cpp
+namespace rapidjson {
+
+template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename Allocator = CrtAllocator<> >
+class Writer {
+public:
+ Writer(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth)
+// ...
+};
+
+} // namespace rapidjson
+~~~~~~~~~~
+
+`OutputStream`模æ¿å‚数是输出æµçš„类型。它的类型ä¸å¯ä»¥è¢«è‡ªåŠ¨æŽ¨æ–­ï¼Œå¿…é¡»ç”±ä½¿ç”¨è€…æä¾›ã€‚
+
+`SourceEncoding`模æ¿å‚数指定了`String(const Ch*, ...)`的编ç ã€‚
+
+`TargetEncoding`模æ¿å‚数指定输出æµçš„ç¼–ç ã€‚
+
+最åŽä¸€ä¸ª`Allocator`是分é…器的类型,用于分é…内部数æ®ç»“构(一个堆栈)。
+
+此外,`Writer`的构造函数有一`levelDepth`傿•°ã€‚存储æ¯å±‚阶信æ¯çš„åˆå§‹å†…存分é…é‡å—æ­¤å‚æ•°å½±å“。
+
+## PrettyWriter {#PrettyWriter}
+
+`Writer`所输出的是没有空格字符的最紧凑JSON,适åˆç½‘络传输或储存,但ä¸é€‚åˆäººç±»é˜…读。
+
+因此,RapidJSONæä¾›äº†ä¸€ä¸ª`PrettyWriter`ï¼Œå®ƒåœ¨è¾“å‡ºä¸­åŠ å…¥ç¼©è¿›åŠæ¢è¡Œã€‚
+
+`PrettyWriter`的用法与`Writer`几乎一样,ä¸åŒä¹‹å¤„是`PrettyWriter`æä¾›äº†ä¸€ä¸ª`SetIndent(Ch indentChar, unsigned indentCharCount)`函数。缺çœçš„缩进是4个空格。
+
+## 完整性åŠé‡ç½® {#CompletenessReset}
+
+一个`Writer`åªå¯è¾“出å•个JSON,其根节点å¯ä»¥æ˜¯ä»»ä½•JSON类型。当处ç†å®Œå•个根节点事件(如`String()`),或匹é…的最åŽ`EndObject()`或`EndArray()`事件,输出的JSON是结构完整(well-formed)åŠå®Œæ•´çš„。使用者å¯è°ƒç”¨`Writer::IsComplete()`去检测完整性。
+
+当JSON完整时,`Writer`ä¸èƒ½å†æŽ¥å—新的事件。ä¸ç„¶å…¶è¾“出便会是ä¸åˆæ³•çš„ï¼ˆä¾‹å¦‚æœ‰è¶…è¿‡ä¸€ä¸ªæ ¹èŠ‚ç‚¹ï¼‰ã€‚ä¸ºäº†é‡æ–°åˆ©ç”¨`Writer`对象,使用者å¯è°ƒç”¨`Writer::Reset(OutputStream& os)`去é‡ç½®å…¶æ‰€æœ‰å†…部状æ€åŠè®¾ç½®æ–°çš„输出æµã€‚
+
+# 技巧 {#Techniques}
+
+## è§£æžJSON至自定义结构 {#CustomDataStructure}
+
+`Document`的解æžåŠŸèƒ½å®Œå…¨ä¾é `Reader`。实际上`Document`是一个处ç†å™¨ï¼Œåœ¨è§£æžJSON时接收事件去建立一个DOM。
+
+使用者å¯ä»¥ç›´æŽ¥ä½¿ç”¨`Reader`去建立其他数æ®ç»“构。这消除了建立DOM的步骤,从而å‡å°‘了内存开销并改善性能。
+
+在以下的`messagereader`例å­ä¸­ï¼Œ`ParseMessages()`è§£æžä¸€ä¸ªJSON,该JSON应该是一个å«é”®å€¼å¯¹çš„object。
+
+~~~~~~~~~~cpp
+#include "rapidjson/reader.h"
+#include "rapidjson/error/en.h"
+#include <iostream>
+#include <string>
+#include <map>
+
+using namespace std;
+using namespace rapidjson;
+
+typedef map<string, string> MessageMap;
+
+struct MessageHandler
+ : public BaseReaderHandler<UTF8<>, MessageHandler> {
+ MessageHandler() : state_(kExpectObjectStart) {
+ }
+
+ bool StartObject() {
+ switch (state_) {
+ case kExpectObjectStart:
+ state_ = kExpectNameOrObjectEnd;
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool String(const char* str, SizeType length, bool) {
+ switch (state_) {
+ case kExpectNameOrObjectEnd:
+ name_ = string(str, length);
+ state_ = kExpectValue;
+ return true;
+ case kExpectValue:
+ messages_.insert(MessageMap::value_type(name_, string(str, length)));
+ state_ = kExpectNameOrObjectEnd;
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool EndObject(SizeType) { return state_ == kExpectNameOrObjectEnd; }
+
+ bool Default() { return false; } // All other events are invalid.
+
+ MessageMap messages_;
+ enum State {
+ kExpectObjectStart,
+ kExpectNameOrObjectEnd,
+ kExpectValue,
+ }state_;
+ std::string name_;
+};
+
+void ParseMessages(const char* json, MessageMap& messages) {
+ Reader reader;
+ MessageHandler handler;
+ StringStream ss(json);
+ if (reader.Parse(ss, handler))
+ messages.swap(handler.messages_); // Only change it if success.
+ else {
+ ParseErrorCode e = reader.GetParseErrorCode();
+ size_t o = reader.GetErrorOffset();
+ cout << "Error: " << GetParseError_En(e) << endl;;
+ cout << " at offset " << o << " near '" << string(json).substr(o, 10) << "...'" << endl;
+ }
+}
+
+int main() {
+ MessageMap messages;
+
+ const char* json1 = "{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\" }";
+ cout << json1 << endl;
+ ParseMessages(json1, messages);
+
+ for (MessageMap::const_iterator itr = messages.begin(); itr != messages.end(); ++itr)
+ cout << itr->first << ": " << itr->second << endl;
+
+ cout << endl << "Parse a JSON with invalid schema." << endl;
+ const char* json2 = "{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\", \"foo\" : {} }";
+ cout << json2 << endl;
+ ParseMessages(json2, messages);
+
+ return 0;
+}
+~~~~~~~~~~
+
+~~~~~~~~~~
+{ "greeting" : "Hello!", "farewell" : "bye-bye!" }
+farewell: bye-bye!
+greeting: Hello!
+
+Parse a JSON with invalid schema.
+{ "greeting" : "Hello!", "farewell" : "bye-bye!", "foo" : {} }
+Error: Terminate parsing due to Handler error.
+ at offset 59 near '} }...'
+~~~~~~~~~~
+
+第一个JSON(`json1`)被æˆåŠŸåœ°è§£æžè‡³`MessageMap`。由于`MessageMap`是一个`std::map`ï¼Œæ‰“å°æ¬¡åºæŒ‰é”®å€¼æŽ’åºã€‚此次åºä¸ŽJSON中的次åºä¸åŒã€‚
+
+在第二个JSON(`json2`)中,`foo`的值是一个空object。由于它是一个object,`MessageHandler::StartObject()`会被调用。然而,在`state_ = kExpectValue`的情况下,该函数会返回`false`,并导致解æžè¿‡ç¨‹ç»ˆæ­¢ã€‚é”™è¯¯ä»£ç æ˜¯`kParseErrorTermination`。
+
+## 过滤JSON {#Filtering}
+
+如å‰é¢æåŠè¿‡ï¼Œ`Writer`å¯å¤„ç†`Reader`å‘出的事件。`example/condense/condense.cpp`例å­ç®€å•地设置`Writer`作为一个`Reader`的处ç†å™¨ï¼Œå› æ­¤å®ƒèƒ½ç§»é™¤JSON中的所有空白字符。`example/pretty/pretty.cpp`例å­ä½¿ç”¨åŒæ ·çš„å…³ç³»ï¼Œåªæ˜¯ä»¥`PrettyWriter`å–代`Writer`。因此`pretty`èƒ½å¤Ÿé‡æ–°æ ¼å¼åŒ–JSONï¼ŒåŠ å…¥ç¼©è¿›åŠæ¢è¡Œã€‚
+
+实际上,我们å¯ä»¥ä½¿ç”¨SAX风格API去加入(多个)中间层去过滤JSON的内容。例如`capitalize`例å­å¯ä»¥æŠŠæ‰€æœ‰JSON string改为大写。
+
+~~~~~~~~~~cpp
+#include "rapidjson/reader.h"
+#include "rapidjson/writer.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/filewritestream.h"
+#include "rapidjson/error/en.h"
+#include <vector>
+#include <cctype>
+
+using namespace rapidjson;
+
+template<typename OutputHandler>
+struct CapitalizeFilter {
+ CapitalizeFilter(OutputHandler& out) : out_(out), buffer_() {
+ }
+
+ bool Null() { return out_.Null(); }
+ bool Bool(bool b) { return out_.Bool(b); }
+ bool Int(int i) { return out_.Int(i); }
+ bool Uint(unsigned u) { return out_.Uint(u); }
+ bool Int64(int64_t i) { return out_.Int64(i); }
+ bool Uint64(uint64_t u) { return out_.Uint64(u); }
+ bool Double(double d) { return out_.Double(d); }
+ bool String(const char* str, SizeType length, bool) {
+ buffer_.clear();
+ for (SizeType i = 0; i < length; i++)
+ buffer_.push_back(std::toupper(str[i]));
+ return out_.String(&buffer_.front(), length, true); // true = output handler need to copy the string
+ }
+ bool StartObject() { return out_.StartObject(); }
+ bool Key(const char* str, SizeType length, bool copy) { return String(str, length, copy); }
+ bool EndObject(SizeType memberCount) { return out_.EndObject(memberCount); }
+ bool StartArray() { return out_.StartArray(); }
+ bool EndArray(SizeType elementCount) { return out_.EndArray(elementCount); }
+
+ OutputHandler& out_;
+ std::vector<char> buffer_;
+};
+
+int main(int, char*[]) {
+ // Prepare JSON reader and input stream.
+ Reader reader;
+ char readBuffer[65536];
+ FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
+
+ // Prepare JSON writer and output stream.
+ char writeBuffer[65536];
+ FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
+ Writer<FileWriteStream> writer(os);
+
+ // JSON reader parse from the input stream and let writer generate the output.
+ CapitalizeFilter<Writer<FileWriteStream> > filter(writer);
+ if (!reader.Parse(is, filter)) {
+ fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode()));
+ return 1;
+ }
+
+ return 0;
+}
+~~~~~~~~~~
+
+注æ„到,ä¸å¯ç®€å•地把JSON当作字符串去改为大写。例如:
+~~~~~~~~~~
+["Hello\nWorld"]
+~~~~~~~~~~
+
+简å•地把整个JSON转为大写的è¯ä¼šäº§ç”Ÿé”™è¯¯çš„转义符:
+~~~~~~~~~~
+["HELLO\NWORLD"]
+~~~~~~~~~~
+
+而`capitalize`就会产生正确的结果:
+~~~~~~~~~~
+["HELLO\nWORLD"]
+~~~~~~~~~~
+
+我们还å¯ä»¥å¼€å‘æ›´å¤æ‚的过滤器。然而,由于SAX风格API在æŸä¸€æ—¶é—´ç‚¹åªèƒ½æä¾›å•一事件的信æ¯ï¼Œä½¿ç”¨è€…需è¦è‡ªè¡Œè®°å½•一些上下文信æ¯ï¼ˆä¾‹å¦‚从根节点起的路径ã€å‚¨å­˜å…¶ä»–ç›¸å…³å€¼ï¼‰ã€‚å¯¹äºŽå¤„ç†æŸäº›æƒ…况,用DOM会比SAX更容易实现。
+
diff --git a/3rdparty/rapidjson/doc/schema.md b/3rdparty/rapidjson/doc/schema.md
new file mode 100644
index 00000000000..4e07e9f0eee
--- /dev/null
+++ b/3rdparty/rapidjson/doc/schema.md
@@ -0,0 +1,237 @@
+# Schema
+
+## Status: experimental, shall be included in v1.1
+
+JSON Schema is a draft standard for describing format of JSON. The schema itself is also a JSON. By validating a JSON with JSON Schema, your code can safely access the DOM without manually checking types, or whether a key exists, etc. It can also ensure that the serialized JSON conform to a specified schema.
+
+RapidJSON implemented a JSON Schema validator for [JSON Schema Draft v4](http://json-schema.org/documentation.html). If you do not familiar with JSON Schema, you may refer to [Understanding JSON Schema](http://spacetelescope.github.io/understanding-json-schema/).
+
+[TOC]
+
+## Basic Usage
+
+First of all, you need to parse a JSON Schema into `Document`, and then compile the `Document` into `SchemaDocument`.
+
+Secondly, construct a `SchemaValidator` with the `SchedmaDocument`. It is similar to a `Writer` in the sense of handling SAX events. So, you can use `document.Accept(validator)` to validate a document, and then check the validity.
+
+~~~cpp
+#include "rapidjson/schema.h"
+
+// ...
+
+Document sd;
+if (!sd.Parse(schemaJson)) {
+ // the schema is not a valid JSON.
+ // ...
+}
+SchemaDocument schema(sd); // Compile a Document to SchemaDocument
+// sd is no longer needed here.
+
+Document d;
+if (!d.Parse(inputJson)) {
+ // the input is not a valid JSON.
+ // ...
+}
+
+SchemaValidator validator(schema);
+if (!d.Accept(validator)) {
+ // Input JSON is invalid according to the schema
+ // Output diagnostic information
+ StringBuffer sb;
+ validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
+ printf("Invalid schema: %s\n", sb.GetString());
+ printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
+ sb.Clear();
+ validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
+ printf("Invalid document: %s\n", sb.GetString());
+}
+~~~
+
+Some notes:
+
+* One `SchemaDocment` can be referenced by multiple `SchemaValidator`s. It will not be modified by `SchemaValidator`s.
+* A `SchemaValidator` may be reused to validate multiple documents. To run it for other documents, call `validator.Reset()` first.
+
+## Validation during parsing/serialization
+
+Differ to most JSON Schema validator implementations, RapidJSON provides a SAX-based schema validator. Therefore, you can parse a JSON from a stream while validating it on the fly. If the validator encounters a JSON value that invalidates the supplied schema, the parsing will be terminated immediately. This design is especially useful for parsing large JSON files.
+
+### DOM parsing
+
+For using DOM in parsing, `Document` needs some preparation and finalizing tasks, in addition to receiving SAX events, thus it needs some work to route the reader, validator and the document. `SchemaValidatingReader` is a helper class that doing such work.
+
+~~~cpp
+#include "rapidjson/filereadstream.h"
+
+// ...
+SchemaDocument schema(sd); // Compile a Document to SchemaDocument
+
+// Use reader to parse the JSON
+FILE* fp = fopen("big.json", "r");
+FileReadStream is(fp, buffer, sizeof(buffer));
+
+// Parse JSON from reader, validate the SAX events, and store in d.
+Document d;
+SchemaValidatingReader<kParseDefaultFlags, FileReadStream, UTF8<> > reader(is, schema);
+d.Populate(reader);
+
+if (!reader.GetParseResult()) {
+ // Not a valid JSON
+ // When reader.GetParseResult().Code() == kParseErrorTermination,
+ // it may be terminated by:
+ // (1) the validator found that the JSON is invalid according to schema; or
+ // (2) the input stream has I/O error.
+
+ // Check the validation result
+ if (!reader.IsValid()) {
+ // Input JSON is invalid according to the schema
+ // Output diagnostic information
+ StringBuffer sb;
+ reader.GetInvalidSchemaPointer().StringifyUriFragment(sb);
+ printf("Invalid schema: %s\n", sb.GetString());
+ printf("Invalid keyword: %s\n", reader.GetInvalidSchemaKeyword());
+ sb.Clear();
+ reader.GetInvalidDocumentPointer().StringifyUriFragment(sb);
+ printf("Invalid document: %s\n", sb.GetString());
+ }
+}
+~~~
+
+### SAX parsing
+
+For using SAX in parsing, it is much simpler. If it only need to validate the JSON without further processing, it is simply:
+
+~~~
+SchemaValidator validator(schema);
+Reader reader;
+if (!reader.Parse(stream, validator)) {
+ if (!validator.IsValid()) {
+ // ...
+ }
+}
+~~~
+
+This is exactly the method used in [schemavalidator](example/schemavalidator/schemavalidator.cpp) example. The distinct advantage is low memory usage, no matter how big the JSON was (the memory usage depends on the complexity of the schema).
+
+If you need to handle the SAX events further, then you need to use the template class `GenericSchemaValidator` to set the output handler of the validator:
+
+~~~
+MyHandler handler;
+GenericSchemaValidator<SchemaDocument, MyHandler> validator(schema, handler);
+Reader reader;
+if (!reader.Parse(ss, validator)) {
+ if (!validator.IsValid()) {
+ // ...
+ }
+}
+~~~
+
+### Serialization
+
+It is also possible to do validation during serializing. This can ensure the result JSON is valid according to the JSON schema.
+
+~~~
+StringBuffer sb;
+Writer<StringBuffer> writer(sb);
+GenericSchemaValidator<SchemaDocument, Writer<StringBuffer> > validator(s, writer);
+if (!d.Accept(validator)) {
+ // Some problem during Accept(), it may be validation or encoding issues.
+ if (!validator.IsValid()) {
+ // ...
+ }
+}
+~~~
+
+Of course, if your application only needs SAX-style serialization, it can simply send SAX events to `SchemaValidator` instead of `Writer`.
+
+## Remote Schema
+
+JSON Schema supports [`$ref` keyword](http://spacetelescope.github.io/understanding-json-schema/structuring.html), which is a [JSON pointer](pointer.md) referencing to a local or remote schema. Local pointer is prefixed with `#`, while remote pointer is an relative or absolute URI. For example:
+
+~~~js
+{ "$ref": "definitions.json#/address" }
+~~~
+
+As `SchemaValidator` does not know how to resolve such URI, it needs a user-provided `IRemoteSchemaDocumentProvider` instance to do so.
+
+~~~
+class MyRemoteSchemaDocumentProvider : public IRemoteSchemaDocumentProvider {
+public:
+ virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeTyp length) {
+ // Resolve the uri and returns a pointer to that schema.
+ }
+};
+
+// ...
+
+MyRemoteSchemaDocumentProvider provider;
+SchemaValidator validator(schema, &provider);
+~~~
+
+## Conformance
+
+RapidJSON passed 262 out of 263 tests in [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) (Json Schema draft 4).
+
+The failed test is "changed scope ref invalid" of "change resolution scope" in `refRemote.json`. It is due to that `id` schema keyword and URI combining function are not implemented.
+
+Besides, the `format` schema keyword for string values is ignored, since it is not required by the specification.
+
+### Regular Expression
+
+The schema keyword `pattern` and `patternProperties` uses regular expression to match the required pattern.
+
+RapidJSON implemented a simple NFA regular expression engine, which is used by default. It supports the following syntax.
+
+|Syntax|Description|
+|------|-----------|
+|`ab` | Concatenation
+|`a|b` | Alternation
+|`a?` | Zero or one
+|`a*` | Zero or more
+|`a+` | One or more
+|`a{3}` | Exactly 3 times
+|`a{3,}` | At least 3 times
+|`a{3,5}`| 3 to 5 times
+|`(ab)` | Grouping
+|`^a` | At the beginning
+|`a$` | At the end
+|`.` | Any character
+|`[abc]` | Character classes
+|`[a-c]` | Character class range
+|`[a-z0-9_]` | Character class combination
+|`[^abc]` | Negated character classes
+|`[^a-c]` | Negated character class range
+|`[\b]` | Backspace (U+0008)
+|`\|`, `\\`, ... | Escape characters
+|`\f` | Form feed (U+000C)
+|`\n` | Line feed (U+000A)
+|`\r` | Carriage return (U+000D)
+|`\t` | Tab (U+0009)
+|`\v` | Vertical tab (U+000B)
+
+For C++11 compiler, it is also possible to use the `std::regex` by defining `RAPIDJSON_SCHEMA_USE_INTERNALREGEX=0` and `RAPIDJSON_SCHEMA_USE_STDREGEX=1`. If your schemas do not need `pattern` and `patternProperties`, you can set both macros to zero to disable this feature, which will reduce some code size.
+
+## Performance
+
+Most C++ JSON libraries have not yet supporting JSON Schema. So we tried to evaluate the performance of RapidJSON's JSON Schema validator according to [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark), which tests 11 JavaScript libraries running on Node.js.
+
+That benchmark runs validations on [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite), in which some test suites and tests are excluded. We made the same benchmarking procedure in [`schematest.cpp`](test/perftest/schematest.cpp).
+
+On a Mac Book Pro (2.8 GHz Intel Core i7), the following results are collected.
+
+|Validator|Relative speed|Number of test runs per second|
+|---------|:------------:|:----------------------------:|
+|RapidJSON|155%|30682|
+|[`ajv`](https://github.com/epoberezkin/ajv)|100%|19770 (± 1.31%)|
+|[`is-my-json-valid`](https://github.com/mafintosh/is-my-json-valid)|70%|13835 (± 2.84%)|
+|[`jsen`](https://github.com/bugventure/jsen)|57.7%|11411 (± 1.27%)|
+|[`schemasaurus`](https://github.com/AlexeyGrishin/schemasaurus)|26%|5145 (± 1.62%)|
+|[`themis`](https://github.com/playlyfe/themis)|19.9%|3935 (± 2.69%)|
+|[`z-schema`](https://github.com/zaggino/z-schema)|7%|1388 (± 0.84%)|
+|[`jsck`](https://github.com/pandastrike/jsck#readme)|3.1%|606 (± 2.84%)|
+|[`jsonschema`](https://github.com/tdegrunt/jsonschema#readme)|0.9%|185 (± 1.01%)|
+|[`skeemas`](https://github.com/Prestaul/skeemas#readme)|0.8%|154 (± 0.79%)|
+|tv4|0.5%|93 (± 0.94%)|
+|[`jayschema`](https://github.com/natesilva/jayschema)|0.1%|21 (± 1.14%)|
+
+That is, RapidJSON is about 1.5x faster than the fastest JavaScript library (ajv). And 1400x faster than the slowest one.
diff --git a/3rdparty/rapidjson/doc/schema.zh-cn.md b/3rdparty/rapidjson/doc/schema.zh-cn.md
new file mode 100644
index 00000000000..dd0ec73b85e
--- /dev/null
+++ b/3rdparty/rapidjson/doc/schema.zh-cn.md
@@ -0,0 +1,237 @@
+# Schema
+
+## 状æ€: 实验性,应该会åˆè¿› v1.1
+
+JSON Schema 是æè¿° JSON æ ¼å¼çš„ä¸€ä¸ªæ ‡å‡†è‰æ¡ˆã€‚一个 schema 本身也是一个 JSON。使用 JSON Schema 去校验 JSON,å¯ä»¥è®©ä½ çš„代ç å®‰å…¨åœ°è®¿é—® DOM,而无须检查类型或键值是å¦å­˜åœ¨ç­‰ã€‚这也能确ä¿è¾“出的 JSON æ˜¯ç¬¦åˆæŒ‡å®šçš„ schema。
+
+RapidJSON 实现了一个 [JSON Schema Draft v4](http://json-schema.org/documentation.html) 的校验器。若你ä¸ç†Ÿæ‚‰ JSON Schema,å¯ä»¥å‚考 [Understanding JSON Schema](http://spacetelescope.github.io/understanding-json-schema/)。
+
+[TOC]
+
+## 基本用法
+
+é¦–å…ˆï¼Œä½ è¦æŠŠ JSON Schema è§£æžæˆ `Document`ï¼Œå†æŠŠå®ƒç¼–è¯‘æˆä¸€ä¸ª `SchemaDocument`。
+
+ç„¶åŽï¼Œåˆ©ç”¨è¯¥ `SchemaDocument` 创建一个 `SchemaValidator`。它与 `Writer` ç›¸ä¼¼ï¼Œéƒ½æ˜¯èƒ½å¤Ÿå¤„ç† SAX 事件的。因此,你å¯ä»¥ç”¨ `document.Accept(validator)` 去校验一个 JSON,然åŽå†èŽ·å–æ ¡éªŒç»“果。
+
+~~~cpp
+#include "rapidjson/schema.h"
+
+// ...
+
+Document sd;
+if (!sd.Parse(schemaJson)) {
+ // the schema is not a valid JSON.
+ // ...
+}
+SchemaDocument schema(sd); // Compile a Document to SchemaDocument
+// sd is no longer needed here.
+
+Document d;
+if (!d.Parse(inputJson)) {
+ // the input is not a valid JSON.
+ // ...
+}
+
+SchemaValidator validator(schema);
+if (!d.Accept(validator)) {
+ // Input JSON is invalid according to the schema
+ // Output diagnostic information
+ StringBuffer sb;
+ validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
+ printf("Invalid schema: %s\n", sb.GetString());
+ printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
+ sb.Clear();
+ validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
+ printf("Invalid document: %s\n", sb.GetString());
+}
+~~~
+
+一些注æ„点:
+
+* 一个 `SchemaDocment` 能被多个 `SchemaValidator` åŠç”¨ã€‚它ä¸ä¼šè¢« `SchemaValidator` 修改。
+* 一个 `SchemaValidator` å¯ä»¥é‡å¤ä½¿ç”¨æ¥æ ¡éªŒå¤šä¸ªæ–‡ä»¶ã€‚在校验其他文件å‰ï¼Œå…ˆè°ƒç”¨ `validator.Reset()`。
+
+## 在解æžï¼ç”Ÿæˆæ—¶è¿›è¡Œæ ¡éªŒ
+
+与大部分 JSON Schema 校验器有所ä¸åŒï¼ŒRapidJSON æä¾›äº†ä¸€ä¸ªåŸºäºŽ SAX çš„ schema 校验器实现。因此,你å¯ä»¥åœ¨è¾“å…¥æµè§£æž JSON çš„åŒæ—¶è¿›è¡Œæ ¡éªŒã€‚若校验器é‡åˆ°ä¸€ä¸ªä¸Ž schema ä¸ç¬¦çš„值,就会立å³ç»ˆæ­¢è§£æžã€‚这设计对于解æžå¤§åž‹ JSON 文件时特别有用。
+
+### DOM è§£æž
+
+在使用 DOM è¿›è¡Œè§£æžæ—¶ï¼Œ`Document` 除了接收 SAX 事件外,还需åšä¸€äº›å‡†å¤‡åŠç»“æŸå·¥ä½œï¼Œå› æ­¤ï¼Œä¸ºäº†è¿žæŽ¥ `Reader`ã€`SchemaValidator` å’Œ `Document` è¦åšå¤šä¸€ç‚¹äº‹æƒ…。`SchemaValidatingReader` 是一个辅助类去åšé‚£äº›å·¥ä½œã€‚
+
+~~~cpp
+#include "rapidjson/filereadstream.h"
+
+// ...
+SchemaDocument schema(sd); // Compile a Document to SchemaDocument
+
+// Use reader to parse the JSON
+FILE* fp = fopen("big.json", "r");
+FileReadStream is(fp, buffer, sizeof(buffer));
+
+// Parse JSON from reader, validate the SAX events, and store in d.
+Document d;
+SchemaValidatingReader<kParseDefaultFlags, FileReadStream, UTF8<> > reader(is, schema);
+d.Populate(reader);
+
+if (!reader.GetParseResult()) {
+ // Not a valid JSON
+ // When reader.GetParseResult().Code() == kParseErrorTermination,
+ // it may be terminated by:
+ // (1) the validator found that the JSON is invalid according to schema; or
+ // (2) the input stream has I/O error.
+
+ // Check the validation result
+ if (!reader.IsValid()) {
+ // Input JSON is invalid according to the schema
+ // Output diagnostic information
+ StringBuffer sb;
+ reader.GetInvalidSchemaPointer().StringifyUriFragment(sb);
+ printf("Invalid schema: %s\n", sb.GetString());
+ printf("Invalid keyword: %s\n", reader.GetInvalidSchemaKeyword());
+ sb.Clear();
+ reader.GetInvalidDocumentPointer().StringifyUriFragment(sb);
+ printf("Invalid document: %s\n", sb.GetString());
+ }
+}
+~~~
+
+### SAX è§£æž
+
+使用 SAX è§£æžæ—¶ï¼Œæƒ…况就简å•得多。若åªéœ€è¦æ ¡éªŒ JSON 而无需进一步处ç†ï¼Œé‚£ä¹ˆä»…需è¦ï¼š
+
+~~~
+SchemaValidator validator(schema);
+Reader reader;
+if (!reader.Parse(stream, validator)) {
+ if (!validator.IsValid()) {
+ // ...
+ }
+}
+~~~
+
+è¿™ç§æ–¹å¼å’Œ [schemavalidator](example/schemavalidator/schemavalidator.cpp) 例å­å®Œå…¨ç›¸åŒã€‚这带æ¥çš„独特优势是,无论 JSON 多巨大,永远维æŒä½Žå†…存用é‡ï¼ˆå†…存用é‡åªä¸Ž Schema çš„å¤æ‚度相关)。
+
+若你需è¦è¿›ä¸€æ­¥å¤„ç† SAX 事件,便å¯ä½¿ç”¨æ¨¡æ¿ç±» `GenericSchemaValidator` 去设置校验器的输出 `Handler`:
+
+~~~
+MyHandler handler;
+GenericSchemaValidator<SchemaDocument, MyHandler> validator(schema, handler);
+Reader reader;
+if (!reader.Parse(ss, validator)) {
+ if (!validator.IsValid()) {
+ // ...
+ }
+}
+~~~
+
+### 生æˆ
+
+我们也å¯ä»¥åœ¨ç”Ÿæˆï¼ˆserialization)的时候进行校验。这能确ä¿è¾“出的 JSON 符åˆä¸€ä¸ª JSON Schema。
+
+~~~
+StringBuffer sb;
+Writer<StringBuffer> writer(sb);
+GenericSchemaValidator<SchemaDocument, Writer<StringBuffer> > validator(s, writer);
+if (!d.Accept(validator)) {
+ // Some problem during Accept(), it may be validation or encoding issues.
+ if (!validator.IsValid()) {
+ // ...
+ }
+}
+~~~
+
+å½“ç„¶ï¼Œå¦‚æžœä½ çš„åº”ç”¨ä»…éœ€è¦ SAX 风格的生æˆï¼Œé‚£ä¹ˆåªéœ€è¦æŠŠ SAX 事件由原æ¥å‘é€åˆ° `Writer`,改为å‘é€åˆ° `SchemaValidator`。
+
+## 远程 Schema
+
+JSON Schema æ”¯æŒ [`$ref` 关键字](http://spacetelescope.github.io/understanding-json-schema/structuring.html),它是一个[JSON pointer](pointer.md) 引用至一个本地(local)或远程(remote) schema。本地指针的首字符是 `#`,而远程指针是一个相对或ç»å¯¹ URI。例如:
+
+~~~js
+{ "$ref": "definitions.json#/address" }
+~~~
+
+由于 `SchemaValidator` å¹¶ä¸çŸ¥é“如何处ç†é‚£äº› URI,它需è¦ä½¿ç”¨è€…æä¾›ä¸€ä¸ª `IRemoteSchemaDocumentProvider` 的实例去处ç†ã€‚
+
+~~~
+class MyRemoteSchemaDocumentProvider : public IRemoteSchemaDocumentProvider {
+public:
+ virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeTyp length) {
+ // Resolve the uri and returns a pointer to that schema.
+ }
+};
+
+// ...
+
+MyRemoteSchemaDocumentProvider provider;
+SchemaValidator validator(schema, &provider);
+~~~
+
+## 标准的符åˆç¨‹åº¦
+
+RapidJSON 通过了 [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) (Json Schema draft 4) 中 263 个测试的 262 个。
+
+没通过的测试是 `refRemote.json` 中的 "change resolution scope" - "changed scope ref invalid"。这是由于未实现 `id` schema å…³é”®å­—åŠ URI åˆå¹¶åŠŸèƒ½ã€‚
+
+除此以外,关于字符串类型的 `format` schema 关键字也会被忽略,因为标准中并没需求必须实现。
+
+### 正则表达å¼
+
+`pattern` åŠ `patternProperties` 这两个 schema 关键字使用了正则表达å¼åŽ»åŒ¹é…æ‰€éœ€çš„æ¨¡å¼ã€‚
+
+RapidJSON 实现了一个简å•çš„ NFA 正则表达å¼å¼•擎,并预设使用。它支æŒä»¥ä¸‹è¯­æ³•。
+
+|语法|æè¿°|
+|------|-----------|
+|`ab` | 串è”
+|`a|b` | 交替
+|`a?` | 零或一次
+|`a*` | 零或多次
+|`a+` | 一或多次
+|`a{3}` | 刚好 3 次
+|`a{3,}` | 至少 3 次
+|`a{3,5}`| 3 至 5 次
+|`(ab)` | 分组
+|`^a` | 在开始处
+|`a$` | 在结æŸå¤„
+|`.` | 任何字符
+|`[abc]` | 字符组
+|`[a-c]` | 字符组范围
+|`[a-z0-9_]` | 字符组组åˆ
+|`[^abc]` | 字符组å–å
+|`[^a-c]` | 字符组范围å–å
+|`[\b]` | 退格符 (U+0008)
+|`\|`, `\\`, ... | 转义字符
+|`\f` | 馈页 (U+000C)
+|`\n` | 馈行 (U+000A)
+|`\r` | 回车 (U+000D)
+|`\t` | 制表 (U+0009)
+|`\v` | 垂直制表 (U+000B)
+
+对于使用 C++11 编译器的使用者,也å¯ä½¿ç”¨ `std::regex`,åªéœ€å®šä¹‰ `RAPIDJSON_SCHEMA_USE_INTERNALREGEX=0` åŠ `RAPIDJSON_SCHEMA_USE_STDREGEX=1`。若你的 schema 无需使用 `pattern` 或 `patternProperties`,å¯ä»¥æŠŠä¸¤ä¸ªå®éƒ½è®¾ä¸ºé›¶ï¼Œä»¥ç¦ç”¨æ­¤åŠŸèƒ½ï¼Œè¿™æ ·åšå¯èŠ‚çœä¸€äº›ä»£ç ä½“积。
+
+## 性能
+
+大部分 C++ JSON åº“éƒ½æœªæ”¯æŒ JSON Schema。因此我们å°è¯•按照 [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark) 去评估 RapidJSON çš„ JSON Schema 校验器。该评测测试了 11 个è¿è¡Œåœ¨ node.js 上的 JavaScript 库。
+
+该评测校验 [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) 中的测试,当中排除了一些测试套件åŠä¸ªåˆ«æµ‹è¯•。我们在 [`schematest.cpp`](test/perftest/schematest.cpp) 实现了相åŒçš„评测。
+
+在 MacBook Pro (2.8 GHz Intel Core i7) 上收集到以下结果。
+
+|校验器|相对速度|æ¯ç§’执行的测试数目|
+|---------|:------------:|:----------------------------:|
+|RapidJSON|155%|30682|
+|[`ajv`](https://github.com/epoberezkin/ajv)|100%|19770 (± 1.31%)|
+|[`is-my-json-valid`](https://github.com/mafintosh/is-my-json-valid)|70%|13835 (± 2.84%)|
+|[`jsen`](https://github.com/bugventure/jsen)|57.7%|11411 (± 1.27%)|
+|[`schemasaurus`](https://github.com/AlexeyGrishin/schemasaurus)|26%|5145 (± 1.62%)|
+|[`themis`](https://github.com/playlyfe/themis)|19.9%|3935 (± 2.69%)|
+|[`z-schema`](https://github.com/zaggino/z-schema)|7%|1388 (± 0.84%)|
+|[`jsck`](https://github.com/pandastrike/jsck#readme)|3.1%|606 (± 2.84%)|
+|[`jsonschema`](https://github.com/tdegrunt/jsonschema#readme)|0.9%|185 (± 1.01%)|
+|[`skeemas`](https://github.com/Prestaul/skeemas#readme)|0.8%|154 (± 0.79%)|
+|tv4|0.5%|93 (± 0.94%)|
+|[`jayschema`](https://github.com/natesilva/jayschema)|0.1%|21 (± 1.14%)|
+
+æ¢è¨€ä¹‹ï¼ŒRapidJSON 比最快的 JavaScript 库(ajv)快约 1.5x。比最慢的快 1400x。
diff --git a/3rdparty/rapidjson/doc/stream.md b/3rdparty/rapidjson/doc/stream.md
new file mode 100644
index 00000000000..b79ce537acd
--- /dev/null
+++ b/3rdparty/rapidjson/doc/stream.md
@@ -0,0 +1,426 @@
+# Stream
+
+In RapidJSON, `rapidjson::Stream` is a concept for reading/writing JSON. Here we first show how to use streams provided. And then see how to create a custom stream.
+
+[TOC]
+
+# Memory Streams {#MemoryStreams}
+
+Memory streams store JSON in memory.
+
+## StringStream (Input) {#StringStream}
+
+`StringStream` is the most basic input stream. It represents a complete, read-only JSON stored in memory. It is defined in `rapidjson/rapidjson.h`.
+
+~~~~~~~~~~cpp
+#include "rapidjson/document.h" // will include "rapidjson/rapidjson.h"
+
+using namespace rapidjson;
+
+// ...
+const char json[] = "[1, 2, 3, 4]";
+StringStream s(json);
+
+Document d;
+d.ParseStream(s);
+~~~~~~~~~~
+
+Since this is very common usage, `Document::Parse(const char*)` is provided to do exactly the same as above:
+
+~~~~~~~~~~cpp
+// ...
+const char json[] = "[1, 2, 3, 4]";
+Document d;
+d.Parse(json);
+~~~~~~~~~~
+
+Note that, `StringStream` is a typedef of `GenericStringStream<UTF8<> >`, user may use another encodings to represent the character set of the stream.
+
+## StringBuffer (Output) {#StringBuffer}
+
+`StringBuffer` is a simple output stream. It allocates a memory buffer for writing the whole JSON. Use `GetString()` to obtain the buffer.
+
+~~~~~~~~~~cpp
+#include "rapidjson/stringbuffer.h"
+
+StringBuffer buffer;
+Writer<StringBuffer> writer(buffer);
+d.Accept(writer);
+
+const char* output = buffer.GetString();
+~~~~~~~~~~
+
+When the buffer is full, it will increases the capacity automatically. The default capacity is 256 characters (256 bytes for UTF8, 512 bytes for UTF16, etc.). User can provide an allocator and a initial capacity.
+
+~~~~~~~~~~cpp
+StringBuffer buffer1(0, 1024); // Use its allocator, initial size = 1024
+StringBuffer buffer2(allocator, 1024);
+~~~~~~~~~~
+
+By default, `StringBuffer` will instantiate an internal allocator.
+
+Similarly, `StringBuffer` is a typedef of `GenericStringBuffer<UTF8<> >`.
+
+# File Streams {#FileStreams}
+
+When parsing a JSON from file, you may read the whole JSON into memory and use ``StringStream`` above.
+
+However, if the JSON is big, or memory is limited, you can use `FileReadStream`. It only read a part of JSON from file into buffer, and then let the part be parsed. If it runs out of characters in the buffer, it will read the next part from file.
+
+## FileReadStream (Input) {#FileReadStream}
+
+`FileReadStream` reads the file via a `FILE` pointer. And user need to provide a buffer.
+
+~~~~~~~~~~cpp
+#include "rapidjson/filereadstream.h"
+#include <cstdio>
+
+using namespace rapidjson;
+
+FILE* fp = fopen("big.json", "rb"); // non-Windows use "r"
+
+char readBuffer[65536];
+FileReadStream is(fp, readBuffer, sizeof(readBuffer));
+
+Document d;
+d.ParseStream(is);
+
+fclose(fp);
+~~~~~~~~~~
+
+Different from string streams, `FileReadStream` is byte stream. It does not handle encodings. If the file is not UTF-8, the byte stream can be wrapped in a `EncodedInputStream`. It will be discussed very soon.
+
+Apart from reading file, user can also use `FileReadStream` to read `stdin`.
+
+## FileWriteStream (Output) {#FileWriteStream}
+
+`FileWriteStream` is buffered output stream. Its usage is very similar to `FileReadStream`.
+
+~~~~~~~~~~cpp
+#include "rapidjson/filewritestream.h"
+#include <cstdio>
+
+using namespace rapidjson;
+
+Document d;
+d.Parse(json);
+// ...
+
+FILE* fp = fopen("output.json", "wb"); // non-Windows use "w"
+
+char writeBuffer[65536];
+FileWriteStream os(fp, writeBuffer, sizeof(writeBuffer));
+
+Writer<FileWriteStream> writer(os);
+d.Accept(writer);
+
+fclose(fp);
+~~~~~~~~~~
+
+It can also directs the output to `stdout`.
+
+# iostream Wrapper {#iostreamWrapper}
+
+Due to users' requests, RapidJSON provided official wrappers for `std::basic_istream` and `std::basic_ostream`. However, please note that the performance will be much lower than the other streams above.
+
+## IStreamWrapper {#IStreamWrapper}
+
+`IStreamWrapper` wraps any class drived from `std::istream`, such as `std::istringstream`, `std::stringstream`, `std::ifstream`, `std::fstream`, into RapidJSON's input stream.
+
+~~~cpp
+#include <rapidjson/document.h>
+#include <rapidjson/istreamwrapper.h>
+#include <fstream>
+
+using namespace rapidjson;
+using namespace std;
+
+ifstream ifs("test.json");
+IStreamWrapper isw(ifs);
+
+Document d;
+d.ParseStream(isw);
+~~~
+
+For classes derived from `std::wistream`, use `WIStreamWrapper`.
+
+## OStreamWrapper {#OStreamWrapper}
+
+Similarly, `OStreamWrapper` wraps any class derived from `std::ostream`, such as `std::ostringstream`, `std::stringstream`, `std::ofstream`, `std::fstream`, into RapidJSON's input stream.
+
+~~~cpp
+#include <rapidjson/document.h>
+#include <rapidjson/ostreamwrapper.h>
+#include <rapidjson/writer.h>
+#include <fstream>
+
+using namespace rapidjson;
+using namespace std;
+
+Document d;
+d.Parse(json);
+
+// ...
+
+ofstream ofs("output.json");
+OStreamWrapper osw(ofs);
+
+Writer<OStreamWrapper> writer(osw);
+d.Accept(writer);
+~~~
+
+For classes derived from `std::wostream`, use `WOStreamWrapper`.
+
+# Encoded Streams {#EncodedStreams}
+
+Encoded streams do not contain JSON itself, but they wrap byte streams to provide basic encoding/decoding function.
+
+As mentioned above, UTF-8 byte streams can be read directly. However, UTF-16 and UTF-32 have endian issue. To handle endian correctly, it needs to convert bytes into characters (e.g. `wchar_t` for UTF-16) while reading, and characters into bytes while writing.
+
+Besides, it also need to handle [byte order mark (BOM)](http://en.wikipedia.org/wiki/Byte_order_mark). When reading from a byte stream, it is needed to detect or just consume the BOM if exists. When writing to a byte stream, it can optionally write BOM.
+
+If the encoding of stream is known in compile-time, you may use `EncodedInputStream` and `EncodedOutputStream`. If the stream can be UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE JSON, and it is only known in runtime, you may use `AutoUTFInputStream` and `AutoUTFOutputStream`. These streams are defined in `rapidjson/encodedstream.h`.
+
+Note that, these encoded streams can be applied to streams other than file. For example, you may have a file in memory, or a custom byte stream, be wrapped in encoded streams.
+
+## EncodedInputStream {#EncodedInputStream}
+
+`EncodedInputStream` has two template parameters. The first one is a `Encoding` class, such as `UTF8`, `UTF16LE`, defined in `rapidjson/encodings.h`. The second one is the class of stream to be wrapped.
+
+~~~~~~~~~~cpp
+#include "rapidjson/document.h"
+#include "rapidjson/filereadstream.h" // FileReadStream
+#include "rapidjson/encodedstream.h" // EncodedInputStream
+#include <cstdio>
+
+using namespace rapidjson;
+
+FILE* fp = fopen("utf16le.json", "rb"); // non-Windows use "r"
+
+char readBuffer[256];
+FileReadStream bis(fp, readBuffer, sizeof(readBuffer));
+
+EncodedInputStream<UTF16LE<>, FileReadStream> eis(bis); // wraps bis into eis
+
+Document d; // Document is GenericDocument<UTF8<> >
+d.ParseStream<0, UTF16LE<> >(eis); // Parses UTF-16LE file into UTF-8 in memory
+
+fclose(fp);
+~~~~~~~~~~
+
+## EncodedOutputStream {#EncodedOutputStream}
+
+`EncodedOutputStream` is similar but it has a `bool putBOM` parameter in the constructor, controlling whether to write BOM into output byte stream.
+
+~~~~~~~~~~cpp
+#include "rapidjson/filewritestream.h" // FileWriteStream
+#include "rapidjson/encodedstream.h" // EncodedOutputStream
+#include <cstdio>
+
+Document d; // Document is GenericDocument<UTF8<> >
+// ...
+
+FILE* fp = fopen("output_utf32le.json", "wb"); // non-Windows use "w"
+
+char writeBuffer[256];
+FileWriteStream bos(fp, writeBuffer, sizeof(writeBuffer));
+
+typedef EncodedOutputStream<UTF32LE<>, FileWriteStream> OutputStream;
+OutputStream eos(bos, true); // Write BOM
+
+Writer<OutputStream, UTF32LE<>, UTF8<>> writer(eos);
+d.Accept(writer); // This generates UTF32-LE file from UTF-8 in memory
+
+fclose(fp);
+~~~~~~~~~~
+
+## AutoUTFInputStream {#AutoUTFInputStream}
+
+Sometimes an application may want to handle all supported JSON encoding. `AutoUTFInputStream` will detection encoding by BOM first. If BOM is unavailable, it will use characteristics of valid JSON to make detection. If neither method success, it falls back to the UTF type provided in constructor.
+
+Since the characters (code units) may be 8-bit, 16-bit or 32-bit. `AutoUTFInputStream` requires a character type which can hold at least 32-bit. We may use `unsigned`, as in the template parameter:
+
+~~~~~~~~~~cpp
+#include "rapidjson/document.h"
+#include "rapidjson/filereadstream.h" // FileReadStream
+#include "rapidjson/encodedstream.h" // AutoUTFInputStream
+#include <cstdio>
+
+using namespace rapidjson;
+
+FILE* fp = fopen("any.json", "rb"); // non-Windows use "r"
+
+char readBuffer[256];
+FileReadStream bis(fp, readBuffer, sizeof(readBuffer));
+
+AutoUTFInputStream<unsigned, FileReadStream> eis(bis); // wraps bis into eis
+
+Document d; // Document is GenericDocument<UTF8<> >
+d.ParseStream<0, AutoUTF<unsigned> >(eis); // This parses any UTF file into UTF-8 in memory
+
+fclose(fp);
+~~~~~~~~~~
+
+When specifying the encoding of stream, uses `AutoUTF<CharType>` as in `ParseStream()` above.
+
+You can obtain the type of UTF via `UTFType GetType()`. And check whether a BOM is found by `HasBOM()`
+
+## AutoUTFOutputStream {#AutoUTFOutputStream}
+
+Similarly, to choose encoding for output during runtime, we can use `AutoUTFOutputStream`. This class is not automatic *per se*. You need to specify the UTF type and whether to write BOM in runtime.
+
+~~~~~~~~~~cpp
+using namespace rapidjson;
+
+void WriteJSONFile(FILE* fp, UTFType type, bool putBOM, const Document& d) {
+ char writeBuffer[256];
+ FileWriteStream bos(fp, writeBuffer, sizeof(writeBuffer));
+
+ typedef AutoUTFOutputStream<unsigned, FileWriteStream> OutputStream;
+ OutputStream eos(bos, type, putBOM);
+
+ Writer<OutputStream, UTF8<>, AutoUTF<> > writer;
+ d.Accept(writer);
+}
+~~~~~~~~~~
+
+`AutoUTFInputStream` and `AutoUTFOutputStream` is more convenient than `EncodedInputStream` and `EncodedOutputStream`. They just incur a little bit runtime overheads.
+
+# Custom Stream {#CustomStream}
+
+In addition to memory/file streams, user can create their own stream classes which fits RapidJSON's API. For example, you may create network stream, stream from compressed file, etc.
+
+RapidJSON combines different types using templates. A class containing all required interface can be a stream. The Stream interface is defined in comments of `rapidjson/rapidjson.h`:
+
+~~~~~~~~~~cpp
+concept Stream {
+ typename Ch; //!< Character type of the stream.
+
+ //! Read the current character from stream without moving the read cursor.
+ Ch Peek() const;
+
+ //! Read the current character from stream and moving the read cursor to next character.
+ Ch Take();
+
+ //! Get the current read cursor.
+ //! \return Number of characters read from start.
+ size_t Tell();
+
+ //! Begin writing operation at the current read pointer.
+ //! \return The begin writer pointer.
+ Ch* PutBegin();
+
+ //! Write a character.
+ void Put(Ch c);
+
+ //! Flush the buffer.
+ void Flush();
+
+ //! End the writing operation.
+ //! \param begin The begin write pointer returned by PutBegin().
+ //! \return Number of characters written.
+ size_t PutEnd(Ch* begin);
+}
+~~~~~~~~~~
+
+For input stream, they must implement `Peek()`, `Take()` and `Tell()`.
+For output stream, they must implement `Put()` and `Flush()`.
+There are two special interface, `PutBegin()` and `PutEnd()`, which are only for *in situ* parsing. Normal streams do not implement them. However, if the interface is not needed for a particular stream, it is still need to a dummy implementation, otherwise will generate compilation error.
+
+## Example: istream wrapper {#ExampleIStreamWrapper}
+
+The following example is a simple wrapper of `std::istream`, which only implements 3 functions.
+
+~~~~~~~~~~cpp
+class MyIStreamWrapper {
+public:
+ typedef char Ch;
+
+ MyIStreamWrapper(std::istream& is) : is_(is) {
+ }
+
+ Ch Peek() const { // 1
+ int c = is_.peek();
+ return c == std::char_traits<char>::eof() ? '\0' : (Ch)c;
+ }
+
+ Ch Take() { // 2
+ int c = is_.get();
+ return c == std::char_traits<char>::eof() ? '\0' : (Ch)c;
+ }
+
+ size_t Tell() const { return (size_t)is_.tellg(); } // 3
+
+ Ch* PutBegin() { assert(false); return 0; }
+ void Put(Ch) { assert(false); }
+ void Flush() { assert(false); }
+ size_t PutEnd(Ch*) { assert(false); return 0; }
+
+private:
+ MyIStreamWrapper(const MyIStreamWrapper&);
+ MyIStreamWrapper& operator=(const MyIStreamWrapper&);
+
+ std::istream& is_;
+};
+~~~~~~~~~~
+
+User can use it to wrap instances of `std::stringstream`, `std::ifstream`.
+
+~~~~~~~~~~cpp
+const char* json = "[1,2,3,4]";
+std::stringstream ss(json);
+MyIStreamWrapper is(ss);
+
+Document d;
+d.ParseStream(is);
+~~~~~~~~~~
+
+Note that, this implementation may not be as efficient as RapidJSON's memory or file streams, due to internal overheads of the standard library.
+
+## Example: ostream wrapper {#ExampleOStreamWrapper}
+
+The following example is a simple wrapper of `std::istream`, which only implements 2 functions.
+
+~~~~~~~~~~cpp
+class MyOStreamWrapper {
+public:
+ typedef char Ch;
+
+ MyOStreamWrapper(std::ostream& os) : os_(os) {
+ }
+
+ Ch Peek() const { assert(false); return '\0'; }
+ Ch Take() { assert(false); return '\0'; }
+ size_t Tell() const { }
+
+ Ch* PutBegin() { assert(false); return 0; }
+ void Put(Ch c) { os_.put(c); } // 1
+ void Flush() { os_.flush(); } // 2
+ size_t PutEnd(Ch*) { assert(false); return 0; }
+
+private:
+ MyOStreamWrapper(const MyOStreamWrapper&);
+ MyOStreamWrapper& operator=(const MyOStreamWrapper&);
+
+ std::ostream& os_;
+};
+~~~~~~~~~~
+
+User can use it to wrap instances of `std::stringstream`, `std::ofstream`.
+
+~~~~~~~~~~cpp
+Document d;
+// ...
+
+std::stringstream ss;
+MyOStreamWrapper os(ss);
+
+Writer<MyOStreamWrapper> writer(os);
+d.Accept(writer);
+~~~~~~~~~~
+
+Note that, this implementation may not be as efficient as RapidJSON's memory or file streams, due to internal overheads of the standard library.
+
+# Summary {#Summary}
+
+This section describes stream classes available in RapidJSON. Memory streams are simple. File stream can reduce the memory required during JSON parsing and generation, if the JSON is stored in file system. Encoded streams converts between byte streams and character streams. Finally, user may create custom streams using a simple interface.
diff --git a/3rdparty/rapidjson/doc/stream.zh-cn.md b/3rdparty/rapidjson/doc/stream.zh-cn.md
new file mode 100644
index 00000000000..5cc9c0d939b
--- /dev/null
+++ b/3rdparty/rapidjson/doc/stream.zh-cn.md
@@ -0,0 +1,426 @@
+# æµ
+
+在RapidJSON中,`rapidjson::Stream`是用於读写JSON的概念(概念是指C++çš„concept)。在这里我们先介ç»å¦‚何使用RapidJSONæä¾›çš„å„ç§æµã€‚ç„¶åŽå†çœ‹çœ‹å¦‚何自行定义æµã€‚
+
+[TOC]
+
+# å†…å­˜æµ {#MemoryStreams}
+
+å†…å­˜æµæŠŠJSON存储在内存之中。
+
+## StringStream(输入){#StringStream}
+
+`StringStream`是最基本的输入æµï¼Œå®ƒè¡¨ç¤ºä¸€ä¸ªå®Œæ•´çš„ã€åªè¯»çš„ã€å­˜å‚¨äºŽå†…存的JSON。它在`rapidjson/rapidjson.h`中定义。
+
+~~~~~~~~~~cpp
+#include "rapidjson/document.h" // ä¼šåŒ…å« "rapidjson/rapidjson.h"
+
+using namespace rapidjson;
+
+// ...
+const char json[] = "[1, 2, 3, 4]";
+StringStream s(json);
+
+Document d;
+d.ParseStream(s);
+~~~~~~~~~~
+
+由于这是éžå¸¸å¸¸ç”¨çš„用法,RapidJSONæä¾›`Document::Parse(const char*)`去åšå®Œå…¨ç›¸åŒçš„事情:
+
+~~~~~~~~~~cpp
+// ...
+const char json[] = "[1, 2, 3, 4]";
+Document d;
+d.Parse(json);
+~~~~~~~~~~
+
+éœ€è¦æ³¨æ„,`StringStream`是`GenericStringStream<UTF8<> >`çš„typedef,使用者å¯ç”¨å…¶ä»–ç¼–ç ç±»åŽ»ä»£è¡¨æµæ‰€ä½¿ç”¨çš„字符集。
+
+## StringBuffer(输出){#StringBuffer}
+
+`StringBuffer`是一个简å•的输出æµã€‚它分é…一个内存缓冲区,供写入整个JSON。å¯ä½¿ç”¨`GetString()`æ¥èŽ·å–该缓冲区。
+
+~~~~~~~~~~cpp
+#include "rapidjson/stringbuffer.h"
+
+StringBuffer buffer;
+Writer<StringBuffer> writer(buffer);
+d.Accept(writer);
+
+const char* output = buffer.GetString();
+~~~~~~~~~~
+
+当缓冲区满溢,它将自动增加容é‡ã€‚缺çœå®¹é‡æ˜¯256个字符(UTF8是256字节,UTF16是512字节等)。使用者能自行æä¾›åˆ†é…器åŠåˆå§‹å®¹é‡ã€‚
+
+~~~~~~~~~~cpp
+StringBuffer buffer1(0, 1024); // 使用它的分é…器,åˆå§‹å¤§å° = 1024
+StringBuffer buffer2(allocator, 1024);
+~~~~~~~~~~
+
+如无设置分é…器,`StringBuffer`会自行实例化一个内部分é…器。
+
+相似地,`StringBuffer`是`GenericStringBuffer<UTF8<> >`的typedef。
+
+# æ–‡ä»¶æµ {#FileStreams}
+
+当è¦ä»Žæ–‡ä»¶è§£æžä¸€ä¸ªJSON,你å¯ä»¥æŠŠæ•´ä¸ªJSON读入内存并使用上述的`StringStream`。
+
+然而,若JSON很大,或是内存有é™ï¼Œä½ å¯ä»¥æ”¹ç”¨`FileReadStream`。它åªä¼šä»Žæ–‡ä»¶è¯»å–一部分至缓冲区,然åŽè®©é‚£éƒ¨åˆ†è¢«è§£æžã€‚若缓冲区的字符都被读完,它会å†ä»Žæ–‡ä»¶è¯»å–下一部分。
+
+## FileReadStream(输入) {#FileReadStream}
+
+`FileReadStream`通过`FILE`æŒ‡é’ˆè¯»å–æ–‡ä»¶ã€‚ä½¿ç”¨è€…éœ€è¦æä¾›ä¸€ä¸ªç¼“å†²åŒºã€‚
+
+~~~~~~~~~~cpp
+#include "rapidjson/filereadstream.h"
+#include <cstdio>
+
+using namespace rapidjson;
+
+FILE* fp = fopen("big.json", "rb"); // éžWindowså¹³å°ä½¿ç”¨"r"
+
+char readBuffer[65536];
+FileReadStream is(fp, readBuffer, sizeof(readBuffer));
+
+Document d;
+d.ParseStream(is);
+
+fclose(fp);
+~~~~~~~~~~
+
+与`StringStreams`ä¸ä¸€æ ·ï¼Œ`FileReadStream`是一个字节æµã€‚它ä¸å¤„ç†ç¼–ç ã€‚若文件并éžUTF-8ç¼–ç ï¼Œå¯ä»¥æŠŠå­—节æµç”¨`EncodedInputStream`包装。我们很快会讨论这个问题。
+
+é™¤äº†è¯»å–æ–‡ä»¶ï¼Œä½¿ç”¨è€…也å¯ä»¥ä½¿ç”¨`FileReadStream`æ¥è¯»å–`stdin`。
+
+## FileWriteStream(输出){#FileWriteStream}
+
+`FileWriteStream`是一个å«ç¼“冲功能的输出æµã€‚它的用法与`FileReadStream`éžå¸¸ç›¸ä¼¼ã€‚
+
+~~~~~~~~~~cpp
+#include "rapidjson/filewritestream.h"
+#include <cstdio>
+
+using namespace rapidjson;
+
+Document d;
+d.Parse(json);
+// ...
+
+FILE* fp = fopen("output.json", "wb"); // éžWindowså¹³å°ä½¿ç”¨"w"
+
+char writeBuffer[65536];
+FileWriteStream os(fp, writeBuffer, sizeof(writeBuffer));
+
+Writer<FileWriteStream> writer(os);
+d.Accept(writer);
+
+fclose(fp);
+~~~~~~~~~~
+
+它也å¯ä»¥æŠŠè¾“出导å‘`stdout`。
+
+# iostream 包装类 {#iostreamWrapper}
+
+åŸºäºŽç”¨æˆ·çš„è¦æ±‚,RapidJSONæä¾›äº†æ­£å¼çš„ `std::basic_istream` å’Œ `std::basic_ostream` 包装类。然而,请注æ„其性能会大大低于以上的其他æµã€‚
+
+## IStreamWrapper {#IStreamWrapper}
+
+`IStreamWrapper` 把任何继承自 `std::istream` 的类(如 `std::istringstream`ã€`std::stringstream`ã€`std::ifstream`ã€`std::fstream`ï¼‰åŒ…è£…æˆ RapidJSON 的输入æµã€‚
+
+~~~cpp
+#include <rapidjson/document.h>
+#include <rapidjson/istreamwrapper.h>
+#include <fstream>
+
+using namespace rapidjson;
+using namespace std;
+
+ifstream ifs("test.json");
+IStreamWrapper isw(ifs);
+
+Document d;
+d.ParseStream(isw);
+~~~
+
+对于继承自 `std::wistream` 的类,则使用 `WIStreamWrapper`。
+
+## OStreamWrapper {#OStreamWrapper}
+
+相似地,`OStreamWrapper` 把任何继承自 `std::ostream` 的类(如 `std::ostringstream`ã€`std::stringstream`ã€`std::ofstream`ã€`std::fstream`ï¼‰åŒ…è£…æˆ RapidJSON 的输出æµã€‚
+
+~~~cpp
+#include <rapidjson/document.h>
+#include <rapidjson/ostreamwrapper.h>
+#include <rapidjson/writer.h>
+#include <fstream>
+
+using namespace rapidjson;
+using namespace std;
+
+Document d;
+d.Parse(json);
+
+// ...
+
+ofstream ofs("output.json");
+OStreamWrapper osw(ofs);
+
+Writer<OStreamWrapper> writer(osw);
+d.Accept(writer);
+~~~
+
+对于继承自 `std::wistream` 的类,则使用 `WIStreamWrapper`。
+
+# ç¼–ç æµ {#EncodedStreams}
+
+ç¼–ç æµï¼ˆencoded streams)本身ä¸å­˜å‚¨JSONï¼Œå®ƒä»¬æ˜¯é€šè¿‡åŒ…è£…å­—èŠ‚æµæ¥æä¾›åŸºæœ¬çš„ç¼–ç ï¼è§£ç åŠŸèƒ½ã€‚
+
+如上所述,我们å¯ä»¥ç›´æŽ¥è¯»å…¥UTF-8字节æµã€‚然而,UTF-16åŠUTF-32有字节åºï¼ˆendianï¼‰é—®é¢˜ã€‚è¦æ­£ç¡®åœ°å¤„ç†å­—节åºï¼Œéœ€è¦åœ¨è¯»å–æ—¶æŠŠå­—èŠ‚è½¬æ¢æˆå­—符(如对UTF-16使用`wchar_t`),以åŠåœ¨å†™å…¥æ—¶æŠŠå­—符转æ¢ä¸ºå­—节。
+
+除此以外,我们也需è¦å¤„ç†[å­—èŠ‚é¡ºåºæ ‡è®°ï¼ˆbyte order mark, BOM)](http://en.wikipedia.org/wiki/Byte_order_mark)。当从一个字节æµè¯»å–æ—¶ï¼Œéœ€è¦æ£€æµ‹BOM,或者仅仅是把存在的BOM消去。当把JSONå†™å…¥å­—èŠ‚æµæ—¶ï¼Œä¹Ÿå¯é€‰æ‹©å†™å…¥BOM。
+
+若一个æµçš„ç¼–ç åœ¨ç¼–译期已知,你å¯ä½¿ç”¨`EncodedInputStream`åŠ`EncodedOutputStream`。若一个æµå¯èƒ½å­˜å‚¨UTF-8ã€UTF-16LEã€UTF-16BEã€UTF-32LEã€UTF-32BEçš„JSON,并且编ç åªèƒ½åœ¨è¿è¡Œæ—¶å¾—知,你便å¯ä»¥ä½¿ç”¨`AutoUTFInputStream`åŠ`AutoUTFOutputStream`。这些æµå®šä¹‰åœ¨`rapidjson/encodedstream.h`。
+
+注æ„åˆ°ï¼Œè¿™äº›ç¼–ç æµå¯ä»¥æ–½äºŽæ–‡ä»¶ä»¥å¤–çš„æµã€‚例如,你å¯ä»¥ç”¨ç¼–ç æµåŒ…装内存中的文件或自定义的字节æµã€‚
+
+## EncodedInputStream {#EncodedInputStream}
+
+`EncodedInputStream`å«ä¸¤ä¸ªæ¨¡æ¿å‚数。第一个是`Encoding`类型,例如定义于`rapidjson/encodings.h`çš„`UTF8`ã€`UTF16LE`ã€‚ç¬¬äºŒä¸ªå‚æ•°æ˜¯è¢«åŒ…装的æµçš„类型。
+
+~~~~~~~~~~cpp
+#include "rapidjson/document.h"
+#include "rapidjson/filereadstream.h" // FileReadStream
+#include "rapidjson/encodedstream.h" // EncodedInputStream
+#include <cstdio>
+
+using namespace rapidjson;
+
+FILE* fp = fopen("utf16le.json", "rb"); // éžWindowså¹³å°ä½¿ç”¨"r"
+
+char readBuffer[256];
+FileReadStream bis(fp, readBuffer, sizeof(readBuffer));
+
+EncodedInputStream<UTF16LE<>, FileReadStream> eis(bis); // 用eis包装bis
+
+Document d; // Document为GenericDocument<UTF8<> >
+d.ParseStream<0, UTF16LE<> >(eis); // 把UTF-16LE文件解æžè‡³å†…存中的UTF-8
+
+fclose(fp);
+~~~~~~~~~~
+
+## EncodedOutputStream {#EncodedOutputStream}
+
+`EncodedOutputStream`也是相似的,但它的构造函数有一个`bool putBOM`傿•°ï¼Œç”¨äºŽæŽ§åˆ¶æ˜¯å¦åœ¨è¾“出字节æµå†™å…¥BOM。
+
+~~~~~~~~~~cpp
+#include "rapidjson/filewritestream.h" // FileWriteStream
+#include "rapidjson/encodedstream.h" // EncodedOutputStream
+#include <cstdio>
+
+Document d; // Document为GenericDocument<UTF8<> >
+// ...
+
+FILE* fp = fopen("output_utf32le.json", "wb"); // éžWindowså¹³å°ä½¿ç”¨"w"
+
+char writeBuffer[256];
+FileWriteStream bos(fp, writeBuffer, sizeof(writeBuffer));
+
+typedef EncodedOutputStream<UTF32LE<>, FileWriteStream> OutputStream;
+OutputStream eos(bos, true); // 写入BOM
+
+Writer<OutputStream, UTF32LE<>, UTF8<>> writer(eos);
+d.Accept(writer); // 这里从内存的UTF-8生æˆUTF32-LE文件
+
+fclose(fp);
+~~~~~~~~~~
+
+## AutoUTFInputStream {#AutoUTFInputStream}
+
+有时候,应用软件å¯èƒ½éœ€è¦ã²ƒç†æ‰€æœ‰å¯æ”¯æŒçš„JSONç¼–ç ã€‚`AutoUTFInputStream`会先使用BOMæ¥æ£€æµ‹ç¼–ç ã€‚è‹¥BOMä¸å­˜åœ¨ï¼Œå®ƒä¾¿ä¼šä½¿ç”¨åˆæ³•JSONçš„ç‰¹æ€§æ¥æ£€æµ‹ã€‚è‹¥ä¸¤ç§æ–¹æ³•都失败,它就会倒退至构造函数æä¾›çš„UTF类型。
+
+由于字符(编ç å•å…ƒï¼code unit)å¯èƒ½æ˜¯8ä½ã€16使ˆ–32ä½ï¼Œ`AutoUTFInputStream` 需è¦ä¸€ä¸ªèƒ½è‡³å°‘储存32ä½çš„字符类型。我们å¯ä»¥ä½¿ç”¨`unsigned`作为模æ¿å‚数:
+
+~~~~~~~~~~cpp
+#include "rapidjson/document.h"
+#include "rapidjson/filereadstream.h" // FileReadStream
+#include "rapidjson/encodedstream.h" // AutoUTFInputStream
+#include <cstdio>
+
+using namespace rapidjson;
+
+FILE* fp = fopen("any.json", "rb"); // éžWindowså¹³å°ä½¿ç”¨"r"
+
+char readBuffer[256];
+FileReadStream bis(fp, readBuffer, sizeof(readBuffer));
+
+AutoUTFInputStream<unsigned, FileReadStream> eis(bis); // 用eis包装bis
+
+Document d; // Document为GenericDocument<UTF8<> >
+d.ParseStream<0, AutoUTF<unsigned> >(eis); // 把任何UTFç¼–ç çš„æ–‡ä»¶è§£æžè‡³å†…存中的UTF-8
+
+fclose(fp);
+~~~~~~~~~~
+
+å½“è¦æŒ‡å®šæµçš„ç¼–ç ï¼Œå¯ä½¿ç”¨ä¸Šé¢ä¾‹å­ä¸­`ParseStream()`çš„å‚æ•°`AutoUTF<CharType>`。
+
+ä½ å¯ä»¥ä½¿ç”¨`UTFType GetType()`去获å–UTF类型,并且用`HasBOM()`æ£€æµ‹è¾“å…¥æµæ˜¯å¦å«æœ‰BOM。
+
+## AutoUTFOutputStream {#AutoUTFOutputStream}
+
+相似地,è¦åœ¨è¿è¡Œæ—¶é€‰æ‹©è¾“出的编ç ï¼Œæˆ‘们å¯ä½¿ç”¨`AutoUTFOutputStream`。这个类本身并éžã€Œè‡ªåЍã€ã€‚你需è¦åœ¨è¿è¡Œæ—¶æŒ‡å®šUTFç±»åž‹ï¼Œä»¥åŠæ˜¯å¦å†™å…¥BOM。
+
+~~~~~~~~~~cpp
+using namespace rapidjson;
+
+void WriteJSONFile(FILE* fp, UTFType type, bool putBOM, const Document& d) {
+ char writeBuffer[256];
+ FileWriteStream bos(fp, writeBuffer, sizeof(writeBuffer));
+
+ typedef AutoUTFOutputStream<unsigned, FileWriteStream> OutputStream;
+ OutputStream eos(bos, type, putBOM);
+
+ Writer<OutputStream, UTF8<>, AutoUTF<> > writer;
+ d.Accept(writer);
+}
+~~~~~~~~~~
+
+`AutoUTFInputStream`ï¼`AutoUTFOutputStream`是比`EncodedInputStream`ï¼`EncodedOutputStream`方便。但å‰è€…会产生一点è¿è¡ŒæœŸé¢å¤–开销。
+
+# è‡ªå®šä¹‰æµ {#CustomStream}
+
+é™¤äº†å†…å­˜ï¼æ–‡ä»¶æµï¼Œä½¿ç”¨è€…å¯åˆ›å»ºè‡ªè¡Œå®šä¹‰é€‚é…RapidJSON APIçš„æµç±»ã€‚例如,你å¯ä»¥åˆ›å»ºç½‘络æµã€ä»ŽåŽ‹ç¼©æ–‡ä»¶è¯»å–çš„æµç­‰ç­‰ã€‚
+
+RapidJSON利用模æ¿ç»“åˆä¸åŒçš„类型。åªè¦ä¸€ä¸ªç±»åŒ…嫿‰€æœ‰æ‰€éœ€çš„æŽ¥å£ï¼Œå°±å¯ä»¥ä½œä¸ºä¸€ä¸ªæµã€‚æµçš„æŽ¥åˆå®šä¹‰åœ¨`rapidjson/rapidjson.h`的注释里:
+
+~~~~~~~~~~cpp
+concept Stream {
+ typename Ch; //!< æµçš„字符类型
+
+ //! 从æµè¯»å–当å‰å­—符,ä¸ç§»åŠ¨è¯»å–æŒ‡é’ˆï¼ˆread cursor)
+ Ch Peek() const;
+
+ //! 从æµè¯»å–当å‰å­—ç¬¦ï¼Œç§»åŠ¨è¯»å–æŒ‡é’ˆè‡³ä¸‹ä¸€å­—符。
+ Ch Take();
+
+ //! 获å–è¯»å–æŒ‡é’ˆã€‚
+ //! \return ä»Žå¼€å§‹ä»¥æ¥æ‰€è¯»è¿‡çš„字符数é‡ã€‚
+ size_t Tell();
+
+ //! 从当å‰è¯»å–指针开始写入æ“作。
+ //! \return 返回开始写入的指针。
+ Ch* PutBegin();
+
+ //! 写入一个字符。
+ void Put(Ch c);
+
+ //! 清空缓冲区。
+ void Flush();
+
+ //! 完æˆå†™ä½œæ“作。
+ //! \param begin PutBegin()返回的开始写入指针。
+ //! \return 已写入的字符数é‡ã€‚
+ size_t PutEnd(Ch* begin);
+}
+~~~~~~~~~~
+
+输入æµå¿…须实现`Peek()`ã€`Take()`åŠ`Tell()`。
+输出æµå¿…须实现`Put()`åŠ`Flush()`。
+`PutBegin()`åŠ`PutEnd()`是特殊的接å£ï¼Œä»…用于原ä½ï¼ˆ*in situ*)解æžã€‚一般的æµä¸éœ€å®žçŽ°å®ƒä»¬ã€‚ç„¶è€Œï¼Œå³ä½¿æŽ¥å£ä¸éœ€ç”¨äºŽæŸäº›æµï¼Œä»ç„¶éœ€è¦æä¾›ç©ºå®žçŽ°ï¼Œå¦åˆ™ä¼šäº§ç”Ÿç¼–译错误。
+
+## 例å­ï¼šistream的包装类 {#ExampleIStreamWrapper}
+
+以下的简å•例孿˜¯`std::istream`的包装类,它åªéœ€çް3个函数。
+
+~~~~~~~~~~cpp
+class MyIStreamWrapper {
+public:
+ typedef char Ch;
+
+ MyIStreamWrapper(std::istream& is) : is_(is) {
+ }
+
+ Ch Peek() const { // 1
+ int c = is_.peek();
+ return c == std::char_traits<char>::eof() ? '\0' : (Ch)c;
+ }
+
+ Ch Take() { // 2
+ int c = is_.get();
+ return c == std::char_traits<char>::eof() ? '\0' : (Ch)c;
+ }
+
+ size_t Tell() const { return (size_t)is_.tellg(); } // 3
+
+ Ch* PutBegin() { assert(false); return 0; }
+ void Put(Ch) { assert(false); }
+ void Flush() { assert(false); }
+ size_t PutEnd(Ch*) { assert(false); return 0; }
+
+private:
+ MyIStreamWrapper(const MyIStreamWrapper&);
+ MyIStreamWrapper& operator=(const MyIStreamWrapper&);
+
+ std::istream& is_;
+};
+~~~~~~~~~~
+
+使用者能用它æ¥åŒ…装`std::stringstream`ã€`std::ifstream`的实例。
+
+~~~~~~~~~~cpp
+const char* json = "[1,2,3,4]";
+std::stringstream ss(json);
+MyIStreamWrapper is(ss);
+
+Document d;
+d.ParseStream(is);
+~~~~~~~~~~
+
+ä½†è¦æ³¨æ„,由于标准库的内部开销问,此实现的性能å¯èƒ½ä¸å¦‚RapidJSONçš„å†…å­˜ï¼æ–‡ä»¶æµã€‚
+
+## 例å­ï¼šostream的包装类 {#ExampleOStreamWrapper}
+
+ä»¥ä¸‹çš„ä¾‹å­æ˜¯`std::istream`的包装类,它åªéœ€å®žçް2个函数。
+
+~~~~~~~~~~cpp
+class MyOStreamWrapper {
+public:
+ typedef char Ch;
+
+ OStreamWrapper(std::ostream& os) : os_(os) {
+ }
+
+ Ch Peek() const { assert(false); return '\0'; }
+ Ch Take() { assert(false); return '\0'; }
+ size_t Tell() const { }
+
+ Ch* PutBegin() { assert(false); return 0; }
+ void Put(Ch c) { os_.put(c); } // 1
+ void Flush() { os_.flush(); } // 2
+ size_t PutEnd(Ch*) { assert(false); return 0; }
+
+private:
+ MyOStreamWrapper(const MyOStreamWrapper&);
+ MyOStreamWrapper& operator=(const MyOStreamWrapper&);
+
+ std::ostream& os_;
+};
+~~~~~~~~~~
+
+使用者能用它æ¥åŒ…装`std::stringstream`ã€`std::ofstream`的实例。
+
+~~~~~~~~~~cpp
+Document d;
+// ...
+
+std::stringstream ss;
+MyOStreamWrapper os(ss);
+
+Writer<MyOStreamWrapper> writer(os);
+d.Accept(writer);
+~~~~~~~~~~
+
+ä½†è¦æ³¨æ„,由于标准库的内部开销问,此实现的性能å¯èƒ½ä¸å¦‚RapidJSONçš„å†…å­˜ï¼æ–‡ä»¶æµã€‚
+
+# 总结 {#Summary}
+
+本节æè¿°äº†RapidJSONæä¾›çš„å„ç§æµçš„类。内存æµå¾ˆç®€å•。若JSON存储在文件中,文件æµå¯å‡å°‘JSONè§£æžåŠç”Ÿæˆæ‰€éœ€çš„内存é‡ã€‚ç¼–ç æµåœ¨å­—节æµå’Œå­—符æµä¹‹é—´ä½œè½¬æ¢ã€‚最åŽï¼Œä½¿ç”¨è€…å¯ä½¿ç”¨ä¸€ä¸ªç®€å•接å£åˆ›å»ºè‡ªå®šä¹‰çš„æµã€‚
diff --git a/3rdparty/rapidjson/doc/tutorial.md b/3rdparty/rapidjson/doc/tutorial.md
new file mode 100644
index 00000000000..121102345b4
--- /dev/null
+++ b/3rdparty/rapidjson/doc/tutorial.md
@@ -0,0 +1,517 @@
+# Tutorial
+
+This tutorial introduces the basics of the Document Object Model(DOM) API.
+
+As shown in [Usage at a glance](@ref index), a JSON can be parsed into DOM, and then the DOM can be queried and modified easily, and finally be converted back to JSON.
+
+[TOC]
+
+# Value & Document {#ValueDocument}
+
+Each JSON value is stored in a type called `Value`. A `Document`, representing the DOM, contains the root `Value` of the DOM tree. All public types and functions of RapidJSON are defined in the `rapidjson` namespace.
+
+# Query Value {#QueryValue}
+
+In this section, we will use excerpt of `example/tutorial/tutorial.cpp`.
+
+Assumes we have a JSON stored in a C string (`const char* json`):
+~~~~~~~~~~js
+{
+ "hello": "world",
+ "t": true ,
+ "f": false,
+ "n": null,
+ "i": 123,
+ "pi": 3.1416,
+ "a": [1, 2, 3, 4]
+}
+~~~~~~~~~~
+
+Parse it into a `Document`:
+~~~~~~~~~~cpp
+#include "rapidjson/document.h"
+
+using namespace rapidjson;
+
+// ...
+Document document;
+document.Parse(json);
+~~~~~~~~~~
+
+The JSON is now parsed into `document` as a *DOM tree*:
+
+![DOM in the tutorial](diagram/tutorial.png)
+
+Since the update to RFC 7159, the root of a conforming JSON document can be any JSON value. In earlier RFC 4627, only objects or arrays were allowed as root values. In this case, the root is an object.
+~~~~~~~~~~cpp
+assert(document.IsObject());
+~~~~~~~~~~
+
+Let's query whether a `"hello"` member exists in the root object. Since a `Value` can contain different types of value, we may need to verify its type and use suitable API to obtain the value. In this example, `"hello"` member associates with a JSON string.
+~~~~~~~~~~cpp
+assert(document.HasMember("hello"));
+assert(document["hello"].IsString());
+printf("hello = %s\n", document["hello"].GetString());
+~~~~~~~~~~
+
+~~~~~~~~~~
+world
+~~~~~~~~~~
+
+JSON true/false values are represented as `bool`.
+~~~~~~~~~~cpp
+assert(document["t"].IsBool());
+printf("t = %s\n", document["t"].GetBool() ? "true" : "false");
+~~~~~~~~~~
+
+~~~~~~~~~~
+true
+~~~~~~~~~~
+
+JSON null can be queryed by `IsNull()`.
+~~~~~~~~~~cpp
+printf("n = %s\n", document["n"].IsNull() ? "null" : "?");
+~~~~~~~~~~
+
+~~~~~~~~~~
+null
+~~~~~~~~~~
+
+JSON number type represents all numeric values. However, C++ needs more specific type for manipulation.
+
+~~~~~~~~~~cpp
+assert(document["i"].IsNumber());
+
+// In this case, IsUint()/IsInt64()/IsUInt64() also return true.
+assert(document["i"].IsInt());
+printf("i = %d\n", document["i"].GetInt());
+// Alternative (int)document["i"]
+
+assert(document["pi"].IsNumber());
+assert(document["pi"].IsDouble());
+printf("pi = %g\n", document["pi"].GetDouble());
+~~~~~~~~~~
+
+~~~~~~~~~~
+i = 123
+pi = 3.1416
+~~~~~~~~~~
+
+JSON array contains a number of elements.
+~~~~~~~~~~cpp
+// Using a reference for consecutive access is handy and faster.
+const Value& a = document["a"];
+assert(a.IsArray());
+for (SizeType i = 0; i < a.Size(); i++) // Uses SizeType instead of size_t
+ printf("a[%d] = %d\n", i, a[i].GetInt());
+~~~~~~~~~~
+
+~~~~~~~~~~
+a[0] = 1
+a[1] = 2
+a[2] = 3
+a[3] = 4
+~~~~~~~~~~
+
+Note that, RapidJSON does not automatically convert values between JSON types. If a value is a string, it is invalid to call `GetInt()`, for example. In debug mode it will fail an assertion. In release mode, the behavior is undefined.
+
+In the following, details about querying individual types are discussed.
+
+## Query Array {#QueryArray}
+
+By default, `SizeType` is typedef of `unsigned`. In most systems, array is limited to store up to 2^32-1 elements.
+
+You may access the elements in array by integer literal, for example, `a[0]`, `a[1]`, `a[2]`.
+
+Array is similar to `std::vector`, instead of using indices, you may also use iterator to access all the elements.
+~~~~~~~~~~cpp
+for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
+ printf("%d ", itr->GetInt());
+~~~~~~~~~~
+
+And other familiar query functions:
+* `SizeType Capacity() const`
+* `bool Empty() const`
+
+## Query Object {#QueryObject}
+
+Similar to array, we can access all object members by iterator:
+
+~~~~~~~~~~cpp
+static const char* kTypeNames[] =
+ { "Null", "False", "True", "Object", "Array", "String", "Number" };
+
+for (Value::ConstMemberIterator itr = document.MemberBegin();
+ itr != document.MemberEnd(); ++itr)
+{
+ printf("Type of member %s is %s\n",
+ itr->name.GetString(), kTypeNames[itr->value.GetType()]);
+}
+~~~~~~~~~~
+
+~~~~~~~~~~
+Type of member hello is String
+Type of member t is True
+Type of member f is False
+Type of member n is Null
+Type of member i is Number
+Type of member pi is Number
+Type of member a is Array
+~~~~~~~~~~
+
+Note that, when `operator[](const char*)` cannot find the member, it will fail an assertion.
+
+If we are unsure whether a member exists, we need to call `HasMember()` before calling `operator[](const char*)`. However, this incurs two lookup. A better way is to call `FindMember()`, which can check the existence of member and obtain its value at once:
+
+~~~~~~~~~~cpp
+Value::ConstMemberIterator itr = document.FindMember("hello");
+if (itr != document.MemberEnd())
+ printf("%s %s\n", itr->value.GetString());
+~~~~~~~~~~
+
+## Querying Number {#QueryNumber}
+
+JSON provide a single numerical type called Number. Number can be integer or real numbers. RFC 4627 says the range of Number is specified by parser.
+
+As C++ provides several integer and floating point number types, the DOM tries to handle these with widest possible range and good performance.
+
+When a Number is parsed, it is stored in the DOM as either one of the following type:
+
+Type | Description
+-----------|---------------------------------------
+`unsigned` | 32-bit unsigned integer
+`int` | 32-bit signed integer
+`uint64_t` | 64-bit unsigned integer
+`int64_t` | 64-bit signed integer
+`double` | 64-bit double precision floating point
+
+When querying a number, you can check whether the number can be obtained as target type:
+
+Checking | Obtaining
+------------------|---------------------
+`bool IsNumber()` | N/A
+`bool IsUint()` | `unsigned GetUint()`
+`bool IsInt()` | `int GetInt()`
+`bool IsUint64()` | `uint64_t GetUint64()`
+`bool IsInt64()` | `int64_t GetInt64()`
+`bool IsDouble()` | `double GetDouble()`
+
+Note that, an integer value may be obtained in various ways without conversion. For example, A value `x` containing 123 will make `x.IsInt() == x.IsUint() == x.IsInt64() == x.IsUint64() == true`. But a value `y` containing -3000000000 will only makes `x.IsInt64() == true`.
+
+When obtaining the numeric values, `GetDouble()` will convert internal integer representation to a `double`. Note that, `int` and `unsigned` can be safely convert to `double`, but `int64_t` and `uint64_t` may lose precision (since mantissa of `double` is only 52-bits).
+
+## Query String {#QueryString}
+
+In addition to `GetString()`, the `Value` class also contains `GetStringLength()`. Here explains why.
+
+According to RFC 4627, JSON strings can contain Unicode character `U+0000`, which must be escaped as `"\u0000"`. The problem is that, C/C++ often uses null-terminated string, which treats ``\0'` as the terminator symbol.
+
+To conform RFC 4627, RapidJSON supports string containing `U+0000`. If you need to handle this, you can use `GetStringLength()` API to obtain the correct length of string.
+
+For example, after parsing a the following JSON to `Document d`:
+
+~~~~~~~~~~js
+{ "s" : "a\u0000b" }
+~~~~~~~~~~
+The correct length of the value `"a\u0000b"` is 3. But `strlen()` returns 1.
+
+`GetStringLength()` can also improve performance, as user may often need to call `strlen()` for allocating buffer.
+
+Besides, `std::string` also support a constructor:
+
+~~~~~~~~~~cpp
+string(const char* s, size_t count);
+~~~~~~~~~~
+
+which accepts the length of string as parameter. This constructor supports storing null character within the string, and should also provide better performance.
+
+## Comparing values
+
+You can use `==` and `!=` to compare values. Two values are equal if and only if they are have same type and contents. You can also compare values with primitive types. Here is an example.
+
+~~~~~~~~~~cpp
+if (document["hello"] == document["n"]) /*...*/; // Compare values
+if (document["hello"] == "world") /*...*/; // Compare value with literal string
+if (document["i"] != 123) /*...*/; // Compare with integers
+if (document["pi"] != 3.14) /*...*/; // Compare with double.
+~~~~~~~~~~
+
+Array/object compares their elements/members in order. They are equal if and only if their whole subtrees are equal.
+
+Note that, currently if an object contains duplicated named member, comparing equality with any object is always `false`.
+
+# Create/Modify Values {#CreateModifyValues}
+
+There are several ways to create values. After a DOM tree is created and/or modified, it can be saved as JSON again using `Writer`.
+
+## Change Value Type {#ChangeValueType}
+When creating a Value or Document by default constructor, its type is Null. To change its type, call `SetXXX()` or assignment operator, for example:
+
+~~~~~~~~~~cpp
+Document d; // Null
+d.SetObject();
+
+Value v; // Null
+v.SetInt(10);
+v = 10; // Shortcut, same as above
+~~~~~~~~~~
+
+### Overloaded Constructors
+There are also overloaded constructors for several types:
+
+~~~~~~~~~~cpp
+Value b(true); // calls Value(bool)
+Value i(-123); // calls Value(int)
+Value u(123u); // calls Value(unsigned)
+Value d(1.5); // calls Value(double)
+~~~~~~~~~~
+
+To create empty object or array, you may use `SetObject()`/`SetArray()` after default constructor, or using the `Value(Type)` in one shot:
+
+~~~~~~~~~~cpp
+Value o(kObjectType);
+Value a(kArrayType);
+~~~~~~~~~~
+
+## Move Semantics {#MoveSemantics}
+
+A very special decision during design of RapidJSON is that, assignment of value does not copy the source value to destination value. Instead, the value from source is moved to the destination. For example,
+
+~~~~~~~~~~cpp
+Value a(123);
+Value b(456);
+b = a; // a becomes a Null value, b becomes number 123.
+~~~~~~~~~~
+
+![Assignment with move semantics.](diagram/move1.png)
+
+Why? What is the advantage of this semantics?
+
+The simple answer is performance. For fixed size JSON types (Number, True, False, Null), copying them is fast and easy. However, For variable size JSON types (String, Array, Object), copying them will incur a lot of overheads. And these overheads are often unnoticed. Especially when we need to create temporary object, copy it to another variable, and then destruct it.
+
+For example, if normal *copy* semantics was used:
+
+~~~~~~~~~~cpp
+Document d;
+Value o(kObjectType);
+{
+ Value contacts(kArrayType);
+ // adding elements to contacts array.
+ // ...
+ o.AddMember("contacts", contacts, d.GetAllocator()); // deep clone contacts (may be with lots of allocations)
+ // destruct contacts.
+}
+~~~~~~~~~~
+
+![Copy semantics makes a lots of copy operations.](diagram/move2.png)
+
+The object `o` needs to allocate a buffer of same size as contacts, makes a deep clone of it, and then finally contacts is destructed. This will incur a lot of unnecessary allocations/deallocations and memory copying.
+
+There are solutions to prevent actual copying these data, such as reference counting and garbage collection(GC).
+
+To make RapidJSON simple and fast, we chose to use *move* semantics for assignment. It is similar to `std::auto_ptr` which transfer ownership during assignment. Move is much faster and simpler, it just destructs the original value, `memcpy()` the source to destination, and finally sets the source as Null type.
+
+So, with move semantics, the above example becomes:
+
+~~~~~~~~~~cpp
+Document d;
+Value o(kObjectType);
+{
+ Value contacts(kArrayType);
+ // adding elements to contacts array.
+ o.AddMember("contacts", contacts, d.GetAllocator()); // just memcpy() of contacts itself to the value of new member (16 bytes)
+ // contacts became Null here. Its destruction is trivial.
+}
+~~~~~~~~~~
+
+![Move semantics makes no copying.](diagram/move3.png)
+
+This is called move assignment operator in C++11. As RapidJSON supports C++03, it adopts move semantics using assignment operator, and all other modifying function like `AddMember()`, `PushBack()`.
+
+### Move semantics and temporary values {#TemporaryValues}
+
+Sometimes, it is convenient to construct a Value in place, before passing it to one of the "moving" functions, like `PushBack()` or `AddMember()`. As temporary objects can't be converted to proper Value references, the convenience function `Move()` is available:
+
+~~~~~~~~~~cpp
+Value a(kArrayType);
+Document::AllocatorType& allocator = document.GetAllocator();
+// a.PushBack(Value(42), allocator); // will not compile
+a.PushBack(Value().SetInt(42), allocator); // fluent API
+a.PushBack(Value(42).Move(), allocator); // same as above
+~~~~~~~~~~
+
+## Create String {#CreateString}
+RapidJSON provide two strategies for storing string.
+
+1. copy-string: allocates a buffer, and then copy the source data into it.
+2. const-string: simply store a pointer of string.
+
+Copy-string is always safe because it owns a copy of the data. Const-string can be used for storing string literal, and in-situ parsing which we will mentioned in Document section.
+
+To make memory allocation customizable, RapidJSON requires user to pass an instance of allocator, whenever an operation may require allocation. This design is needed to prevent storing a allocator (or Document) pointer per Value.
+
+Therefore, when we assign a copy-string, we call this overloaded `SetString()` with allocator:
+
+~~~~~~~~~~cpp
+Document document;
+Value author;
+char buffer[10];
+int len = sprintf(buffer, "%s %s", "Milo", "Yip"); // dynamically created string.
+author.SetString(buffer, len, document.GetAllocator());
+memset(buffer, 0, sizeof(buffer));
+// author.GetString() still contains "Milo Yip" after buffer is destroyed
+~~~~~~~~~~
+
+In this example, we get the allocator from a `Document` instance. This is a common idiom when using RapidJSON. But you may use other instances of allocator.
+
+Besides, the above `SetString()` requires length. This can handle null characters within a string. There is another `SetString()` overloaded function without the length parameter. And it assumes the input is null-terminated and calls a `strlen()`-like function to obtain the length.
+
+Finally, for string literal or string with safe life-cycle can use const-string version of `SetString()`, which lacks allocator parameter. For string literals (or constant character arrays), simply passing the literal as parameter is safe and efficient:
+
+~~~~~~~~~~cpp
+Value s;
+s.SetString("rapidjson"); // can contain null character, length derived at compile time
+s = "rapidjson"; // shortcut, same as above
+~~~~~~~~~~
+
+For character pointer, the RapidJSON requires to mark it as safe before using it without copying. This can be achieved by using the `StringRef` function:
+
+~~~~~~~~~cpp
+const char * cstr = getenv("USER");
+size_t cstr_len = ...; // in case length is available
+Value s;
+// s.SetString(cstr); // will not compile
+s.SetString(StringRef(cstr)); // ok, assume safe lifetime, null-terminated
+s = StringRef(cstr); // shortcut, same as above
+s.SetString(StringRef(cstr,cstr_len)); // faster, can contain null character
+s = StringRef(cstr,cstr_len); // shortcut, same as above
+
+~~~~~~~~~
+
+## Modify Array {#ModifyArray}
+Value with array type provides similar APIs as `std::vector`.
+
+* `Clear()`
+* `Reserve(SizeType, Allocator&)`
+* `Value& PushBack(Value&, Allocator&)`
+* `template <typename T> GenericValue& PushBack(T, Allocator&)`
+* `Value& PopBack()`
+* `ValueIterator Erase(ConstValueIterator pos)`
+* `ValueIterator Erase(ConstValueIterator first, ConstValueIterator last)`
+
+Note that, `Reserve(...)` and `PushBack(...)` may allocate memory for the array elements, therefore require an allocator.
+
+Here is an example of `PushBack()`:
+
+~~~~~~~~~~cpp
+Value a(kArrayType);
+Document::AllocatorType& allocator = document.GetAllocator();
+
+for (int i = 5; i <= 10; i++)
+ a.PushBack(i, allocator); // allocator is needed for potential realloc().
+
+// Fluent interface
+a.PushBack("Lua", allocator).PushBack("Mio", allocator);
+~~~~~~~~~~
+
+Differs from STL, `PushBack()`/`PopBack()` returns the array reference itself. This is called _fluent interface_.
+
+If you want to add a non-constant string or a string without sufficient lifetime (see [Create String](#CreateString)) to the array, you need to create a string Value by using the copy-string API. To avoid the need for an intermediate variable, you can use a [temporary value](#TemporaryValues) in place:
+
+~~~~~~~~~~cpp
+// in-place Value parameter
+contact.PushBack(Value("copy", document.GetAllocator()).Move(), // copy string
+ document.GetAllocator());
+
+// explicit parameters
+Value val("key", document.GetAllocator()); // copy string
+contact.PushBack(val, document.GetAllocator());
+~~~~~~~~~~
+
+## Modify Object {#ModifyObject}
+Object is a collection of key-value pairs (members). Each key must be a string value. To modify an object, either add or remove members. THe following APIs are for adding members:
+
+* `Value& AddMember(Value&, Value&, Allocator& allocator)`
+* `Value& AddMember(StringRefType, Value&, Allocator&)`
+* `template <typename T> Value& AddMember(StringRefType, T value, Allocator&)`
+
+Here is an example.
+
+~~~~~~~~~~cpp
+Value contact(kObject);
+contact.AddMember("name", "Milo", document.GetAllocator());
+contact.AddMember("married", true, document.GetAllocator());
+~~~~~~~~~~
+
+The name parameter with `StringRefType` is similar to the interface of `SetString` function for string values. These overloads are used to avoid the need for copying the `name` string, as constant key names are very common in JSON objects.
+
+If you need to create a name from a non-constant string or a string without sufficient lifetime (see [Create String](#CreateString)), you need to create a string Value by using the copy-string API. To avoid the need for an intermediate variable, you can use a [temporary value](#TemporaryValues) in place:
+
+~~~~~~~~~~cpp
+// in-place Value parameter
+contact.AddMember(Value("copy", document.GetAllocator()).Move(), // copy string
+ Value().Move(), // null value
+ document.GetAllocator());
+
+// explicit parameters
+Value key("key", document.GetAllocator()); // copy string name
+Value val(42); // some value
+contact.AddMember(key, val, document.GetAllocator());
+~~~~~~~~~~
+
+For removing members, there are several choices:
+
+* `bool RemoveMember(const Ch* name)`: Remove a member by search its name (linear time complexity).
+* `bool RemoveMember(const Value& name)`: same as above but `name` is a Value.
+* `MemberIterator RemoveMember(MemberIterator)`: Remove a member by iterator (_constant_ time complexity).
+* `MemberIterator EraseMember(MemberIterator)`: similar to the above but it preserves order of members (linear time complexity).
+* `MemberIterator EraseMember(MemberIterator first, MemberIterator last)`: remove a range of members, preserves order (linear time complexity).
+
+`MemberIterator RemoveMember(MemberIterator)` uses a "move-last" trick to achieve constant time complexity. Basically the member at iterator is destructed, and then the last element is moved to that position. So the order of the remaining members are changed.
+
+## Deep Copy Value {#DeepCopyValue}
+If we really need to copy a DOM tree, we can use two APIs for deep copy: constructor with allocator, and `CopyFrom()`.
+
+~~~~~~~~~~cpp
+Document d;
+Document::AllocatorType& a = d.GetAllocator();
+Value v1("foo");
+// Value v2(v1); // not allowed
+
+Value v2(v1, a); // make a copy
+assert(v1.IsString()); // v1 untouched
+d.SetArray().PushBack(v1, a).PushBack(v2, a);
+assert(v1.IsNull() && v2.IsNull()); // both moved to d
+
+v2.CopyFrom(d, a); // copy whole document to v2
+assert(d.IsArray() && d.Size() == 2); // d untouched
+v1.SetObject().AddMember("array", v2, a);
+d.PushBack(v1, a);
+~~~~~~~~~~
+
+## Swap Values {#SwapValues}
+
+`Swap()` is also provided.
+
+~~~~~~~~~~cpp
+Value a(123);
+Value b("Hello");
+a.Swap(b);
+assert(a.IsString());
+assert(b.IsInt());
+~~~~~~~~~~
+
+Swapping two DOM trees is fast (constant time), despite the complexity of the trees.
+
+# What's next {#WhatsNext}
+
+This tutorial shows the basics of DOM tree query and manipulation. There are several important concepts in RapidJSON:
+
+1. [Streams](doc/stream.md) are channels for reading/writing JSON, which can be a in-memory string, or file stream, etc. User can also create their streams.
+2. [Encoding](doc/encoding.md) defines which character encoding is used in streams and memory. RapidJSON also provide Unicode conversion/validation internally.
+3. [DOM](doc/dom.md)'s basics are already covered in this tutorial. Uncover more advanced features such as *in situ* parsing, other parsing options and advanced usages.
+4. [SAX](doc/sax.md) is the foundation of parsing/generating facility in RapidJSON. Learn how to use `Reader`/`Writer` to implement even faster applications. Also try `PrettyWriter` to format the JSON.
+5. [Performance](doc/performance.md) shows some in-house and third-party benchmarks.
+6. [Internals](doc/internals.md) describes some internal designs and techniques of RapidJSON.
+
+You may also refer to the [FAQ](doc/faq.md), API documentation, examples and unit tests.
diff --git a/3rdparty/rapidjson/doc/tutorial.zh-cn.md b/3rdparty/rapidjson/doc/tutorial.zh-cn.md
new file mode 100644
index 00000000000..37808b08669
--- /dev/null
+++ b/3rdparty/rapidjson/doc/tutorial.zh-cn.md
@@ -0,0 +1,515 @@
+# 教程
+
+本教程简介文件对象模型(Document Object Model, DOM)API。
+
+如[用法一览](../readme.zh-cn.md#用法一览)中所示,å¯ä»¥è§£æžä¸€ä¸ªJSON至DOM,然åŽå°±å¯ä»¥è½»æ¾æŸ¥è¯¢åŠä¿®æ”¹DOM,并最终转æ¢å›žJSON。
+
+[TOC]
+
+# Value åŠ Document {#ValueDocument}
+
+æ¯ä¸ªJSON值都储存为`Value`类,而`Document`类则表示整个DOM,它存储了一个DOM树的根`Value`。RapidJSON的所有公开类型åŠå‡½æ•°éƒ½åœ¨`rapidjson`命å空间中。
+
+# 查询Value {#QueryValue}
+
+在本节中,我们会使用到`example/tutorial/tutorial.cpp`中的代ç ç‰‡æ®µã€‚
+
+å‡è®¾æˆ‘们用C语言的字符串储存一个JSON(`const char* json`):
+~~~~~~~~~~js
+{
+ "hello": "world",
+ "t": true ,
+ "f": false,
+ "n": null,
+ "i": 123,
+ "pi": 3.1416,
+ "a": [1, 2, 3, 4]
+}
+~~~~~~~~~~
+
+把它解æžè‡³ä¸€ä¸ª`Document`:
+~~~~~~~~~~cpp
+#include "rapidjson/document.h"
+
+using namespace rapidjson;
+
+// ...
+Document document;
+document.Parse(json);
+~~~~~~~~~~
+
+那么现在该JSON就会被解æžè‡³`document`中,æˆä¸ºä¸€æ£µ*DOMæ ‘*:
+
+![教程中的DOM](diagram/tutorial.png)
+
+自从RFC 7159ä½œå‡ºæ›´æ–°ï¼Œåˆæ³•JSON文件的根å¯ä»¥æ˜¯ä»»ä½•类型的JSON值。而在较早的RFC 4627中,根值åªå…许是Object或Array。而在上述例å­ä¸­ï¼Œæ ¹æ˜¯ä¸€ä¸ªObject。
+~~~~~~~~~~cpp
+assert(document.IsObject());
+~~~~~~~~~~
+
+让我们查询一下根Object中有没有`"hello"`æˆå‘˜ã€‚由于一个`Value`å¯åŒ…å«ä¸åŒç±»åž‹çš„值,我们å¯èƒ½éœ€è¦éªŒè¯å®ƒçš„类型,并使用åˆé€‚çš„API去获å–其值。在此例中,`"hello"`æˆå‘˜å…³è”到一个JSON String。
+~~~~~~~~~~cpp
+assert(document.HasMember("hello"));
+assert(document["hello"].IsString());
+printf("hello = %s\n", document["hello"].GetString());
+~~~~~~~~~~
+
+~~~~~~~~~~
+world
+~~~~~~~~~~
+
+JSON True/False值是以`bool`表示的。
+~~~~~~~~~~cpp
+assert(document["t"].IsBool());
+printf("t = %s\n", document["t"].GetBool() ? "true" : "false");
+~~~~~~~~~~
+
+~~~~~~~~~~
+true
+~~~~~~~~~~
+
+JSON Null值å¯ç”¨`IsNull()`查询。
+~~~~~~~~~~cpp
+printf("n = %s\n", document["n"].IsNull() ? "null" : "?");
+~~~~~~~~~~
+
+~~~~~~~~~~
+null
+~~~~~~~~~~
+
+JSON Number类型表示所有数值。然而,C++需è¦ä½¿ç”¨æ›´ä¸“门的类型。
+
+~~~~~~~~~~cpp
+assert(document["i"].IsNumber());
+
+// 在此情况下,IsUint()/IsInt64()/IsUInt64()也会返回 true
+assert(document["i"].IsInt());
+printf("i = %d\n", document["i"].GetInt());
+// å¦ä¸€ç§ç”¨æ³•: (int)document["i"]
+
+assert(document["pi"].IsNumber());
+assert(document["pi"].IsDouble());
+printf("pi = %g\n", document["pi"].GetDouble());
+~~~~~~~~~~
+
+~~~~~~~~~~
+i = 123
+pi = 3.1416
+~~~~~~~~~~
+
+JSON Array包å«ä¸€äº›å…ƒç´ ã€‚
+~~~~~~~~~~cpp
+// 使用引用æ¥è¿žç»­è®¿é—®ï¼Œæ–¹ä¾¿ä¹‹ä½™è¿˜æ›´é«˜æ•ˆã€‚
+const Value& a = document["a"];
+assert(a.IsArray());
+for (SizeType i = 0; i < a.Size(); i++) // 使用 SizeType è€Œä¸æ˜¯ size_t
+ printf("a[%d] = %d\n", i, a[i].GetInt());
+~~~~~~~~~~
+
+~~~~~~~~~~
+a[0] = 1
+a[1] = 2
+a[2] = 3
+a[3] = 4
+~~~~~~~~~~
+
+注æ„,RapidJSONå¹¶ä¸è‡ªåŠ¨è½¬æ¢å„ç§JSON类型。例如,对一个Stringçš„Value调用`GetInt()`æ˜¯éžæ³•的。在调试模å¼ä¸‹ï¼Œå®ƒä¼šè¢«æ–­è¨€å¤±è´¥ã€‚在å‘布模å¼ä¸‹ï¼Œå…¶è¡Œä¸ºæ˜¯æœªå®šä¹‰çš„。
+
+以下将会讨论有关查询å„类型的细节。
+
+## 查询Array {#QueryArray}
+
+ç¼ºçœæƒ…况下,`SizeType`是`unsigned`çš„typedef。在多数系统中,Array最多能存储2^32-1个元素。
+
+ä½ å¯ä»¥ç”¨æ•´æ•°å­—é¢é‡è®¿é—®å…ƒç´ ï¼Œå¦‚`a[0]`ã€`a[1]`ã€`a[2]`。
+
+Array与`std::vector`相似,除了使用索引,也å¯ä½¿ç”¨è¿­ä»£å™¨æ¥è®¿é—®æ‰€æœ‰å…ƒç´ ã€‚
+~~~~~~~~~~cpp
+for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
+ printf("%d ", itr->GetInt());
+~~~~~~~~~~
+
+还有一些熟悉的查询函数:
+* `SizeType Capacity() const`
+* `bool Empty() const`
+
+## 查询Object {#QueryObject}
+
+å’ŒArray相似,我们å¯ä»¥ç”¨è¿­ä»£å™¨åŽ»è®¿é—®æ‰€æœ‰Objectæˆå‘˜ï¼š
+
+~~~~~~~~~~cpp
+static const char* kTypeNames[] =
+ { "Null", "False", "True", "Object", "Array", "String", "Number" };
+
+for (Value::ConstMemberIterator itr = document.MemberBegin();
+ itr != document.MemberEnd(); ++itr)
+{
+ printf("Type of member %s is %s\n",
+ itr->name.GetString(), kTypeNames[itr->value.GetType()]);
+}
+~~~~~~~~~~
+
+~~~~~~~~~~
+Type of member hello is String
+Type of member t is True
+Type of member f is False
+Type of member n is Null
+Type of member i is Number
+Type of member pi is Number
+Type of member a is Array
+~~~~~~~~~~
+
+注æ„,当`operator[](const char*)`找ä¸åˆ°æˆå‘˜ï¼Œå®ƒä¼šæ–­è¨€å¤±è´¥ã€‚
+
+若我们ä¸ç¡®å®šä¸€ä¸ªæˆå‘˜æ˜¯å¦å­˜åœ¨ï¼Œä¾¿éœ€è¦åœ¨è°ƒç”¨`operator[](const char*)`å‰å…ˆè°ƒç”¨`HasMember()`ã€‚ç„¶è€Œï¼Œè¿™ä¼šå¯¼è‡´ä¸¤æ¬¡æŸ¥æ‰¾ã€‚æ›´å¥½çš„åšæ³•是调用`FindMember()`ï¼Œå®ƒèƒ½åŒæ—¶æ£€æŸ¥æˆå‘˜æ˜¯å¦å­˜åœ¨å¹¶è¿”回它的Value:
+
+~~~~~~~~~~cpp
+Value::ConstMemberIterator itr = document.FindMember("hello");
+if (itr != document.MemberEnd())
+ printf("%s %s\n", itr->value.GetString());
+~~~~~~~~~~
+
+## 查询Number {#QueryNumber}
+
+JSONåªæä¾›ä¸€ç§æ•°å€¼ç±»åž‹â”€â”€Number。数字å¯ä»¥æ˜¯æ•´æ•°æˆ–实数。RFC 4627规定数字的范围由解æžå™¨æŒ‡å®šã€‚
+
+由于C++æä¾›å¤šç§æ•´æ•°åŠæµ®ç‚¹æ•°ç±»åž‹ï¼ŒDOMå°è¯•å°½é‡æä¾›æœ€å¹¿çš„èŒƒå›´åŠè‰¯å¥½æ€§èƒ½ã€‚
+
+当解æžä¸€ä¸ªNumberæ—¶, 它会被存储在DOM之中,æˆä¸ºä¸‹åˆ—其中一个类型:
+
+类型 | æè¿°
+-----------|---------------------------------------
+`unsigned` | 32使— å·æ•´æ•°
+`int` | 32使œ‰å·æ•´æ•°
+`uint64_t` | 64使— å·æ•´æ•°
+`int64_t` | 64使œ‰å·æ•´æ•°
+`double` | 64ä½åŒç²¾åº¦æµ®ç‚¹æ•°
+
+当查询一个Numberæ—¶, ä½ å¯ä»¥æ£€æŸ¥è¯¥æ•°å­—是å¦èƒ½ä»¥ç›®æ ‡ç±»åž‹æ¥æå–:
+
+查检 | æå–
+------------------|---------------------
+`bool IsNumber()` | ä¸é€‚用
+`bool IsUint()` | `unsigned GetUint()`
+`bool IsInt()` | `int GetInt()`
+`bool IsUint64()` | `uint64_t GetUint64()`
+`bool IsInt64()` | `int64_t GetInt64()`
+`bool IsDouble()` | `double GetDouble()`
+
+注æ„,一个整数å¯èƒ½ç”¨å‡ ç§ç±»åž‹æ¥æå–,而无需转æ¢ã€‚例如,一个å为`x`çš„Value包å«123,那么`x.IsInt() == x.IsUint() == x.IsInt64() == x.IsUint64() == true`。但如果一个å为`y`çš„Value包å«-3000000000,那么仅会令`x.IsInt64() == true`。
+
+å½“è¦æå–Number类型,`GetDouble()`æ˜¯ä¼šæŠŠå†…éƒ¨æ•´æ•°çš„è¡¨ç¤ºè½¬æ¢æˆ`double`。注æ„`int` å’Œ`unsigned`å¯ä»¥å®‰å…¨åœ°è½¬æ¢è‡³`double`,但`int64_t`åŠ`uint64_t`å¯èƒ½ä¼šä¸§å¤±ç²¾åº¦ï¼ˆå› ä¸º`double`çš„å°¾æ•°åªæœ‰52ä½ï¼‰ã€‚
+
+## 查询String {#QueryString}
+
+除了`GetString()`,`Value`类也有一个`GetStringLength()`。这里会解释个中原因。
+
+æ ¹æ®RFC 4627,JSON Stringå¯åŒ…å«Unicode字符`U+0000`,在JSON中会表示为`"\u0000"`。问题是,C/C++通常使用空字符结尾字符串(null-terminated string),这ç§å­—符串把``\0'`作为结æŸç¬¦å·ã€‚
+
+为了符åˆRFC 4627,RapidJSON支æŒåŒ…å«`U+0000`çš„String。若你需è¦å¤„ç†è¿™äº›String,便å¯ä½¿ç”¨`GetStringLength()`去获得正确的字符串长度。
+
+例如,当解æžä»¥ä¸‹çš„JSON至`Document d`之åŽï¼š
+
+~~~~~~~~~~js
+{ "s" : "a\u0000b" }
+~~~~~~~~~~
+`"a\u0000b"`值的正确长度应该是3。但`strlen()`会返回1。
+
+`GetStringLength()`也å¯ä»¥æé«˜æ€§èƒ½ï¼Œå› ä¸ºç”¨æˆ·å¯èƒ½éœ€è¦è°ƒç”¨`strlen()`去分é…缓冲。
+
+此外,`std::string`也支æŒè¿™ä¸ªæž„造函数:
+
+~~~~~~~~~~cpp
+string(const char* s, size_t count);
+~~~~~~~~~~
+
+此构造函数接å—å­—ç¬¦ä¸²é•¿åº¦ä½œä¸ºå‚æ•°ã€‚它支æŒåœ¨å­—符串中存储空字符,也应该会有更好的性能。
+
+## 比较两个Value
+
+ä½ å¯ä½¿ç”¨`==`åŠ`!=`去比较两个Value。当且仅当两个Value的类型åŠå†…容相åŒï¼Œå®ƒä»¬æ‰å½“作相等。你也å¯ä»¥æ¯”较Value和它的原生类型值。以下是一个例å­ã€‚
+
+~~~~~~~~~~cpp
+if (document["hello"] == document["n"]) /*...*/; // 比较两个值
+if (document["hello"] == "world") /*...*/; // 与字符串家é¢é‡ä½œæ¯”较
+if (document["i"] != 123) /*...*/; // 与整数作比较
+if (document["pi"] != 3.14) /*...*/; // 与double作比较
+~~~~~~~~~~
+
+Arrayï¼Object顺åºä»¥å®ƒä»¬çš„å…ƒç´ ï¼æˆå‘˜ä½œæ¯”è¾ƒã€‚å½“ä¸”ä»…å½“å®ƒä»¬çš„æ•´ä¸ªå­æ ‘相等,它们æ‰å½“作相等。
+
+注æ„,现时若一个Object嫿œ‰é‡å¤å‘½åçš„æˆå‘˜ï¼Œå®ƒä¸Žä»»ä½•Object作比较都总会返回`false`。
+
+# 创建ï¼ä¿®æ”¹å€¼ {#CreateModifyValues}
+
+æœ‰å¤šç§æ–¹æ³•去创建值。 当一个DOM树被创建或修改åŽï¼Œå¯ä½¿ç”¨`Writer`冿¬¡å­˜å‚¨ä¸ºJSON。
+
+## 改å˜Value类型 {#ChangeValueType}
+当使用默认构造函数创建一个Value或Document,它的类型便会是Nullã€‚è¦æ”¹å˜å…¶ç±»åž‹ï¼Œéœ€è°ƒç”¨`SetXXX()`或赋值æ“作,例如:
+
+~~~~~~~~~~cpp
+Document d; // Null
+d.SetObject();
+
+Value v; // Null
+v.SetInt(10);
+v = 10; // 简写,和上é¢çš„相åŒ
+~~~~~~~~~~
+
+### 构造函数的å„个é‡è½½
+几个类型也有é‡è½½æž„造函数:
+
+~~~~~~~~~~cpp
+Value b(true); // 调用Value(bool)
+Value i(-123); // 调用 Value(int)
+Value u(123u); // 调用Value(unsigned)
+Value d(1.5); // 调用Value(double)
+~~~~~~~~~~
+
+è¦é‡å»ºç©ºObject或Array,å¯åœ¨é»˜è®¤æž„造函数åŽä½¿ç”¨ `SetObject()`/`SetArray()`,或一次性使用`Value(Type)`:
+
+~~~~~~~~~~cpp
+Value o(kObjectType);
+Value a(kArrayType);
+~~~~~~~~~~
+
+## 转移语æ„(Move Semantics) {#MoveSemantics}
+
+在设计RapidJSON时有一个éžå¸¸ç‰¹åˆ«çš„决定,就是Valueèµ‹å€¼å¹¶ä¸æ˜¯æŠŠæ¥æºValueå¤åˆ¶è‡³ç›®çš„Valueï¼Œè€Œæ˜¯æŠŠæŠŠæ¥æºValue转移(move)至目的Value。例如:
+
+~~~~~~~~~~cpp
+Value a(123);
+Value b(456);
+b = a; // aå˜æˆNull,bå˜æˆæ•°å­—123。
+~~~~~~~~~~
+
+![使用移动语æ„赋值。](diagram/move1.png)
+
+ä¸ºä»€ä¹ˆï¼Ÿæ­¤è¯­æ„æœ‰ä½•优点?
+
+最简å•的答案就是性能。对于固定大å°çš„JSON类型(Numberã€Trueã€Falseã€Null),å¤åˆ¶å®ƒä»¬æ˜¯ç®€å•å¿«æ·ã€‚然而,对于å¯å˜å¤§å°çš„JSON类型(Stringã€Arrayã€Object),å¤åˆ¶å®ƒä»¬ä¼šäº§ç”Ÿå¤§é‡å¼€é”€ï¼Œè€Œä¸”这些开销常常ä¸è¢«å¯Ÿè§‰ã€‚尤其是当我们需è¦åˆ›å»ºä¸´æ—¶Object,把它å¤åˆ¶è‡³å¦ä¸€å˜é‡ï¼Œç„¶åŽå†æžæž„它。
+
+例如,若使用正常*å¤åˆ¶*语æ„:
+
+~~~~~~~~~~cpp
+Value o(kObjectType);
+{
+ Value contacts(kArrayType);
+ // 把元素加进contacts数组。
+ // ...
+ o.AddMember("contacts", contacts, d.GetAllocator()); // 深度å¤åˆ¶contacts (å¯èƒ½æœ‰å¤§é‡å†…存分é…)
+ // æžæž„contacts。
+}
+~~~~~~~~~~
+
+![å¤åˆ¶è¯­æ„产生大é‡çš„å¤åˆ¶æ“作。](diagram/move2.png)
+
+那个`o` Object需è¦åˆ†é…一个和contacts相åŒå¤§å°çš„缓冲区,对conactsåšæ·±åº¦å¤åˆ¶ï¼Œå¹¶æœ€ç»ˆè¦æžæž„contactsã€‚è¿™æ ·ä¼šäº§ç”Ÿå¤§é‡æ— å¿…è¦çš„内存分é…ï¼é‡Šæ”¾ï¼Œä»¥åŠå†…å­˜å¤åˆ¶ã€‚
+
+有一些方案å¯é¿å…实质地å¤åˆ¶è¿™äº›æ•°æ®ï¼Œä¾‹å¦‚引用计数(reference counting)ã€åžƒåœ¾å›žæ”¶ï¼ˆgarbage collection, GC)。
+
+为了使RapidJSON简å•åŠå¿«é€Ÿï¼Œæˆ‘们选择了对赋值采用*转移*语æ„。这方法与`std::auto_ptr`相似,都是在赋值时转移拥有æƒã€‚转移快得多简å•得多,åªéœ€è¦æžæž„原æ¥çš„Valueï¼ŒæŠŠæ¥æº`memcpy()`è‡³ç›®æ ‡ï¼Œæœ€åŽæŠŠæ¥æºè®¾ç½®ä¸ºNull类型。
+
+因此,使用转移语æ„åŽï¼Œä¸Šé¢çš„例å­å˜æˆï¼š
+
+~~~~~~~~~~cpp
+Value o(kObjectType);
+{
+ Value contacts(kArrayType);
+ // adding elements to contacts array.
+ o.AddMember("contacts", contacts, d.GetAllocator()); // åªéœ€ memcpy() contacts本身至新æˆå‘˜çš„Value(16字节)
+ // contactsåœ¨è¿™é‡Œå˜æˆNullã€‚å®ƒçš„æžæž„是平凡的。
+}
+~~~~~~~~~~
+
+![转移语æ„ä¸éœ€å¤åˆ¶ã€‚](diagram/move3.png)
+
+在C++11中这称为转移赋值æ“作(move assignment operator)。由于RapidJSON 支æŒC++03,它在赋值æ“作采用转移语æ„,其它修改形函数如`AddMember()`, `PushBack()`也采用转移语æ„。
+
+### 转移语æ„åŠä¸´æ—¶å€¼ {#TemporaryValues}
+
+有时候,我们想直接构造一个Value并传递给一个“转移â€å‡½æ•°ï¼ˆå¦‚`PushBack()`ã€`AddMember()`)。由于临时对象是ä¸èƒ½è½¬æ¢ä¸ºæ­£å¸¸çš„Value引用,我们加入了一个方便的`Move()`函数:
+
+~~~~~~~~~~cpp
+Value a(kArrayType);
+Document::AllocatorType& allocator = document.GetAllocator();
+// a.PushBack(Value(42), allocator); // ä¸èƒ½é€šè¿‡ç¼–译
+a.PushBack(Value().SetInt(42), allocator); // fluent API
+a.PushBack(Value(42).Move(), allocator); // 和上一行相åŒ
+~~~~~~~~~~
+
+## 创建String {#CreateString}
+RapidJSONæä¾›ä¸¤ä¸ªString的存储策略。
+
+1. copy-string: 分é…ç¼“å†²åŒºï¼Œç„¶åŽæŠŠæ¥æºæ•°æ®å¤åˆ¶è‡³å®ƒã€‚
+2. const-string: 简å•地储存字符串的指针。
+
+Copy-string总是安全的,因为它拥有数æ®çš„克隆。Const-stringå¯ç”¨äºŽå­˜å‚¨å­—符串字é¢é‡ï¼Œä»¥åŠç”¨äºŽåœ¨DOM一节中将会æåˆ°çš„in-situè§£æžä¸­ã€‚
+
+ä¸ºäº†è®©ç”¨æˆ·è‡ªå®šä¹‰å†…å­˜åˆ†é…æ–¹å¼ï¼Œå½“一个æ“作å¯èƒ½éœ€è¦å†…å­˜åˆ†é…æ—¶ï¼ŒRapidJSONè¦æ±‚用户传递一个allocator实例作为API傿•°ã€‚此设计é¿å…了在æ¯ä¸ªValue存储allocator(或document)的指针。
+
+因此,当我们把一个copy-string赋值时, è°ƒç”¨å«æœ‰allocatorçš„`SetString()`é‡è½½å‡½æ•°ï¼š
+
+~~~~~~~~~~cpp
+Document document;
+Value author;
+char buffer[10];
+int len = sprintf(buffer, "%s %s", "Milo", "Yip"); // 动æ€åˆ›å»ºçš„字符串。
+author.SetString(buffer, len, document.GetAllocator());
+memset(buffer, 0, sizeof(buffer));
+// 清空bufferåŽauthor.GetString() ä»ç„¶åŒ…å« "Milo Yip"
+~~~~~~~~~~
+
+在此例å­ä¸­ï¼Œæˆ‘们使用`Document`实例的allocator。这是使用RapidJSON时常用的惯用法。但你也å¯ä»¥ç”¨å…¶ä»–allocator实例。
+
+å¦å¤–,上é¢çš„`SetString()`需è¦é•¿åº¦å‚数。这个API能处ç†å«æœ‰ç©ºå­—符的字符串。å¦ä¸€ä¸ª`SetString()`é‡è½½å‡½æ•°æ²¡æœ‰é•¿åº¦å‚数,它å‡è®¾è¾“入是空字符结尾的,并会调用类似`strlen()`的函数去获å–长度。
+
+最åŽï¼Œå¯¹äºŽå­—符串字é¢é‡æˆ–有安全生命周期的字符串,å¯ä»¥ä½¿ç”¨const-string版本的`SetString()`,它没有allocator傿•°ã€‚对于字符串家é¢é‡ï¼ˆæˆ–字符数组常é‡ï¼‰ï¼Œåªéœ€ç®€å•地传递字é¢é‡ï¼Œåˆå®‰å…¨åˆé«˜æ•ˆï¼š
+
+~~~~~~~~~~cpp
+Value s;
+s.SetString("rapidjson"); // å¯åŒ…å«ç©ºå­—ç¬¦ï¼Œé•¿åº¦åœ¨ç¼–è¯‘èæŽ¨å¯¼
+s = "rapidjson"; // 上行的缩写
+~~~~~~~~~~
+
+对于字符指针,RapidJSON需è¦ä½œä¸€ä¸ªæ ‡è®°ï¼Œä»£è¡¨å®ƒä¸å¤åˆ¶ä¹Ÿæ˜¯å®‰å…¨çš„。å¯ä»¥ä½¿ç”¨`StringRef`函数:
+
+~~~~~~~~~cpp
+const char * cstr = getenv("USER");
+size_t cstr_len = ...; // 如果有长度
+Value s;
+// s.SetString(cstr); // è¿™ä¸èƒ½é€šè¿‡ç¼–译
+s.SetString(StringRef(cstr)); // å¯ä»¥ï¼Œå‡è®¾å®ƒçš„生命周期案全,并且是以空字符结尾的
+s = StringRef(cstr); // 上行的缩写
+s.SetString(StringRef(cstr, cstr_len));// 更快,å¯å¤„ç†ç©ºå­—符
+s = StringRef(cstr, cstr_len); // 上行的缩写
+
+~~~~~~~~~
+
+## 修改Array {#ModifyArray}
+Array类型的Valueæä¾›ä¸Ž`std::vector`相似的API。
+
+* `Clear()`
+* `Reserve(SizeType, Allocator&)`
+* `Value& PushBack(Value&, Allocator&)`
+* `template <typename T> GenericValue& PushBack(T, Allocator&)`
+* `Value& PopBack()`
+* `ValueIterator Erase(ConstValueIterator pos)`
+* `ValueIterator Erase(ConstValueIterator first, ConstValueIterator last)`
+
+注æ„,`Reserve(...)`åŠ`PushBack(...)`å¯èƒ½ä¼šä¸ºæ•°ç»„元素分é…内存,所以需è¦ä¸€ä¸ªallocator。
+
+以下是`PushBack()`的例å­ï¼š
+
+~~~~~~~~~~cpp
+Value a(kArrayType);
+Document::AllocatorType& allocator = document.GetAllocator();
+
+for (int i = 5; i <= 10; i++)
+ a.PushBack(i, allocator); // å¯èƒ½éœ€è¦è°ƒç”¨realloc()所以需è¦allocator
+
+// æµç•…接å£ï¼ˆFluent interface)
+a.PushBack("Lua", allocator).PushBack("Mio", allocator);
+~~~~~~~~~~
+
+与STLä¸ä¸€æ ·çš„æ˜¯ï¼Œ`PushBack()`/`PopBack()`返回Array本身的引用。这称为æµç•…接å£ï¼ˆ_fluent interface_)。
+
+如果你想在Array中加入一个éžå¸¸é‡å­—符串,或是一个没有足够生命周期的字符串(è§[Create String](#CreateString)),你需è¦ä½¿ç”¨copy-string API去创建一个String。为了é¿å…加入中间å˜é‡ï¼Œå¯ä»¥å°±åœ°ä½¿ç”¨ä¸€ä¸ª[临时值](#TemporaryValues):
+
+~~~~~~~~~~cpp
+// 就地Value傿•°
+contact.PushBack(Value("copy", document.GetAllocator()).Move(), // copy string
+ document.GetAllocator());
+
+// 显å¼Value傿•°
+Value val("key", document.GetAllocator()); // copy string
+contact.PushBack(val, document.GetAllocator());
+~~~~~~~~~~
+
+## 修改Object {#ModifyObject}
+Object是键值对的集åˆã€‚æ¯ä¸ªé”®å¿…须为String。è¦ä¿®æ”¹Object,方法是增加或移除æˆå‘˜ã€‚以下的API用æ¥å¢žåŠ åŸŽå‘˜ï¼š
+
+* `Value& AddMember(Value&, Value&, Allocator& allocator)`
+* `Value& AddMember(StringRefType, Value&, Allocator&)`
+* `template <typename T> Value& AddMember(StringRefType, T value, Allocator&)`
+
+以下是一个例å­ã€‚
+
+~~~~~~~~~~cpp
+Value contact(kObject);
+contact.AddMember("name", "Milo", document.GetAllocator());
+contact.AddMember("married", true, document.GetAllocator());
+~~~~~~~~~~
+
+使用`StringRefType`作为name傿•°çš„é‡è½½ç‰ˆæœ¬ä¸Žå­—符串的`SetString`的接å£ç›¸ä¼¼ã€‚ 这些é‡è½½æ˜¯ä¸ºäº†é¿å…å¤åˆ¶`name`字符串,因为JSON object中ç»å¸¸ä¼šä½¿ç”¨å¸¸æ•°é”®å。
+
+如果你需è¦ä»Žéžå¸¸æ•°å­—符串或生命周期ä¸è¶³çš„字符串创建键å(è§[创建String](#CreateString)),你需è¦ä½¿ç”¨copy-string API。为了é¿å…中间å˜é‡ï¼Œå¯ä»¥å°±åœ°ä½¿ç”¨[临时值](#TemporaryValues):
+
+~~~~~~~~~~cpp
+// 就地Value傿•°
+contact.AddMember(Value("copy", document.GetAllocator()).Move(), // copy string
+ Value().Move(), // null value
+ document.GetAllocator());
+
+// 显å¼å‚æ•°
+Value key("key", document.GetAllocator()); // copy string name
+Value val(42); // æŸValue
+contact.AddMember(key, val, document.GetAllocator());
+~~~~~~~~~~
+
+移除æˆå‘˜æœ‰å‡ ä¸ªé€‰æ‹©ï¼š
+
+* `bool RemoveMember(const Ch* name)`ï¼šä½¿ç”¨é”®åæ¥ç§»é™¤æˆå‘˜ï¼ˆçº¿æ€§æ—¶é—´å¤æ‚度)。
+* `bool RemoveMember(const Value& name)`:除了`name`是一个Value,和上一行相åŒã€‚
+* `MemberIterator RemoveMember(MemberIterator)`:使用迭代器移除æˆå‘˜ï¼ˆ_常数_æ—¶é—´å¤æ‚度)。
+* `MemberIterator EraseMember(MemberIterator)`ï¼šå’Œä¸Šè¡Œç›¸ä¼¼ä½†ç»´æŒæˆå‘˜æ¬¡åºï¼ˆçº¿æ€§æ—¶é—´å¤æ‚度)。
+* `MemberIterator EraseMember(MemberIterator first, MemberIterator last)`:移除一个范围内的æˆå‘˜ï¼Œç»´æŒæ¬¡åºï¼ˆçº¿æ€§æ—¶é—´å¤æ‚度)。
+
+`MemberIterator RemoveMember(MemberIterator)`使用了“转移最åŽâ€æ‰‹æ³•æ¥è¾¾æˆå¸¸æ•°æ—¶é—´å¤æ‚åº¦ã€‚åŸºæœ¬ä¸Šå°±æ˜¯æžæž„迭代器ä½ç½®çš„æˆå‘˜ï¼Œç„¶åŽæŠŠæœ€åŽçš„æˆå‘˜è½¬ç§»è‡³è¿­ä»£å™¨ä½ç½®ã€‚因此,æˆå‘˜çš„æ¬¡åºä¼šè¢«æ”¹å˜ã€‚
+
+## æ·±å¤åˆ¶Value {#DeepCopyValue}
+若我们真的è¦å¤åˆ¶ä¸€ä¸ªDOM树,我们å¯ä½¿ç”¨ä¸¤ä¸ªAPIs作深å¤åˆ¶ï¼šå«allocator的构造函数åŠ`CopyFrom()`。
+
+~~~~~~~~~~cpp
+Document d;
+Document::AllocatorType& a = d.GetAllocator();
+Value v1("foo");
+// Value v2(v1); // ä¸å®¹è®¸
+
+Value v2(v1, a); // 制造一个克隆
+assert(v1.IsString()); // v1ä¸å˜
+d.SetArray().PushBack(v1, a).PushBack(v2, a);
+assert(v1.IsNull() && v2.IsNull()); // 两个都转移动d
+
+v2.CopyFrom(d, a); // 把整个documentå¤åˆ¶è‡³v2
+assert(d.IsArray() && d.Size() == 2); // dä¸å˜
+v1.SetObject().AddMember("array", v2, a);
+d.PushBack(v1, a);
+~~~~~~~~~~
+
+## 交æ¢Value {#SwapValues}
+
+RapidJSON也æä¾›`Swap()`。
+
+~~~~~~~~~~cpp
+Value a(123);
+Value b("Hello");
+a.Swap(b);
+assert(a.IsString());
+assert(b.IsInt());
+~~~~~~~~~~
+
+无论两棵DOMæ ‘æœ‰å¤šå¤æ‚ï¼Œäº¤æ¢æ˜¯å¾ˆå¿«çš„(常数时间)。
+
+# 下一部分 {#WhatsNext}
+
+本教程展示了如何询查åŠä¿®æ”¹DOM树。RapidJSON还有一个é‡è¦æ¦‚念:
+
+1. [æµ](doc/stream.zh-cn.md) 是读写JSON的通é“。æµå¯ä»¥æ˜¯å†…å­˜å­—ç¬¦ä¸²ã€æ–‡ä»¶æµç­‰ã€‚用户也å¯ä»¥è‡ªå®šä¹‰æµã€‚
+2. [ç¼–ç ](doc/encoding.zh-cn.md)å®šä¹‰åœ¨æµæˆ–内存中使用的字符编ç ã€‚RapidJSON也在内部æä¾›Unicode转æ¢åŠæ ¡éªŒåŠŸèƒ½ã€‚
+3. [DOM](doc/dom.zh-cn.md)的基本功能已在本教程里介ç»ã€‚还有更高级的功能,如原ä½ï¼ˆ*in situ*)解æžã€å…¶ä»–è§£æžé€‰é¡¹åŠé«˜çº§ç”¨æ³•。
+4. [SAX](doc/sax.zh-cn.md) 是RapidJSONè§£æžï¼ç”ŸæˆåŠŸèƒ½çš„åŸºç¡€ã€‚å­¦ä¹ ä½¿ç”¨`Reader`/`Writer`去实现更高性能的应用程åºã€‚也å¯ä»¥ä½¿ç”¨`PrettyWriter`去格å¼åŒ–JSON。
+5. [性能](doc/performance.zh-cn.md)展示一些我们åšçš„åŠç¬¬ä¸‰æ–¹çš„æ€§èƒ½æµ‹è¯•。
+6. [技术内幕](doc/internals.zh-cn.md)讲述一些RapidJSONå†…éƒ¨çš„è®¾è®¡åŠæŠ€æœ¯ã€‚
+
+你也å¯ä»¥å‚考[常è§é—®é¢˜](faq.zh-cn.md)ã€API文档ã€ä¾‹å­åŠå•元测试。
diff --git a/3rdparty/rapidjson/example/CMakeLists.txt b/3rdparty/rapidjson/example/CMakeLists.txt
new file mode 100644
index 00000000000..c6b8449ffb1
--- /dev/null
+++ b/3rdparty/rapidjson/example/CMakeLists.txt
@@ -0,0 +1,36 @@
+# Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
+# Copyright (c) 2013 Rafal Jeczalik (rjeczalik@gmail.com)
+# Distributed under the MIT License (see license.txt file)
+cmake_minimum_required(VERSION 2.8)
+
+set(EXAMPLES
+ capitalize
+ condense
+ jsonx
+ messagereader
+ pretty
+ prettyauto
+ schemavalidator
+ serialize
+ simpledom
+ simplereader
+ simplewriter
+ tutorial)
+
+include_directories("../include/")
+
+add_definitions(-D__STDC_FORMAT_MACROS)
+
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default")
+elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal -Wimplicit-fallthrough -Weverything")
+elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
+endif()
+
+foreach (example ${EXAMPLES})
+ add_executable(${example} ${example}/${example}.cpp)
+endforeach()
+
+add_custom_target(examples ALL DEPENDS ${EXAMPLES})
diff --git a/3rdparty/rapidjson/example/capitalize/capitalize.cpp b/3rdparty/rapidjson/example/capitalize/capitalize.cpp
new file mode 100644
index 00000000000..adc32b52da1
--- /dev/null
+++ b/3rdparty/rapidjson/example/capitalize/capitalize.cpp
@@ -0,0 +1,66 @@
+// JSON condenser example
+
+// This example parses JSON from stdin with validation,
+// and re-output the JSON content to stdout with all string capitalized, and without whitespace.
+
+#include "rapidjson/reader.h"
+#include "rapidjson/writer.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/filewritestream.h"
+#include "rapidjson/error/en.h"
+#include <vector>
+#include <cctype>
+
+using namespace rapidjson;
+
+template<typename OutputHandler>
+struct CapitalizeFilter {
+ CapitalizeFilter(OutputHandler& out) : out_(out), buffer_() {}
+
+ bool Null() { return out_.Null(); }
+ bool Bool(bool b) { return out_.Bool(b); }
+ bool Int(int i) { return out_.Int(i); }
+ bool Uint(unsigned u) { return out_.Uint(u); }
+ bool Int64(int64_t i) { return out_.Int64(i); }
+ bool Uint64(uint64_t u) { return out_.Uint64(u); }
+ bool Double(double d) { return out_.Double(d); }
+ bool String(const char* str, SizeType length, bool) {
+ buffer_.clear();
+ for (SizeType i = 0; i < length; i++)
+ buffer_.push_back(static_cast<char>(std::toupper(str[i])));
+ return out_.String(&buffer_.front(), length, true); // true = output handler need to copy the string
+ }
+ bool StartObject() { return out_.StartObject(); }
+ bool Key(const char* str, SizeType length, bool copy) { return String(str, length, copy); }
+ bool EndObject(SizeType memberCount) { return out_.EndObject(memberCount); }
+ bool StartArray() { return out_.StartArray(); }
+ bool EndArray(SizeType elementCount) { return out_.EndArray(elementCount); }
+
+ OutputHandler& out_;
+ std::vector<char> buffer_;
+
+private:
+ CapitalizeFilter(const CapitalizeFilter&);
+ CapitalizeFilter& operator=(const CapitalizeFilter&);
+};
+
+int main(int, char*[]) {
+ // Prepare JSON reader and input stream.
+ Reader reader;
+ char readBuffer[65536];
+ FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
+
+ // Prepare JSON writer and output stream.
+ char writeBuffer[65536];
+ FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
+ Writer<FileWriteStream> writer(os);
+
+ // JSON reader parse from the input stream and let writer generate the output.
+ CapitalizeFilter<Writer<FileWriteStream> > filter(writer);
+ if (!reader.Parse(is, filter)) {
+ fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/3rdparty/rapidjson/example/condense/condense.cpp b/3rdparty/rapidjson/example/condense/condense.cpp
new file mode 100644
index 00000000000..46dc3504397
--- /dev/null
+++ b/3rdparty/rapidjson/example/condense/condense.cpp
@@ -0,0 +1,32 @@
+// JSON condenser example
+
+// This example parses JSON text from stdin with validation,
+// and re-output the JSON content to stdout without whitespace.
+
+#include "rapidjson/reader.h"
+#include "rapidjson/writer.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/filewritestream.h"
+#include "rapidjson/error/en.h"
+
+using namespace rapidjson;
+
+int main(int, char*[]) {
+ // Prepare JSON reader and input stream.
+ Reader reader;
+ char readBuffer[65536];
+ FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
+
+ // Prepare JSON writer and output stream.
+ char writeBuffer[65536];
+ FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
+ Writer<FileWriteStream> writer(os);
+
+ // JSON reader parse from the input stream and let writer generate the output.
+ if (!reader.Parse(is, writer)) {
+ fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/3rdparty/rapidjson/example/jsonx/jsonx.cpp b/3rdparty/rapidjson/example/jsonx/jsonx.cpp
new file mode 100644
index 00000000000..c253ac096df
--- /dev/null
+++ b/3rdparty/rapidjson/example/jsonx/jsonx.cpp
@@ -0,0 +1,200 @@
+// JSON to JSONx conversion exmaple, using SAX API.
+// JSONx is an IBM standard format to represent JSON as XML.
+// https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html
+// This example parses JSON text from stdin with validation,
+// and convert to JSONx format to stdout.
+// Need compile with -D__STDC_FORMAT_MACROS for defining PRId64 and PRIu64 macros.
+
+#include "rapidjson/reader.h"
+#include "rapidjson/stringbuffer.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/filewritestream.h"
+#include "rapidjson/error/en.h"
+#include <cstdio>
+
+using namespace rapidjson;
+
+// For simplicity, this example only read/write in UTF-8 encoding
+template <typename OutputStream>
+class JsonxWriter {
+public:
+ JsonxWriter(OutputStream& os) : os_(os), name_(), level_(0), hasName_(false) {
+ }
+
+ bool Null() {
+ return WriteStartElement("null", true);
+ }
+
+ bool Bool(bool b) {
+ return
+ WriteStartElement("boolean") &&
+ WriteString(b ? "true" : "false") &&
+ WriteEndElement("boolean");
+ }
+
+ bool Int(int i) {
+ char buffer[12];
+ return WriteNumberElement(buffer, sprintf(buffer, "%d", i));
+ }
+
+ bool Uint(unsigned i) {
+ char buffer[11];
+ return WriteNumberElement(buffer, sprintf(buffer, "%u", i));
+ }
+
+ bool Int64(int64_t i) {
+ char buffer[21];
+ return WriteNumberElement(buffer, sprintf(buffer, "%" PRId64, i));
+ }
+
+ bool Uint64(uint64_t i) {
+ char buffer[21];
+ return WriteNumberElement(buffer, sprintf(buffer, "%" PRIu64, i));
+ }
+
+ bool Double(double d) {
+ char buffer[30];
+ return WriteNumberElement(buffer, sprintf(buffer, "%.17g", d));
+ }
+
+ bool String(const char* str, SizeType length, bool) {
+ return
+ WriteStartElement("string") &&
+ WriteEscapedText(str, length) &&
+ WriteEndElement("string");
+ }
+
+ bool StartObject() {
+ return WriteStartElement("object");
+ }
+
+ bool Key(const char* str, SizeType length, bool) {
+ // backup key to name_
+ name_.Clear();
+ for (SizeType i = 0; i < length; i++)
+ name_.Put(str[i]);
+ hasName_ = true;
+ return true;
+ }
+
+ bool EndObject(SizeType) {
+ return WriteEndElement("object");
+ }
+
+ bool StartArray() {
+ return WriteStartElement("array");
+ }
+
+ bool EndArray(SizeType) {
+ return WriteEndElement("array");
+ }
+
+private:
+ bool WriteString(const char* s) {
+ while (*s)
+ os_.Put(*s++);
+ return true;
+ }
+
+ bool WriteEscapedAttributeValue(const char* s, size_t length) {
+ for (size_t i = 0; i < length; i++) {
+ switch (s[i]) {
+ case '&': WriteString("&amp;"); break;
+ case '<': WriteString("&lt;"); break;
+ case '"': WriteString("&quot;"); break;
+ default: os_.Put(s[i]); break;
+ }
+ }
+ return true;
+ }
+
+ bool WriteEscapedText(const char* s, size_t length) {
+ for (size_t i = 0; i < length; i++) {
+ switch (s[i]) {
+ case '&': WriteString("&amp;"); break;
+ case '<': WriteString("&lt;"); break;
+ default: os_.Put(s[i]); break;
+ }
+ }
+ return true;
+ }
+
+ bool WriteStartElement(const char* type, bool emptyElement = false) {
+ if (level_ == 0)
+ if (!WriteString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"))
+ return false;
+
+ if (!WriteString("<json:") || !WriteString(type))
+ return false;
+
+ // For root element, need to add declarations
+ if (level_ == 0) {
+ if (!WriteString(
+ " xsi:schemaLocation=\"http://www.datapower.com/schemas/json jsonx.xsd\""
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
+ " xmlns:json=\"http://www.ibm.com/xmlns/prod/2009/jsonx\""))
+ return false;
+ }
+
+ if (hasName_) {
+ hasName_ = false;
+ if (!WriteString(" name=\"") ||
+ !WriteEscapedAttributeValue(name_.GetString(), name_.GetSize()) ||
+ !WriteString("\""))
+ return false;
+ }
+
+ if (emptyElement)
+ return WriteString("/>");
+ else {
+ level_++;
+ return WriteString(">");
+ }
+ }
+
+ bool WriteEndElement(const char* type) {
+ if (!WriteString("</json:") ||
+ !WriteString(type) ||
+ !WriteString(">"))
+ return false;
+
+ // For the last end tag, flush the output stream.
+ if (--level_ == 0)
+ os_.Flush();
+
+ return true;
+ }
+
+ bool WriteNumberElement(const char* buffer, int length) {
+ if (!WriteStartElement("number"))
+ return false;
+ for (int j = 0; j < length; j++)
+ os_.Put(buffer[j]);
+ return WriteEndElement("number");
+ }
+
+ OutputStream& os_;
+ StringBuffer name_;
+ unsigned level_;
+ bool hasName_;
+};
+
+int main(int, char*[]) {
+ // Prepare JSON reader and input stream.
+ Reader reader;
+ char readBuffer[65536];
+ FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
+
+ // Prepare JSON writer and output stream.
+ char writeBuffer[65536];
+ FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
+ JsonxWriter<FileWriteStream> writer(os);
+
+ // JSON reader parse from the input stream and let writer generate the output.
+ if (!reader.Parse(is, writer)) {
+ fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/3rdparty/rapidjson/example/messagereader/messagereader.cpp b/3rdparty/rapidjson/example/messagereader/messagereader.cpp
new file mode 100644
index 00000000000..3399bc9400e
--- /dev/null
+++ b/3rdparty/rapidjson/example/messagereader/messagereader.cpp
@@ -0,0 +1,105 @@
+// Reading a message JSON with Reader (SAX-style API).
+// The JSON should be an object with key-string pairs.
+
+#include "rapidjson/reader.h"
+#include "rapidjson/error/en.h"
+#include <iostream>
+#include <string>
+#include <map>
+
+using namespace std;
+using namespace rapidjson;
+
+typedef map<string, string> MessageMap;
+
+#if defined(__GNUC__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(switch-enum)
+#endif
+
+struct MessageHandler
+ : public BaseReaderHandler<UTF8<>, MessageHandler> {
+ MessageHandler() : messages_(), state_(kExpectObjectStart), name_() {}
+
+ bool StartObject() {
+ switch (state_) {
+ case kExpectObjectStart:
+ state_ = kExpectNameOrObjectEnd;
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool String(const char* str, SizeType length, bool) {
+ switch (state_) {
+ case kExpectNameOrObjectEnd:
+ name_ = string(str, length);
+ state_ = kExpectValue;
+ return true;
+ case kExpectValue:
+ messages_.insert(MessageMap::value_type(name_, string(str, length)));
+ state_ = kExpectNameOrObjectEnd;
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool EndObject(SizeType) { return state_ == kExpectNameOrObjectEnd; }
+
+ bool Default() { return false; } // All other events are invalid.
+
+ MessageMap messages_;
+ enum State {
+ kExpectObjectStart,
+ kExpectNameOrObjectEnd,
+ kExpectValue
+ }state_;
+ std::string name_;
+};
+
+#if defined(__GNUC__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+static void ParseMessages(const char* json, MessageMap& messages) {
+ Reader reader;
+ MessageHandler handler;
+ StringStream ss(json);
+ if (reader.Parse(ss, handler))
+ messages.swap(handler.messages_); // Only change it if success.
+ else {
+ ParseErrorCode e = reader.GetParseErrorCode();
+ size_t o = reader.GetErrorOffset();
+ cout << "Error: " << GetParseError_En(e) << endl;;
+ cout << " at offset " << o << " near '" << string(json).substr(o, 10) << "...'" << endl;
+ }
+}
+
+int main() {
+ MessageMap messages;
+
+ const char* json1 = "{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\" }";
+ cout << json1 << endl;
+ ParseMessages(json1, messages);
+
+ for (MessageMap::const_iterator itr = messages.begin(); itr != messages.end(); ++itr)
+ cout << itr->first << ": " << itr->second << endl;
+
+ cout << endl << "Parse a JSON with invalid schema." << endl;
+ const char* json2 = "{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\", \"foo\" : {} }";
+ cout << json2 << endl;
+ ParseMessages(json2, messages);
+
+ return 0;
+}
diff --git a/3rdparty/rapidjson/example/pretty/pretty.cpp b/3rdparty/rapidjson/example/pretty/pretty.cpp
new file mode 100644
index 00000000000..2feff5d02ea
--- /dev/null
+++ b/3rdparty/rapidjson/example/pretty/pretty.cpp
@@ -0,0 +1,30 @@
+// JSON pretty formatting example
+// This example can only handle UTF-8. For handling other encodings, see prettyauto example.
+
+#include "rapidjson/reader.h"
+#include "rapidjson/prettywriter.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/filewritestream.h"
+#include "rapidjson/error/en.h"
+
+using namespace rapidjson;
+
+int main(int, char*[]) {
+ // Prepare reader and input stream.
+ Reader reader;
+ char readBuffer[65536];
+ FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
+
+ // Prepare writer and output stream.
+ char writeBuffer[65536];
+ FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
+ PrettyWriter<FileWriteStream> writer(os);
+
+ // JSON reader parse from the input stream and let writer generate the output.
+ if (!reader.Parse<kParseValidateEncodingFlag>(is, writer)) {
+ fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/3rdparty/rapidjson/example/prettyauto/prettyauto.cpp b/3rdparty/rapidjson/example/prettyauto/prettyauto.cpp
new file mode 100644
index 00000000000..1687bae5559
--- /dev/null
+++ b/3rdparty/rapidjson/example/prettyauto/prettyauto.cpp
@@ -0,0 +1,56 @@
+// JSON pretty formatting example
+// This example can handle UTF-8/UTF-16LE/UTF-16BE/UTF-32LE/UTF-32BE.
+// The input firstly convert to UTF8, and then write to the original encoding with pretty formatting.
+
+#include "rapidjson/reader.h"
+#include "rapidjson/prettywriter.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/filewritestream.h"
+#include "rapidjson/encodedstream.h" // NEW
+#include "rapidjson/error/en.h"
+#ifdef _WIN32
+#include <fcntl.h>
+#include <io.h>
+#endif
+
+using namespace rapidjson;
+
+int main(int, char*[]) {
+#ifdef _WIN32
+ // Prevent Windows converting between CR+LF and LF
+ _setmode(_fileno(stdin), _O_BINARY); // NEW
+ _setmode(_fileno(stdout), _O_BINARY); // NEW
+#endif
+
+ // Prepare reader and input stream.
+ //Reader reader;
+ GenericReader<AutoUTF<unsigned>, UTF8<> > reader; // CHANGED
+ char readBuffer[65536];
+ FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
+ AutoUTFInputStream<unsigned, FileReadStream> eis(is); // NEW
+
+ // Prepare writer and output stream.
+ char writeBuffer[65536];
+ FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
+
+#if 1
+ // Use the same Encoding of the input. Also use BOM according to input.
+ typedef AutoUTFOutputStream<unsigned, FileWriteStream> OutputStream; // NEW
+ OutputStream eos(os, eis.GetType(), eis.HasBOM()); // NEW
+ PrettyWriter<OutputStream, UTF8<>, AutoUTF<unsigned> > writer(eos); // CHANGED
+#else
+ // You may also use static bound encoding type, such as output to UTF-16LE with BOM
+ typedef EncodedOutputStream<UTF16LE<>,FileWriteStream> OutputStream; // NEW
+ OutputStream eos(os, true); // NEW
+ PrettyWriter<OutputStream, UTF8<>, UTF16LE<> > writer(eos); // CHANGED
+#endif
+
+ // JSON reader parse from the input stream and let writer generate the output.
+ //if (!reader.Parse<kParseValidateEncodingFlag>(is, writer)) {
+ if (!reader.Parse<kParseValidateEncodingFlag>(eis, writer)) { // CHANGED
+ fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/3rdparty/rapidjson/example/schemavalidator/schemavalidator.cpp b/3rdparty/rapidjson/example/schemavalidator/schemavalidator.cpp
new file mode 100644
index 00000000000..ce36ea95f00
--- /dev/null
+++ b/3rdparty/rapidjson/example/schemavalidator/schemavalidator.cpp
@@ -0,0 +1,72 @@
+// Schema Validator example
+
+// The example validates JSON text from stdin with a JSON schema specified in the argument.
+
+#include "rapidjson/error/en.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/schema.h"
+#include "rapidjson/stringbuffer.h"
+
+using namespace rapidjson;
+
+int main(int argc, char *argv[]) {
+ if (argc != 2) {
+ fprintf(stderr, "Usage: schemavalidator schema.json < input.json\n");
+ return EXIT_FAILURE;
+ }
+
+ // Read a JSON schema from file into Document
+ Document d;
+ char buffer[4096];
+
+ {
+ FILE *fp = fopen(argv[1], "r");
+ if (!fp) {
+ printf("Schema file '%s' not found\n", argv[1]);
+ return -1;
+ }
+ FileReadStream fs(fp, buffer, sizeof(buffer));
+ d.ParseStream(fs);
+ if (d.HasParseError()) {
+ fprintf(stderr, "Schema file '%s' is not a valid JSON\n", argv[1]);
+ fprintf(stderr, "Error(offset %u): %s\n",
+ static_cast<unsigned>(d.GetErrorOffset()),
+ GetParseError_En(d.GetParseError()));
+ fclose(fp);
+ return EXIT_FAILURE;
+ }
+ fclose(fp);
+ }
+
+ // Then convert the Document into SchemaDocument
+ SchemaDocument sd(d);
+
+ // Use reader to parse the JSON in stdin, and forward SAX events to validator
+ SchemaValidator validator(sd);
+ Reader reader;
+ FileReadStream is(stdin, buffer, sizeof(buffer));
+ if (!reader.Parse(is, validator) && reader.GetParseErrorCode() != kParseErrorTermination) {
+ // Schema validator error would cause kParseErrorTermination, which will handle it in next step.
+ fprintf(stderr, "Input is not a valid JSON\n");
+ fprintf(stderr, "Error(offset %u): %s\n",
+ static_cast<unsigned>(reader.GetErrorOffset()),
+ GetParseError_En(reader.GetParseErrorCode()));
+ }
+
+ // Check the validation result
+ if (validator.IsValid()) {
+ printf("Input JSON is valid.\n");
+ return EXIT_SUCCESS;
+ }
+ else {
+ printf("Input JSON is invalid.\n");
+ StringBuffer sb;
+ validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
+ fprintf(stderr, "Invalid schema: %s\n", sb.GetString());
+ fprintf(stderr, "Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
+ sb.Clear();
+ validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
+ fprintf(stderr, "Invalid document: %s\n", sb.GetString());
+ return EXIT_FAILURE;
+ }
+}
diff --git a/3rdparty/rapidjson/example/serialize/serialize.cpp b/3rdparty/rapidjson/example/serialize/serialize.cpp
new file mode 100644
index 00000000000..12d87151e64
--- /dev/null
+++ b/3rdparty/rapidjson/example/serialize/serialize.cpp
@@ -0,0 +1,173 @@
+// Serialize example
+// This example shows writing JSON string with writer directly.
+
+#include "rapidjson/prettywriter.h" // for stringify JSON
+#include <cstdio>
+#include <string>
+#include <vector>
+
+using namespace rapidjson;
+
+class Person {
+public:
+ Person(const std::string& name, unsigned age) : name_(name), age_(age) {}
+ Person(const Person& rhs) : name_(rhs.name_), age_(rhs.age_) {}
+ virtual ~Person();
+
+ Person& operator=(const Person& rhs) {
+ name_ = rhs.name_;
+ age_ = rhs.age_;
+ return *this;
+ }
+
+protected:
+ template <typename Writer>
+ void Serialize(Writer& writer) const {
+ // This base class just write out name-value pairs, without wrapping within an object.
+ writer.String("name");
+#if RAPIDJSON_HAS_STDSTRING
+ writer.String(name_);
+#else
+ writer.String(name_.c_str(), static_cast<SizeType>(name_.length())); // Supplying length of string is faster.
+#endif
+ writer.String("age");
+ writer.Uint(age_);
+ }
+
+private:
+ std::string name_;
+ unsigned age_;
+};
+
+Person::~Person() {
+}
+
+class Education {
+public:
+ Education(const std::string& school, double GPA) : school_(school), GPA_(GPA) {}
+ Education(const Education& rhs) : school_(rhs.school_), GPA_(rhs.GPA_) {}
+
+ template <typename Writer>
+ void Serialize(Writer& writer) const {
+ writer.StartObject();
+
+ writer.String("school");
+#if RAPIDJSON_HAS_STDSTRING
+ writer.String(school_);
+#else
+ writer.String(school_.c_str(), static_cast<SizeType>(school_.length()));
+#endif
+
+ writer.String("GPA");
+ writer.Double(GPA_);
+
+ writer.EndObject();
+ }
+
+private:
+ std::string school_;
+ double GPA_;
+};
+
+class Dependent : public Person {
+public:
+ Dependent(const std::string& name, unsigned age, Education* education = 0) : Person(name, age), education_(education) {}
+ Dependent(const Dependent& rhs) : Person(rhs), education_(0) { education_ = (rhs.education_ == 0) ? 0 : new Education(*rhs.education_); }
+ virtual ~Dependent();
+
+ Dependent& operator=(const Dependent& rhs) {
+ if (this == &rhs)
+ return *this;
+ delete education_;
+ education_ = (rhs.education_ == 0) ? 0 : new Education(*rhs.education_);
+ return *this;
+ }
+
+ template <typename Writer>
+ void Serialize(Writer& writer) const {
+ writer.StartObject();
+
+ Person::Serialize(writer);
+
+ writer.String("education");
+ if (education_)
+ education_->Serialize(writer);
+ else
+ writer.Null();
+
+ writer.EndObject();
+ }
+
+private:
+
+ Education *education_;
+};
+
+Dependent::~Dependent() {
+ delete education_;
+}
+
+class Employee : public Person {
+public:
+ Employee(const std::string& name, unsigned age, bool married) : Person(name, age), dependents_(), married_(married) {}
+ Employee(const Employee& rhs) : Person(rhs), dependents_(rhs.dependents_), married_(rhs.married_) {}
+ virtual ~Employee();
+
+ Employee& operator=(const Employee& rhs) {
+ static_cast<Person&>(*this) = rhs;
+ dependents_ = rhs.dependents_;
+ married_ = rhs.married_;
+ return *this;
+ }
+
+ void AddDependent(const Dependent& dependent) {
+ dependents_.push_back(dependent);
+ }
+
+ template <typename Writer>
+ void Serialize(Writer& writer) const {
+ writer.StartObject();
+
+ Person::Serialize(writer);
+
+ writer.String("married");
+ writer.Bool(married_);
+
+ writer.String(("dependents"));
+ writer.StartArray();
+ for (std::vector<Dependent>::const_iterator dependentItr = dependents_.begin(); dependentItr != dependents_.end(); ++dependentItr)
+ dependentItr->Serialize(writer);
+ writer.EndArray();
+
+ writer.EndObject();
+ }
+
+private:
+ std::vector<Dependent> dependents_;
+ bool married_;
+};
+
+Employee::~Employee() {
+}
+
+int main(int, char*[]) {
+ std::vector<Employee> employees;
+
+ employees.push_back(Employee("Milo YIP", 34, true));
+ employees.back().AddDependent(Dependent("Lua YIP", 3, new Education("Happy Kindergarten", 3.5)));
+ employees.back().AddDependent(Dependent("Mio YIP", 1));
+
+ employees.push_back(Employee("Percy TSE", 30, false));
+
+ StringBuffer sb;
+ PrettyWriter<StringBuffer> writer(sb);
+
+ writer.StartArray();
+ for (std::vector<Employee>::const_iterator employeeItr = employees.begin(); employeeItr != employees.end(); ++employeeItr)
+ employeeItr->Serialize(writer);
+ writer.EndArray();
+
+ puts(sb.GetString());
+
+ return 0;
+}
diff --git a/3rdparty/rapidjson/example/simpledom/simpledom.cpp b/3rdparty/rapidjson/example/simpledom/simpledom.cpp
new file mode 100644
index 00000000000..80384199a92
--- /dev/null
+++ b/3rdparty/rapidjson/example/simpledom/simpledom.cpp
@@ -0,0 +1,29 @@
+// JSON simple example
+// This example does not handle errors.
+
+#include "rapidjson/document.h"
+#include "rapidjson/writer.h"
+#include "rapidjson/stringbuffer.h"
+#include <iostream>
+
+using namespace rapidjson;
+
+int main() {
+ // 1. Parse a JSON string into DOM.
+ const char* json = "{\"project\":\"rapidjson\",\"stars\":10}";
+ Document d;
+ d.Parse(json);
+
+ // 2. Modify it by DOM.
+ Value& s = d["stars"];
+ s.SetInt(s.GetInt() + 1);
+
+ // 3. Stringify the DOM
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ d.Accept(writer);
+
+ // Output {"project":"rapidjson","stars":11}
+ std::cout << buffer.GetString() << std::endl;
+ return 0;
+}
diff --git a/3rdparty/rapidjson/example/simplereader/simplereader.cpp b/3rdparty/rapidjson/example/simplereader/simplereader.cpp
new file mode 100644
index 00000000000..edbdb6352c5
--- /dev/null
+++ b/3rdparty/rapidjson/example/simplereader/simplereader.cpp
@@ -0,0 +1,38 @@
+#include "rapidjson/reader.h"
+#include <iostream>
+
+using namespace rapidjson;
+using namespace std;
+
+struct MyHandler {
+ bool Null() { cout << "Null()" << endl; return true; }
+ bool Bool(bool b) { cout << "Bool(" << boolalpha << b << ")" << endl; return true; }
+ bool Int(int i) { cout << "Int(" << i << ")" << endl; return true; }
+ bool Uint(unsigned u) { cout << "Uint(" << u << ")" << endl; return true; }
+ bool Int64(int64_t i) { cout << "Int64(" << i << ")" << endl; return true; }
+ bool Uint64(uint64_t u) { cout << "Uint64(" << u << ")" << endl; return true; }
+ bool Double(double d) { cout << "Double(" << d << ")" << endl; return true; }
+ bool String(const char* str, SizeType length, bool copy) {
+ cout << "String(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
+ return true;
+ }
+ bool StartObject() { cout << "StartObject()" << endl; return true; }
+ bool Key(const char* str, SizeType length, bool copy) {
+ cout << "Key(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
+ return true;
+ }
+ bool EndObject(SizeType memberCount) { cout << "EndObject(" << memberCount << ")" << endl; return true; }
+ bool StartArray() { cout << "StartArray()" << endl; return true; }
+ bool EndArray(SizeType elementCount) { cout << "EndArray(" << elementCount << ")" << endl; return true; }
+};
+
+int main() {
+ const char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";
+
+ MyHandler handler;
+ Reader reader;
+ StringStream ss(json);
+ reader.Parse(ss, handler);
+
+ return 0;
+}
diff --git a/3rdparty/rapidjson/example/simplewriter/simplewriter.cpp b/3rdparty/rapidjson/example/simplewriter/simplewriter.cpp
new file mode 100644
index 00000000000..f8891504bc8
--- /dev/null
+++ b/3rdparty/rapidjson/example/simplewriter/simplewriter.cpp
@@ -0,0 +1,35 @@
+#include "rapidjson/writer.h"
+#include "rapidjson/stringbuffer.h"
+#include <iostream>
+
+using namespace rapidjson;
+using namespace std;
+
+int main() {
+ StringBuffer s;
+ Writer<StringBuffer> writer(s);
+
+ writer.StartObject();
+ writer.String("hello");
+ writer.String("world");
+ writer.String("t");
+ writer.Bool(true);
+ writer.String("f");
+ writer.Bool(false);
+ writer.String("n");
+ writer.Null();
+ writer.String("i");
+ writer.Uint(123);
+ writer.String("pi");
+ writer.Double(3.1416);
+ writer.String("a");
+ writer.StartArray();
+ for (unsigned i = 0; i < 4; i++)
+ writer.Uint(i);
+ writer.EndArray();
+ writer.EndObject();
+
+ cout << s.GetString() << endl;
+
+ return 0;
+}
diff --git a/3rdparty/rapidjson/example/tutorial/tutorial.cpp b/3rdparty/rapidjson/example/tutorial/tutorial.cpp
new file mode 100644
index 00000000000..c8bfcc14c18
--- /dev/null
+++ b/3rdparty/rapidjson/example/tutorial/tutorial.cpp
@@ -0,0 +1,151 @@
+// Hello World example
+// This example shows basic usage of DOM-style API.
+
+#include "rapidjson/document.h" // rapidjson's DOM-style API
+#include "rapidjson/prettywriter.h" // for stringify JSON
+#include <cstdio>
+
+using namespace rapidjson;
+using namespace std;
+
+int main(int, char*[]) {
+ ////////////////////////////////////////////////////////////////////////////
+ // 1. Parse a JSON text string to a document.
+
+ const char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";
+ printf("Original JSON:\n %s\n", json);
+
+ Document document; // Default template parameter uses UTF8 and MemoryPoolAllocator.
+
+#if 0
+ // "normal" parsing, decode strings to new buffers. Can use other input stream via ParseStream().
+ if (document.Parse(json).HasParseError())
+ return 1;
+#else
+ // In-situ parsing, decode strings directly in the source string. Source must be string.
+ char buffer[sizeof(json)];
+ memcpy(buffer, json, sizeof(json));
+ if (document.ParseInsitu(buffer).HasParseError())
+ return 1;
+#endif
+
+ printf("\nParsing to document succeeded.\n");
+
+ ////////////////////////////////////////////////////////////////////////////
+ // 2. Access values in document.
+
+ printf("\nAccess values in document:\n");
+ assert(document.IsObject()); // Document is a JSON value represents the root of DOM. Root can be either an object or array.
+
+ assert(document.HasMember("hello"));
+ assert(document["hello"].IsString());
+ printf("hello = %s\n", document["hello"].GetString());
+
+ // Since version 0.2, you can use single lookup to check the existing of member and its value:
+ Value::MemberIterator hello = document.FindMember("hello");
+ assert(hello != document.MemberEnd());
+ assert(hello->value.IsString());
+ assert(strcmp("world", hello->value.GetString()) == 0);
+ (void)hello;
+
+ assert(document["t"].IsBool()); // JSON true/false are bool. Can also uses more specific function IsTrue().
+ printf("t = %s\n", document["t"].GetBool() ? "true" : "false");
+
+ assert(document["f"].IsBool());
+ printf("f = %s\n", document["f"].GetBool() ? "true" : "false");
+
+ printf("n = %s\n", document["n"].IsNull() ? "null" : "?");
+
+ assert(document["i"].IsNumber()); // Number is a JSON type, but C++ needs more specific type.
+ assert(document["i"].IsInt()); // In this case, IsUint()/IsInt64()/IsUInt64() also return true.
+ printf("i = %d\n", document["i"].GetInt()); // Alternative (int)document["i"]
+
+ assert(document["pi"].IsNumber());
+ assert(document["pi"].IsDouble());
+ printf("pi = %g\n", document["pi"].GetDouble());
+
+ {
+ const Value& a = document["a"]; // Using a reference for consecutive access is handy and faster.
+ assert(a.IsArray());
+ for (SizeType i = 0; i < a.Size(); i++) // rapidjson uses SizeType instead of size_t.
+ printf("a[%d] = %d\n", i, a[i].GetInt());
+
+ int y = a[0].GetInt();
+ (void)y;
+
+ // Iterating array with iterators
+ printf("a = ");
+ for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
+ printf("%d ", itr->GetInt());
+ printf("\n");
+ }
+
+ // Iterating object members
+ static const char* kTypeNames[] = { "Null", "False", "True", "Object", "Array", "String", "Number" };
+ for (Value::ConstMemberIterator itr = document.MemberBegin(); itr != document.MemberEnd(); ++itr)
+ printf("Type of member %s is %s\n", itr->name.GetString(), kTypeNames[itr->value.GetType()]);
+
+ ////////////////////////////////////////////////////////////////////////////
+ // 3. Modify values in document.
+
+ // Change i to a bigger number
+ {
+ uint64_t f20 = 1; // compute factorial of 20
+ for (uint64_t j = 1; j <= 20; j++)
+ f20 *= j;
+ document["i"] = f20; // Alternate form: document["i"].SetUint64(f20)
+ assert(!document["i"].IsInt()); // No longer can be cast as int or uint.
+ }
+
+ // Adding values to array.
+ {
+ Value& a = document["a"]; // This time we uses non-const reference.
+ Document::AllocatorType& allocator = document.GetAllocator();
+ for (int i = 5; i <= 10; i++)
+ a.PushBack(i, allocator); // May look a bit strange, allocator is needed for potentially realloc. We normally uses the document's.
+
+ // Fluent API
+ a.PushBack("Lua", allocator).PushBack("Mio", allocator);
+ }
+
+ // Making string values.
+
+ // This version of SetString() just store the pointer to the string.
+ // So it is for literal and string that exists within value's life-cycle.
+ {
+ document["hello"] = "rapidjson"; // This will invoke strlen()
+ // Faster version:
+ // document["hello"].SetString("rapidjson", 9);
+ }
+
+ // This version of SetString() needs an allocator, which means it will allocate a new buffer and copy the the string into the buffer.
+ Value author;
+ {
+ char buffer2[10];
+ int len = sprintf(buffer2, "%s %s", "Milo", "Yip"); // synthetic example of dynamically created string.
+
+ author.SetString(buffer2, static_cast<SizeType>(len), document.GetAllocator());
+ // Shorter but slower version:
+ // document["hello"].SetString(buffer, document.GetAllocator());
+
+ // Constructor version:
+ // Value author(buffer, len, document.GetAllocator());
+ // Value author(buffer, document.GetAllocator());
+ memset(buffer2, 0, sizeof(buffer2)); // For demonstration purpose.
+ }
+ // Variable 'buffer' is unusable now but 'author' has already made a copy.
+ document.AddMember("author", author, document.GetAllocator());
+
+ assert(author.IsNull()); // Move semantic for assignment. After this variable is assigned as a member, the variable becomes null.
+
+ ////////////////////////////////////////////////////////////////////////////
+ // 4. Stringify JSON
+
+ printf("\nModified JSON with reformatting:\n");
+ StringBuffer sb;
+ PrettyWriter<StringBuffer> writer(sb);
+ document.Accept(writer); // Accept() traverses the DOM and generates Handler events.
+ puts(sb.GetString());
+
+ return 0;
+}
diff --git a/3rdparty/rapidjson/include/rapidjson/allocators.h b/3rdparty/rapidjson/include/rapidjson/allocators.h
new file mode 100644
index 00000000000..c705969729a
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/allocators.h
@@ -0,0 +1,263 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ALLOCATORS_H_
+#define RAPIDJSON_ALLOCATORS_H_
+
+#include "rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Allocator
+
+/*! \class rapidjson::Allocator
+ \brief Concept for allocating, resizing and freeing memory block.
+
+ Note that Malloc() and Realloc() are non-static but Free() is static.
+
+ So if an allocator need to support Free(), it needs to put its pointer in
+ the header of memory block.
+
+\code
+concept Allocator {
+ static const bool kNeedFree; //!< Whether this allocator needs to call Free().
+
+ // Allocate a memory block.
+ // \param size of the memory block in bytes.
+ // \returns pointer to the memory block.
+ void* Malloc(size_t size);
+
+ // Resize a memory block.
+ // \param originalPtr The pointer to current memory block. Null pointer is permitted.
+ // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
+ // \param newSize the new size in bytes.
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
+
+ // Free a memory block.
+ // \param pointer to the memory block. Null pointer is permitted.
+ static void Free(void *ptr);
+};
+\endcode
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// CrtAllocator
+
+//! C-runtime library allocator.
+/*! This class is just wrapper for standard C library memory routines.
+ \note implements Allocator concept
+*/
+class CrtAllocator {
+public:
+ static const bool kNeedFree = true;
+ void* Malloc(size_t size) {
+ if (size) // behavior of malloc(0) is implementation defined.
+ return std::malloc(size);
+ else
+ return NULL; // standardize to returning NULL.
+ }
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
+ (void)originalSize;
+ if (newSize == 0) {
+ std::free(originalPtr);
+ return NULL;
+ }
+ return std::realloc(originalPtr, newSize);
+ }
+ static void Free(void *ptr) { std::free(ptr); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// MemoryPoolAllocator
+
+//! Default memory allocator used by the parser and DOM.
+/*! This allocator allocate memory blocks from pre-allocated memory chunks.
+
+ It does not free memory blocks. And Realloc() only allocate new memory.
+
+ The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
+
+ User may also supply a buffer as the first chunk.
+
+ If the user-buffer is full then additional chunks are allocated by BaseAllocator.
+
+ The user-buffer is not deallocated by this allocator.
+
+ \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
+ \note implements Allocator concept
+*/
+template <typename BaseAllocator = CrtAllocator>
+class MemoryPoolAllocator {
+public:
+ static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
+
+ //! Constructor with chunkSize.
+ /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
+ \param baseAllocator The allocator for allocating memory chunks.
+ */
+ MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
+ chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+ {
+ }
+
+ //! Constructor with user-supplied buffer.
+ /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
+
+ The user buffer will not be deallocated when this allocator is destructed.
+
+ \param buffer User supplied buffer.
+ \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
+ \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
+ \param baseAllocator The allocator for allocating memory chunks.
+ */
+ MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
+ chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+ {
+ RAPIDJSON_ASSERT(buffer != 0);
+ RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
+ chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
+ chunkHead_->capacity = size - sizeof(ChunkHeader);
+ chunkHead_->size = 0;
+ chunkHead_->next = 0;
+ }
+
+ //! Destructor.
+ /*! This deallocates all memory chunks, excluding the user-supplied buffer.
+ */
+ ~MemoryPoolAllocator() {
+ Clear();
+ RAPIDJSON_DELETE(ownBaseAllocator_);
+ }
+
+ //! Deallocates all memory chunks, excluding the user-supplied buffer.
+ void Clear() {
+ while (chunkHead_ && chunkHead_ != userBuffer_) {
+ ChunkHeader* next = chunkHead_->next;
+ baseAllocator_->Free(chunkHead_);
+ chunkHead_ = next;
+ }
+ if (chunkHead_ && chunkHead_ == userBuffer_)
+ chunkHead_->size = 0; // Clear user buffer
+ }
+
+ //! Computes the total capacity of allocated memory chunks.
+ /*! \return total capacity in bytes.
+ */
+ size_t Capacity() const {
+ size_t capacity = 0;
+ for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+ capacity += c->capacity;
+ return capacity;
+ }
+
+ //! Computes the memory blocks allocated.
+ /*! \return total used bytes.
+ */
+ size_t Size() const {
+ size_t size = 0;
+ for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+ size += c->size;
+ return size;
+ }
+
+ //! Allocates a memory block. (concept Allocator)
+ void* Malloc(size_t size) {
+ if (!size)
+ return NULL;
+
+ size = RAPIDJSON_ALIGN(size);
+ if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
+ AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
+
+ void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
+ chunkHead_->size += size;
+ return buffer;
+ }
+
+ //! Resizes a memory block (concept Allocator)
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
+ if (originalPtr == 0)
+ return Malloc(newSize);
+
+ if (newSize == 0)
+ return NULL;
+
+ originalSize = RAPIDJSON_ALIGN(originalSize);
+ newSize = RAPIDJSON_ALIGN(newSize);
+
+ // Do not shrink if new size is smaller than original
+ if (originalSize >= newSize)
+ return originalPtr;
+
+ // Simply expand it if it is the last allocation and there is sufficient space
+ if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
+ size_t increment = static_cast<size_t>(newSize - originalSize);
+ if (chunkHead_->size + increment <= chunkHead_->capacity) {
+ chunkHead_->size += increment;
+ return originalPtr;
+ }
+ }
+
+ // Realloc process: allocate and copy memory, do not free original buffer.
+ void* newBuffer = Malloc(newSize);
+ RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly.
+ if (originalSize)
+ std::memcpy(newBuffer, originalPtr, originalSize);
+ return newBuffer;
+ }
+
+ //! Frees a memory block (concept Allocator)
+ static void Free(void *ptr) { (void)ptr; } // Do nothing
+
+private:
+ //! Copy constructor is not permitted.
+ MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
+ //! Copy assignment operator is not permitted.
+ MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
+
+ //! Creates a new chunk.
+ /*! \param capacity Capacity of the chunk in bytes.
+ */
+ void AddChunk(size_t capacity) {
+ if (!baseAllocator_)
+ ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
+ ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity));
+ chunk->capacity = capacity;
+ chunk->size = 0;
+ chunk->next = chunkHead_;
+ chunkHead_ = chunk;
+ }
+
+ static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
+
+ //! Chunk header for perpending to each chunk.
+ /*! Chunks are stored as a singly linked list.
+ */
+ struct ChunkHeader {
+ size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
+ size_t size; //!< Current size of allocated memory in bytes.
+ ChunkHeader *next; //!< Next chunk in the linked list.
+ };
+
+ ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
+ size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
+ void *userBuffer_; //!< User supplied buffer.
+ BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
+ BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ENCODINGS_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/document.h b/3rdparty/rapidjson/include/rapidjson/document.h
new file mode 100644
index 00000000000..b3c9e0667e6
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/document.h
@@ -0,0 +1,2189 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_DOCUMENT_H_
+#define RAPIDJSON_DOCUMENT_H_
+
+/*! \file document.h */
+
+#include "reader.h"
+#include "internal/meta.h"
+#include "internal/strfunc.h"
+#include <new> // placement new
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(switch-enum)
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
+#include <iterator> // std::iterator, std::random_access_iterator_tag
+#endif
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#include <utility> // std::move
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+// Forward declaration.
+template <typename Encoding, typename Allocator>
+class GenericValue;
+
+template <typename Encoding, typename Allocator, typename StackAllocator>
+class GenericDocument;
+
+//! Name-value pair in a JSON object value.
+/*!
+ This class was internal to GenericValue. It used to be a inner struct.
+ But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct.
+ https://code.google.com/p/rapidjson/issues/detail?id=64
+*/
+template <typename Encoding, typename Allocator>
+struct GenericMember {
+ GenericValue<Encoding, Allocator> name; //!< name of member (must be a string)
+ GenericValue<Encoding, Allocator> value; //!< value of member.
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericMemberIterator
+
+#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
+
+//! (Constant) member iterator for a JSON object value
+/*!
+ \tparam Const Is this a constant iterator?
+ \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
+ \tparam Allocator Allocator type for allocating memory of object, array and string.
+
+ This class implements a Random Access Iterator for GenericMember elements
+ of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements].
+
+ \note This iterator implementation is mainly intended to avoid implicit
+ conversions from iterator values to \c NULL,
+ e.g. from GenericValue::FindMember.
+
+ \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a
+ pointer-based implementation, if your platform doesn't provide
+ the C++ <iterator> header.
+
+ \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator
+ */
+template <bool Const, typename Encoding, typename Allocator>
+class GenericMemberIterator
+ : public std::iterator<std::random_access_iterator_tag
+ , typename internal::MaybeAddConst<Const,GenericMember<Encoding,Allocator> >::Type> {
+
+ friend class GenericValue<Encoding,Allocator>;
+ template <bool, typename, typename> friend class GenericMemberIterator;
+
+ typedef GenericMember<Encoding,Allocator> PlainType;
+ typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
+ typedef std::iterator<std::random_access_iterator_tag,ValueType> BaseType;
+
+public:
+ //! Iterator type itself
+ typedef GenericMemberIterator Iterator;
+ //! Constant iterator type
+ typedef GenericMemberIterator<true,Encoding,Allocator> ConstIterator;
+ //! Non-constant iterator type
+ typedef GenericMemberIterator<false,Encoding,Allocator> NonConstIterator;
+
+ //! Pointer to (const) GenericMember
+ typedef typename BaseType::pointer Pointer;
+ //! Reference to (const) GenericMember
+ typedef typename BaseType::reference Reference;
+ //! Signed integer type (e.g. \c ptrdiff_t)
+ typedef typename BaseType::difference_type DifferenceType;
+
+ //! Default constructor (singular value)
+ /*! Creates an iterator pointing to no element.
+ \note All operations, except for comparisons, are undefined on such values.
+ */
+ GenericMemberIterator() : ptr_() {}
+
+ //! Iterator conversions to more const
+ /*!
+ \param it (Non-const) iterator to copy from
+
+ Allows the creation of an iterator from another GenericMemberIterator
+ that is "less const". Especially, creating a non-constant iterator
+ from a constant iterator are disabled:
+ \li const -> non-const (not ok)
+ \li const -> const (ok)
+ \li non-const -> const (ok)
+ \li non-const -> non-const (ok)
+
+ \note If the \c Const template parameter is already \c false, this
+ constructor effectively defines a regular copy-constructor.
+ Otherwise, the copy constructor is implicitly defined.
+ */
+ GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {}
+ Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; }
+
+ //! @name stepping
+ //@{
+ Iterator& operator++(){ ++ptr_; return *this; }
+ Iterator& operator--(){ --ptr_; return *this; }
+ Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; }
+ Iterator operator--(int){ Iterator old(*this); --ptr_; return old; }
+ //@}
+
+ //! @name increment/decrement
+ //@{
+ Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); }
+ Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); }
+
+ Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; }
+ Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; }
+ //@}
+
+ //! @name relations
+ //@{
+ bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; }
+ bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; }
+ bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; }
+ bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; }
+ bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; }
+ bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; }
+ //@}
+
+ //! @name dereference
+ //@{
+ Reference operator*() const { return *ptr_; }
+ Pointer operator->() const { return ptr_; }
+ Reference operator[](DifferenceType n) const { return ptr_[n]; }
+ //@}
+
+ //! Distance
+ DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; }
+
+private:
+ //! Internal constructor from plain pointer
+ explicit GenericMemberIterator(Pointer p) : ptr_(p) {}
+
+ Pointer ptr_; //!< raw pointer
+};
+
+#else // RAPIDJSON_NOMEMBERITERATORCLASS
+
+// class-based member iterator implementation disabled, use plain pointers
+
+template <bool Const, typename Encoding, typename Allocator>
+struct GenericMemberIterator;
+
+//! non-const GenericMemberIterator
+template <typename Encoding, typename Allocator>
+struct GenericMemberIterator<false,Encoding,Allocator> {
+ //! use plain pointer as iterator type
+ typedef GenericMember<Encoding,Allocator>* Iterator;
+};
+//! const GenericMemberIterator
+template <typename Encoding, typename Allocator>
+struct GenericMemberIterator<true,Encoding,Allocator> {
+ //! use plain const pointer as iterator type
+ typedef const GenericMember<Encoding,Allocator>* Iterator;
+};
+
+#endif // RAPIDJSON_NOMEMBERITERATORCLASS
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericStringRef
+
+//! Reference to a constant string (not taking a copy)
+/*!
+ \tparam CharType character type of the string
+
+ This helper class is used to automatically infer constant string
+ references for string literals, especially from \c const \b (!)
+ character arrays.
+
+ The main use is for creating JSON string values without copying the
+ source string via an \ref Allocator. This requires that the referenced
+ string pointers have a sufficient lifetime, which exceeds the lifetime
+ of the associated GenericValue.
+
+ \b Example
+ \code
+ Value v("foo"); // ok, no need to copy & calculate length
+ const char foo[] = "foo";
+ v.SetString(foo); // ok
+
+ const char* bar = foo;
+ // Value x(bar); // not ok, can't rely on bar's lifetime
+ Value x(StringRef(bar)); // lifetime explicitly guaranteed by user
+ Value y(StringRef(bar, 3)); // ok, explicitly pass length
+ \endcode
+
+ \see StringRef, GenericValue::SetString
+*/
+template<typename CharType>
+struct GenericStringRef {
+ typedef CharType Ch; //!< character type of the string
+
+ //! Create string reference from \c const character array
+#ifndef __clang__ // -Wdocumentation
+ /*!
+ This constructor implicitly creates a constant string reference from
+ a \c const character array. It has better performance than
+ \ref StringRef(const CharType*) by inferring the string \ref length
+ from the array length, and also supports strings containing null
+ characters.
+
+ \tparam N length of the string, automatically inferred
+
+ \param str Constant character array, lifetime assumed to be longer
+ than the use of the string in e.g. a GenericValue
+
+ \post \ref s == str
+
+ \note Constant complexity.
+ \note There is a hidden, private overload to disallow references to
+ non-const character arrays to be created via this constructor.
+ By this, e.g. function-scope arrays used to be filled via
+ \c snprintf are excluded from consideration.
+ In such cases, the referenced string should be \b copied to the
+ GenericValue instead.
+ */
+#endif
+ template<SizeType N>
+ GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT
+ : s(str), length(N-1) {}
+
+ //! Explicitly create string reference from \c const character pointer
+#ifndef __clang__ // -Wdocumentation
+ /*!
+ This constructor can be used to \b explicitly create a reference to
+ a constant string pointer.
+
+ \see StringRef(const CharType*)
+
+ \param str Constant character pointer, lifetime assumed to be longer
+ than the use of the string in e.g. a GenericValue
+
+ \post \ref s == str
+
+ \note There is a hidden, private overload to disallow references to
+ non-const character arrays to be created via this constructor.
+ By this, e.g. function-scope arrays used to be filled via
+ \c snprintf are excluded from consideration.
+ In such cases, the referenced string should be \b copied to the
+ GenericValue instead.
+ */
+#endif
+ explicit GenericStringRef(const CharType* str)
+ : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != NULL); }
+
+ //! Create constant string reference from pointer and length
+#ifndef __clang__ // -Wdocumentation
+ /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+ \param len length of the string, excluding the trailing NULL terminator
+
+ \post \ref s == str && \ref length == len
+ \note Constant complexity.
+ */
+#endif
+ GenericStringRef(const CharType* str, SizeType len)
+ : s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); }
+
+ //! implicit conversion to plain CharType pointer
+ operator const Ch *() const { return s; }
+
+ const Ch* const s; //!< plain CharType pointer
+ const SizeType length; //!< length of the string (excluding the trailing NULL terminator)
+
+private:
+ //! Disallow construction from non-const array
+ template<SizeType N>
+ GenericStringRef(CharType (&str)[N]) /* = delete */;
+};
+
+//! Mark a character pointer as constant string
+/*! Mark a plain character pointer as a "string literal". This function
+ can be used to avoid copying a character string to be referenced as a
+ value in a JSON GenericValue object, if the string's lifetime is known
+ to be valid long enough.
+ \tparam CharType Character type of the string
+ \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+ \return GenericStringRef string reference object
+ \relatesalso GenericStringRef
+
+ \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember
+*/
+template<typename CharType>
+inline GenericStringRef<CharType> StringRef(const CharType* str) {
+ return GenericStringRef<CharType>(str, internal::StrLen(str));
+}
+
+//! Mark a character pointer as constant string
+/*! Mark a plain character pointer as a "string literal". This function
+ can be used to avoid copying a character string to be referenced as a
+ value in a JSON GenericValue object, if the string's lifetime is known
+ to be valid long enough.
+
+ This version has better performance with supplied length, and also
+ supports string containing null characters.
+
+ \tparam CharType character type of the string
+ \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+ \param length The length of source string.
+ \return GenericStringRef string reference object
+ \relatesalso GenericStringRef
+*/
+template<typename CharType>
+inline GenericStringRef<CharType> StringRef(const CharType* str, size_t length) {
+ return GenericStringRef<CharType>(str, SizeType(length));
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+//! Mark a string object as constant string
+/*! Mark a string object (e.g. \c std::string) as a "string literal".
+ This function can be used to avoid copying a string to be referenced as a
+ value in a JSON GenericValue object, if the string's lifetime is known
+ to be valid long enough.
+
+ \tparam CharType character type of the string
+ \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+ \return GenericStringRef string reference object
+ \relatesalso GenericStringRef
+ \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+*/
+template<typename CharType>
+inline GenericStringRef<CharType> StringRef(const std::basic_string<CharType>& str) {
+ return GenericStringRef<CharType>(str.data(), SizeType(str.size()));
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericValue type traits
+namespace internal {
+
+template <typename T, typename Encoding = void, typename Allocator = void>
+struct IsGenericValueImpl : FalseType {};
+
+// select candidates according to nested encoding and allocator types
+template <typename T> struct IsGenericValueImpl<T, typename Void<typename T::EncodingType>::Type, typename Void<typename T::AllocatorType>::Type>
+ : IsBaseOf<GenericValue<typename T::EncodingType, typename T::AllocatorType>, T>::Type {};
+
+// helper to match arbitrary GenericValue instantiations, including derived classes
+template <typename T> struct IsGenericValue : IsGenericValueImpl<T>::Type {};
+
+} // namespace internal
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericValue
+
+//! Represents a JSON value. Use Value for UTF8 encoding and default allocator.
+/*!
+ A JSON value can be one of 7 types. This class is a variant type supporting
+ these types.
+
+ Use the Value if UTF8 and default allocator
+
+ \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
+ \tparam Allocator Allocator type for allocating memory of object, array and string.
+*/
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
+class GenericValue {
+public:
+ //! Name-value pair in an object.
+ typedef GenericMember<Encoding, Allocator> Member;
+ typedef Encoding EncodingType; //!< Encoding type from template parameter.
+ typedef Allocator AllocatorType; //!< Allocator type from template parameter.
+ typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
+ typedef GenericStringRef<Ch> StringRefType; //!< Reference to a constant string
+ typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator MemberIterator; //!< Member iterator for iterating in object.
+ typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object.
+ typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array.
+ typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.
+ typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of itself.
+
+ //!@name Constructors and destructor.
+ //@{
+
+ //! Default constructor creates a null value.
+ GenericValue() RAPIDJSON_NOEXCEPT : data_(), flags_(kNullFlag) {}
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move constructor in C++11
+ GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_), flags_(rhs.flags_) {
+ rhs.flags_ = kNullFlag; // give up contents
+ }
+#endif
+
+private:
+ //! Copy constructor is not permitted.
+ GenericValue(const GenericValue& rhs);
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Moving from a GenericDocument is not permitted.
+ template <typename StackAllocator>
+ GenericValue(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);
+
+ //! Move assignment from a GenericDocument is not permitted.
+ template <typename StackAllocator>
+ GenericValue& operator=(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);
+#endif
+
+public:
+
+ //! Constructor with JSON value type.
+ /*! This creates a Value of specified type with default content.
+ \param type Type of the value.
+ \note Default content for number is zero.
+ */
+ explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_(), flags_() {
+ static const unsigned defaultFlags[7] = {
+ kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,
+ kNumberAnyFlag
+ };
+ RAPIDJSON_ASSERT(type <= kNumberType);
+ flags_ = defaultFlags[type];
+
+ // Use ShortString to store empty string.
+ if (type == kStringType)
+ data_.ss.SetLength(0);
+ }
+
+ //! Explicit copy constructor (with allocator)
+ /*! Creates a copy of a Value by using the given Allocator
+ \tparam SourceAllocator allocator of \c rhs
+ \param rhs Value to copy from (read-only)
+ \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator().
+ \see CopyFrom()
+ */
+ template< typename SourceAllocator >
+ GenericValue(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator & allocator);
+
+ //! Constructor for boolean value.
+ /*! \param b Boolean value
+ \note This constructor is limited to \em real boolean values and rejects
+ implicitly converted types like arbitrary pointers. Use an explicit cast
+ to \c bool, if you want to construct a boolean JSON value in such cases.
+ */
+#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen
+ template <typename T>
+ explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<bool, T>))) RAPIDJSON_NOEXCEPT // See #472
+#else
+ explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT
+#endif
+ : data_(), flags_(b ? kTrueFlag : kFalseFlag) {
+ // safe-guard against failing SFINAE
+ RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value));
+ }
+
+ //! Constructor for int value.
+ explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberIntFlag) {
+ data_.n.i64 = i;
+ if (i >= 0)
+ flags_ |= kUintFlag | kUint64Flag;
+ }
+
+ //! Constructor for unsigned value.
+ explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUintFlag) {
+ data_.n.u64 = u;
+ if (!(u & 0x80000000))
+ flags_ |= kIntFlag | kInt64Flag;
+ }
+
+ //! Constructor for int64_t value.
+ explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberInt64Flag) {
+ data_.n.i64 = i64;
+ if (i64 >= 0) {
+ flags_ |= kNumberUint64Flag;
+ if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
+ flags_ |= kUintFlag;
+ if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+ flags_ |= kIntFlag;
+ }
+ else if (i64 >= static_cast<int64_t>(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+ flags_ |= kIntFlag;
+ }
+
+ //! Constructor for uint64_t value.
+ explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUint64Flag) {
+ data_.n.u64 = u64;
+ if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))
+ flags_ |= kInt64Flag;
+ if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
+ flags_ |= kUintFlag;
+ if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+ flags_ |= kIntFlag;
+ }
+
+ //! Constructor for double value.
+ explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; }
+
+ //! Constructor for constant string (i.e. do not make a copy of string)
+ GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(StringRef(s, length)); }
+
+ //! Constructor for constant string (i.e. do not make a copy of string)
+ explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(s); }
+
+ //! Constructor for copy-string (i.e. do make a copy of string)
+ GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s, length), allocator); }
+
+ //! Constructor for copy-string (i.e. do make a copy of string)
+ GenericValue(const Ch*s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Constructor for copy-string from a string object (i.e. do make a copy of string)
+ /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+ */
+ GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); }
+#endif
+
+ //! Destructor.
+ /*! Need to destruct elements of array, members of object, or copy-string.
+ */
+ ~GenericValue() {
+ if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
+ switch(flags_) {
+ case kArrayFlag:
+ for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
+ v->~GenericValue();
+ Allocator::Free(data_.a.elements);
+ break;
+
+ case kObjectFlag:
+ for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
+ m->~Member();
+ Allocator::Free(data_.o.members);
+ break;
+
+ case kCopyStringFlag:
+ Allocator::Free(const_cast<Ch*>(data_.s.str));
+ break;
+
+ default:
+ break; // Do nothing for other types.
+ }
+ }
+ }
+
+ //@}
+
+ //!@name Assignment operators
+ //@{
+
+ //! Assignment with move semantics.
+ /*! \param rhs Source of the assignment. It will become a null value after assignment.
+ */
+ GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
+ RAPIDJSON_ASSERT(this != &rhs);
+ this->~GenericValue();
+ RawAssign(rhs);
+ return *this;
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move assignment in C++11
+ GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT {
+ return *this = rhs.Move();
+ }
+#endif
+
+ //! Assignment of constant string reference (no copy)
+ /*! \param str Constant string reference to be assigned
+ \note This overload is needed to avoid clashes with the generic primitive type assignment overload below.
+ \see GenericStringRef, operator=(T)
+ */
+ GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT {
+ GenericValue s(str);
+ return *this = s;
+ }
+
+ //! Assignment with primitive types.
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+ \param value The value to be assigned.
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref SetString(const Ch*, Allocator&) (for copying) or
+ \ref StringRef() (to explicitly mark the pointer as constant) instead.
+ All other pointer types would implicitly convert to \c bool,
+ use \ref SetBool() instead.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer<T>), (GenericValue&))
+ operator=(T value) {
+ GenericValue v(value);
+ return *this = v;
+ }
+
+ //! Deep-copy assignment from Value
+ /*! Assigns a \b copy of the Value to the current Value object
+ \tparam SourceAllocator Allocator type of \c rhs
+ \param rhs Value to copy from (read-only)
+ \param allocator Allocator to use for copying
+ */
+ template <typename SourceAllocator>
+ GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator) {
+ RAPIDJSON_ASSERT(static_cast<void*>(this) != static_cast<void const*>(&rhs));
+ this->~GenericValue();
+ new (this) GenericValue(rhs, allocator);
+ return *this;
+ }
+
+ //! Exchange the contents of this value with those of other.
+ /*!
+ \param other Another value.
+ \note Constant complexity.
+ */
+ GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT {
+ GenericValue temp;
+ temp.RawAssign(*this);
+ RawAssign(other);
+ other.RawAssign(temp);
+ return *this;
+ }
+
+ //! free-standing swap function helper
+ /*!
+ Helper function to enable support for common swap implementation pattern based on \c std::swap:
+ \code
+ void swap(MyClass& a, MyClass& b) {
+ using std::swap;
+ swap(a.value, b.value);
+ // ...
+ }
+ \endcode
+ \see Swap()
+ */
+ friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
+
+ //! Prepare Value for move semantics
+ /*! \return *this */
+ GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; }
+ //@}
+
+ //!@name Equal-to and not-equal-to operators
+ //@{
+ //! Equal-to operator
+ /*!
+ \note If an object contains duplicated named member, comparing equality with any object is always \c false.
+ \note Linear time complexity (number of all values in the subtree and total lengths of all strings).
+ */
+ template <typename SourceAllocator>
+ bool operator==(const GenericValue<Encoding, SourceAllocator>& rhs) const {
+ typedef GenericValue<Encoding, SourceAllocator> RhsType;
+ if (GetType() != rhs.GetType())
+ return false;
+
+ switch (GetType()) {
+ case kObjectType: // Warning: O(n^2) inner-loop
+ if (data_.o.size != rhs.data_.o.size)
+ return false;
+ for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) {
+ typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name);
+ if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value)
+ return false;
+ }
+ return true;
+
+ case kArrayType:
+ if (data_.a.size != rhs.data_.a.size)
+ return false;
+ for (SizeType i = 0; i < data_.a.size; i++)
+ if ((*this)[i] != rhs[i])
+ return false;
+ return true;
+
+ case kStringType:
+ return StringEqual(rhs);
+
+ case kNumberType:
+ if (IsDouble() || rhs.IsDouble()) {
+ double a = GetDouble(); // May convert from integer to double.
+ double b = rhs.GetDouble(); // Ditto
+ return a >= b && a <= b; // Prevent -Wfloat-equal
+ }
+ else
+ return data_.n.u64 == rhs.data_.n.u64;
+
+ default:
+ return true;
+ }
+ }
+
+ //! Equal-to operator with const C-string pointer
+ bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Equal-to operator with string object
+ /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+ */
+ bool operator==(const std::basic_string<Ch>& rhs) const { return *this == GenericValue(StringRef(rhs)); }
+#endif
+
+ //! Equal-to operator with primitive types
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false
+ */
+ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>,internal::IsGenericValue<T> >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); }
+
+ //! Not-equal-to operator
+ /*! \return !(*this == rhs)
+ */
+ template <typename SourceAllocator>
+ bool operator!=(const GenericValue<Encoding, SourceAllocator>& rhs) const { return !(*this == rhs); }
+
+ //! Not-equal-to operator with const C-string pointer
+ bool operator!=(const Ch* rhs) const { return !(*this == rhs); }
+
+ //! Not-equal-to operator with arbitrary types
+ /*! \return !(*this == rhs)
+ */
+ template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); }
+
+ //! Equal-to operator with arbitrary types (symmetric version)
+ /*! \return (rhs == lhs)
+ */
+ template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; }
+
+ //! Not-Equal-to operator with arbitrary types (symmetric version)
+ /*! \return !(rhs == lhs)
+ */
+ template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }
+ //@}
+
+ //!@name Type
+ //@{
+
+ Type GetType() const { return static_cast<Type>(flags_ & kTypeMask); }
+ bool IsNull() const { return flags_ == kNullFlag; }
+ bool IsFalse() const { return flags_ == kFalseFlag; }
+ bool IsTrue() const { return flags_ == kTrueFlag; }
+ bool IsBool() const { return (flags_ & kBoolFlag) != 0; }
+ bool IsObject() const { return flags_ == kObjectFlag; }
+ bool IsArray() const { return flags_ == kArrayFlag; }
+ bool IsNumber() const { return (flags_ & kNumberFlag) != 0; }
+ bool IsInt() const { return (flags_ & kIntFlag) != 0; }
+ bool IsUint() const { return (flags_ & kUintFlag) != 0; }
+ bool IsInt64() const { return (flags_ & kInt64Flag) != 0; }
+ bool IsUint64() const { return (flags_ & kUint64Flag) != 0; }
+ bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; }
+ bool IsString() const { return (flags_ & kStringFlag) != 0; }
+
+ // Checks whether a number can be losslessly converted to a double.
+ bool IsLosslessDouble() const {
+ if (!IsNumber()) return false;
+ if (IsUint64()) {
+ uint64_t u = GetUint64();
+ volatile double d = static_cast<double>(u);
+ return static_cast<uint64_t>(d) == u;
+ }
+ if (IsInt64()) {
+ int64_t i = GetInt64();
+ volatile double d = static_cast<double>(i);
+ return static_cast< int64_t>(d) == i;
+ }
+ return true; // double, int, uint are always lossless
+ }
+
+ // Checks whether a number is a float (possible lossy).
+ bool IsFloat() const {
+ if ((flags_ & kDoubleFlag) == 0)
+ return false;
+ double d = GetDouble();
+ return d >= -3.4028234e38 && d <= 3.4028234e38;
+ }
+ // Checks whether a number can be losslessly converted to a float.
+ bool IsLosslessFloat() const {
+ if (!IsNumber()) return false;
+ double a = GetDouble();
+ double b = static_cast<double>(static_cast<float>(a));
+ return a >= b && a <= b; // Prevent -Wfloat-equal
+ }
+
+ //@}
+
+ //!@name Null
+ //@{
+
+ GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; }
+
+ //@}
+
+ //!@name Bool
+ //@{
+
+ bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; }
+ //!< Set boolean value
+ /*! \post IsBool() == true */
+ GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }
+
+ //@}
+
+ //!@name Object
+ //@{
+
+ //! Set this value as an empty object.
+ /*! \post IsObject() == true */
+ GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; }
+
+ //! Get the number of members in the object.
+ SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; }
+
+ //! Check whether the object is empty.
+ bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; }
+
+ //! Get a value from an object associated with the name.
+ /*! \pre IsObject() == true
+ \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType))
+ \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7.
+ Since 0.2, if the name is not correct, it will assert.
+ If user is unsure whether a member exists, user should use HasMember() first.
+ A better approach is to use FindMember().
+ \note Linear time complexity.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(GenericValue&)) operator[](T* name) {
+ GenericValue n(StringRef(name));
+ return (*this)[n];
+ }
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast<GenericValue&>(*this)[name]; }
+
+ //! Get a value from an object associated with the name.
+ /*! \pre IsObject() == true
+ \tparam SourceAllocator Allocator of the \c name value
+
+ \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen().
+ And it can also handle strings with embedded null characters.
+
+ \note Linear time complexity.
+ */
+ template <typename SourceAllocator>
+ GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) {
+ MemberIterator member = FindMember(name);
+ if (member != MemberEnd())
+ return member->value;
+ else {
+ RAPIDJSON_ASSERT(false); // see above note
+
+ // This will generate -Wexit-time-destructors in clang
+ // static GenericValue NullValue;
+ // return NullValue;
+
+ // Use static buffer and placement-new to prevent destruction
+ static char buffer[sizeof(GenericValue)];
+ return *new (buffer) GenericValue();
+ }
+ }
+ template <typename SourceAllocator>
+ const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this)[name]; }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Get a value from an object associated with name (string object).
+ GenericValue& operator[](const std::basic_string<Ch>& name) { return (*this)[GenericValue(StringRef(name))]; }
+ const GenericValue& operator[](const std::basic_string<Ch>& name) const { return (*this)[GenericValue(StringRef(name))]; }
+#endif
+
+ //! Const member iterator
+ /*! \pre IsObject() == true */
+ ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); }
+ //! Const \em past-the-end member iterator
+ /*! \pre IsObject() == true */
+ ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members + data_.o.size); }
+ //! Member iterator
+ /*! \pre IsObject() == true */
+ MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members); }
+ //! \em Past-the-end member iterator
+ /*! \pre IsObject() == true */
+ MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members + data_.o.size); }
+
+ //! Check whether a member exists in the object.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Whether a member with that name exists.
+ \note It is better to use FindMember() directly if you need the obtain the value as well.
+ \note Linear time complexity.
+ */
+ bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Check whether a member exists in the object with string object.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Whether a member with that name exists.
+ \note It is better to use FindMember() directly if you need the obtain the value as well.
+ \note Linear time complexity.
+ */
+ bool HasMember(const std::basic_string<Ch>& name) const { return FindMember(name) != MemberEnd(); }
+#endif
+
+ //! Check whether a member exists in the object with GenericValue name.
+ /*!
+ This version is faster because it does not need a StrLen(). It can also handle string with null character.
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Whether a member with that name exists.
+ \note It is better to use FindMember() directly if you need the obtain the value as well.
+ \note Linear time complexity.
+ */
+ template <typename SourceAllocator>
+ bool HasMember(const GenericValue<Encoding, SourceAllocator>& name) const { return FindMember(name) != MemberEnd(); }
+
+ //! Find member by name.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Iterator to member, if it exists.
+ Otherwise returns \ref MemberEnd().
+
+ \note Earlier versions of Rapidjson returned a \c NULL pointer, in case
+ the requested member doesn't exist. For consistency with e.g.
+ \c std::map, this has been changed to MemberEnd() now.
+ \note Linear time complexity.
+ */
+ MemberIterator FindMember(const Ch* name) {
+ GenericValue n(StringRef(name));
+ return FindMember(n);
+ }
+
+ ConstMemberIterator FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
+
+ //! Find member by name.
+ /*!
+ This version is faster because it does not need a StrLen(). It can also handle string with null character.
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Iterator to member, if it exists.
+ Otherwise returns \ref MemberEnd().
+
+ \note Earlier versions of Rapidjson returned a \c NULL pointer, in case
+ the requested member doesn't exist. For consistency with e.g.
+ \c std::map, this has been changed to MemberEnd() now.
+ \note Linear time complexity.
+ */
+ template <typename SourceAllocator>
+ MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(name.IsString());
+ MemberIterator member = MemberBegin();
+ for ( ; member != MemberEnd(); ++member)
+ if (name.StringEqual(member->name))
+ break;
+ return member;
+ }
+ template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Find member by string object name.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Iterator to member, if it exists.
+ Otherwise returns \ref MemberEnd().
+ */
+ MemberIterator FindMember(const std::basic_string<Ch>& name) { return FindMember(StringRef(name)); }
+ ConstMemberIterator FindMember(const std::basic_string<Ch>& name) const { return FindMember(StringRef(name)); }
+#endif
+
+ //! Add a member (name-value pair) to the object.
+ /*! \param name A string value as name of member.
+ \param value Value of any type.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \note The ownership of \c name and \c value will be transferred to this object on success.
+ \pre IsObject() && name.IsString()
+ \post name.IsNull() && value.IsNull()
+ \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(name.IsString());
+
+ Object& o = data_.o;
+ if (o.size >= o.capacity) {
+ if (o.capacity == 0) {
+ o.capacity = kDefaultObjectCapacity;
+ o.members = reinterpret_cast<Member*>(allocator.Malloc(o.capacity * sizeof(Member)));
+ }
+ else {
+ SizeType oldCapacity = o.capacity;
+ o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5
+ o.members = reinterpret_cast<Member*>(allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member)));
+ }
+ }
+ o.members[o.size].name.RawAssign(name);
+ o.members[o.size].value.RawAssign(value);
+ o.size++;
+ return *this;
+ }
+
+ //! Add a constant string value as member (name-value pair) to the object.
+ /*! \param name A string value as name of member.
+ \param value constant string reference as value of member.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+ \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
+ \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) {
+ GenericValue v(value);
+ return AddMember(name, v, allocator);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Add a string object as member (name-value pair) to the object.
+ /*! \param name A string value as name of member.
+ \param value constant string reference as value of member.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+ \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
+ \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(GenericValue& name, std::basic_string<Ch>& value, Allocator& allocator) {
+ GenericValue v(value, allocator);
+ return AddMember(name, v, allocator);
+ }
+#endif
+
+ //! Add any primitive value as member (name-value pair) to the object.
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+ \param name A string value as name of member.
+ \param value Value of primitive type \c T as value of member
+ \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
+ AddMember(StringRefType, StringRefType, Allocator&).
+ All other pointer types would implicitly convert to \c bool,
+ use an explicit cast instead, if needed.
+ \note Amortized Constant time complexity.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
+ AddMember(GenericValue& name, T value, Allocator& allocator) {
+ GenericValue v(value);
+ return AddMember(name, v, allocator);
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) {
+ return AddMember(name, value, allocator);
+ }
+ GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) {
+ return AddMember(name, value, allocator);
+ }
+ GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) {
+ return AddMember(name, value, allocator);
+ }
+ GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) {
+ GenericValue n(name);
+ return AddMember(n, value, allocator);
+ }
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+
+ //! Add a member (name-value pair) to the object.
+ /*! \param name A constant string reference as name of member.
+ \param value Value of any type.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \note The ownership of \c value will be transferred to this object on success.
+ \pre IsObject()
+ \post value.IsNull()
+ \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) {
+ GenericValue n(name);
+ return AddMember(n, value, allocator);
+ }
+
+ //! Add a constant string value as member (name-value pair) to the object.
+ /*! \param name A constant string reference as name of member.
+ \param value constant string reference as value of member.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+ \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below.
+ \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) {
+ GenericValue v(value);
+ return AddMember(name, v, allocator);
+ }
+
+ //! Add any primitive value as member (name-value pair) to the object.
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+ \param name A constant string reference as name of member.
+ \param value Value of primitive type \c T as value of member
+ \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \pre IsObject()
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
+ AddMember(StringRefType, StringRefType, Allocator&).
+ All other pointer types would implicitly convert to \c bool,
+ use an explicit cast instead, if needed.
+ \note Amortized Constant time complexity.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
+ AddMember(StringRefType name, T value, Allocator& allocator) {
+ GenericValue n(name);
+ return AddMember(n, value, allocator);
+ }
+
+ //! Remove all members in the object.
+ /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged.
+ \note Linear time complexity.
+ */
+ void RemoveAllMembers() {
+ RAPIDJSON_ASSERT(IsObject());
+ for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
+ m->~Member();
+ data_.o.size = 0;
+ }
+
+ //! Remove a member in object by its name.
+ /*! \param name Name of member to be removed.
+ \return Whether the member existed.
+ \note This function may reorder the object members. Use \ref
+ EraseMember(ConstMemberIterator) if you need to preserve the
+ relative order of the remaining members.
+ \note Linear time complexity.
+ */
+ bool RemoveMember(const Ch* name) {
+ GenericValue n(StringRef(name));
+ return RemoveMember(n);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ bool RemoveMember(const std::basic_string<Ch>& name) { return RemoveMember(GenericValue(StringRef(name))); }
+#endif
+
+ template <typename SourceAllocator>
+ bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) {
+ MemberIterator m = FindMember(name);
+ if (m != MemberEnd()) {
+ RemoveMember(m);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ //! Remove a member in object by iterator.
+ /*! \param m member iterator (obtained by FindMember() or MemberBegin()).
+ \return the new iterator after removal.
+ \note This function may reorder the object members. Use \ref
+ EraseMember(ConstMemberIterator) if you need to preserve the
+ relative order of the remaining members.
+ \note Constant time complexity.
+ */
+ MemberIterator RemoveMember(MemberIterator m) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(data_.o.size > 0);
+ RAPIDJSON_ASSERT(data_.o.members != 0);
+ RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());
+
+ MemberIterator last(data_.o.members + (data_.o.size - 1));
+ if (data_.o.size > 1 && m != last) {
+ // Move the last one to this place
+ *m = *last;
+ }
+ else {
+ // Only one left, just destroy
+ m->~Member();
+ }
+ --data_.o.size;
+ return m;
+ }
+
+ //! Remove a member from an object by iterator.
+ /*! \param pos iterator to the member to remove
+ \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd()
+ \return Iterator following the removed element.
+ If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned.
+ \note This function preserves the relative order of the remaining object
+ members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator).
+ \note Linear time complexity.
+ */
+ MemberIterator EraseMember(ConstMemberIterator pos) {
+ return EraseMember(pos, pos +1);
+ }
+
+ //! Remove members in the range [first, last) from an object.
+ /*! \param first iterator to the first member to remove
+ \param last iterator following the last member to remove
+ \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd()
+ \return Iterator following the last removed element.
+ \note This function preserves the relative order of the remaining object
+ members.
+ \note Linear time complexity.
+ */
+ MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(data_.o.size > 0);
+ RAPIDJSON_ASSERT(data_.o.members != 0);
+ RAPIDJSON_ASSERT(first >= MemberBegin());
+ RAPIDJSON_ASSERT(first <= last);
+ RAPIDJSON_ASSERT(last <= MemberEnd());
+
+ MemberIterator pos = MemberBegin() + (first - MemberBegin());
+ for (MemberIterator itr = pos; itr != last; ++itr)
+ itr->~Member();
+ std::memmove(&*pos, &*last, static_cast<size_t>(MemberEnd() - last) * sizeof(Member));
+ data_.o.size -= static_cast<SizeType>(last - first);
+ return pos;
+ }
+
+ //! Erase a member in object by its name.
+ /*! \param name Name of member to be removed.
+ \return Whether the member existed.
+ \note Linear time complexity.
+ */
+ bool EraseMember(const Ch* name) {
+ GenericValue n(StringRef(name));
+ return EraseMember(n);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ bool EraseMember(const std::basic_string<Ch>& name) { return EraseMember(GenericValue(StringRef(name))); }
+#endif
+
+ template <typename SourceAllocator>
+ bool EraseMember(const GenericValue<Encoding, SourceAllocator>& name) {
+ MemberIterator m = FindMember(name);
+ if (m != MemberEnd()) {
+ EraseMember(m);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ //@}
+
+ //!@name Array
+ //@{
+
+ //! Set this value as an empty array.
+ /*! \post IsArray == true */
+ GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }
+
+ //! Get the number of elements in array.
+ SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }
+
+ //! Get the capacity of array.
+ SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; }
+
+ //! Check whether the array is empty.
+ bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; }
+
+ //! Remove all elements in the array.
+ /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged.
+ \note Linear time complexity.
+ */
+ void Clear() {
+ RAPIDJSON_ASSERT(IsArray());
+ for (SizeType i = 0; i < data_.a.size; ++i)
+ data_.a.elements[i].~GenericValue();
+ data_.a.size = 0;
+ }
+
+ //! Get an element from array by index.
+ /*! \pre IsArray() == true
+ \param index Zero-based index of element.
+ \see operator[](T*)
+ */
+ GenericValue& operator[](SizeType index) {
+ RAPIDJSON_ASSERT(IsArray());
+ RAPIDJSON_ASSERT(index < data_.a.size);
+ return data_.a.elements[index];
+ }
+ const GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; }
+
+ //! Element iterator
+ /*! \pre IsArray() == true */
+ ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements; }
+ //! \em Past-the-end element iterator
+ /*! \pre IsArray() == true */
+ ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; }
+ //! Constant element iterator
+ /*! \pre IsArray() == true */
+ ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); }
+ //! Constant \em past-the-end element iterator
+ /*! \pre IsArray() == true */
+ ConstValueIterator End() const { return const_cast<GenericValue&>(*this).End(); }
+
+ //! Request the array to have enough capacity to store elements.
+ /*! \param newCapacity The capacity that the array at least need to have.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \note Linear time complexity.
+ */
+ GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
+ RAPIDJSON_ASSERT(IsArray());
+ if (newCapacity > data_.a.capacity) {
+ data_.a.elements = static_cast<GenericValue*>(allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)));
+ data_.a.capacity = newCapacity;
+ }
+ return *this;
+ }
+
+ //! Append a GenericValue at the end of the array.
+ /*! \param value Value to be appended.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \pre IsArray() == true
+ \post value.IsNull() == true
+ \return The value itself for fluent API.
+ \note The ownership of \c value will be transferred to this array on success.
+ \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+ \note Amortized constant time complexity.
+ */
+ GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
+ RAPIDJSON_ASSERT(IsArray());
+ if (data_.a.size >= data_.a.capacity)
+ Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator);
+ data_.a.elements[data_.a.size++].RawAssign(value);
+ return *this;
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericValue& PushBack(GenericValue&& value, Allocator& allocator) {
+ return PushBack(value, allocator);
+ }
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+ //! Append a constant string reference at the end of the array.
+ /*! \param value Constant string reference to be appended.
+ \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator().
+ \pre IsArray() == true
+ \return The value itself for fluent API.
+ \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+ \note Amortized constant time complexity.
+ \see GenericStringRef
+ */
+ GenericValue& PushBack(StringRefType value, Allocator& allocator) {
+ return (*this).template PushBack<StringRefType>(value, allocator);
+ }
+
+ //! Append a primitive value at the end of the array.
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+ \param value Value of primitive type T to be appended.
+ \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+ \pre IsArray() == true
+ \return The value itself for fluent API.
+ \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref PushBack(GenericValue&, Allocator&) or \ref
+ PushBack(StringRefType, Allocator&).
+ All other pointer types would implicitly convert to \c bool,
+ use an explicit cast instead, if needed.
+ \note Amortized constant time complexity.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
+ PushBack(T value, Allocator& allocator) {
+ GenericValue v(value);
+ return PushBack(v, allocator);
+ }
+
+ //! Remove the last element in the array.
+ /*!
+ \note Constant time complexity.
+ */
+ GenericValue& PopBack() {
+ RAPIDJSON_ASSERT(IsArray());
+ RAPIDJSON_ASSERT(!Empty());
+ data_.a.elements[--data_.a.size].~GenericValue();
+ return *this;
+ }
+
+ //! Remove an element of array by iterator.
+ /*!
+ \param pos iterator to the element to remove
+ \pre IsArray() == true && \ref Begin() <= \c pos < \ref End()
+ \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned.
+ \note Linear time complexity.
+ */
+ ValueIterator Erase(ConstValueIterator pos) {
+ return Erase(pos, pos + 1);
+ }
+
+ //! Remove elements in the range [first, last) of the array.
+ /*!
+ \param first iterator to the first element to remove
+ \param last iterator following the last element to remove
+ \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End()
+ \return Iterator following the last removed element.
+ \note Linear time complexity.
+ */
+ ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) {
+ RAPIDJSON_ASSERT(IsArray());
+ RAPIDJSON_ASSERT(data_.a.size > 0);
+ RAPIDJSON_ASSERT(data_.a.elements != 0);
+ RAPIDJSON_ASSERT(first >= Begin());
+ RAPIDJSON_ASSERT(first <= last);
+ RAPIDJSON_ASSERT(last <= End());
+ ValueIterator pos = Begin() + (first - Begin());
+ for (ValueIterator itr = pos; itr != last; ++itr)
+ itr->~GenericValue();
+ std::memmove(pos, last, static_cast<size_t>(End() - last) * sizeof(GenericValue));
+ data_.a.size -= static_cast<SizeType>(last - first);
+ return pos;
+ }
+
+ //@}
+
+ //!@name Number
+ //@{
+
+ int GetInt() const { RAPIDJSON_ASSERT(flags_ & kIntFlag); return data_.n.i.i; }
+ unsigned GetUint() const { RAPIDJSON_ASSERT(flags_ & kUintFlag); return data_.n.u.u; }
+ int64_t GetInt64() const { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; }
+ uint64_t GetUint64() const { RAPIDJSON_ASSERT(flags_ & kUint64Flag); return data_.n.u64; }
+
+ //! Get the value as double type.
+ /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless.
+ */
+ double GetDouble() const {
+ RAPIDJSON_ASSERT(IsNumber());
+ if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion.
+ if ((flags_ & kIntFlag) != 0) return data_.n.i.i; // int -> double
+ if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double
+ if ((flags_ & kInt64Flag) != 0) return static_cast<double>(data_.n.i64); // int64_t -> double (may lose precision)
+ RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return static_cast<double>(data_.n.u64); // uint64_t -> double (may lose precision)
+ }
+
+ //! Get the value as float type.
+ /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the converison is lossless.
+ */
+ float GetFloat() const {
+ RAPIDJSON_ASSERT(IsFloat());
+ return static_cast<float>(GetDouble());
+ }
+
+ GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; }
+ GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; }
+ GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; }
+ GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; }
+ GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; }
+ GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(f); return *this; }
+
+ //@}
+
+ //!@name String
+ //@{
+
+ const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? data_.ss.str : data_.s.str); }
+
+ //! Get the length of string.
+ /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
+ */
+ SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); }
+
+ //! Set this value as a string without copying source string.
+ /*! This version has better performance with supplied length, and also support string containing null character.
+ \param s source string pointer.
+ \param length The length of source string, excluding the trailing null terminator.
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() == s && GetStringLength() == length
+ \see SetString(StringRefType)
+ */
+ GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); }
+
+ //! Set this value as a string without copying source string.
+ /*! \param s source string reference
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() == s && GetStringLength() == s.length
+ */
+ GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; }
+
+ //! Set this value as a string by copying from source string.
+ /*! This version has better performance with supplied length, and also support string containing null character.
+ \param s source string.
+ \param length The length of source string, excluding the trailing null terminator.
+ \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
+ */
+ GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; }
+
+ //! Set this value as a string by copying from source string.
+ /*! \param s source string.
+ \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
+ */
+ GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Set this value as a string by copying from source string.
+ /*! \param s source string.
+ \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size()
+ \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+ */
+ GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); }
+#endif
+
+ //@}
+
+ //! Generate events of this value to a Handler.
+ /*! This function adopts the GoF visitor pattern.
+ Typical usage is to output this JSON value as JSON text via Writer, which is a Handler.
+ It can also be used to deep clone this value via GenericDocument, which is also a Handler.
+ \tparam Handler type of handler.
+ \param handler An object implementing concept Handler.
+ */
+ template <typename Handler>
+ bool Accept(Handler& handler) const {
+ switch(GetType()) {
+ case kNullType: return handler.Null();
+ case kFalseType: return handler.Bool(false);
+ case kTrueType: return handler.Bool(true);
+
+ case kObjectType:
+ if (RAPIDJSON_UNLIKELY(!handler.StartObject()))
+ return false;
+ for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) {
+ RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator.
+ if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.flags_ & kCopyFlag) != 0)))
+ return false;
+ if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler)))
+ return false;
+ }
+ return handler.EndObject(data_.o.size);
+
+ case kArrayType:
+ if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
+ return false;
+ for (const GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v)
+ if (RAPIDJSON_UNLIKELY(!v->Accept(handler)))
+ return false;
+ return handler.EndArray(data_.a.size);
+
+ case kStringType:
+ return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0);
+
+ default:
+ RAPIDJSON_ASSERT(GetType() == kNumberType);
+ if (IsDouble()) return handler.Double(data_.n.d);
+ else if (IsInt()) return handler.Int(data_.n.i.i);
+ else if (IsUint()) return handler.Uint(data_.n.u.u);
+ else if (IsInt64()) return handler.Int64(data_.n.i64);
+ else return handler.Uint64(data_.n.u64);
+ }
+ }
+
+private:
+ template <typename, typename> friend class GenericValue;
+ template <typename, typename, typename> friend class GenericDocument;
+
+ enum {
+ kBoolFlag = 0x100,
+ kNumberFlag = 0x200,
+ kIntFlag = 0x400,
+ kUintFlag = 0x800,
+ kInt64Flag = 0x1000,
+ kUint64Flag = 0x2000,
+ kDoubleFlag = 0x4000,
+ kStringFlag = 0x100000,
+ kCopyFlag = 0x200000,
+ kInlineStrFlag = 0x400000,
+
+ // Initial flags of different types.
+ kNullFlag = kNullType,
+ kTrueFlag = kTrueType | kBoolFlag,
+ kFalseFlag = kFalseType | kBoolFlag,
+ kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,
+ kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag,
+ kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,
+ kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,
+ kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,
+ kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag,
+ kConstStringFlag = kStringType | kStringFlag,
+ kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,
+ kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag,
+ kObjectFlag = kObjectType,
+ kArrayFlag = kArrayType,
+
+ kTypeMask = 0xFF // bitwise-and with mask of 0xFF can be optimized by compiler
+ };
+
+ static const SizeType kDefaultArrayCapacity = 16;
+ static const SizeType kDefaultObjectCapacity = 16;
+
+ struct String {
+ const Ch* str;
+ SizeType length;
+ unsigned hashcode; //!< reserved
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars
+ // (excluding the terminating zero) and store a value to determine the length of the contained
+ // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string
+ // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as
+ // the string terminator as well. For getting the string length back from that value just use
+ // "MaxSize - str[LenPos]".
+ // This allows to store 11-chars strings in 32-bit mode and 15-chars strings in 64-bit mode
+ // inline (for `UTF8`-encoded strings).
+ struct ShortString {
+ enum { MaxChars = sizeof(String) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };
+ Ch str[MaxChars];
+
+ inline static bool Usable(SizeType len) { return (MaxSize >= len); }
+ inline void SetLength(SizeType len) { str[LenPos] = static_cast<Ch>(MaxSize - len); }
+ inline SizeType GetLength() const { return static_cast<SizeType>(MaxSize - str[LenPos]); }
+ }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ // By using proper binary layout, retrieval of different integer types do not need conversions.
+ union Number {
+#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN
+ struct I {
+ int i;
+ char padding[4];
+ }i;
+ struct U {
+ unsigned u;
+ char padding2[4];
+ }u;
+#else
+ struct I {
+ char padding[4];
+ int i;
+ }i;
+ struct U {
+ char padding2[4];
+ unsigned u;
+ }u;
+#endif
+ int64_t i64;
+ uint64_t u64;
+ double d;
+ }; // 8 bytes
+
+ struct Object {
+ Member* members;
+ SizeType size;
+ SizeType capacity;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ struct Array {
+ GenericValue* elements;
+ SizeType size;
+ SizeType capacity;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ union Data {
+ String s;
+ ShortString ss;
+ Number n;
+ Object o;
+ Array a;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ // Initialize this value as array with initial data, without calling destructor.
+ void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
+ flags_ = kArrayFlag;
+ if (count) {
+ data_.a.elements = static_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
+ std::memcpy(data_.a.elements, values, count * sizeof(GenericValue));
+ }
+ else
+ data_.a.elements = NULL;
+ data_.a.size = data_.a.capacity = count;
+ }
+
+ //! Initialize this value as object with initial data, without calling destructor.
+ void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
+ flags_ = kObjectFlag;
+ if (count) {
+ data_.o.members = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
+ std::memcpy(data_.o.members, members, count * sizeof(Member));
+ }
+ else
+ data_.o.members = NULL;
+ data_.o.size = data_.o.capacity = count;
+ }
+
+ //! Initialize this value as constant string, without calling destructor.
+ void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT {
+ flags_ = kConstStringFlag;
+ data_.s.str = s;
+ data_.s.length = s.length;
+ }
+
+ //! Initialize this value as copy string with initial data, without calling destructor.
+ void SetStringRaw(StringRefType s, Allocator& allocator) {
+ Ch* str = NULL;
+ if(ShortString::Usable(s.length)) {
+ flags_ = kShortStringFlag;
+ data_.ss.SetLength(s.length);
+ str = data_.ss.str;
+ } else {
+ flags_ = kCopyStringFlag;
+ data_.s.length = s.length;
+ str = static_cast<Ch *>(allocator.Malloc((s.length + 1) * sizeof(Ch)));
+ data_.s.str = str;
+ }
+ std::memcpy(str, s, s.length * sizeof(Ch));
+ str[s.length] = '\0';
+ }
+
+ //! Assignment without calling destructor
+ void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
+ data_ = rhs.data_;
+ flags_ = rhs.flags_;
+ rhs.flags_ = kNullFlag;
+ }
+
+ template <typename SourceAllocator>
+ bool StringEqual(const GenericValue<Encoding, SourceAllocator>& rhs) const {
+ RAPIDJSON_ASSERT(IsString());
+ RAPIDJSON_ASSERT(rhs.IsString());
+
+ const SizeType len1 = GetStringLength();
+ const SizeType len2 = rhs.GetStringLength();
+ if(len1 != len2) { return false; }
+
+ const Ch* const str1 = GetString();
+ const Ch* const str2 = rhs.GetString();
+ if(str1 == str2) { return true; } // fast path for constant string
+
+ return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0);
+ }
+
+ Data data_;
+ unsigned flags_;
+};
+
+//! GenericValue with UTF8 encoding
+typedef GenericValue<UTF8<> > Value;
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericDocument
+
+//! A document for parsing JSON text as DOM.
+/*!
+ \note implements Handler concept
+ \tparam Encoding Encoding for both parsing and string storage.
+ \tparam Allocator Allocator for allocating memory for the DOM
+ \tparam StackAllocator Allocator for allocating memory for stack during parsing.
+ \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue.
+*/
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<>, typename StackAllocator = CrtAllocator>
+class GenericDocument : public GenericValue<Encoding, Allocator> {
+public:
+ typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
+ typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of the document.
+ typedef Allocator AllocatorType; //!< Allocator type from template parameter.
+
+ //! Constructor
+ /*! Creates an empty document of specified type.
+ \param type Mandatory type of object to create.
+ \param allocator Optional allocator for allocating memory.
+ \param stackCapacity Optional initial capacity of stack in bytes.
+ \param stackAllocator Optional allocator for allocating memory for stack.
+ */
+ explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :
+ GenericValue<Encoding, Allocator>(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
+ {
+ if (!allocator_)
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+ }
+
+ //! Constructor
+ /*! Creates an empty document which type is Null.
+ \param allocator Optional allocator for allocating memory.
+ \param stackCapacity Optional initial capacity of stack in bytes.
+ \param stackAllocator Optional allocator for allocating memory for stack.
+ */
+ GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :
+ allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
+ {
+ if (!allocator_)
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move constructor in C++11
+ GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
+ : ValueType(std::forward<ValueType>(rhs)), // explicit cast to avoid prohibited move from Document
+ allocator_(rhs.allocator_),
+ ownAllocator_(rhs.ownAllocator_),
+ stack_(std::move(rhs.stack_)),
+ parseResult_(rhs.parseResult_)
+ {
+ rhs.allocator_ = 0;
+ rhs.ownAllocator_ = 0;
+ rhs.parseResult_ = ParseResult();
+ }
+#endif
+
+ ~GenericDocument() {
+ Destroy();
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move assignment in C++11
+ GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
+ {
+ // The cast to ValueType is necessary here, because otherwise it would
+ // attempt to call GenericValue's templated assignment operator.
+ ValueType::operator=(std::forward<ValueType>(rhs));
+
+ // Calling the destructor here would prematurely call stack_'s destructor
+ Destroy();
+
+ allocator_ = rhs.allocator_;
+ ownAllocator_ = rhs.ownAllocator_;
+ stack_ = std::move(rhs.stack_);
+ parseResult_ = rhs.parseResult_;
+
+ rhs.allocator_ = 0;
+ rhs.ownAllocator_ = 0;
+ rhs.parseResult_ = ParseResult();
+
+ return *this;
+ }
+#endif
+
+ //! Exchange the contents of this document with those of another.
+ /*!
+ \param rhs Another document.
+ \note Constant complexity.
+ \see GenericValue::Swap
+ */
+ GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT {
+ ValueType::Swap(rhs);
+ stack_.Swap(rhs.stack_);
+ internal::Swap(allocator_, rhs.allocator_);
+ internal::Swap(ownAllocator_, rhs.ownAllocator_);
+ internal::Swap(parseResult_, rhs.parseResult_);
+ return *this;
+ }
+
+ //! free-standing swap function helper
+ /*!
+ Helper function to enable support for common swap implementation pattern based on \c std::swap:
+ \code
+ void swap(MyClass& a, MyClass& b) {
+ using std::swap;
+ swap(a.doc, b.doc);
+ // ...
+ }
+ \endcode
+ \see Swap()
+ */
+ friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
+
+ //! Populate this document by a generator which produces SAX events.
+ /*! \tparam Generator A functor with <tt>bool f(Handler)</tt> prototype.
+ \param g Generator functor which sends SAX events to the parameter.
+ \return The document itself for fluent API.
+ */
+ template <typename Generator>
+ GenericDocument& Populate(Generator& g) {
+ ClearStackOnExit scope(*this);
+ if (g(*this)) {
+ RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
+ ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document
+ }
+ return *this;
+ }
+
+ //!@name Parse from stream
+ //!@{
+
+ //! Parse JSON text from an input stream (with Encoding conversion)
+ /*! \tparam parseFlags Combination of \ref ParseFlag.
+ \tparam SourceEncoding Encoding of input stream
+ \tparam InputStream Type of input stream, implementing Stream concept
+ \param is Input stream to be parsed.
+ \return The document itself for fluent API.
+ */
+ template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
+ GenericDocument& ParseStream(InputStream& is) {
+ GenericReader<SourceEncoding, Encoding, StackAllocator> reader(
+ stack_.HasAllocator() ? &stack_.GetAllocator() : 0);
+ ClearStackOnExit scope(*this);
+ parseResult_ = reader.template Parse<parseFlags>(is, *this);
+ if (parseResult_) {
+ RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
+ ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document
+ }
+ return *this;
+ }
+
+ //! Parse JSON text from an input stream
+ /*! \tparam parseFlags Combination of \ref ParseFlag.
+ \tparam InputStream Type of input stream, implementing Stream concept
+ \param is Input stream to be parsed.
+ \return The document itself for fluent API.
+ */
+ template <unsigned parseFlags, typename InputStream>
+ GenericDocument& ParseStream(InputStream& is) {
+ return ParseStream<parseFlags, Encoding, InputStream>(is);
+ }
+
+ //! Parse JSON text from an input stream (with \ref kParseDefaultFlags)
+ /*! \tparam InputStream Type of input stream, implementing Stream concept
+ \param is Input stream to be parsed.
+ \return The document itself for fluent API.
+ */
+ template <typename InputStream>
+ GenericDocument& ParseStream(InputStream& is) {
+ return ParseStream<kParseDefaultFlags, Encoding, InputStream>(is);
+ }
+ //!@}
+
+ //!@name Parse in-place from mutable string
+ //!@{
+
+ //! Parse JSON text from a mutable string
+ /*! \tparam parseFlags Combination of \ref ParseFlag.
+ \param str Mutable zero-terminated string to be parsed.
+ \return The document itself for fluent API.
+ */
+ template <unsigned parseFlags>
+ GenericDocument& ParseInsitu(Ch* str) {
+ GenericInsituStringStream<Encoding> s(str);
+ return ParseStream<parseFlags | kParseInsituFlag>(s);
+ }
+
+ //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags)
+ /*! \param str Mutable zero-terminated string to be parsed.
+ \return The document itself for fluent API.
+ */
+ GenericDocument& ParseInsitu(Ch* str) {
+ return ParseInsitu<kParseDefaultFlags>(str);
+ }
+ //!@}
+
+ //!@name Parse from read-only string
+ //!@{
+
+ //! Parse JSON text from a read-only string (with Encoding conversion)
+ /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag).
+ \tparam SourceEncoding Transcoding from input Encoding
+ \param str Read-only zero-terminated string to be parsed.
+ */
+ template <unsigned parseFlags, typename SourceEncoding>
+ GenericDocument& Parse(const typename SourceEncoding::Ch* str) {
+ RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
+ GenericStringStream<SourceEncoding> s(str);
+ return ParseStream<parseFlags, SourceEncoding>(s);
+ }
+
+ //! Parse JSON text from a read-only string
+ /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag).
+ \param str Read-only zero-terminated string to be parsed.
+ */
+ template <unsigned parseFlags>
+ GenericDocument& Parse(const Ch* str) {
+ return Parse<parseFlags, Encoding>(str);
+ }
+
+ //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags)
+ /*! \param str Read-only zero-terminated string to be parsed.
+ */
+ GenericDocument& Parse(const Ch* str) {
+ return Parse<kParseDefaultFlags>(str);
+ }
+ //!@}
+
+ //!@name Handling parse errors
+ //!@{
+
+ //! Whether a parse error has occured in the last parsing.
+ bool HasParseError() const { return parseResult_.IsError(); }
+
+ //! Get the \ref ParseErrorCode of last parsing.
+ ParseErrorCode GetParseError() const { return parseResult_.Code(); }
+
+ //! Get the position of last parsing error in input, 0 otherwise.
+ size_t GetErrorOffset() const { return parseResult_.Offset(); }
+
+ //! Implicit conversion to get the last parse result
+#ifndef __clang // -Wdocumentation
+ /*! \return \ref ParseResult of the last parse operation
+
+ \code
+ Document doc;
+ ParseResult ok = doc.Parse(json);
+ if (!ok)
+ printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset());
+ \endcode
+ */
+#endif
+ operator ParseResult() const { return parseResult_; }
+ //!@}
+
+ //! Get the allocator of this document.
+ Allocator& GetAllocator() {
+ RAPIDJSON_ASSERT(allocator_);
+ return *allocator_;
+ }
+
+ //! Get the capacity of stack in bytes.
+ size_t GetStackCapacity() const { return stack_.GetCapacity(); }
+
+private:
+ // clear stack on any exit from ParseStream, e.g. due to exception
+ struct ClearStackOnExit {
+ explicit ClearStackOnExit(GenericDocument& d) : d_(d) {}
+ ~ClearStackOnExit() { d_.ClearStack(); }
+ private:
+ ClearStackOnExit(const ClearStackOnExit&);
+ ClearStackOnExit& operator=(const ClearStackOnExit&);
+ GenericDocument& d_;
+ };
+
+ // callers of the following private Handler functions
+ // template <typename,typename,typename> friend class GenericReader; // for parsing
+ template <typename, typename> friend class GenericValue; // for deep copying
+
+public:
+ // Implementation of Handler
+ bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return true; }
+ bool Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); return true; }
+ bool Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+ bool Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+ bool Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+ bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+ bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); return true; }
+
+ bool String(const Ch* str, SizeType length, bool copy) {
+ if (copy)
+ new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
+ else
+ new (stack_.template Push<ValueType>()) ValueType(str, length);
+ return true;
+ }
+
+ bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); return true; }
+
+ bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); }
+
+ bool EndObject(SizeType memberCount) {
+ typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
+ stack_.template Top<ValueType>()->SetObjectRaw(members, memberCount, GetAllocator());
+ return true;
+ }
+
+ bool StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); return true; }
+
+ bool EndArray(SizeType elementCount) {
+ ValueType* elements = stack_.template Pop<ValueType>(elementCount);
+ stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator());
+ return true;
+ }
+
+private:
+ //! Prohibit copying
+ GenericDocument(const GenericDocument&);
+ //! Prohibit assignment
+ GenericDocument& operator=(const GenericDocument&);
+
+ void ClearStack() {
+ if (Allocator::kNeedFree)
+ while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects)
+ (stack_.template Pop<ValueType>(1))->~ValueType();
+ else
+ stack_.Clear();
+ stack_.ShrinkToFit();
+ }
+
+ void Destroy() {
+ RAPIDJSON_DELETE(ownAllocator_);
+ }
+
+ static const size_t kDefaultStackCapacity = 1024;
+ Allocator* allocator_;
+ Allocator* ownAllocator_;
+ internal::Stack<StackAllocator> stack_;
+ ParseResult parseResult_;
+};
+
+//! GenericDocument with UTF8 encoding
+typedef GenericDocument<UTF8<> > Document;
+
+// defined here due to the dependency on GenericDocument
+template <typename Encoding, typename Allocator>
+template <typename SourceAllocator>
+inline
+GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator)
+{
+ switch (rhs.GetType()) {
+ case kObjectType:
+ case kArrayType: { // perform deep copy via SAX Handler
+ GenericDocument<Encoding,Allocator> d(&allocator);
+ rhs.Accept(d);
+ RawAssign(*d.stack_.template Pop<GenericValue>(1));
+ }
+ break;
+ case kStringType:
+ if (rhs.flags_ == kConstStringFlag) {
+ flags_ = rhs.flags_;
+ data_ = *reinterpret_cast<const Data*>(&rhs.data_);
+ } else {
+ SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);
+ }
+ break;
+ default:
+ flags_ = rhs.flags_;
+ data_ = *reinterpret_cast<const Data*>(&rhs.data_);
+ break;
+ }
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_DOCUMENT_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/encodedstream.h b/3rdparty/rapidjson/include/rapidjson/encodedstream.h
new file mode 100644
index 00000000000..87d09bbb150
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/encodedstream.h
@@ -0,0 +1,270 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ENCODEDSTREAM_H_
+#define RAPIDJSON_ENCODEDSTREAM_H_
+
+#include "stream.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Input byte stream wrapper with a statically bound encoding.
+/*!
+ \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
+ \tparam InputByteStream Type of input byte stream. For example, FileReadStream.
+*/
+template <typename Encoding, typename InputByteStream>
+class EncodedInputStream {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+public:
+ typedef typename Encoding::Ch Ch;
+
+ EncodedInputStream(InputByteStream& is) : is_(is) {
+ current_ = Encoding::TakeBOM(is_);
+ }
+
+ Ch Peek() const { return current_; }
+ Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
+ size_t Tell() const { return is_.Tell(); }
+
+ // Not implemented
+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
+ void Flush() { RAPIDJSON_ASSERT(false); }
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+ EncodedInputStream(const EncodedInputStream&);
+ EncodedInputStream& operator=(const EncodedInputStream&);
+
+ InputByteStream& is_;
+ Ch current_;
+};
+
+//! Output byte stream wrapper with statically bound encoding.
+/*!
+ \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
+ \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.
+*/
+template <typename Encoding, typename OutputByteStream>
+class EncodedOutputStream {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+public:
+ typedef typename Encoding::Ch Ch;
+
+ EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) {
+ if (putBOM)
+ Encoding::PutBOM(os_);
+ }
+
+ void Put(Ch c) { Encoding::Put(os_, c); }
+ void Flush() { os_.Flush(); }
+
+ // Not implemented
+ Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
+ Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
+ size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+ EncodedOutputStream(const EncodedOutputStream&);
+ EncodedOutputStream& operator=(const EncodedOutputStream&);
+
+ OutputByteStream& os_;
+};
+
+#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
+
+//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
+/*!
+ \tparam CharType Type of character for reading.
+ \tparam InputByteStream type of input byte stream to be wrapped.
+*/
+template <typename CharType, typename InputByteStream>
+class AutoUTFInputStream {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+public:
+ typedef CharType Ch;
+
+ //! Constructor.
+ /*!
+ \param is input stream to be wrapped.
+ \param type UTF encoding type if it is not detected from the stream.
+ */
+ AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
+ RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
+ DetectType();
+ static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
+ takeFunc_ = f[type_];
+ current_ = takeFunc_(*is_);
+ }
+
+ UTFType GetType() const { return type_; }
+ bool HasBOM() const { return hasBOM_; }
+
+ Ch Peek() const { return current_; }
+ Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
+ size_t Tell() const { return is_->Tell(); }
+
+ // Not implemented
+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
+ void Flush() { RAPIDJSON_ASSERT(false); }
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+ AutoUTFInputStream(const AutoUTFInputStream&);
+ AutoUTFInputStream& operator=(const AutoUTFInputStream&);
+
+ // Detect encoding type with BOM or RFC 4627
+ void DetectType() {
+ // BOM (Byte Order Mark):
+ // 00 00 FE FF UTF-32BE
+ // FF FE 00 00 UTF-32LE
+ // FE FF UTF-16BE
+ // FF FE UTF-16LE
+ // EF BB BF UTF-8
+
+ const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());
+ if (!c)
+ return;
+
+ unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
+ hasBOM_ = false;
+ if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
+ else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
+ else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
+ else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
+ else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
+
+ // RFC 4627: Section 3
+ // "Since the first two characters of a JSON text will always be ASCII
+ // characters [RFC0020], it is possible to determine whether an octet
+ // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
+ // at the pattern of nulls in the first four octets."
+ // 00 00 00 xx UTF-32BE
+ // 00 xx 00 xx UTF-16BE
+ // xx 00 00 00 UTF-32LE
+ // xx 00 xx 00 UTF-16LE
+ // xx xx xx xx UTF-8
+
+ if (!hasBOM_) {
+ unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
+ switch (pattern) {
+ case 0x08: type_ = kUTF32BE; break;
+ case 0x0A: type_ = kUTF16BE; break;
+ case 0x01: type_ = kUTF32LE; break;
+ case 0x05: type_ = kUTF16LE; break;
+ case 0x0F: type_ = kUTF8; break;
+ default: break; // Use type defined by user.
+ }
+ }
+
+ // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
+ if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
+ if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
+ }
+
+ typedef Ch (*TakeFunc)(InputByteStream& is);
+ InputByteStream* is_;
+ UTFType type_;
+ Ch current_;
+ TakeFunc takeFunc_;
+ bool hasBOM_;
+};
+
+//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
+/*!
+ \tparam CharType Type of character for writing.
+ \tparam OutputByteStream type of output byte stream to be wrapped.
+*/
+template <typename CharType, typename OutputByteStream>
+class AutoUTFOutputStream {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+public:
+ typedef CharType Ch;
+
+ //! Constructor.
+ /*!
+ \param os output stream to be wrapped.
+ \param type UTF encoding type.
+ \param putBOM Whether to write BOM at the beginning of the stream.
+ */
+ AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
+ RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
+
+ // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
+ if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
+ if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
+
+ static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
+ putFunc_ = f[type_];
+
+ if (putBOM)
+ PutBOM();
+ }
+
+ UTFType GetType() const { return type_; }
+
+ void Put(Ch c) { putFunc_(*os_, c); }
+ void Flush() { os_->Flush(); }
+
+ // Not implemented
+ Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
+ Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
+ size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+ AutoUTFOutputStream(const AutoUTFOutputStream&);
+ AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
+
+ void PutBOM() {
+ typedef void (*PutBOMFunc)(OutputByteStream&);
+ static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
+ f[type_](*os_);
+ }
+
+ typedef void (*PutFunc)(OutputByteStream&, Ch);
+
+ OutputByteStream* os_;
+ UTFType type_;
+ PutFunc putFunc_;
+};
+
+#undef RAPIDJSON_ENCODINGS_FUNC
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_FILESTREAM_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/encodings.h b/3rdparty/rapidjson/include/rapidjson/encodings.h
new file mode 100644
index 00000000000..edfc9901615
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/encodings.h
@@ -0,0 +1,712 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ENCODINGS_H_
+#define RAPIDJSON_ENCODINGS_H_
+
+#include "rapidjson.h"
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
+RAPIDJSON_DIAG_OFF(4702) // unreachable code
+#elif defined(__GNUC__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+RAPIDJSON_DIAG_OFF(overflow)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Encoding
+
+/*! \class rapidjson::Encoding
+ \brief Concept for encoding of Unicode characters.
+
+\code
+concept Encoding {
+ typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition.
+
+ enum { supportUnicode = 1 }; // or 0 if not supporting unicode
+
+ //! \brief Encode a Unicode codepoint to an output stream.
+ //! \param os Output stream.
+ //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
+ template<typename OutputStream>
+ static void Encode(OutputStream& os, unsigned codepoint);
+
+ //! \brief Decode a Unicode codepoint from an input stream.
+ //! \param is Input stream.
+ //! \param codepoint Output of the unicode codepoint.
+ //! \return true if a valid codepoint can be decoded from the stream.
+ template <typename InputStream>
+ static bool Decode(InputStream& is, unsigned* codepoint);
+
+ //! \brief Validate one Unicode codepoint from an encoded stream.
+ //! \param is Input stream to obtain codepoint.
+ //! \param os Output for copying one codepoint.
+ //! \return true if it is valid.
+ //! \note This function just validating and copying the codepoint without actually decode it.
+ template <typename InputStream, typename OutputStream>
+ static bool Validate(InputStream& is, OutputStream& os);
+
+ // The following functions are deal with byte streams.
+
+ //! Take a character from input byte stream, skip BOM if exist.
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is);
+
+ //! Take a character from input byte stream.
+ template <typename InputByteStream>
+ static Ch Take(InputByteStream& is);
+
+ //! Put BOM to output byte stream.
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os);
+
+ //! Put a character to output byte stream.
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, Ch c);
+};
+\endcode
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF8
+
+//! UTF-8 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-8
+ http://tools.ietf.org/html/rfc3629
+ \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
+ \note implements Encoding concept
+*/
+template<typename CharType = char>
+struct UTF8 {
+ typedef CharType Ch;
+
+ enum { supportUnicode = 1 };
+
+ template<typename OutputStream>
+ static void Encode(OutputStream& os, unsigned codepoint) {
+ if (codepoint <= 0x7F)
+ os.Put(static_cast<Ch>(codepoint & 0xFF));
+ else if (codepoint <= 0x7FF) {
+ os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
+ os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
+ }
+ else if (codepoint <= 0xFFFF) {
+ os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
+ os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+ os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+ }
+ else {
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
+ os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
+ os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+ os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+ }
+ }
+
+ template<typename OutputStream>
+ static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+ if (codepoint <= 0x7F)
+ PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
+ else if (codepoint <= 0x7FF) {
+ PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
+ PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
+ }
+ else if (codepoint <= 0xFFFF) {
+ PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
+ PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+ PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+ }
+ else {
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
+ PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
+ PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+ PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+ }
+ }
+
+ template <typename InputStream>
+ static bool Decode(InputStream& is, unsigned* codepoint) {
+#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
+#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
+#define TAIL() COPY(); TRANS(0x70)
+ typename InputStream::Ch c = is.Take();
+ if (!(c & 0x80)) {
+ *codepoint = static_cast<unsigned char>(c);
+ return true;
+ }
+
+ unsigned char type = GetRange(static_cast<unsigned char>(c));
+ *codepoint = (0xFF >> type) & static_cast<unsigned char>(c);
+ bool result = true;
+ switch (type) {
+ case 2: TAIL(); return result;
+ case 3: TAIL(); TAIL(); return result;
+ case 4: COPY(); TRANS(0x50); TAIL(); return result;
+ case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
+ case 6: TAIL(); TAIL(); TAIL(); return result;
+ case 10: COPY(); TRANS(0x20); TAIL(); return result;
+ case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
+ default: return false;
+ }
+#undef COPY
+#undef TRANS
+#undef TAIL
+ }
+
+ template <typename InputStream, typename OutputStream>
+ static bool Validate(InputStream& is, OutputStream& os) {
+#define COPY() os.Put(c = is.Take())
+#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
+#define TAIL() COPY(); TRANS(0x70)
+ Ch c;
+ COPY();
+ if (!(c & 0x80))
+ return true;
+
+ bool result = true;
+ switch (GetRange(static_cast<unsigned char>(c))) {
+ case 2: TAIL(); return result;
+ case 3: TAIL(); TAIL(); return result;
+ case 4: COPY(); TRANS(0x50); TAIL(); return result;
+ case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
+ case 6: TAIL(); TAIL(); TAIL(); return result;
+ case 10: COPY(); TRANS(0x20); TAIL(); return result;
+ case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
+ default: return false;
+ }
+#undef COPY
+#undef TRANS
+#undef TAIL
+ }
+
+ static unsigned char GetRange(unsigned char c) {
+ // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
+ // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
+ static const unsigned char type[] = {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+ 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
+ };
+ return type[c];
+ }
+
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ typename InputByteStream::Ch c = Take(is);
+ if (static_cast<unsigned char>(c) != 0xEFu) return c;
+ c = is.Take();
+ if (static_cast<unsigned char>(c) != 0xBBu) return c;
+ c = is.Take();
+ if (static_cast<unsigned char>(c) != 0xBFu) return c;
+ c = is.Take();
+ return c;
+ }
+
+ template <typename InputByteStream>
+ static Ch Take(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ return static_cast<Ch>(is.Take());
+ }
+
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu));
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xBFu));
+ }
+
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, Ch c) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(c));
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF16
+
+//! UTF-16 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-16
+ http://tools.ietf.org/html/rfc2781
+ \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
+ \note implements Encoding concept
+
+ \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
+ For streaming, use UTF16LE and UTF16BE, which handle endianness.
+*/
+template<typename CharType = wchar_t>
+struct UTF16 {
+ typedef CharType Ch;
+ RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
+
+ enum { supportUnicode = 1 };
+
+ template<typename OutputStream>
+ static void Encode(OutputStream& os, unsigned codepoint) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
+ if (codepoint <= 0xFFFF) {
+ RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
+ os.Put(static_cast<typename OutputStream::Ch>(codepoint));
+ }
+ else {
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ unsigned v = codepoint - 0x10000;
+ os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
+ os.Put((v & 0x3FF) | 0xDC00);
+ }
+ }
+
+
+ template<typename OutputStream>
+ static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
+ if (codepoint <= 0xFFFF) {
+ RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
+ PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint));
+ }
+ else {
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ unsigned v = codepoint - 0x10000;
+ PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
+ PutUnsafe(os, (v & 0x3FF) | 0xDC00);
+ }
+ }
+
+ template <typename InputStream>
+ static bool Decode(InputStream& is, unsigned* codepoint) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
+ typename InputStream::Ch c = is.Take();
+ if (c < 0xD800 || c > 0xDFFF) {
+ *codepoint = static_cast<unsigned>(c);
+ return true;
+ }
+ else if (c <= 0xDBFF) {
+ *codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10;
+ c = is.Take();
+ *codepoint |= (static_cast<unsigned>(c) & 0x3FF);
+ *codepoint += 0x10000;
+ return c >= 0xDC00 && c <= 0xDFFF;
+ }
+ return false;
+ }
+
+ template <typename InputStream, typename OutputStream>
+ static bool Validate(InputStream& is, OutputStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
+ typename InputStream::Ch c;
+ os.Put(static_cast<typename OutputStream::Ch>(c = is.Take()));
+ if (c < 0xD800 || c > 0xDFFF)
+ return true;
+ else if (c <= 0xDBFF) {
+ os.Put(c = is.Take());
+ return c >= 0xDC00 && c <= 0xDFFF;
+ }
+ return false;
+ }
+};
+
+//! UTF-16 little endian encoding.
+template<typename CharType = wchar_t>
+struct UTF16LE : UTF16<CharType> {
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ CharType c = Take(is);
+ return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
+ }
+
+ template <typename InputByteStream>
+ static CharType Take(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ unsigned c = static_cast<uint8_t>(is.Take());
+ c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
+ return static_cast<CharType>(c);
+ }
+
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
+ }
+
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, CharType c) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
+ }
+};
+
+//! UTF-16 big endian encoding.
+template<typename CharType = wchar_t>
+struct UTF16BE : UTF16<CharType> {
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ CharType c = Take(is);
+ return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
+ }
+
+ template <typename InputByteStream>
+ static CharType Take(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
+ c |= static_cast<uint8_t>(is.Take());
+ return static_cast<CharType>(c);
+ }
+
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
+ }
+
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, CharType c) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF32
+
+//! UTF-32 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-32
+ \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
+ \note implements Encoding concept
+
+ \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
+ For streaming, use UTF32LE and UTF32BE, which handle endianness.
+*/
+template<typename CharType = unsigned>
+struct UTF32 {
+ typedef CharType Ch;
+ RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
+
+ enum { supportUnicode = 1 };
+
+ template<typename OutputStream>
+ static void Encode(OutputStream& os, unsigned codepoint) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ os.Put(codepoint);
+ }
+
+ template<typename OutputStream>
+ static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ PutUnsafe(os, codepoint);
+ }
+
+ template <typename InputStream>
+ static bool Decode(InputStream& is, unsigned* codepoint) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
+ Ch c = is.Take();
+ *codepoint = c;
+ return c <= 0x10FFFF;
+ }
+
+ template <typename InputStream, typename OutputStream>
+ static bool Validate(InputStream& is, OutputStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
+ Ch c;
+ os.Put(c = is.Take());
+ return c <= 0x10FFFF;
+ }
+};
+
+//! UTF-32 little endian enocoding.
+template<typename CharType = unsigned>
+struct UTF32LE : UTF32<CharType> {
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ CharType c = Take(is);
+ return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
+ }
+
+ template <typename InputByteStream>
+ static CharType Take(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ unsigned c = static_cast<uint8_t>(is.Take());
+ c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
+ c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
+ c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
+ return static_cast<CharType>(c);
+ }
+
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
+ os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
+ os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
+ }
+
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, CharType c) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
+ }
+};
+
+//! UTF-32 big endian encoding.
+template<typename CharType = unsigned>
+struct UTF32BE : UTF32<CharType> {
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ CharType c = Take(is);
+ return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
+ }
+
+ template <typename InputByteStream>
+ static CharType Take(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
+ c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
+ c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
+ c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
+ return static_cast<CharType>(c);
+ }
+
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
+ os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
+ os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
+ }
+
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, CharType c) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
+ os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// ASCII
+
+//! ASCII encoding.
+/*! http://en.wikipedia.org/wiki/ASCII
+ \tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
+ \note implements Encoding concept
+*/
+template<typename CharType = char>
+struct ASCII {
+ typedef CharType Ch;
+
+ enum { supportUnicode = 0 };
+
+ template<typename OutputStream>
+ static void Encode(OutputStream& os, unsigned codepoint) {
+ RAPIDJSON_ASSERT(codepoint <= 0x7F);
+ os.Put(static_cast<Ch>(codepoint & 0xFF));
+ }
+
+ template<typename OutputStream>
+ static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+ RAPIDJSON_ASSERT(codepoint <= 0x7F);
+ PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
+ }
+
+ template <typename InputStream>
+ static bool Decode(InputStream& is, unsigned* codepoint) {
+ uint8_t c = static_cast<uint8_t>(is.Take());
+ *codepoint = c;
+ return c <= 0X7F;
+ }
+
+ template <typename InputStream, typename OutputStream>
+ static bool Validate(InputStream& is, OutputStream& os) {
+ uint8_t c = static_cast<uint8_t>(is.Take());
+ os.Put(static_cast<typename OutputStream::Ch>(c));
+ return c <= 0x7F;
+ }
+
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ uint8_t c = static_cast<uint8_t>(Take(is));
+ return static_cast<Ch>(c);
+ }
+
+ template <typename InputByteStream>
+ static Ch Take(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ return static_cast<Ch>(is.Take());
+ }
+
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ (void)os;
+ }
+
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, Ch c) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(c));
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// AutoUTF
+
+//! Runtime-specified UTF encoding type of a stream.
+enum UTFType {
+ kUTF8 = 0, //!< UTF-8.
+ kUTF16LE = 1, //!< UTF-16 little endian.
+ kUTF16BE = 2, //!< UTF-16 big endian.
+ kUTF32LE = 3, //!< UTF-32 little endian.
+ kUTF32BE = 4 //!< UTF-32 big endian.
+};
+
+//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
+/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
+*/
+template<typename CharType>
+struct AutoUTF {
+ typedef CharType Ch;
+
+ enum { supportUnicode = 1 };
+
+#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
+
+ template<typename OutputStream>
+ RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) {
+ typedef void (*EncodeFunc)(OutputStream&, unsigned);
+ static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
+ (*f[os.GetType()])(os, codepoint);
+ }
+
+ template<typename OutputStream>
+ RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+ typedef void (*EncodeFunc)(OutputStream&, unsigned);
+ static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) };
+ (*f[os.GetType()])(os, codepoint);
+ }
+
+ template <typename InputStream>
+ RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
+ typedef bool (*DecodeFunc)(InputStream&, unsigned*);
+ static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
+ return (*f[is.GetType()])(is, codepoint);
+ }
+
+ template <typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+ typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
+ static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
+ return (*f[is.GetType()])(is, os);
+ }
+
+#undef RAPIDJSON_ENCODINGS_FUNC
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Transcoder
+
+//! Encoding conversion.
+template<typename SourceEncoding, typename TargetEncoding>
+struct Transcoder {
+ //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
+ template<typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
+ unsigned codepoint;
+ if (!SourceEncoding::Decode(is, &codepoint))
+ return false;
+ TargetEncoding::Encode(os, codepoint);
+ return true;
+ }
+
+ template<typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
+ unsigned codepoint;
+ if (!SourceEncoding::Decode(is, &codepoint))
+ return false;
+ TargetEncoding::EncodeUnsafe(os, codepoint);
+ return true;
+ }
+
+ //! Validate one Unicode codepoint from an encoded stream.
+ template<typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+ return Transcode(is, os); // Since source/target encoding is different, must transcode.
+ }
+};
+
+// Forward declaration.
+template<typename Stream>
+inline void PutUnsafe(Stream& stream, typename Stream::Ch c);
+
+//! Specialization of Transcoder with same source and target encoding.
+template<typename Encoding>
+struct Transcoder<Encoding, Encoding> {
+ template<typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
+ os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
+ return true;
+ }
+
+ template<typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
+ PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class.
+ return true;
+ }
+
+ template<typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+ return Encoding::Validate(is, os); // source/target encoding are the same
+ }
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__GNUC__) || defined(_MSC_VER)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_ENCODINGS_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/error/en.h b/3rdparty/rapidjson/include/rapidjson/error/en.h
new file mode 100644
index 00000000000..c2315fda7d5
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/error/en.h
@@ -0,0 +1,74 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ERROR_EN_H_
+#define RAPIDJSON_ERROR_EN_H_
+
+#include "error.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(switch-enum)
+RAPIDJSON_DIAG_OFF(covered-switch-default)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Maps error code of parsing into error message.
+/*!
+ \ingroup RAPIDJSON_ERRORS
+ \param parseErrorCode Error code obtained in parsing.
+ \return the error message.
+ \note User can make a copy of this function for localization.
+ Using switch-case is safer for future modification of error codes.
+*/
+inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
+ switch (parseErrorCode) {
+ case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
+
+ case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
+ case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow by other values.");
+
+ case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");
+
+ case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
+ case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
+ case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
+
+ case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
+
+ case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
+ case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
+ case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
+ case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
+ case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
+
+ case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
+ case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
+ case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
+
+ case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
+ case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
+
+ default: return RAPIDJSON_ERROR_STRING("Unknown error.");
+ }
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_ERROR_EN_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/error/error.h b/3rdparty/rapidjson/include/rapidjson/error/error.h
new file mode 100644
index 00000000000..95cb31a72fe
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/error/error.h
@@ -0,0 +1,155 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ERROR_ERROR_H_
+#define RAPIDJSON_ERROR_ERROR_H_
+
+#include "../rapidjson.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+/*! \file error.h */
+
+/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ERROR_CHARTYPE
+
+//! Character type of error messages.
+/*! \ingroup RAPIDJSON_ERRORS
+ The default character type is \c char.
+ On Windows, user can define this macro as \c TCHAR for supporting both
+ unicode/non-unicode settings.
+*/
+#ifndef RAPIDJSON_ERROR_CHARTYPE
+#define RAPIDJSON_ERROR_CHARTYPE char
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ERROR_STRING
+
+//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
+/*! \ingroup RAPIDJSON_ERRORS
+ By default this conversion macro does nothing.
+ On Windows, user can define this macro as \c _T(x) for supporting both
+ unicode/non-unicode settings.
+*/
+#ifndef RAPIDJSON_ERROR_STRING
+#define RAPIDJSON_ERROR_STRING(x) x
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseErrorCode
+
+//! Error code of parsing.
+/*! \ingroup RAPIDJSON_ERRORS
+ \see GenericReader::Parse, GenericReader::GetParseErrorCode
+*/
+enum ParseErrorCode {
+ kParseErrorNone = 0, //!< No error.
+
+ kParseErrorDocumentEmpty, //!< The document is empty.
+ kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values.
+
+ kParseErrorValueInvalid, //!< Invalid value.
+
+ kParseErrorObjectMissName, //!< Missing a name for object member.
+ kParseErrorObjectMissColon, //!< Missing a colon after a name of object member.
+ kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member.
+
+ kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element.
+
+ kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string.
+ kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid.
+ kParseErrorStringEscapeInvalid, //!< Invalid escape character in string.
+ kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string.
+ kParseErrorStringInvalidEncoding, //!< Invalid encoding in string.
+
+ kParseErrorNumberTooBig, //!< Number too big to be stored in double.
+ kParseErrorNumberMissFraction, //!< Miss fraction part in number.
+ kParseErrorNumberMissExponent, //!< Miss exponent in number.
+
+ kParseErrorTermination, //!< Parsing was terminated.
+ kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
+};
+
+//! Result of parsing (wraps ParseErrorCode)
+/*!
+ \ingroup RAPIDJSON_ERRORS
+ \code
+ Document doc;
+ ParseResult ok = doc.Parse("[42]");
+ if (!ok) {
+ fprintf(stderr, "JSON parse error: %s (%u)",
+ GetParseError_En(ok.Code()), ok.Offset());
+ exit(EXIT_FAILURE);
+ }
+ \endcode
+ \see GenericReader::Parse, GenericDocument::Parse
+*/
+struct ParseResult {
+public:
+ //! Default constructor, no error.
+ ParseResult() : code_(kParseErrorNone), offset_(0) {}
+ //! Constructor to set an error.
+ ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
+
+ //! Get the error code.
+ ParseErrorCode Code() const { return code_; }
+ //! Get the error offset, if \ref IsError(), 0 otherwise.
+ size_t Offset() const { return offset_; }
+
+ //! Conversion to \c bool, returns \c true, iff !\ref IsError().
+ operator bool() const { return !IsError(); }
+ //! Whether the result is an error.
+ bool IsError() const { return code_ != kParseErrorNone; }
+
+ bool operator==(const ParseResult& that) const { return code_ == that.code_; }
+ bool operator==(ParseErrorCode code) const { return code_ == code; }
+ friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
+
+ //! Reset error code.
+ void Clear() { Set(kParseErrorNone); }
+ //! Update error code and offset.
+ void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
+
+private:
+ ParseErrorCode code_;
+ size_t offset_;
+};
+
+//! Function pointer type of GetParseError().
+/*! \ingroup RAPIDJSON_ERRORS
+
+ This is the prototype for \c GetParseError_X(), where \c X is a locale.
+ User can dynamically change locale in runtime, e.g.:
+\code
+ GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
+ const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
+\endcode
+*/
+typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_ERROR_ERROR_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/filereadstream.h b/3rdparty/rapidjson/include/rapidjson/filereadstream.h
new file mode 100644
index 00000000000..b56ea13b342
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/filereadstream.h
@@ -0,0 +1,99 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_FILEREADSTREAM_H_
+#define RAPIDJSON_FILEREADSTREAM_H_
+
+#include "stream.h"
+#include <cstdio>
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(unreachable-code)
+RAPIDJSON_DIAG_OFF(missing-noreturn)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! File byte stream for input using fread().
+/*!
+ \note implements Stream concept
+*/
+class FileReadStream {
+public:
+ typedef char Ch; //!< Character type (byte).
+
+ //! Constructor.
+ /*!
+ \param fp File pointer opened for read.
+ \param buffer user-supplied buffer.
+ \param bufferSize size of buffer in bytes. Must >=4 bytes.
+ */
+ FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
+ RAPIDJSON_ASSERT(fp_ != 0);
+ RAPIDJSON_ASSERT(bufferSize >= 4);
+ Read();
+ }
+
+ Ch Peek() const { return *current_; }
+ Ch Take() { Ch c = *current_; Read(); return c; }
+ size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
+
+ // Not implemented
+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
+ void Flush() { RAPIDJSON_ASSERT(false); }
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+ // For encoding detection only.
+ const Ch* Peek4() const {
+ return (current_ + 4 <= bufferLast_) ? current_ : 0;
+ }
+
+private:
+ void Read() {
+ if (current_ < bufferLast_)
+ ++current_;
+ else if (!eof_) {
+ count_ += readCount_;
+ readCount_ = fread(buffer_, 1, bufferSize_, fp_);
+ bufferLast_ = buffer_ + readCount_ - 1;
+ current_ = buffer_;
+
+ if (readCount_ < bufferSize_) {
+ buffer_[readCount_] = '\0';
+ ++bufferLast_;
+ eof_ = true;
+ }
+ }
+ }
+
+ std::FILE* fp_;
+ Ch *buffer_;
+ size_t bufferSize_;
+ Ch *bufferLast_;
+ Ch *current_;
+ size_t readCount_;
+ size_t count_; //!< Number of characters read
+ bool eof_;
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_FILESTREAM_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/filewritestream.h b/3rdparty/rapidjson/include/rapidjson/filewritestream.h
new file mode 100644
index 00000000000..6378dd60ed4
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/filewritestream.h
@@ -0,0 +1,104 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_FILEWRITESTREAM_H_
+#define RAPIDJSON_FILEWRITESTREAM_H_
+
+#include "stream.h"
+#include <cstdio>
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(unreachable-code)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Wrapper of C file stream for input using fread().
+/*!
+ \note implements Stream concept
+*/
+class FileWriteStream {
+public:
+ typedef char Ch; //!< Character type. Only support char.
+
+ FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
+ RAPIDJSON_ASSERT(fp_ != 0);
+ }
+
+ void Put(char c) {
+ if (current_ >= bufferEnd_)
+ Flush();
+
+ *current_++ = c;
+ }
+
+ void PutN(char c, size_t n) {
+ size_t avail = static_cast<size_t>(bufferEnd_ - current_);
+ while (n > avail) {
+ std::memset(current_, c, avail);
+ current_ += avail;
+ Flush();
+ n -= avail;
+ avail = static_cast<size_t>(bufferEnd_ - current_);
+ }
+
+ if (n > 0) {
+ std::memset(current_, c, n);
+ current_ += n;
+ }
+ }
+
+ void Flush() {
+ if (current_ != buffer_) {
+ size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
+ if (result < static_cast<size_t>(current_ - buffer_)) {
+ // failure deliberately ignored at this time
+ // added to avoid warn_unused_result build errors
+ }
+ current_ = buffer_;
+ }
+ }
+
+ // Not implemented
+ char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
+ char Take() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
+ char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+ // Prohibit copy constructor & assignment operator.
+ FileWriteStream(const FileWriteStream&);
+ FileWriteStream& operator=(const FileWriteStream&);
+
+ std::FILE* fp_;
+ char *buffer_;
+ char *bufferEnd_;
+ char *current_;
+};
+
+//! Implement specialized version of PutN() with memset() for better performance.
+template<>
+inline void PutN(FileWriteStream& stream, char c, size_t n) {
+ stream.PutN(c, n);
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_FILESTREAM_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/fwd.h b/3rdparty/rapidjson/include/rapidjson/fwd.h
new file mode 100644
index 00000000000..e8104e841bc
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/fwd.h
@@ -0,0 +1,151 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_FWD_H_
+#define RAPIDJSON_FWD_H_
+
+#include "rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+// encodings.h
+
+template<typename CharType> struct UTF8;
+template<typename CharType> struct UTF16;
+template<typename CharType> struct UTF16BE;
+template<typename CharType> struct UTF16LE;
+template<typename CharType> struct UTF32;
+template<typename CharType> struct UTF32BE;
+template<typename CharType> struct UTF32LE;
+template<typename CharType> struct ASCII;
+template<typename CharType> struct AutoUTF;
+
+template<typename SourceEncoding, typename TargetEncoding>
+struct Transcoder;
+
+// allocators.h
+
+class CrtAllocator;
+
+template <typename BaseAllocator>
+class MemoryPoolAllocator;
+
+// stream.h
+
+template <typename Encoding>
+struct GenericStringStream;
+
+typedef GenericStringStream<UTF8<char> > StringStream;
+
+template <typename Encoding>
+struct GenericInsituStringStream;
+
+typedef GenericInsituStringStream<UTF8<char> > InsituStringStream;
+
+// stringbuffer.h
+
+template <typename Encoding, typename Allocator>
+class GenericStringBuffer;
+
+typedef GenericStringBuffer<UTF8<char>, CrtAllocator> StringBuffer;
+
+// filereadstream.h
+
+class FileReadStream;
+
+// filewritestream.h
+
+class FileWriteStream;
+
+// memorybuffer.h
+
+template <typename Allocator>
+struct GenericMemoryBuffer;
+
+typedef GenericMemoryBuffer<CrtAllocator> MemoryBuffer;
+
+// memorystream.h
+
+struct MemoryStream;
+
+// reader.h
+
+template<typename Encoding, typename Derived>
+struct BaseReaderHandler;
+
+template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator>
+class GenericReader;
+
+typedef GenericReader<UTF8<char>, UTF8<char>, CrtAllocator> Reader;
+
+// writer.h
+
+template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
+class Writer;
+
+// prettywriter.h
+
+template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
+class PrettyWriter;
+
+// document.h
+
+template <typename Encoding, typename Allocator>
+struct GenericMember;
+
+template <bool Const, typename Encoding, typename Allocator>
+class GenericMemberIterator;
+
+template<typename CharType>
+struct GenericStringRef;
+
+template <typename Encoding, typename Allocator>
+class GenericValue;
+
+typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value;
+
+template <typename Encoding, typename Allocator, typename StackAllocator>
+class GenericDocument;
+
+typedef GenericDocument<UTF8<char>, MemoryPoolAllocator<CrtAllocator>, CrtAllocator> Document;
+
+// pointer.h
+
+template <typename ValueType, typename Allocator>
+class GenericPointer;
+
+typedef GenericPointer<Value, CrtAllocator> Pointer;
+
+// schema.h
+
+template <typename SchemaDocumentType>
+class IGenericRemoteSchemaDocumentProvider;
+
+template <typename ValueT, typename Allocator>
+class GenericSchemaDocument;
+
+typedef GenericSchemaDocument<Value, CrtAllocator> SchemaDocument;
+typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
+
+template <
+ typename SchemaDocumentType,
+ typename OutputHandler,
+ typename StateAllocator>
+class GenericSchemaValidator;
+
+typedef GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<char>, void>, CrtAllocator> SchemaValidator;
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_RAPIDJSONFWD_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/biginteger.h b/3rdparty/rapidjson/include/rapidjson/internal/biginteger.h
new file mode 100644
index 00000000000..9d3e88c9981
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/internal/biginteger.h
@@ -0,0 +1,290 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_BIGINTEGER_H_
+#define RAPIDJSON_BIGINTEGER_H_
+
+#include "../rapidjson.h"
+
+#if defined(_MSC_VER) && defined(_M_AMD64)
+#include <intrin.h> // for _umul128
+#pragma intrinsic(_umul128)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+class BigInteger {
+public:
+ typedef uint64_t Type;
+
+ BigInteger(const BigInteger& rhs) : count_(rhs.count_) {
+ std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
+ }
+
+ explicit BigInteger(uint64_t u) : count_(1) {
+ digits_[0] = u;
+ }
+
+ BigInteger(const char* decimals, size_t length) : count_(1) {
+ RAPIDJSON_ASSERT(length > 0);
+ digits_[0] = 0;
+ size_t i = 0;
+ const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19
+ while (length >= kMaxDigitPerIteration) {
+ AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
+ length -= kMaxDigitPerIteration;
+ i += kMaxDigitPerIteration;
+ }
+
+ if (length > 0)
+ AppendDecimal64(decimals + i, decimals + i + length);
+ }
+
+ BigInteger& operator=(const BigInteger &rhs)
+ {
+ if (this != &rhs) {
+ count_ = rhs.count_;
+ std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
+ }
+ return *this;
+ }
+
+ BigInteger& operator=(uint64_t u) {
+ digits_[0] = u;
+ count_ = 1;
+ return *this;
+ }
+
+ BigInteger& operator+=(uint64_t u) {
+ Type backup = digits_[0];
+ digits_[0] += u;
+ for (size_t i = 0; i < count_ - 1; i++) {
+ if (digits_[i] >= backup)
+ return *this; // no carry
+ backup = digits_[i + 1];
+ digits_[i + 1] += 1;
+ }
+
+ // Last carry
+ if (digits_[count_ - 1] < backup)
+ PushBack(1);
+
+ return *this;
+ }
+
+ BigInteger& operator*=(uint64_t u) {
+ if (u == 0) return *this = 0;
+ if (u == 1) return *this;
+ if (*this == 1) return *this = u;
+
+ uint64_t k = 0;
+ for (size_t i = 0; i < count_; i++) {
+ uint64_t hi;
+ digits_[i] = MulAdd64(digits_[i], u, k, &hi);
+ k = hi;
+ }
+
+ if (k > 0)
+ PushBack(k);
+
+ return *this;
+ }
+
+ BigInteger& operator*=(uint32_t u) {
+ if (u == 0) return *this = 0;
+ if (u == 1) return *this;
+ if (*this == 1) return *this = u;
+
+ uint64_t k = 0;
+ for (size_t i = 0; i < count_; i++) {
+ const uint64_t c = digits_[i] >> 32;
+ const uint64_t d = digits_[i] & 0xFFFFFFFF;
+ const uint64_t uc = u * c;
+ const uint64_t ud = u * d;
+ const uint64_t p0 = ud + k;
+ const uint64_t p1 = uc + (p0 >> 32);
+ digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
+ k = p1 >> 32;
+ }
+
+ if (k > 0)
+ PushBack(k);
+
+ return *this;
+ }
+
+ BigInteger& operator<<=(size_t shift) {
+ if (IsZero() || shift == 0) return *this;
+
+ size_t offset = shift / kTypeBit;
+ size_t interShift = shift % kTypeBit;
+ RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
+
+ if (interShift == 0) {
+ std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));
+ count_ += offset;
+ }
+ else {
+ digits_[count_] = 0;
+ for (size_t i = count_; i > 0; i--)
+ digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
+ digits_[offset] = digits_[0] << interShift;
+ count_ += offset;
+ if (digits_[count_])
+ count_++;
+ }
+
+ std::memset(digits_, 0, offset * sizeof(Type));
+
+ return *this;
+ }
+
+ bool operator==(const BigInteger& rhs) const {
+ return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
+ }
+
+ bool operator==(const Type rhs) const {
+ return count_ == 1 && digits_[0] == rhs;
+ }
+
+ BigInteger& MultiplyPow5(unsigned exp) {
+ static const uint32_t kPow5[12] = {
+ 5,
+ 5 * 5,
+ 5 * 5 * 5,
+ 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
+ };
+ if (exp == 0) return *this;
+ for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
+ for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
+ if (exp > 0) *this *= kPow5[exp - 1];
+ return *this;
+ }
+
+ // Compute absolute difference of this and rhs.
+ // Assume this != rhs
+ bool Difference(const BigInteger& rhs, BigInteger* out) const {
+ int cmp = Compare(rhs);
+ RAPIDJSON_ASSERT(cmp != 0);
+ const BigInteger *a, *b; // Makes a > b
+ bool ret;
+ if (cmp < 0) { a = &rhs; b = this; ret = true; }
+ else { a = this; b = &rhs; ret = false; }
+
+ Type borrow = 0;
+ for (size_t i = 0; i < a->count_; i++) {
+ Type d = a->digits_[i] - borrow;
+ if (i < b->count_)
+ d -= b->digits_[i];
+ borrow = (d > a->digits_[i]) ? 1 : 0;
+ out->digits_[i] = d;
+ if (d != 0)
+ out->count_ = i + 1;
+ }
+
+ return ret;
+ }
+
+ int Compare(const BigInteger& rhs) const {
+ if (count_ != rhs.count_)
+ return count_ < rhs.count_ ? -1 : 1;
+
+ for (size_t i = count_; i-- > 0;)
+ if (digits_[i] != rhs.digits_[i])
+ return digits_[i] < rhs.digits_[i] ? -1 : 1;
+
+ return 0;
+ }
+
+ size_t GetCount() const { return count_; }
+ Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }
+ bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
+
+private:
+ void AppendDecimal64(const char* begin, const char* end) {
+ uint64_t u = ParseUint64(begin, end);
+ if (IsZero())
+ *this = u;
+ else {
+ unsigned exp = static_cast<unsigned>(end - begin);
+ (MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
+ }
+ }
+
+ void PushBack(Type digit) {
+ RAPIDJSON_ASSERT(count_ < kCapacity);
+ digits_[count_++] = digit;
+ }
+
+ static uint64_t ParseUint64(const char* begin, const char* end) {
+ uint64_t r = 0;
+ for (const char* p = begin; p != end; ++p) {
+ RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
+ r = r * 10u + static_cast<unsigned>(*p - '0');
+ }
+ return r;
+ }
+
+ // Assume a * b + k < 2^128
+ static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+ uint64_t low = _umul128(a, b, outHigh) + k;
+ if (low < k)
+ (*outHigh)++;
+ return low;
+#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
+ __extension__ typedef unsigned __int128 uint128;
+ uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
+ p += k;
+ *outHigh = static_cast<uint64_t>(p >> 64);
+ return static_cast<uint64_t>(p);
+#else
+ const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
+ uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
+ x1 += (x0 >> 32); // can't give carry
+ x1 += x2;
+ if (x1 < x2)
+ x3 += (static_cast<uint64_t>(1) << 32);
+ uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
+ uint64_t hi = x3 + (x1 >> 32);
+
+ lo += k;
+ if (lo < k)
+ hi++;
+ *outHigh = hi;
+ return lo;
+#endif
+ }
+
+ static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000
+ static const size_t kCapacity = kBitCount / sizeof(Type);
+ static const size_t kTypeBit = sizeof(Type) * 8;
+
+ Type digits_[kCapacity];
+ size_t count_;
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_BIGINTEGER_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/diyfp.h b/3rdparty/rapidjson/include/rapidjson/internal/diyfp.h
new file mode 100644
index 00000000000..c9fefdc6139
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/internal/diyfp.h
@@ -0,0 +1,258 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
+// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
+// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
+
+#ifndef RAPIDJSON_DIYFP_H_
+#define RAPIDJSON_DIYFP_H_
+
+#include "../rapidjson.h"
+
+#if defined(_MSC_VER) && defined(_M_AMD64)
+#include <intrin.h>
+#pragma intrinsic(_BitScanReverse64)
+#pragma intrinsic(_umul128)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+struct DiyFp {
+ DiyFp() : f(), e() {}
+
+ DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
+
+ explicit DiyFp(double d) {
+ union {
+ double d;
+ uint64_t u64;
+ } u = { d };
+
+ int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
+ uint64_t significand = (u.u64 & kDpSignificandMask);
+ if (biased_e != 0) {
+ f = significand + kDpHiddenBit;
+ e = biased_e - kDpExponentBias;
+ }
+ else {
+ f = significand;
+ e = kDpMinExponent + 1;
+ }
+ }
+
+ DiyFp operator-(const DiyFp& rhs) const {
+ return DiyFp(f - rhs.f, e);
+ }
+
+ DiyFp operator*(const DiyFp& rhs) const {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+ uint64_t h;
+ uint64_t l = _umul128(f, rhs.f, &h);
+ if (l & (uint64_t(1) << 63)) // rounding
+ h++;
+ return DiyFp(h, e + rhs.e + 64);
+#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
+ __extension__ typedef unsigned __int128 uint128;
+ uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
+ uint64_t h = static_cast<uint64_t>(p >> 64);
+ uint64_t l = static_cast<uint64_t>(p);
+ if (l & (uint64_t(1) << 63)) // rounding
+ h++;
+ return DiyFp(h, e + rhs.e + 64);
+#else
+ const uint64_t M32 = 0xFFFFFFFF;
+ const uint64_t a = f >> 32;
+ const uint64_t b = f & M32;
+ const uint64_t c = rhs.f >> 32;
+ const uint64_t d = rhs.f & M32;
+ const uint64_t ac = a * c;
+ const uint64_t bc = b * c;
+ const uint64_t ad = a * d;
+ const uint64_t bd = b * d;
+ uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
+ tmp += 1U << 31; /// mult_round
+ return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
+#endif
+ }
+
+ DiyFp Normalize() const {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+ unsigned long index;
+ _BitScanReverse64(&index, f);
+ return DiyFp(f << (63 - index), e - (63 - index));
+#elif defined(__GNUC__) && __GNUC__ >= 4
+ int s = __builtin_clzll(f);
+ return DiyFp(f << s, e - s);
+#else
+ DiyFp res = *this;
+ while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
+ res.f <<= 1;
+ res.e--;
+ }
+ return res;
+#endif
+ }
+
+ DiyFp NormalizeBoundary() const {
+ DiyFp res = *this;
+ while (!(res.f & (kDpHiddenBit << 1))) {
+ res.f <<= 1;
+ res.e--;
+ }
+ res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
+ res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
+ return res;
+ }
+
+ void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
+ DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
+ DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
+ mi.f <<= mi.e - pl.e;
+ mi.e = pl.e;
+ *plus = pl;
+ *minus = mi;
+ }
+
+ double ToDouble() const {
+ union {
+ double d;
+ uint64_t u64;
+ }u;
+ const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
+ static_cast<uint64_t>(e + kDpExponentBias);
+ u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
+ return u.d;
+ }
+
+ static const int kDiySignificandSize = 64;
+ static const int kDpSignificandSize = 52;
+ static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
+ static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
+ static const int kDpMinExponent = -kDpExponentBias;
+ static const int kDpDenormalExponent = -kDpExponentBias + 1;
+ static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
+ static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
+ static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
+
+ uint64_t f;
+ int e;
+};
+
+inline DiyFp GetCachedPowerByIndex(size_t index) {
+ // 10^-348, 10^-340, ..., 10^340
+ static const uint64_t kCachedPowers_F[] = {
+ RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
+ RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
+ RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
+ RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
+ RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
+ RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
+ RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
+ RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
+ RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
+ RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
+ RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
+ RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
+ RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
+ RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
+ RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
+ RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
+ RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
+ RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
+ RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
+ RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
+ RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
+ RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
+ RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
+ RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
+ RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
+ RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
+ RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
+ RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
+ RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
+ RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
+ RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
+ RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
+ RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
+ RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
+ RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
+ RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
+ RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
+ RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
+ RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
+ RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
+ RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
+ RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
+ RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
+ RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
+ };
+ static const int16_t kCachedPowers_E[] = {
+ -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
+ -954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
+ -688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
+ -422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
+ -157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
+ 109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
+ 375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
+ 641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
+ 907, 933, 960, 986, 1013, 1039, 1066
+ };
+ return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
+}
+
+inline DiyFp GetCachedPower(int e, int* K) {
+
+ //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
+ double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
+ int k = static_cast<int>(dk);
+ if (dk - k > 0.0)
+ k++;
+
+ unsigned index = static_cast<unsigned>((k >> 3) + 1);
+ *K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
+
+ return GetCachedPowerByIndex(index);
+}
+
+inline DiyFp GetCachedPower10(int exp, int *outExp) {
+ unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
+ *outExp = -348 + static_cast<int>(index) * 8;
+ return GetCachedPowerByIndex(index);
+ }
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_DIYFP_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/dtoa.h b/3rdparty/rapidjson/include/rapidjson/internal/dtoa.h
new file mode 100644
index 00000000000..940d61a0548
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/internal/dtoa.h
@@ -0,0 +1,243 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
+// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
+// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
+
+#ifndef RAPIDJSON_DTOA_
+#define RAPIDJSON_DTOA_
+
+#include "itoa.h" // GetDigitsLut()
+#include "diyfp.h"
+#include "ieee754.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
+ while (rest < wp_w && delta - rest >= ten_kappa &&
+ (rest + ten_kappa < wp_w || /// closer
+ wp_w - rest > rest + ten_kappa - wp_w)) {
+ buffer[len - 1]--;
+ rest += ten_kappa;
+ }
+}
+
+inline unsigned CountDecimalDigit32(uint32_t n) {
+ // Simple pure C++ implementation was faster than __builtin_clz version in this situation.
+ if (n < 10) return 1;
+ if (n < 100) return 2;
+ if (n < 1000) return 3;
+ if (n < 10000) return 4;
+ if (n < 100000) return 5;
+ if (n < 1000000) return 6;
+ if (n < 10000000) return 7;
+ if (n < 100000000) return 8;
+ // Will not reach 10 digits in DigitGen()
+ //if (n < 1000000000) return 9;
+ //return 10;
+ return 9;
+}
+
+inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
+ static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
+ const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
+ const DiyFp wp_w = Mp - W;
+ uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
+ uint64_t p2 = Mp.f & (one.f - 1);
+ unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
+ *len = 0;
+
+ while (kappa > 0) {
+ uint32_t d = 0;
+ switch (kappa) {
+ case 9: d = p1 / 100000000; p1 %= 100000000; break;
+ case 8: d = p1 / 10000000; p1 %= 10000000; break;
+ case 7: d = p1 / 1000000; p1 %= 1000000; break;
+ case 6: d = p1 / 100000; p1 %= 100000; break;
+ case 5: d = p1 / 10000; p1 %= 10000; break;
+ case 4: d = p1 / 1000; p1 %= 1000; break;
+ case 3: d = p1 / 100; p1 %= 100; break;
+ case 2: d = p1 / 10; p1 %= 10; break;
+ case 1: d = p1; p1 = 0; break;
+ default:;
+ }
+ if (d || *len)
+ buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
+ kappa--;
+ uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
+ if (tmp <= delta) {
+ *K += kappa;
+ GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
+ return;
+ }
+ }
+
+ // kappa = 0
+ for (;;) {
+ p2 *= 10;
+ delta *= 10;
+ char d = static_cast<char>(p2 >> -one.e);
+ if (d || *len)
+ buffer[(*len)++] = static_cast<char>('0' + d);
+ p2 &= one.f - 1;
+ kappa--;
+ if (p2 < delta) {
+ *K += kappa;
+ GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-static_cast<int>(kappa)]);
+ return;
+ }
+ }
+}
+
+inline void Grisu2(double value, char* buffer, int* length, int* K) {
+ const DiyFp v(value);
+ DiyFp w_m, w_p;
+ v.NormalizedBoundaries(&w_m, &w_p);
+
+ const DiyFp c_mk = GetCachedPower(w_p.e, K);
+ const DiyFp W = v.Normalize() * c_mk;
+ DiyFp Wp = w_p * c_mk;
+ DiyFp Wm = w_m * c_mk;
+ Wm.f++;
+ Wp.f--;
+ DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
+}
+
+inline char* WriteExponent(int K, char* buffer) {
+ if (K < 0) {
+ *buffer++ = '-';
+ K = -K;
+ }
+
+ if (K >= 100) {
+ *buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
+ K %= 100;
+ const char* d = GetDigitsLut() + K * 2;
+ *buffer++ = d[0];
+ *buffer++ = d[1];
+ }
+ else if (K >= 10) {
+ const char* d = GetDigitsLut() + K * 2;
+ *buffer++ = d[0];
+ *buffer++ = d[1];
+ }
+ else
+ *buffer++ = static_cast<char>('0' + static_cast<char>(K));
+
+ return buffer;
+}
+
+inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
+ const int kk = length + k; // 10^(kk-1) <= v < 10^kk
+
+ if (length <= kk && kk <= 21) {
+ // 1234e7 -> 12340000000
+ for (int i = length; i < kk; i++)
+ buffer[i] = '0';
+ buffer[kk] = '.';
+ buffer[kk + 1] = '0';
+ return &buffer[kk + 2];
+ }
+ else if (0 < kk && kk <= 21) {
+ // 1234e-2 -> 12.34
+ std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
+ buffer[kk] = '.';
+ if (length > kk + maxDecimalPlaces) {
+ // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
+ // Remove extra trailing zeros (at least one) after truncation.
+ for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
+ if (buffer[i] != '0')
+ return &buffer[i + 1];
+ return &buffer[kk + 2]; // Reserve one zero
+ }
+ else
+ return &buffer[length + 1];
+ }
+ else if (-6 < kk && kk <= 0) {
+ // 1234e-6 -> 0.001234
+ const int offset = 2 - kk;
+ std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
+ buffer[0] = '0';
+ buffer[1] = '.';
+ for (int i = 2; i < offset; i++)
+ buffer[i] = '0';
+ if (length + offset > maxDecimalPlaces) {
+ // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
+ // Remove extra trailing zeros (at least one) after truncation.
+ for (int i = maxDecimalPlaces + 1; i > 2; i--)
+ if (buffer[i] != '0')
+ return &buffer[i + 1];
+ return &buffer[3]; // Reserve one zero
+ }
+ else
+ return &buffer[length + offset];
+ }
+ else if (kk < -maxDecimalPlaces) {
+ // Truncate to zero
+ buffer[0] = '0';
+ buffer[1] = '.';
+ buffer[2] = '0';
+ return &buffer[3];
+ }
+ else if (length == 1) {
+ // 1e30
+ buffer[1] = 'e';
+ return WriteExponent(kk - 1, &buffer[2]);
+ }
+ else {
+ // 1234e30 -> 1.234e33
+ std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
+ buffer[1] = '.';
+ buffer[length + 1] = 'e';
+ return WriteExponent(kk - 1, &buffer[0 + length + 2]);
+ }
+}
+
+inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) {
+ RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
+ Double d(value);
+ if (d.IsZero()) {
+ if (d.Sign())
+ *buffer++ = '-'; // -0.0, Issue #289
+ buffer[0] = '0';
+ buffer[1] = '.';
+ buffer[2] = '0';
+ return &buffer[3];
+ }
+ else {
+ if (value < 0) {
+ *buffer++ = '-';
+ value = -value;
+ }
+ int length, K;
+ Grisu2(value, buffer, &length, &K);
+ return Prettify(buffer, length, K, maxDecimalPlaces);
+ }
+}
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_DTOA_
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/ieee754.h b/3rdparty/rapidjson/include/rapidjson/internal/ieee754.h
new file mode 100644
index 00000000000..82bb0b99e5c
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/internal/ieee754.h
@@ -0,0 +1,78 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_IEEE754_
+#define RAPIDJSON_IEEE754_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+class Double {
+public:
+ Double() {}
+ Double(double d) : d_(d) {}
+ Double(uint64_t u) : u_(u) {}
+
+ double Value() const { return d_; }
+ uint64_t Uint64Value() const { return u_; }
+
+ double NextPositiveDouble() const {
+ RAPIDJSON_ASSERT(!Sign());
+ return Double(u_ + 1).Value();
+ }
+
+ bool Sign() const { return (u_ & kSignMask) != 0; }
+ uint64_t Significand() const { return u_ & kSignificandMask; }
+ int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
+
+ bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
+ bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
+ bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; }
+ bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
+ bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
+
+ uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
+ int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
+ uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
+
+ static unsigned EffectiveSignificandSize(int order) {
+ if (order >= -1021)
+ return 53;
+ else if (order <= -1074)
+ return 0;
+ else
+ return static_cast<unsigned>(order) + 1074;
+ }
+
+private:
+ static const int kSignificandSize = 52;
+ static const int kExponentBias = 0x3FF;
+ static const int kDenormalExponent = 1 - kExponentBias;
+ static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
+ static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
+ static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
+ static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
+
+ union {
+ double d_;
+ uint64_t u_;
+ };
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_IEEE754_
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/itoa.h b/3rdparty/rapidjson/include/rapidjson/internal/itoa.h
new file mode 100644
index 00000000000..01a4e7e72d7
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/internal/itoa.h
@@ -0,0 +1,304 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ITOA_
+#define RAPIDJSON_ITOA_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+inline const char* GetDigitsLut() {
+ static const char cDigitsLut[200] = {
+ '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',
+ '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',
+ '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',
+ '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',
+ '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',
+ '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',
+ '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',
+ '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',
+ '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',
+ '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'
+ };
+ return cDigitsLut;
+}
+
+inline char* u32toa(uint32_t value, char* buffer) {
+ const char* cDigitsLut = GetDigitsLut();
+
+ if (value < 10000) {
+ const uint32_t d1 = (value / 100) << 1;
+ const uint32_t d2 = (value % 100) << 1;
+
+ if (value >= 1000)
+ *buffer++ = cDigitsLut[d1];
+ if (value >= 100)
+ *buffer++ = cDigitsLut[d1 + 1];
+ if (value >= 10)
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+ }
+ else if (value < 100000000) {
+ // value = bbbbcccc
+ const uint32_t b = value / 10000;
+ const uint32_t c = value % 10000;
+
+ const uint32_t d1 = (b / 100) << 1;
+ const uint32_t d2 = (b % 100) << 1;
+
+ const uint32_t d3 = (c / 100) << 1;
+ const uint32_t d4 = (c % 100) << 1;
+
+ if (value >= 10000000)
+ *buffer++ = cDigitsLut[d1];
+ if (value >= 1000000)
+ *buffer++ = cDigitsLut[d1 + 1];
+ if (value >= 100000)
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+
+ *buffer++ = cDigitsLut[d3];
+ *buffer++ = cDigitsLut[d3 + 1];
+ *buffer++ = cDigitsLut[d4];
+ *buffer++ = cDigitsLut[d4 + 1];
+ }
+ else {
+ // value = aabbbbcccc in decimal
+
+ const uint32_t a = value / 100000000; // 1 to 42
+ value %= 100000000;
+
+ if (a >= 10) {
+ const unsigned i = a << 1;
+ *buffer++ = cDigitsLut[i];
+ *buffer++ = cDigitsLut[i + 1];
+ }
+ else
+ *buffer++ = static_cast<char>('0' + static_cast<char>(a));
+
+ const uint32_t b = value / 10000; // 0 to 9999
+ const uint32_t c = value % 10000; // 0 to 9999
+
+ const uint32_t d1 = (b / 100) << 1;
+ const uint32_t d2 = (b % 100) << 1;
+
+ const uint32_t d3 = (c / 100) << 1;
+ const uint32_t d4 = (c % 100) << 1;
+
+ *buffer++ = cDigitsLut[d1];
+ *buffer++ = cDigitsLut[d1 + 1];
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+ *buffer++ = cDigitsLut[d3];
+ *buffer++ = cDigitsLut[d3 + 1];
+ *buffer++ = cDigitsLut[d4];
+ *buffer++ = cDigitsLut[d4 + 1];
+ }
+ return buffer;
+}
+
+inline char* i32toa(int32_t value, char* buffer) {
+ uint32_t u = static_cast<uint32_t>(value);
+ if (value < 0) {
+ *buffer++ = '-';
+ u = ~u + 1;
+ }
+
+ return u32toa(u, buffer);
+}
+
+inline char* u64toa(uint64_t value, char* buffer) {
+ const char* cDigitsLut = GetDigitsLut();
+ const uint64_t kTen8 = 100000000;
+ const uint64_t kTen9 = kTen8 * 10;
+ const uint64_t kTen10 = kTen8 * 100;
+ const uint64_t kTen11 = kTen8 * 1000;
+ const uint64_t kTen12 = kTen8 * 10000;
+ const uint64_t kTen13 = kTen8 * 100000;
+ const uint64_t kTen14 = kTen8 * 1000000;
+ const uint64_t kTen15 = kTen8 * 10000000;
+ const uint64_t kTen16 = kTen8 * kTen8;
+
+ if (value < kTen8) {
+ uint32_t v = static_cast<uint32_t>(value);
+ if (v < 10000) {
+ const uint32_t d1 = (v / 100) << 1;
+ const uint32_t d2 = (v % 100) << 1;
+
+ if (v >= 1000)
+ *buffer++ = cDigitsLut[d1];
+ if (v >= 100)
+ *buffer++ = cDigitsLut[d1 + 1];
+ if (v >= 10)
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+ }
+ else {
+ // value = bbbbcccc
+ const uint32_t b = v / 10000;
+ const uint32_t c = v % 10000;
+
+ const uint32_t d1 = (b / 100) << 1;
+ const uint32_t d2 = (b % 100) << 1;
+
+ const uint32_t d3 = (c / 100) << 1;
+ const uint32_t d4 = (c % 100) << 1;
+
+ if (value >= 10000000)
+ *buffer++ = cDigitsLut[d1];
+ if (value >= 1000000)
+ *buffer++ = cDigitsLut[d1 + 1];
+ if (value >= 100000)
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+
+ *buffer++ = cDigitsLut[d3];
+ *buffer++ = cDigitsLut[d3 + 1];
+ *buffer++ = cDigitsLut[d4];
+ *buffer++ = cDigitsLut[d4 + 1];
+ }
+ }
+ else if (value < kTen16) {
+ const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
+ const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
+
+ const uint32_t b0 = v0 / 10000;
+ const uint32_t c0 = v0 % 10000;
+
+ const uint32_t d1 = (b0 / 100) << 1;
+ const uint32_t d2 = (b0 % 100) << 1;
+
+ const uint32_t d3 = (c0 / 100) << 1;
+ const uint32_t d4 = (c0 % 100) << 1;
+
+ const uint32_t b1 = v1 / 10000;
+ const uint32_t c1 = v1 % 10000;
+
+ const uint32_t d5 = (b1 / 100) << 1;
+ const uint32_t d6 = (b1 % 100) << 1;
+
+ const uint32_t d7 = (c1 / 100) << 1;
+ const uint32_t d8 = (c1 % 100) << 1;
+
+ if (value >= kTen15)
+ *buffer++ = cDigitsLut[d1];
+ if (value >= kTen14)
+ *buffer++ = cDigitsLut[d1 + 1];
+ if (value >= kTen13)
+ *buffer++ = cDigitsLut[d2];
+ if (value >= kTen12)
+ *buffer++ = cDigitsLut[d2 + 1];
+ if (value >= kTen11)
+ *buffer++ = cDigitsLut[d3];
+ if (value >= kTen10)
+ *buffer++ = cDigitsLut[d3 + 1];
+ if (value >= kTen9)
+ *buffer++ = cDigitsLut[d4];
+ if (value >= kTen8)
+ *buffer++ = cDigitsLut[d4 + 1];
+
+ *buffer++ = cDigitsLut[d5];
+ *buffer++ = cDigitsLut[d5 + 1];
+ *buffer++ = cDigitsLut[d6];
+ *buffer++ = cDigitsLut[d6 + 1];
+ *buffer++ = cDigitsLut[d7];
+ *buffer++ = cDigitsLut[d7 + 1];
+ *buffer++ = cDigitsLut[d8];
+ *buffer++ = cDigitsLut[d8 + 1];
+ }
+ else {
+ const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
+ value %= kTen16;
+
+ if (a < 10)
+ *buffer++ = static_cast<char>('0' + static_cast<char>(a));
+ else if (a < 100) {
+ const uint32_t i = a << 1;
+ *buffer++ = cDigitsLut[i];
+ *buffer++ = cDigitsLut[i + 1];
+ }
+ else if (a < 1000) {
+ *buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
+
+ const uint32_t i = (a % 100) << 1;
+ *buffer++ = cDigitsLut[i];
+ *buffer++ = cDigitsLut[i + 1];
+ }
+ else {
+ const uint32_t i = (a / 100) << 1;
+ const uint32_t j = (a % 100) << 1;
+ *buffer++ = cDigitsLut[i];
+ *buffer++ = cDigitsLut[i + 1];
+ *buffer++ = cDigitsLut[j];
+ *buffer++ = cDigitsLut[j + 1];
+ }
+
+ const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
+ const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
+
+ const uint32_t b0 = v0 / 10000;
+ const uint32_t c0 = v0 % 10000;
+
+ const uint32_t d1 = (b0 / 100) << 1;
+ const uint32_t d2 = (b0 % 100) << 1;
+
+ const uint32_t d3 = (c0 / 100) << 1;
+ const uint32_t d4 = (c0 % 100) << 1;
+
+ const uint32_t b1 = v1 / 10000;
+ const uint32_t c1 = v1 % 10000;
+
+ const uint32_t d5 = (b1 / 100) << 1;
+ const uint32_t d6 = (b1 % 100) << 1;
+
+ const uint32_t d7 = (c1 / 100) << 1;
+ const uint32_t d8 = (c1 % 100) << 1;
+
+ *buffer++ = cDigitsLut[d1];
+ *buffer++ = cDigitsLut[d1 + 1];
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+ *buffer++ = cDigitsLut[d3];
+ *buffer++ = cDigitsLut[d3 + 1];
+ *buffer++ = cDigitsLut[d4];
+ *buffer++ = cDigitsLut[d4 + 1];
+ *buffer++ = cDigitsLut[d5];
+ *buffer++ = cDigitsLut[d5 + 1];
+ *buffer++ = cDigitsLut[d6];
+ *buffer++ = cDigitsLut[d6 + 1];
+ *buffer++ = cDigitsLut[d7];
+ *buffer++ = cDigitsLut[d7 + 1];
+ *buffer++ = cDigitsLut[d8];
+ *buffer++ = cDigitsLut[d8 + 1];
+ }
+
+ return buffer;
+}
+
+inline char* i64toa(int64_t value, char* buffer) {
+ uint64_t u = static_cast<uint64_t>(value);
+ if (value < 0) {
+ *buffer++ = '-';
+ u = ~u + 1;
+ }
+
+ return u64toa(u, buffer);
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ITOA_
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/meta.h b/3rdparty/rapidjson/include/rapidjson/internal/meta.h
new file mode 100644
index 00000000000..5a9aaa42866
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/internal/meta.h
@@ -0,0 +1,181 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_META_H_
+#define RAPIDJSON_INTERNAL_META_H_
+
+#include "../rapidjson.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+#if defined(_MSC_VER)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(6334)
+#endif
+
+#if RAPIDJSON_HAS_CXX11_TYPETRAITS
+#include <type_traits>
+#endif
+
+//@cond RAPIDJSON_INTERNAL
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
+template <typename T> struct Void { typedef void Type; };
+
+///////////////////////////////////////////////////////////////////////////////
+// BoolType, TrueType, FalseType
+//
+template <bool Cond> struct BoolType {
+ static const bool Value = Cond;
+ typedef BoolType Type;
+};
+typedef BoolType<true> TrueType;
+typedef BoolType<false> FalseType;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
+//
+
+template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
+template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
+template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
+template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
+
+template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
+template <> struct AndExprCond<true, true> : TrueType {};
+template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
+template <> struct OrExprCond<false, false> : FalseType {};
+
+template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
+template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {};
+template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
+template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// AddConst, MaybeAddConst, RemoveConst
+template <typename T> struct AddConst { typedef const T Type; };
+template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
+template <typename T> struct RemoveConst { typedef T Type; };
+template <typename T> struct RemoveConst<const T> { typedef T Type; };
+
+
+///////////////////////////////////////////////////////////////////////////////
+// IsSame, IsConst, IsMoreConst, IsPointer
+//
+template <typename T, typename U> struct IsSame : FalseType {};
+template <typename T> struct IsSame<T, T> : TrueType {};
+
+template <typename T> struct IsConst : FalseType {};
+template <typename T> struct IsConst<const T> : TrueType {};
+
+template <typename CT, typename T>
+struct IsMoreConst
+ : AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
+ BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
+
+template <typename T> struct IsPointer : FalseType {};
+template <typename T> struct IsPointer<T*> : TrueType {};
+
+///////////////////////////////////////////////////////////////////////////////
+// IsBaseOf
+//
+#if RAPIDJSON_HAS_CXX11_TYPETRAITS
+
+template <typename B, typename D> struct IsBaseOf
+ : BoolType< ::std::is_base_of<B,D>::value> {};
+
+#else // simplified version adopted from Boost
+
+template<typename B, typename D> struct IsBaseOfImpl {
+ RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
+ RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
+
+ typedef char (&Yes)[1];
+ typedef char (&No) [2];
+
+ template <typename T>
+ static Yes Check(const D*, T);
+ static No Check(const B*, int);
+
+ struct Host {
+ operator const B*() const;
+ operator const D*();
+ };
+
+ enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
+};
+
+template <typename B, typename D> struct IsBaseOf
+ : OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
+
+#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
+
+
+//////////////////////////////////////////////////////////////////////////
+// EnableIf / DisableIf
+//
+template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; };
+template <typename T> struct EnableIfCond<false, T> { /* empty */ };
+
+template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
+template <typename T> struct DisableIfCond<true, T> { /* empty */ };
+
+template <typename Condition, typename T = void>
+struct EnableIf : EnableIfCond<Condition::Value, T> {};
+
+template <typename Condition, typename T = void>
+struct DisableIf : DisableIfCond<Condition::Value, T> {};
+
+// SFINAE helpers
+struct SfinaeTag {};
+template <typename T> struct RemoveSfinaeTag;
+template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
+
+#define RAPIDJSON_REMOVEFPTR_(type) \
+ typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
+ < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
+
+#define RAPIDJSON_ENABLEIF(cond) \
+ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
+ <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
+
+#define RAPIDJSON_DISABLEIF(cond) \
+ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
+ <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
+
+#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
+ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
+ <RAPIDJSON_REMOVEFPTR_(cond), \
+ RAPIDJSON_REMOVEFPTR_(returntype)>::Type
+
+#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
+ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
+ <RAPIDJSON_REMOVEFPTR_(cond), \
+ RAPIDJSON_REMOVEFPTR_(returntype)>::Type
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+//@endcond
+
+#if defined(__GNUC__) || defined(_MSC_VER)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_INTERNAL_META_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/pow10.h b/3rdparty/rapidjson/include/rapidjson/internal/pow10.h
new file mode 100644
index 00000000000..02f475d705f
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/internal/pow10.h
@@ -0,0 +1,55 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_POW10_
+#define RAPIDJSON_POW10_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+//! Computes integer powers of 10 in double (10.0^n).
+/*! This function uses lookup table for fast and accurate results.
+ \param n non-negative exponent. Must <= 308.
+ \return 10.0^n
+*/
+inline double Pow10(int n) {
+ static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
+ 1e+0,
+ 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
+ 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
+ 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
+ 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
+ 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
+ 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
+ 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
+ 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
+ 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
+ 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
+ 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
+ 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
+ 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
+ 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
+ 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
+ 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
+ };
+ RAPIDJSON_ASSERT(n >= 0 && n <= 308);
+ return e[n];
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_POW10_
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/regex.h b/3rdparty/rapidjson/include/rapidjson/internal/regex.h
new file mode 100644
index 00000000000..aeb0e3ef535
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/internal/regex.h
@@ -0,0 +1,696 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_REGEX_H_
+#define RAPIDJSON_INTERNAL_REGEX_H_
+
+#include "../allocators.h"
+#include "../stream.h"
+#include "stack.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(switch-enum)
+RAPIDJSON_DIAG_OFF(implicit-fallthrough)
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#ifndef RAPIDJSON_REGEX_VERBOSE
+#define RAPIDJSON_REGEX_VERBOSE 0
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericRegex
+
+static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1
+static const SizeType kRegexInvalidRange = ~SizeType(0);
+
+//! Regular expression engine with subset of ECMAscript grammar.
+/*!
+ Supported regular expression syntax:
+ - \c ab Concatenation
+ - \c a|b Alternation
+ - \c a? Zero or one
+ - \c a* Zero or more
+ - \c a+ One or more
+ - \c a{3} Exactly 3 times
+ - \c a{3,} At least 3 times
+ - \c a{3,5} 3 to 5 times
+ - \c (ab) Grouping
+ - \c ^a At the beginning
+ - \c a$ At the end
+ - \c . Any character
+ - \c [abc] Character classes
+ - \c [a-c] Character class range
+ - \c [a-z0-9_] Character class combination
+ - \c [^abc] Negated character classes
+ - \c [^a-c] Negated character class range
+ - \c [\b] Backspace (U+0008)
+ - \c \\| \\\\ ... Escape characters
+ - \c \\f Form feed (U+000C)
+ - \c \\n Line feed (U+000A)
+ - \c \\r Carriage return (U+000D)
+ - \c \\t Tab (U+0009)
+ - \c \\v Vertical tab (U+000B)
+
+ \note This is a Thompson NFA engine, implemented with reference to
+ Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).",
+ https://swtch.com/~rsc/regexp/regexp1.html
+*/
+template <typename Encoding, typename Allocator = CrtAllocator>
+class GenericRegex {
+public:
+ typedef typename Encoding::Ch Ch;
+
+ GenericRegex(const Ch* source, Allocator* allocator = 0) :
+ states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
+ stateSet_(), state0_(allocator, 0), state1_(allocator, 0), anchorBegin_(), anchorEnd_()
+ {
+ GenericStringStream<Encoding> ss(source);
+ DecodedStream<GenericStringStream<Encoding> > ds(ss);
+ Parse(ds);
+ }
+
+ ~GenericRegex() {
+ Allocator::Free(stateSet_);
+ }
+
+ bool IsValid() const {
+ return root_ != kRegexInvalidState;
+ }
+
+ template <typename InputStream>
+ bool Match(InputStream& is) const {
+ return SearchWithAnchoring(is, true, true);
+ }
+
+ bool Match(const Ch* s) const {
+ GenericStringStream<Encoding> is(s);
+ return Match(is);
+ }
+
+ template <typename InputStream>
+ bool Search(InputStream& is) const {
+ return SearchWithAnchoring(is, anchorBegin_, anchorEnd_);
+ }
+
+ bool Search(const Ch* s) const {
+ GenericStringStream<Encoding> is(s);
+ return Search(is);
+ }
+
+private:
+ enum Operator {
+ kZeroOrOne,
+ kZeroOrMore,
+ kOneOrMore,
+ kConcatenation,
+ kAlternation,
+ kLeftParenthesis
+ };
+
+ static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.'
+ static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
+ static const unsigned kRangeNegationFlag = 0x80000000;
+
+ struct Range {
+ unsigned start; //
+ unsigned end;
+ SizeType next;
+ };
+
+ struct State {
+ SizeType out; //!< Equals to kInvalid for matching state
+ SizeType out1; //!< Equals to non-kInvalid for split
+ SizeType rangeStart;
+ unsigned codepoint;
+ };
+
+ struct Frag {
+ Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}
+ SizeType start;
+ SizeType out; //!< link-list of all output states
+ SizeType minIndex;
+ };
+
+ template <typename SourceStream>
+ class DecodedStream {
+ public:
+ DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
+ unsigned Peek() { return codepoint_; }
+ unsigned Take() {
+ unsigned c = codepoint_;
+ if (c) // No further decoding when '\0'
+ Decode();
+ return c;
+ }
+
+ private:
+ void Decode() {
+ if (!Encoding::Decode(ss_, &codepoint_))
+ codepoint_ = 0;
+ }
+
+ SourceStream& ss_;
+ unsigned codepoint_;
+ };
+
+ State& GetState(SizeType index) {
+ RAPIDJSON_ASSERT(index < stateCount_);
+ return states_.template Bottom<State>()[index];
+ }
+
+ const State& GetState(SizeType index) const {
+ RAPIDJSON_ASSERT(index < stateCount_);
+ return states_.template Bottom<State>()[index];
+ }
+
+ Range& GetRange(SizeType index) {
+ RAPIDJSON_ASSERT(index < rangeCount_);
+ return ranges_.template Bottom<Range>()[index];
+ }
+
+ const Range& GetRange(SizeType index) const {
+ RAPIDJSON_ASSERT(index < rangeCount_);
+ return ranges_.template Bottom<Range>()[index];
+ }
+
+ template <typename InputStream>
+ void Parse(DecodedStream<InputStream>& ds) {
+ Allocator allocator;
+ Stack<Allocator> operandStack(&allocator, 256); // Frag
+ Stack<Allocator> operatorStack(&allocator, 256); // Operator
+ Stack<Allocator> atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis)
+
+ *atomCountStack.template Push<unsigned>() = 0;
+
+ unsigned codepoint;
+ while (ds.Peek() != 0) {
+ switch (codepoint = ds.Take()) {
+ case '^':
+ anchorBegin_ = true;
+ break;
+
+ case '$':
+ anchorEnd_ = true;
+ break;
+
+ case '|':
+ while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation)
+ if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
+ return;
+ *operatorStack.template Push<Operator>() = kAlternation;
+ *atomCountStack.template Top<unsigned>() = 0;
+ break;
+
+ case '(':
+ *operatorStack.template Push<Operator>() = kLeftParenthesis;
+ *atomCountStack.template Push<unsigned>() = 0;
+ break;
+
+ case ')':
+ while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)
+ if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
+ return;
+ if (operatorStack.Empty())
+ return;
+ operatorStack.template Pop<Operator>(1);
+ atomCountStack.template Pop<unsigned>(1);
+ ImplicitConcatenation(atomCountStack, operatorStack);
+ break;
+
+ case '?':
+ if (!Eval(operandStack, kZeroOrOne))
+ return;
+ break;
+
+ case '*':
+ if (!Eval(operandStack, kZeroOrMore))
+ return;
+ break;
+
+ case '+':
+ if (!Eval(operandStack, kOneOrMore))
+ return;
+ break;
+
+ case '{':
+ {
+ unsigned n, m;
+ if (!ParseUnsigned(ds, &n))
+ return;
+
+ if (ds.Peek() == ',') {
+ ds.Take();
+ if (ds.Peek() == '}')
+ m = kInfinityQuantifier;
+ else if (!ParseUnsigned(ds, &m) || m < n)
+ return;
+ }
+ else
+ m = n;
+
+ if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')
+ return;
+ ds.Take();
+ }
+ break;
+
+ case '.':
+ PushOperand(operandStack, kAnyCharacterClass);
+ ImplicitConcatenation(atomCountStack, operatorStack);
+ break;
+
+ case '[':
+ {
+ SizeType range;
+ if (!ParseRange(ds, &range))
+ return;
+ SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);
+ GetState(s).rangeStart = range;
+ *operandStack.template Push<Frag>() = Frag(s, s, s);
+ }
+ ImplicitConcatenation(atomCountStack, operatorStack);
+ break;
+
+ case '\\': // Escape character
+ if (!CharacterEscape(ds, &codepoint))
+ return; // Unsupported escape character
+ // fall through to default
+
+ default: // Pattern character
+ PushOperand(operandStack, codepoint);
+ ImplicitConcatenation(atomCountStack, operatorStack);
+ }
+ }
+
+ while (!operatorStack.Empty())
+ if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
+ return;
+
+ // Link the operand to matching state.
+ if (operandStack.GetSize() == sizeof(Frag)) {
+ Frag* e = operandStack.template Pop<Frag>(1);
+ Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
+ root_ = e->start;
+
+#if RAPIDJSON_REGEX_VERBOSE
+ printf("root: %d\n", root_);
+ for (SizeType i = 0; i < stateCount_ ; i++) {
+ State& s = GetState(i);
+ printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint);
+ }
+ printf("\n");
+#endif
+ }
+
+ // Preallocate buffer for SearchWithAnchoring()
+ RAPIDJSON_ASSERT(stateSet_ == 0);
+ if (stateCount_ > 0) {
+ stateSet_ = static_cast<unsigned*>(states_.GetAllocator().Malloc(GetStateSetSize()));
+ state0_.template Reserve<SizeType>(stateCount_);
+ state1_.template Reserve<SizeType>(stateCount_);
+ }
+ }
+
+ SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
+ State* s = states_.template Push<State>();
+ s->out = out;
+ s->out1 = out1;
+ s->codepoint = codepoint;
+ s->rangeStart = kRegexInvalidRange;
+ return stateCount_++;
+ }
+
+ void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) {
+ SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
+ *operandStack.template Push<Frag>() = Frag(s, s, s);
+ }
+
+ void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack) {
+ if (*atomCountStack.template Top<unsigned>())
+ *operatorStack.template Push<Operator>() = kConcatenation;
+ (*atomCountStack.template Top<unsigned>())++;
+ }
+
+ SizeType Append(SizeType l1, SizeType l2) {
+ SizeType old = l1;
+ while (GetState(l1).out != kRegexInvalidState)
+ l1 = GetState(l1).out;
+ GetState(l1).out = l2;
+ return old;
+ }
+
+ void Patch(SizeType l, SizeType s) {
+ for (SizeType next; l != kRegexInvalidState; l = next) {
+ next = GetState(l).out;
+ GetState(l).out = s;
+ }
+ }
+
+ bool Eval(Stack<Allocator>& operandStack, Operator op) {
+ switch (op) {
+ case kConcatenation:
+ if (operandStack.GetSize() >= sizeof(Frag) * 2) {
+ Frag e2 = *operandStack.template Pop<Frag>(1);
+ Frag e1 = *operandStack.template Pop<Frag>(1);
+ Patch(e1.out, e2.start);
+ *operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));
+ return true;
+ }
+ return false;
+
+ case kAlternation:
+ if (operandStack.GetSize() >= sizeof(Frag) * 2) {
+ Frag e2 = *operandStack.template Pop<Frag>(1);
+ Frag e1 = *operandStack.template Pop<Frag>(1);
+ SizeType s = NewState(e1.start, e2.start, 0);
+ *operandStack.template Push<Frag>() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex));
+ return true;
+ }
+ return false;
+
+ case kZeroOrOne:
+ if (operandStack.GetSize() >= sizeof(Frag)) {
+ Frag e = *operandStack.template Pop<Frag>(1);
+ SizeType s = NewState(kRegexInvalidState, e.start, 0);
+ *operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex);
+ return true;
+ }
+ return false;
+
+ case kZeroOrMore:
+ if (operandStack.GetSize() >= sizeof(Frag)) {
+ Frag e = *operandStack.template Pop<Frag>(1);
+ SizeType s = NewState(kRegexInvalidState, e.start, 0);
+ Patch(e.out, s);
+ *operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);
+ return true;
+ }
+ return false;
+
+ case kOneOrMore:
+ if (operandStack.GetSize() >= sizeof(Frag)) {
+ Frag e = *operandStack.template Pop<Frag>(1);
+ SizeType s = NewState(kRegexInvalidState, e.start, 0);
+ Patch(e.out, s);
+ *operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);
+ return true;
+ }
+ return false;
+
+ default:
+ return false;
+ }
+ }
+
+ bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {
+ RAPIDJSON_ASSERT(n <= m);
+ if (operandStack.GetSize() < sizeof(Frag))
+ return false;
+
+ if (n == 0) {
+ if (m == 0) // a{0} not support
+ return false;
+ else if (m == kInfinityQuantifier)
+ Eval(operandStack, kZeroOrMore); // a{0,} -> a*
+ else {
+ Eval(operandStack, kZeroOrOne); // a{0,5} -> a?
+ for (unsigned i = 0; i < m - 1; i++)
+ CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a?
+ for (unsigned i = 0; i < m - 1; i++)
+ Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?
+ }
+ return true;
+ }
+
+ for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a
+ CloneTopOperand(operandStack);
+
+ if (m == kInfinityQuantifier)
+ Eval(operandStack, kOneOrMore); // a{3,} -> a a a+
+ else if (m > n) {
+ CloneTopOperand(operandStack); // a{3,5} -> a a a a
+ Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a?
+ for (unsigned i = n; i < m - 1; i++)
+ CloneTopOperand(operandStack); // a{3,5} -> a a a a? a?
+ for (unsigned i = n; i < m; i++)
+ Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a?
+ }
+
+ for (unsigned i = 0; i < n - 1; i++)
+ Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?
+
+ return true;
+ }
+
+ static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }
+
+ void CloneTopOperand(Stack<Allocator>& operandStack) {
+ const Frag *src = operandStack.template Top<Frag>();
+ SizeType count = stateCount_ - src->minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)
+ State* s = states_.template Push<State>(count);
+ memcpy(s, &GetState(src->minIndex), count * sizeof(State));
+ for (SizeType j = 0; j < count; j++) {
+ if (s[j].out != kRegexInvalidState)
+ s[j].out += count;
+ if (s[j].out1 != kRegexInvalidState)
+ s[j].out1 += count;
+ }
+ *operandStack.template Push<Frag>() = Frag(src->start + count, src->out + count, src->minIndex + count);
+ stateCount_ += count;
+ }
+
+ template <typename InputStream>
+ bool ParseUnsigned(DecodedStream<InputStream>& ds, unsigned* u) {
+ unsigned r = 0;
+ if (ds.Peek() < '0' || ds.Peek() > '9')
+ return false;
+ while (ds.Peek() >= '0' && ds.Peek() <= '9') {
+ if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295
+ return false; // overflow
+ r = r * 10 + (ds.Take() - '0');
+ }
+ *u = r;
+ return true;
+ }
+
+ template <typename InputStream>
+ bool ParseRange(DecodedStream<InputStream>& ds, SizeType* range) {
+ bool isBegin = true;
+ bool negate = false;
+ int step = 0;
+ SizeType start = kRegexInvalidRange;
+ SizeType current = kRegexInvalidRange;
+ unsigned codepoint;
+ while ((codepoint = ds.Take()) != 0) {
+ if (isBegin) {
+ isBegin = false;
+ if (codepoint == '^') {
+ negate = true;
+ continue;
+ }
+ }
+
+ switch (codepoint) {
+ case ']':
+ if (start == kRegexInvalidRange)
+ return false; // Error: nothing inside []
+ if (step == 2) { // Add trailing '-'
+ SizeType r = NewRange('-');
+ RAPIDJSON_ASSERT(current != kRegexInvalidRange);
+ GetRange(current).next = r;
+ }
+ if (negate)
+ GetRange(start).start |= kRangeNegationFlag;
+ *range = start;
+ return true;
+
+ case '\\':
+ if (ds.Peek() == 'b') {
+ ds.Take();
+ codepoint = 0x0008; // Escape backspace character
+ }
+ else if (!CharacterEscape(ds, &codepoint))
+ return false;
+ // fall through to default
+
+ default:
+ switch (step) {
+ case 1:
+ if (codepoint == '-') {
+ step++;
+ break;
+ }
+ // fall through to step 0 for other characters
+
+ case 0:
+ {
+ SizeType r = NewRange(codepoint);
+ if (current != kRegexInvalidRange)
+ GetRange(current).next = r;
+ if (start == kRegexInvalidRange)
+ start = r;
+ current = r;
+ }
+ step = 1;
+ break;
+
+ default:
+ RAPIDJSON_ASSERT(step == 2);
+ GetRange(current).end = codepoint;
+ step = 0;
+ }
+ }
+ }
+ return false;
+ }
+
+ SizeType NewRange(unsigned codepoint) {
+ Range* r = ranges_.template Push<Range>();
+ r->start = r->end = codepoint;
+ r->next = kRegexInvalidRange;
+ return rangeCount_++;
+ }
+
+ template <typename InputStream>
+ bool CharacterEscape(DecodedStream<InputStream>& ds, unsigned* escapedCodepoint) {
+ unsigned codepoint;
+ switch (codepoint = ds.Take()) {
+ case '^':
+ case '$':
+ case '|':
+ case '(':
+ case ')':
+ case '?':
+ case '*':
+ case '+':
+ case '.':
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ case '\\':
+ *escapedCodepoint = codepoint; return true;
+ case 'f': *escapedCodepoint = 0x000C; return true;
+ case 'n': *escapedCodepoint = 0x000A; return true;
+ case 'r': *escapedCodepoint = 0x000D; return true;
+ case 't': *escapedCodepoint = 0x0009; return true;
+ case 'v': *escapedCodepoint = 0x000B; return true;
+ default:
+ return false; // Unsupported escape character
+ }
+ }
+
+ template <typename InputStream>
+ bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) const {
+ RAPIDJSON_ASSERT(IsValid());
+ DecodedStream<InputStream> ds(is);
+
+ state0_.Clear();
+ Stack<Allocator> *current = &state0_, *next = &state1_;
+ const size_t stateSetSize = GetStateSetSize();
+ std::memset(stateSet_, 0, stateSetSize);
+
+ bool matched = AddState(*current, root_);
+ unsigned codepoint;
+ while (!current->Empty() && (codepoint = ds.Take()) != 0) {
+ std::memset(stateSet_, 0, stateSetSize);
+ next->Clear();
+ matched = false;
+ for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
+ const State& sr = GetState(*s);
+ if (sr.codepoint == codepoint ||
+ sr.codepoint == kAnyCharacterClass ||
+ (sr.codepoint == kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
+ {
+ matched = AddState(*next, sr.out) || matched;
+ if (!anchorEnd && matched)
+ return true;
+ }
+ if (!anchorBegin)
+ AddState(*next, root_);
+ }
+ internal::Swap(current, next);
+ }
+
+ return matched;
+ }
+
+ size_t GetStateSetSize() const {
+ return (stateCount_ + 31) / 32 * 4;
+ }
+
+ // Return whether the added states is a match state
+ bool AddState(Stack<Allocator>& l, SizeType index) const {
+ if (index == kRegexInvalidState)
+ return true;
+
+ const State& s = GetState(index);
+ if (s.out1 != kRegexInvalidState) { // Split
+ bool matched = AddState(l, s.out);
+ return AddState(l, s.out1) || matched;
+ }
+ else if (!(stateSet_[index >> 5] & (1 << (index & 31)))) {
+ stateSet_[index >> 5] |= (1 << (index & 31));
+ *l.template PushUnsafe<SizeType>() = index;
+ }
+ return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.
+ }
+
+ bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
+ bool yes = (GetRange(rangeIndex).start & kRangeNegationFlag) == 0;
+ while (rangeIndex != kRegexInvalidRange) {
+ const Range& r = GetRange(rangeIndex);
+ if (codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end)
+ return yes;
+ rangeIndex = r.next;
+ }
+ return !yes;
+ }
+
+ Stack<Allocator> states_;
+ Stack<Allocator> ranges_;
+ SizeType root_;
+ SizeType stateCount_;
+ SizeType rangeCount_;
+
+ static const unsigned kInfinityQuantifier = ~0u;
+
+ // For SearchWithAnchoring()
+ uint32_t* stateSet_; // allocated by states_.GetAllocator()
+ mutable Stack<Allocator> state0_;
+ mutable Stack<Allocator> state1_;
+ bool anchorBegin_;
+ bool anchorEnd_;
+};
+
+typedef GenericRegex<UTF8<> > Regex;
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_INTERNAL_REGEX_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/stack.h b/3rdparty/rapidjson/include/rapidjson/internal/stack.h
new file mode 100644
index 00000000000..022c9aab411
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/internal/stack.h
@@ -0,0 +1,230 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_STACK_H_
+#define RAPIDJSON_INTERNAL_STACK_H_
+
+#include "../allocators.h"
+#include "swap.h"
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+///////////////////////////////////////////////////////////////////////////////
+// Stack
+
+//! A type-unsafe stack for storing different types of data.
+/*! \tparam Allocator Allocator for allocating stack memory.
+*/
+template <typename Allocator>
+class Stack {
+public:
+ // Optimization note: Do not allocate memory for stack_ in constructor.
+ // Do it lazily when first Push() -> Expand() -> Resize().
+ Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ Stack(Stack&& rhs)
+ : allocator_(rhs.allocator_),
+ ownAllocator_(rhs.ownAllocator_),
+ stack_(rhs.stack_),
+ stackTop_(rhs.stackTop_),
+ stackEnd_(rhs.stackEnd_),
+ initialCapacity_(rhs.initialCapacity_)
+ {
+ rhs.allocator_ = 0;
+ rhs.ownAllocator_ = 0;
+ rhs.stack_ = 0;
+ rhs.stackTop_ = 0;
+ rhs.stackEnd_ = 0;
+ rhs.initialCapacity_ = 0;
+ }
+#endif
+
+ ~Stack() {
+ Destroy();
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ Stack& operator=(Stack&& rhs) {
+ if (&rhs != this)
+ {
+ Destroy();
+
+ allocator_ = rhs.allocator_;
+ ownAllocator_ = rhs.ownAllocator_;
+ stack_ = rhs.stack_;
+ stackTop_ = rhs.stackTop_;
+ stackEnd_ = rhs.stackEnd_;
+ initialCapacity_ = rhs.initialCapacity_;
+
+ rhs.allocator_ = 0;
+ rhs.ownAllocator_ = 0;
+ rhs.stack_ = 0;
+ rhs.stackTop_ = 0;
+ rhs.stackEnd_ = 0;
+ rhs.initialCapacity_ = 0;
+ }
+ return *this;
+ }
+#endif
+
+ void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
+ internal::Swap(allocator_, rhs.allocator_);
+ internal::Swap(ownAllocator_, rhs.ownAllocator_);
+ internal::Swap(stack_, rhs.stack_);
+ internal::Swap(stackTop_, rhs.stackTop_);
+ internal::Swap(stackEnd_, rhs.stackEnd_);
+ internal::Swap(initialCapacity_, rhs.initialCapacity_);
+ }
+
+ void Clear() { stackTop_ = stack_; }
+
+ void ShrinkToFit() {
+ if (Empty()) {
+ // If the stack is empty, completely deallocate the memory.
+ Allocator::Free(stack_);
+ stack_ = 0;
+ stackTop_ = 0;
+ stackEnd_ = 0;
+ }
+ else
+ Resize(GetSize());
+ }
+
+ // Optimization note: try to minimize the size of this function for force inline.
+ // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
+ template<typename T>
+ RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
+ // Expand the stack if needed
+ if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_))
+ Expand<T>(count);
+ }
+
+ template<typename T>
+ RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
+ Reserve<T>(count);
+ return PushUnsafe<T>(count);
+ }
+
+ template<typename T>
+ RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
+ RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_);
+ T* ret = reinterpret_cast<T*>(stackTop_);
+ stackTop_ += sizeof(T) * count;
+ return ret;
+ }
+
+ template<typename T>
+ T* Pop(size_t count) {
+ RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
+ stackTop_ -= count * sizeof(T);
+ return reinterpret_cast<T*>(stackTop_);
+ }
+
+ template<typename T>
+ T* Top() {
+ RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
+ return reinterpret_cast<T*>(stackTop_ - sizeof(T));
+ }
+
+ template<typename T>
+ const T* Top() const {
+ RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
+ return reinterpret_cast<T*>(stackTop_ - sizeof(T));
+ }
+
+ template<typename T>
+ T* End() { return reinterpret_cast<T*>(stackTop_); }
+
+ template<typename T>
+ const T* End() const { return reinterpret_cast<T*>(stackTop_); }
+
+ template<typename T>
+ T* Bottom() { return reinterpret_cast<T*>(stack_); }
+
+ template<typename T>
+ const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
+
+ bool HasAllocator() const {
+ return allocator_ != 0;
+ }
+
+ Allocator& GetAllocator() {
+ RAPIDJSON_ASSERT(allocator_);
+ return *allocator_;
+ }
+
+ bool Empty() const { return stackTop_ == stack_; }
+ size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
+ size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
+
+private:
+ template<typename T>
+ void Expand(size_t count) {
+ // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
+ size_t newCapacity;
+ if (stack_ == 0) {
+ if (!allocator_)
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+ newCapacity = initialCapacity_;
+ } else {
+ newCapacity = GetCapacity();
+ newCapacity += (newCapacity + 1) / 2;
+ }
+ size_t newSize = GetSize() + sizeof(T) * count;
+ if (newCapacity < newSize)
+ newCapacity = newSize;
+
+ Resize(newCapacity);
+ }
+
+ void Resize(size_t newCapacity) {
+ const size_t size = GetSize(); // Backup the current size
+ stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
+ stackTop_ = stack_ + size;
+ stackEnd_ = stack_ + newCapacity;
+ }
+
+ void Destroy() {
+ Allocator::Free(stack_);
+ RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
+ }
+
+ // Prohibit copy constructor & assignment operator.
+ Stack(const Stack&);
+ Stack& operator=(const Stack&);
+
+ Allocator* allocator_;
+ Allocator* ownAllocator_;
+ char *stack_;
+ char *stackTop_;
+ char *stackEnd_;
+ size_t initialCapacity_;
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_STACK_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/strfunc.h b/3rdparty/rapidjson/include/rapidjson/internal/strfunc.h
new file mode 100644
index 00000000000..2edfae52678
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/internal/strfunc.h
@@ -0,0 +1,55 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
+#define RAPIDJSON_INTERNAL_STRFUNC_H_
+
+#include "../stream.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+//! Custom strlen() which works on different character types.
+/*! \tparam Ch Character type (e.g. char, wchar_t, short)
+ \param s Null-terminated input string.
+ \return Number of characters in the string.
+ \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
+*/
+template <typename Ch>
+inline SizeType StrLen(const Ch* s) {
+ const Ch* p = s;
+ while (*p) ++p;
+ return SizeType(p - s);
+}
+
+//! Returns number of code points in a encoded string.
+template<typename Encoding>
+bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
+ GenericStringStream<Encoding> is(s);
+ const typename Encoding::Ch* end = s + length;
+ SizeType count = 0;
+ while (is.src_ < end) {
+ unsigned codepoint;
+ if (!Encoding::Decode(is, &codepoint))
+ return false;
+ count++;
+ }
+ *outCount = count;
+ return true;
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/strtod.h b/3rdparty/rapidjson/include/rapidjson/internal/strtod.h
new file mode 100644
index 00000000000..fd4b01e8dde
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/internal/strtod.h
@@ -0,0 +1,269 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_STRTOD_
+#define RAPIDJSON_STRTOD_
+
+#include "ieee754.h"
+#include "biginteger.h"
+#include "diyfp.h"
+#include "pow10.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+inline double FastPath(double significand, int exp) {
+ if (exp < -308)
+ return 0.0;
+ else if (exp >= 0)
+ return significand * internal::Pow10(exp);
+ else
+ return significand / internal::Pow10(-exp);
+}
+
+inline double StrtodNormalPrecision(double d, int p) {
+ if (p < -308) {
+ // Prevent expSum < -308, making Pow10(p) = 0
+ d = FastPath(d, -308);
+ d = FastPath(d, p + 308);
+ }
+ else
+ d = FastPath(d, p);
+ return d;
+}
+
+template <typename T>
+inline T Min3(T a, T b, T c) {
+ T m = a;
+ if (m > b) m = b;
+ if (m > c) m = c;
+ return m;
+}
+
+inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
+ const Double db(b);
+ const uint64_t bInt = db.IntegerSignificand();
+ const int bExp = db.IntegerExponent();
+ const int hExp = bExp - 1;
+
+ int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
+
+ // Adjust for decimal exponent
+ if (dExp >= 0) {
+ dS_Exp2 += dExp;
+ dS_Exp5 += dExp;
+ }
+ else {
+ bS_Exp2 -= dExp;
+ bS_Exp5 -= dExp;
+ hS_Exp2 -= dExp;
+ hS_Exp5 -= dExp;
+ }
+
+ // Adjust for binary exponent
+ if (bExp >= 0)
+ bS_Exp2 += bExp;
+ else {
+ dS_Exp2 -= bExp;
+ hS_Exp2 -= bExp;
+ }
+
+ // Adjust for half ulp exponent
+ if (hExp >= 0)
+ hS_Exp2 += hExp;
+ else {
+ dS_Exp2 -= hExp;
+ bS_Exp2 -= hExp;
+ }
+
+ // Remove common power of two factor from all three scaled values
+ int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
+ dS_Exp2 -= common_Exp2;
+ bS_Exp2 -= common_Exp2;
+ hS_Exp2 -= common_Exp2;
+
+ BigInteger dS = d;
+ dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
+
+ BigInteger bS(bInt);
+ bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
+
+ BigInteger hS(1);
+ hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
+
+ BigInteger delta(0);
+ dS.Difference(bS, &delta);
+
+ return delta.Compare(hS);
+}
+
+inline bool StrtodFast(double d, int p, double* result) {
+ // Use fast path for string-to-double conversion if possible
+ // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
+ if (p > 22 && p < 22 + 16) {
+ // Fast Path Cases In Disguise
+ d *= internal::Pow10(p - 22);
+ p = 22;
+ }
+
+ if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1
+ *result = FastPath(d, p);
+ return true;
+ }
+ else
+ return false;
+}
+
+// Compute an approximation and see if it is within 1/2 ULP
+inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) {
+ uint64_t significand = 0;
+ size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
+ for (; i < length; i++) {
+ if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
+ (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
+ break;
+ significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
+ }
+
+ if (i < length && decimals[i] >= '5') // Rounding
+ significand++;
+
+ size_t remaining = length - i;
+ const unsigned kUlpShift = 3;
+ const unsigned kUlp = 1 << kUlpShift;
+ int error = (remaining == 0) ? 0 : kUlp / 2;
+
+ DiyFp v(significand, 0);
+ v = v.Normalize();
+ error <<= -v.e;
+
+ const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(i) + exp;
+
+ int actualExp;
+ DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
+ if (actualExp != dExp) {
+ static const DiyFp kPow10[] = {
+ DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1
+ DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2
+ DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3
+ DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4
+ DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5
+ DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6
+ DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7
+ };
+ int adjustment = dExp - actualExp - 1;
+ RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
+ v = v * kPow10[adjustment];
+ if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit
+ error += kUlp / 2;
+ }
+
+ v = v * cachedPower;
+
+ error += kUlp + (error == 0 ? 0 : 1);
+
+ const int oldExp = v.e;
+ v = v.Normalize();
+ error <<= oldExp - v.e;
+
+ const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
+ unsigned precisionSize = 64 - effectiveSignificandSize;
+ if (precisionSize + kUlpShift >= 64) {
+ unsigned scaleExp = (precisionSize + kUlpShift) - 63;
+ v.f >>= scaleExp;
+ v.e += scaleExp;
+ error = (error >> scaleExp) + 1 + static_cast<int>(kUlp);
+ precisionSize -= scaleExp;
+ }
+
+ DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize));
+ const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
+ const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
+ if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
+ rounded.f++;
+ if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
+ rounded.f >>= 1;
+ rounded.e++;
+ }
+ }
+
+ *result = rounded.ToDouble();
+
+ return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
+}
+
+inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
+ const BigInteger dInt(decimals, length);
+ const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp;
+ Double a(approx);
+ int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
+ if (cmp < 0)
+ return a.Value(); // within half ULP
+ else if (cmp == 0) {
+ // Round towards even
+ if (a.Significand() & 1)
+ return a.NextPositiveDouble();
+ else
+ return a.Value();
+ }
+ else // adjustment
+ return a.NextPositiveDouble();
+}
+
+inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
+ RAPIDJSON_ASSERT(d >= 0.0);
+ RAPIDJSON_ASSERT(length >= 1);
+
+ double result;
+ if (StrtodFast(d, p, &result))
+ return result;
+
+ // Trim leading zeros
+ while (*decimals == '0' && length > 1) {
+ length--;
+ decimals++;
+ decimalPosition--;
+ }
+
+ // Trim trailing zeros
+ while (decimals[length - 1] == '0' && length > 1) {
+ length--;
+ decimalPosition--;
+ exp++;
+ }
+
+ // Trim right-most digits
+ const int kMaxDecimalDigit = 780;
+ if (static_cast<int>(length) > kMaxDecimalDigit) {
+ int delta = (static_cast<int>(length) - kMaxDecimalDigit);
+ exp += delta;
+ decimalPosition -= static_cast<unsigned>(delta);
+ length = kMaxDecimalDigit;
+ }
+
+ // If too small, underflow to zero
+ if (int(length) + exp < -324)
+ return 0.0;
+
+ if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result))
+ return result;
+
+ // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
+ return StrtodBigInteger(result, decimals, length, decimalPosition, exp);
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_STRTOD_
diff --git a/3rdparty/rapidjson/include/rapidjson/internal/swap.h b/3rdparty/rapidjson/include/rapidjson/internal/swap.h
new file mode 100644
index 00000000000..666e49f97b6
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/internal/swap.h
@@ -0,0 +1,46 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_SWAP_H_
+#define RAPIDJSON_INTERNAL_SWAP_H_
+
+#include "../rapidjson.h"
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+//! Custom swap() to avoid dependency on C++ <algorithm> header
+/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
+ \note This has the same semantics as std::swap().
+*/
+template <typename T>
+inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
+ T tmp = a;
+ a = b;
+ b = tmp;
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_INTERNAL_SWAP_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/istreamwrapper.h b/3rdparty/rapidjson/include/rapidjson/istreamwrapper.h
new file mode 100644
index 00000000000..9efeea24f46
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/istreamwrapper.h
@@ -0,0 +1,105 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "stream.h"
+#include <iosfwd>
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept.
+/*!
+ The classes can be wrapped including but not limited to:
+
+ - \c std::istringstream
+ - \c std::stringstream
+ - \c std::wistringstream
+ - \c std::wstringstream
+ - \c std::ifstream
+ - \c std::fstream
+ - \c std::wifstream
+ - \c std::wfstream
+
+ \tparam StreamType Class derived from \c std::basic_istream.
+*/
+
+template <typename StreamType>
+class BasicIStreamWrapper {
+public:
+ typedef typename StreamType::char_type Ch;
+ BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {}
+
+ Ch Peek() const {
+ typename StreamType::int_type c = stream_.peek();
+ return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast<Ch>(c) : '\0';
+ }
+
+ Ch Take() {
+ typename StreamType::int_type c = stream_.get();
+ if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) {
+ count_++;
+ return static_cast<Ch>(c);
+ }
+ else
+ return '\0';
+ }
+
+ // tellg() may return -1 when failed. So we count by ourself.
+ size_t Tell() const { return count_; }
+
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
+ void Flush() { RAPIDJSON_ASSERT(false); }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+ // For encoding detection only.
+ const Ch* Peek4() const {
+ RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream.
+ int i;
+ bool hasError = false;
+ for (i = 0; i < 4; ++i) {
+ typename StreamType::int_type c = stream_.get();
+ if (c == StreamType::traits_type::eof()) {
+ hasError = true;
+ stream_.clear();
+ break;
+ }
+ peekBuffer_[i] = static_cast<Ch>(c);
+ }
+ for (--i; i >= 0; --i)
+ stream_.putback(peekBuffer_[i]);
+ return !hasError ? peekBuffer_ : 0;
+ }
+
+private:
+ BasicIStreamWrapper(const BasicIStreamWrapper&);
+ BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
+
+ StreamType& stream_;
+ size_t count_; //!< Number of characters read. Note:
+ mutable Ch peekBuffer_[4];
+};
+
+typedef BasicIStreamWrapper<std::istream> IStreamWrapper;
+typedef BasicIStreamWrapper<std::wistream> WIStreamWrapper;
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+RAPIDJSON_NAMESPACE_END
diff --git a/3rdparty/rapidjson/include/rapidjson/memorybuffer.h b/3rdparty/rapidjson/include/rapidjson/memorybuffer.h
new file mode 100644
index 00000000000..39bee1dec1c
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/memorybuffer.h
@@ -0,0 +1,70 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_MEMORYBUFFER_H_
+#define RAPIDJSON_MEMORYBUFFER_H_
+
+#include "stream.h"
+#include "internal/stack.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Represents an in-memory output byte stream.
+/*!
+ This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.
+
+ It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.
+
+ Differences between MemoryBuffer and StringBuffer:
+ 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer.
+ 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.
+
+ \tparam Allocator type for allocating memory buffer.
+ \note implements Stream concept
+*/
+template <typename Allocator = CrtAllocator>
+struct GenericMemoryBuffer {
+ typedef char Ch; // byte
+
+ GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
+
+ void Put(Ch c) { *stack_.template Push<Ch>() = c; }
+ void Flush() {}
+
+ void Clear() { stack_.Clear(); }
+ void ShrinkToFit() { stack_.ShrinkToFit(); }
+ Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
+ void Pop(size_t count) { stack_.template Pop<Ch>(count); }
+
+ const Ch* GetBuffer() const {
+ return stack_.template Bottom<Ch>();
+ }
+
+ size_t GetSize() const { return stack_.GetSize(); }
+
+ static const size_t kDefaultCapacity = 256;
+ mutable internal::Stack<Allocator> stack_;
+};
+
+typedef GenericMemoryBuffer<> MemoryBuffer;
+
+//! Implement specialized version of PutN() with memset() for better performance.
+template<>
+inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
+ std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_MEMORYBUFFER_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/memorystream.h b/3rdparty/rapidjson/include/rapidjson/memorystream.h
new file mode 100644
index 00000000000..7381e0b7dd2
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/memorystream.h
@@ -0,0 +1,71 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_MEMORYSTREAM_H_
+#define RAPIDJSON_MEMORYSTREAM_H_
+
+#include "stream.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(unreachable-code)
+RAPIDJSON_DIAG_OFF(missing-noreturn)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Represents an in-memory input byte stream.
+/*!
+ This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream.
+
+ It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file.
+
+ Differences between MemoryStream and StringStream:
+ 1. StringStream has encoding but MemoryStream is a byte stream.
+ 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source.
+ 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().
+ \note implements Stream concept
+*/
+struct MemoryStream {
+ typedef char Ch; // byte
+
+ MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
+
+ Ch Peek() const { return (src_ == end_) ? '\0' : *src_; }
+ Ch Take() { return (src_ == end_) ? '\0' : *src_++; }
+ size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
+
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
+ void Flush() { RAPIDJSON_ASSERT(false); }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+ // For encoding detection only.
+ const Ch* Peek4() const {
+ return Tell() + 4 <= size_ ? src_ : 0;
+ }
+
+ const Ch* src_; //!< Current read position.
+ const Ch* begin_; //!< Original head of the string.
+ const Ch* end_; //!< End of stream.
+ size_t size_; //!< Size of the stream.
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_MEMORYBUFFER_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/msinttypes/inttypes.h b/3rdparty/rapidjson/include/rapidjson/msinttypes/inttypes.h
new file mode 100644
index 00000000000..18111286bf5
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/msinttypes/inttypes.h
@@ -0,0 +1,316 @@
+// ISO C9x compliant inttypes.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006-2013 Alexander Chemeris
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the product nor the names of its contributors may
+// be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// The above software in this distribution may have been modified by
+// THL A29 Limited ("Tencent Modifications").
+// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_INTTYPES_H_ // [
+#define _MSC_INTTYPES_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include "stdint.h"
+
+// miloyip: VC supports inttypes.h since VC2013
+#if _MSC_VER >= 1800
+#include <inttypes.h>
+#else
+
+// 7.8 Format conversion of integer types
+
+typedef struct {
+ intmax_t quot;
+ intmax_t rem;
+} imaxdiv_t;
+
+// 7.8.1 Macros for format specifiers
+
+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
+
+// The fprintf macros for signed integers are:
+#define PRId8 "d"
+#define PRIi8 "i"
+#define PRIdLEAST8 "d"
+#define PRIiLEAST8 "i"
+#define PRIdFAST8 "d"
+#define PRIiFAST8 "i"
+
+#define PRId16 "hd"
+#define PRIi16 "hi"
+#define PRIdLEAST16 "hd"
+#define PRIiLEAST16 "hi"
+#define PRIdFAST16 "hd"
+#define PRIiFAST16 "hi"
+
+#define PRId32 "I32d"
+#define PRIi32 "I32i"
+#define PRIdLEAST32 "I32d"
+#define PRIiLEAST32 "I32i"
+#define PRIdFAST32 "I32d"
+#define PRIiFAST32 "I32i"
+
+#define PRId64 "I64d"
+#define PRIi64 "I64i"
+#define PRIdLEAST64 "I64d"
+#define PRIiLEAST64 "I64i"
+#define PRIdFAST64 "I64d"
+#define PRIiFAST64 "I64i"
+
+#define PRIdMAX "I64d"
+#define PRIiMAX "I64i"
+
+#define PRIdPTR "Id"
+#define PRIiPTR "Ii"
+
+// The fprintf macros for unsigned integers are:
+#define PRIo8 "o"
+#define PRIu8 "u"
+#define PRIx8 "x"
+#define PRIX8 "X"
+#define PRIoLEAST8 "o"
+#define PRIuLEAST8 "u"
+#define PRIxLEAST8 "x"
+#define PRIXLEAST8 "X"
+#define PRIoFAST8 "o"
+#define PRIuFAST8 "u"
+#define PRIxFAST8 "x"
+#define PRIXFAST8 "X"
+
+#define PRIo16 "ho"
+#define PRIu16 "hu"
+#define PRIx16 "hx"
+#define PRIX16 "hX"
+#define PRIoLEAST16 "ho"
+#define PRIuLEAST16 "hu"
+#define PRIxLEAST16 "hx"
+#define PRIXLEAST16 "hX"
+#define PRIoFAST16 "ho"
+#define PRIuFAST16 "hu"
+#define PRIxFAST16 "hx"
+#define PRIXFAST16 "hX"
+
+#define PRIo32 "I32o"
+#define PRIu32 "I32u"
+#define PRIx32 "I32x"
+#define PRIX32 "I32X"
+#define PRIoLEAST32 "I32o"
+#define PRIuLEAST32 "I32u"
+#define PRIxLEAST32 "I32x"
+#define PRIXLEAST32 "I32X"
+#define PRIoFAST32 "I32o"
+#define PRIuFAST32 "I32u"
+#define PRIxFAST32 "I32x"
+#define PRIXFAST32 "I32X"
+
+#define PRIo64 "I64o"
+#define PRIu64 "I64u"
+#define PRIx64 "I64x"
+#define PRIX64 "I64X"
+#define PRIoLEAST64 "I64o"
+#define PRIuLEAST64 "I64u"
+#define PRIxLEAST64 "I64x"
+#define PRIXLEAST64 "I64X"
+#define PRIoFAST64 "I64o"
+#define PRIuFAST64 "I64u"
+#define PRIxFAST64 "I64x"
+#define PRIXFAST64 "I64X"
+
+#define PRIoMAX "I64o"
+#define PRIuMAX "I64u"
+#define PRIxMAX "I64x"
+#define PRIXMAX "I64X"
+
+#define PRIoPTR "Io"
+#define PRIuPTR "Iu"
+#define PRIxPTR "Ix"
+#define PRIXPTR "IX"
+
+// The fscanf macros for signed integers are:
+#define SCNd8 "d"
+#define SCNi8 "i"
+#define SCNdLEAST8 "d"
+#define SCNiLEAST8 "i"
+#define SCNdFAST8 "d"
+#define SCNiFAST8 "i"
+
+#define SCNd16 "hd"
+#define SCNi16 "hi"
+#define SCNdLEAST16 "hd"
+#define SCNiLEAST16 "hi"
+#define SCNdFAST16 "hd"
+#define SCNiFAST16 "hi"
+
+#define SCNd32 "ld"
+#define SCNi32 "li"
+#define SCNdLEAST32 "ld"
+#define SCNiLEAST32 "li"
+#define SCNdFAST32 "ld"
+#define SCNiFAST32 "li"
+
+#define SCNd64 "I64d"
+#define SCNi64 "I64i"
+#define SCNdLEAST64 "I64d"
+#define SCNiLEAST64 "I64i"
+#define SCNdFAST64 "I64d"
+#define SCNiFAST64 "I64i"
+
+#define SCNdMAX "I64d"
+#define SCNiMAX "I64i"
+
+#ifdef _WIN64 // [
+# define SCNdPTR "I64d"
+# define SCNiPTR "I64i"
+#else // _WIN64 ][
+# define SCNdPTR "ld"
+# define SCNiPTR "li"
+#endif // _WIN64 ]
+
+// The fscanf macros for unsigned integers are:
+#define SCNo8 "o"
+#define SCNu8 "u"
+#define SCNx8 "x"
+#define SCNX8 "X"
+#define SCNoLEAST8 "o"
+#define SCNuLEAST8 "u"
+#define SCNxLEAST8 "x"
+#define SCNXLEAST8 "X"
+#define SCNoFAST8 "o"
+#define SCNuFAST8 "u"
+#define SCNxFAST8 "x"
+#define SCNXFAST8 "X"
+
+#define SCNo16 "ho"
+#define SCNu16 "hu"
+#define SCNx16 "hx"
+#define SCNX16 "hX"
+#define SCNoLEAST16 "ho"
+#define SCNuLEAST16 "hu"
+#define SCNxLEAST16 "hx"
+#define SCNXLEAST16 "hX"
+#define SCNoFAST16 "ho"
+#define SCNuFAST16 "hu"
+#define SCNxFAST16 "hx"
+#define SCNXFAST16 "hX"
+
+#define SCNo32 "lo"
+#define SCNu32 "lu"
+#define SCNx32 "lx"
+#define SCNX32 "lX"
+#define SCNoLEAST32 "lo"
+#define SCNuLEAST32 "lu"
+#define SCNxLEAST32 "lx"
+#define SCNXLEAST32 "lX"
+#define SCNoFAST32 "lo"
+#define SCNuFAST32 "lu"
+#define SCNxFAST32 "lx"
+#define SCNXFAST32 "lX"
+
+#define SCNo64 "I64o"
+#define SCNu64 "I64u"
+#define SCNx64 "I64x"
+#define SCNX64 "I64X"
+#define SCNoLEAST64 "I64o"
+#define SCNuLEAST64 "I64u"
+#define SCNxLEAST64 "I64x"
+#define SCNXLEAST64 "I64X"
+#define SCNoFAST64 "I64o"
+#define SCNuFAST64 "I64u"
+#define SCNxFAST64 "I64x"
+#define SCNXFAST64 "I64X"
+
+#define SCNoMAX "I64o"
+#define SCNuMAX "I64u"
+#define SCNxMAX "I64x"
+#define SCNXMAX "I64X"
+
+#ifdef _WIN64 // [
+# define SCNoPTR "I64o"
+# define SCNuPTR "I64u"
+# define SCNxPTR "I64x"
+# define SCNXPTR "I64X"
+#else // _WIN64 ][
+# define SCNoPTR "lo"
+# define SCNuPTR "lu"
+# define SCNxPTR "lx"
+# define SCNXPTR "lX"
+#endif // _WIN64 ]
+
+#endif // __STDC_FORMAT_MACROS ]
+
+// 7.8.2 Functions for greatest-width integer types
+
+// 7.8.2.1 The imaxabs function
+#define imaxabs _abs64
+
+// 7.8.2.2 The imaxdiv function
+
+// This is modified version of div() function from Microsoft's div.c found
+// in %MSVC.NET%\crt\src\div.c
+#ifdef STATIC_IMAXDIV // [
+static
+#else // STATIC_IMAXDIV ][
+_inline
+#endif // STATIC_IMAXDIV ]
+imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
+{
+ imaxdiv_t result;
+
+ result.quot = numer / denom;
+ result.rem = numer % denom;
+
+ if (numer < 0 && result.rem > 0) {
+ // did division wrong; must fix up
+ ++result.quot;
+ result.rem -= denom;
+ }
+
+ return result;
+}
+
+// 7.8.2.3 The strtoimax and strtoumax functions
+#define strtoimax _strtoi64
+#define strtoumax _strtoui64
+
+// 7.8.2.4 The wcstoimax and wcstoumax functions
+#define wcstoimax _wcstoi64
+#define wcstoumax _wcstoui64
+
+#endif // _MSC_VER >= 1800
+
+#endif // _MSC_INTTYPES_H_ ]
diff --git a/3rdparty/rapidjson/include/rapidjson/msinttypes/stdint.h b/3rdparty/rapidjson/include/rapidjson/msinttypes/stdint.h
new file mode 100644
index 00000000000..3d4477b9a02
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/msinttypes/stdint.h
@@ -0,0 +1,300 @@
+// ISO C9x compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006-2013 Alexander Chemeris
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the product nor the names of its contributors may
+// be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// The above software in this distribution may have been modified by
+// THL A29 Limited ("Tencent Modifications").
+// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010.
+#if _MSC_VER >= 1600 // [
+#include <stdint.h>
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
+
+#undef INT8_C
+#undef INT16_C
+#undef INT32_C
+#undef INT64_C
+#undef UINT8_C
+#undef UINT16_C
+#undef UINT32_C
+#undef UINT64_C
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val) val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val) val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
+// Check out Issue 9 for the details.
+#ifndef INTMAX_C // [
+# define INTMAX_C INT64_C
+#endif // INTMAX_C ]
+#ifndef UINTMAX_C // [
+# define UINTMAX_C UINT64_C
+#endif // UINTMAX_C ]
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+#else // ] _MSC_VER >= 1700 [
+
+#include <limits.h>
+
+// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
+// compiling for ARM we have to wrap <wchar.h> include with 'extern "C++" {}'
+// or compiler would give many errors like this:
+// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#if defined(__cplusplus) && !defined(_M_ARM)
+extern "C" {
+#endif
+# include <wchar.h>
+#if defined(__cplusplus) && !defined(_M_ARM)
+}
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+# define _W64 __w64
+# else
+# define _W64
+# endif
+#endif
+
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+
+// Visual Studio 6 and Embedded Visual C++ 4 doesn't
+// realize that, e.g. char has the same size as __int8
+// so we give up on __intX for them.
+#if (_MSC_VER < 1300)
+ typedef signed char int8_t;
+ typedef signed short int16_t;
+ typedef signed int int32_t;
+ typedef unsigned char uint8_t;
+ typedef unsigned short uint16_t;
+ typedef unsigned int uint32_t;
+#else
+ typedef signed __int8 int8_t;
+ typedef signed __int16 int16_t;
+ typedef signed __int32 int32_t;
+ typedef unsigned __int8 uint8_t;
+ typedef unsigned __int16 uint16_t;
+ typedef unsigned __int32 uint32_t;
+#endif
+typedef signed __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t int_fast8_t;
+typedef int16_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef int64_t int_fast64_t;
+typedef uint8_t uint_fast8_t;
+typedef uint16_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+typedef uint64_t uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+ typedef signed __int64 intptr_t;
+ typedef unsigned __int64 uintptr_t;
+#else // _WIN64 ][
+ typedef _W64 signed int intptr_t;
+ typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN ((int8_t)_I8_MIN)
+#define INT8_MAX _I8_MAX
+#define INT16_MIN ((int16_t)_I16_MIN)
+#define INT16_MAX _I16_MAX
+#define INT32_MIN ((int32_t)_I32_MIN)
+#define INT32_MAX _I32_MAX
+#define INT64_MIN ((int64_t)_I64_MIN)
+#define INT64_MAX _I64_MAX
+#define UINT8_MAX _UI8_MAX
+#define UINT16_MAX _UI16_MAX
+#define UINT32_MAX _UI32_MAX
+#define UINT64_MAX _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST16_MAX INT16_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+# define INTPTR_MIN INT64_MIN
+# define INTPTR_MAX INT64_MAX
+# define UINTPTR_MAX UINT64_MAX
+#else // _WIN64 ][
+# define INTPTR_MIN INT32_MIN
+# define INTPTR_MAX INT32_MAX
+# define UINTPTR_MAX UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+# define PTRDIFF_MIN _I64_MIN
+# define PTRDIFF_MAX _I64_MAX
+#else // _WIN64 ][
+# define PTRDIFF_MIN _I32_MIN
+# define PTRDIFF_MAX _I32_MAX
+#endif // _WIN64 ]
+
+#define SIG_ATOMIC_MIN INT_MIN
+#define SIG_ATOMIC_MAX INT_MAX
+
+#ifndef SIZE_MAX // [
+# ifdef _WIN64 // [
+# define SIZE_MAX _UI64_MAX
+# else // _WIN64 ][
+# define SIZE_MAX _UI32_MAX
+# endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
+#ifndef WCHAR_MIN // [
+# define WCHAR_MIN 0
+#endif // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+# define WCHAR_MAX _UI16_MAX
+#endif // WCHAR_MAX ]
+
+#define WINT_MIN 0
+#define WINT_MAX _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val) val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val) val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
+// Check out Issue 9 for the details.
+#ifndef INTMAX_C // [
+# define INTMAX_C INT64_C
+#endif // INTMAX_C ]
+#ifndef UINTMAX_C // [
+# define UINTMAX_C UINT64_C
+#endif // UINTMAX_C ]
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+#endif // _MSC_VER >= 1600 ]
+
+#endif // _MSC_STDINT_H_ ]
diff --git a/3rdparty/rapidjson/include/rapidjson/ostreamwrapper.h b/3rdparty/rapidjson/include/rapidjson/ostreamwrapper.h
new file mode 100644
index 00000000000..8bf36dcd04c
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/ostreamwrapper.h
@@ -0,0 +1,76 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "stream.h"
+#include <iosfwd>
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept.
+/*!
+ The classes can be wrapped including but not limited to:
+
+ - \c std::ostringstream
+ - \c std::stringstream
+ - \c std::wpstringstream
+ - \c std::wstringstream
+ - \c std::ifstream
+ - \c std::fstream
+ - \c std::wofstream
+ - \c std::wfstream
+
+ \tparam StreamType Class derived from \c std::basic_ostream.
+*/
+
+template <typename StreamType>
+class BasicOStreamWrapper {
+public:
+ typedef typename StreamType::char_type Ch;
+ BasicOStreamWrapper(StreamType& stream) : stream_(stream) {}
+
+ void Put(Ch c) {
+ stream_.put(c);
+ }
+
+ void Flush() {
+ stream_.flush();
+ }
+
+ // Not implemented
+ char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
+ char Take() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
+ char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+ BasicOStreamWrapper(const BasicOStreamWrapper&);
+ BasicOStreamWrapper& operator=(const BasicOStreamWrapper&);
+
+ StreamType& stream_;
+};
+
+typedef BasicOStreamWrapper<std::ostream> OStreamWrapper;
+typedef BasicOStreamWrapper<std::wostream> WOStreamWrapper;
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+RAPIDJSON_NAMESPACE_END
diff --git a/3rdparty/rapidjson/include/rapidjson/pointer.h b/3rdparty/rapidjson/include/rapidjson/pointer.h
new file mode 100644
index 00000000000..eddeab427ea
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/pointer.h
@@ -0,0 +1,1345 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_POINTER_H_
+#define RAPIDJSON_POINTER_H_
+
+#include "document.h"
+#include "internal/itoa.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(switch-enum)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token
+
+//! Error code of parsing.
+/*! \ingroup RAPIDJSON_ERRORS
+ \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode
+*/
+enum PointerParseErrorCode {
+ kPointerParseErrorNone = 0, //!< The parse is successful
+
+ kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/'
+ kPointerParseErrorInvalidEscape, //!< Invalid escape
+ kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment
+ kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericPointer
+
+//! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
+/*!
+ This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer"
+ (https://tools.ietf.org/html/rfc6901).
+
+ A JSON pointer is for identifying a specific value in a JSON document
+ (GenericDocument). It can simplify coding of DOM tree manipulation, because it
+ can access multiple-level depth of DOM tree with single API call.
+
+ After it parses a string representation (e.g. "/foo/0" or URI fragment
+ representation (e.g. "#/foo/0") into its internal representation (tokens),
+ it can be used to resolve a specific value in multiple documents, or sub-tree
+ of documents.
+
+ Contrary to GenericValue, Pointer can be copy constructed and copy assigned.
+ Apart from assignment, a Pointer cannot be modified after construction.
+
+ Although Pointer is very convenient, please aware that constructing Pointer
+ involves parsing and dynamic memory allocation. A special constructor with user-
+ supplied tokens eliminates these.
+
+ GenericPointer depends on GenericDocument and GenericValue.
+
+ \tparam ValueType The value type of the DOM tree. E.g. GenericValue<UTF8<> >
+ \tparam Allocator The allocator type for allocating memory for internal representation.
+
+ \note GenericPointer uses same encoding of ValueType.
+ However, Allocator of GenericPointer is independent of Allocator of Value.
+*/
+template <typename ValueType, typename Allocator = CrtAllocator>
+class GenericPointer {
+public:
+ typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value
+ typedef typename ValueType::Ch Ch; //!< Character type from Value
+
+ //! A token is the basic units of internal representation.
+ /*!
+ A JSON pointer string representation "/foo/123" is parsed to two tokens:
+ "foo" and 123. 123 will be represented in both numeric form and string form.
+ They are resolved according to the actual value type (object or array).
+
+ For token that are not numbers, or the numeric value is out of bound
+ (greater than limits of SizeType), they are only treated as string form
+ (i.e. the token's index will be equal to kPointerInvalidIndex).
+
+ This struct is public so that user can create a Pointer without parsing and
+ allocation, using a special constructor.
+ */
+ struct Token {
+ const Ch* name; //!< Name of the token. It has null character at the end but it can contain null character.
+ SizeType length; //!< Length of the name.
+ SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex.
+ };
+
+ //!@name Constructors and destructor.
+ //@{
+
+ //! Default constructor.
+ GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
+
+ //! Constructor that parses a string or URI fragment representation.
+ /*!
+ \param source A null-terminated, string or URI fragment representation of JSON pointer.
+ \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
+ */
+ explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
+ Parse(source, internal::StrLen(source));
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Constructor that parses a string or URI fragment representation.
+ /*!
+ \param source A string or URI fragment representation of JSON pointer.
+ \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
+ \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+ */
+ explicit GenericPointer(const std::basic_string<Ch>& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
+ Parse(source.c_str(), source.size());
+ }
+#endif
+
+ //! Constructor that parses a string or URI fragment representation, with length of the source string.
+ /*!
+ \param source A string or URI fragment representation of JSON pointer.
+ \param length Length of source.
+ \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
+ \note Slightly faster than the overload without length.
+ */
+ GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
+ Parse(source, length);
+ }
+
+ //! Constructor with user-supplied tokens.
+ /*!
+ This constructor let user supplies const array of tokens.
+ This prevents the parsing process and eliminates allocation.
+ This is preferred for memory constrained environments.
+
+ \param tokens An constant array of tokens representing the JSON pointer.
+ \param tokenCount Number of tokens.
+
+ \b Example
+ \code
+ #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex }
+ #define INDEX(i) { #i, sizeof(#i) - 1, i }
+
+ static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) };
+ static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
+ // Equivalent to static const Pointer p("/foo/123");
+
+ #undef NAME
+ #undef INDEX
+ \endcode
+ */
+ GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
+
+ //! Copy constructor.
+ GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
+ *this = rhs;
+ }
+
+ //! Destructor.
+ ~GenericPointer() {
+ if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated.
+ Allocator::Free(tokens_);
+ RAPIDJSON_DELETE(ownAllocator_);
+ }
+
+ //! Assignment operator.
+ GenericPointer& operator=(const GenericPointer& rhs) {
+ if (this != &rhs) {
+ // Do not delete ownAllcator
+ if (nameBuffer_)
+ Allocator::Free(tokens_);
+
+ tokenCount_ = rhs.tokenCount_;
+ parseErrorOffset_ = rhs.parseErrorOffset_;
+ parseErrorCode_ = rhs.parseErrorCode_;
+
+ if (rhs.nameBuffer_)
+ CopyFromRaw(rhs); // Normally parsed tokens.
+ else {
+ tokens_ = rhs.tokens_; // User supplied const tokens.
+ nameBuffer_ = 0;
+ }
+ }
+ return *this;
+ }
+
+ //@}
+
+ //!@name Append token
+ //@{
+
+ //! Append a token and return a new Pointer
+ /*!
+ \param token Token to be appended.
+ \param allocator Allocator for the newly return Pointer.
+ \return A new Pointer with appended token.
+ */
+ GenericPointer Append(const Token& token, Allocator* allocator = 0) const {
+ GenericPointer r;
+ r.allocator_ = allocator;
+ Ch *p = r.CopyFromRaw(*this, 1, token.length + 1);
+ std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch));
+ r.tokens_[tokenCount_].name = p;
+ r.tokens_[tokenCount_].length = token.length;
+ r.tokens_[tokenCount_].index = token.index;
+ return r;
+ }
+
+ //! Append a name token with length, and return a new Pointer
+ /*!
+ \param name Name to be appended.
+ \param length Length of name.
+ \param allocator Allocator for the newly return Pointer.
+ \return A new Pointer with appended token.
+ */
+ GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const {
+ Token token = { name, length, kPointerInvalidIndex };
+ return Append(token, allocator);
+ }
+
+ //! Append a name token without length, and return a new Pointer
+ /*!
+ \param name Name (const Ch*) to be appended.
+ \param allocator Allocator for the newly return Pointer.
+ \return A new Pointer with appended token.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer))
+ Append(T* name, Allocator* allocator = 0) const {
+ return Append(name, StrLen(name), allocator);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Append a name token, and return a new Pointer
+ /*!
+ \param name Name to be appended.
+ \param allocator Allocator for the newly return Pointer.
+ \return A new Pointer with appended token.
+ */
+ GenericPointer Append(const std::basic_string<Ch>& name, Allocator* allocator = 0) const {
+ return Append(name.c_str(), static_cast<SizeType>(name.size()), allocator);
+ }
+#endif
+
+ //! Append a index token, and return a new Pointer
+ /*!
+ \param index Index to be appended.
+ \param allocator Allocator for the newly return Pointer.
+ \return A new Pointer with appended token.
+ */
+ GenericPointer Append(SizeType index, Allocator* allocator = 0) const {
+ char buffer[21];
+ char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer);
+ SizeType length = static_cast<SizeType>(end - buffer);
+ buffer[length] = '\0';
+
+ if (sizeof(Ch) == 1) {
+ Token token = { reinterpret_cast<Ch*>(buffer), length, index };
+ return Append(token, allocator);
+ }
+ else {
+ Ch name[21];
+ for (size_t i = 0; i <= length; i++)
+ name[i] = buffer[i];
+ Token token = { name, length, index };
+ return Append(token, allocator);
+ }
+ }
+
+ //! Append a token by value, and return a new Pointer
+ /*!
+ \param token token to be appended.
+ \param allocator Allocator for the newly return Pointer.
+ \return A new Pointer with appended token.
+ */
+ GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const {
+ if (token.IsString())
+ return Append(token.GetString(), token.GetStringLength(), allocator);
+ else {
+ RAPIDJSON_ASSERT(token.IsUint64());
+ RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0));
+ return Append(static_cast<SizeType>(token.GetUint64()), allocator);
+ }
+ }
+
+ //!@name Handling Parse Error
+ //@{
+
+ //! Check whether this is a valid pointer.
+ bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; }
+
+ //! Get the parsing error offset in code unit.
+ size_t GetParseErrorOffset() const { return parseErrorOffset_; }
+
+ //! Get the parsing error code.
+ PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; }
+
+ //@}
+
+ //! Get the allocator of this pointer.
+ Allocator& GetAllocator() { return *allocator_; }
+
+ //!@name Tokens
+ //@{
+
+ //! Get the token array (const version only).
+ const Token* GetTokens() const { return tokens_; }
+
+ //! Get the number of tokens.
+ size_t GetTokenCount() const { return tokenCount_; }
+
+ //@}
+
+ //!@name Equality/inequality operators
+ //@{
+
+ //! Equality operator.
+ /*!
+ \note When any pointers are invalid, always returns false.
+ */
+ bool operator==(const GenericPointer& rhs) const {
+ if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_)
+ return false;
+
+ for (size_t i = 0; i < tokenCount_; i++) {
+ if (tokens_[i].index != rhs.tokens_[i].index ||
+ tokens_[i].length != rhs.tokens_[i].length ||
+ (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ //! Inequality operator.
+ /*!
+ \note When any pointers are invalid, always returns true.
+ */
+ bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); }
+
+ //@}
+
+ //!@name Stringify
+ //@{
+
+ //! Stringify the pointer into string representation.
+ /*!
+ \tparam OutputStream Type of output stream.
+ \param os The output stream.
+ */
+ template<typename OutputStream>
+ bool Stringify(OutputStream& os) const {
+ return Stringify<false, OutputStream>(os);
+ }
+
+ //! Stringify the pointer into URI fragment representation.
+ /*!
+ \tparam OutputStream Type of output stream.
+ \param os The output stream.
+ */
+ template<typename OutputStream>
+ bool StringifyUriFragment(OutputStream& os) const {
+ return Stringify<true, OutputStream>(os);
+ }
+
+ //@}
+
+ //!@name Create value
+ //@{
+
+ //! Create a value in a subtree.
+ /*!
+ If the value is not exist, it creates all parent values and a JSON Null value.
+ So it always succeed and return the newly created or existing value.
+
+ Remind that it may change types of parents according to tokens, so it
+ potentially removes previously stored values. For example, if a document
+ was an array, and "/foo" is used to create a value, then the document
+ will be changed to an object, and all existing array elements are lost.
+
+ \param root Root value of a DOM subtree to be resolved. It can be any value other than document root.
+ \param allocator Allocator for creating the values if the specified value or its parents are not exist.
+ \param alreadyExist If non-null, it stores whether the resolved value is already exist.
+ \return The resolved newly created (a JSON Null value), or already exists value.
+ */
+ ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const {
+ RAPIDJSON_ASSERT(IsValid());
+ ValueType* v = &root;
+ bool exist = true;
+ for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
+ if (v->IsArray() && t->name[0] == '-' && t->length == 1) {
+ v->PushBack(ValueType().Move(), allocator);
+ v = &((*v)[v->Size() - 1]);
+ exist = false;
+ }
+ else {
+ if (t->index == kPointerInvalidIndex) { // must be object name
+ if (!v->IsObject())
+ v->SetObject(); // Change to Object
+ }
+ else { // object name or array index
+ if (!v->IsArray() && !v->IsObject())
+ v->SetArray(); // Change to Array
+ }
+
+ if (v->IsArray()) {
+ if (t->index >= v->Size()) {
+ v->Reserve(t->index + 1, allocator);
+ while (t->index >= v->Size())
+ v->PushBack(ValueType().Move(), allocator);
+ exist = false;
+ }
+ v = &((*v)[t->index]);
+ }
+ else {
+ typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
+ if (m == v->MemberEnd()) {
+ v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator);
+ v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end
+ exist = false;
+ }
+ else
+ v = &m->value;
+ }
+ }
+ }
+
+ if (alreadyExist)
+ *alreadyExist = exist;
+
+ return *v;
+ }
+
+ //! Creates a value in a document.
+ /*!
+ \param document A document to be resolved.
+ \param alreadyExist If non-null, it stores whether the resolved value is already exist.
+ \return The resolved newly created, or already exists value.
+ */
+ template <typename stackAllocator>
+ ValueType& Create(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, bool* alreadyExist = 0) const {
+ return Create(document, document.GetAllocator(), alreadyExist);
+ }
+
+ //@}
+
+ //!@name Query value
+ //@{
+
+ //! Query a value in a subtree.
+ /*!
+ \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
+ \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token.
+ \return Pointer to the value if it can be resolved. Otherwise null.
+
+ \note
+ There are only 3 situations when a value cannot be resolved:
+ 1. A value in the path is not an array nor object.
+ 2. An object value does not contain the token.
+ 3. A token is out of range of an array value.
+
+ Use unresolvedTokenIndex to retrieve the token index.
+ */
+ ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const {
+ RAPIDJSON_ASSERT(IsValid());
+ ValueType* v = &root;
+ for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
+ switch (v->GetType()) {
+ case kObjectType:
+ {
+ typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
+ if (m == v->MemberEnd())
+ break;
+ v = &m->value;
+ }
+ continue;
+ case kArrayType:
+ if (t->index == kPointerInvalidIndex || t->index >= v->Size())
+ break;
+ v = &((*v)[t->index]);
+ continue;
+ default:
+ break;
+ }
+
+ // Error: unresolved token
+ if (unresolvedTokenIndex)
+ *unresolvedTokenIndex = static_cast<size_t>(t - tokens_);
+ return 0;
+ }
+ return v;
+ }
+
+ //! Query a const value in a const subtree.
+ /*!
+ \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
+ \return Pointer to the value if it can be resolved. Otherwise null.
+ */
+ const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const {
+ return Get(const_cast<ValueType&>(root), unresolvedTokenIndex);
+ }
+
+ //@}
+
+ //!@name Query a value with default
+ //@{
+
+ //! Query a value in a subtree with default value.
+ /*!
+ Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value.
+ So that this function always succeed.
+
+ \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
+ \param defaultValue Default value to be cloned if the value was not exists.
+ \param allocator Allocator for creating the values if the specified value or its parents are not exist.
+ \see Create()
+ */
+ ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const {
+ bool alreadyExist;
+ Value& v = Create(root, allocator, &alreadyExist);
+ return alreadyExist ? v : v.CopyFrom(defaultValue, allocator);
+ }
+
+ //! Query a value in a subtree with default null-terminated string.
+ ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const {
+ bool alreadyExist;
+ Value& v = Create(root, allocator, &alreadyExist);
+ return alreadyExist ? v : v.SetString(defaultValue, allocator);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Query a value in a subtree with default std::basic_string.
+ ValueType& GetWithDefault(ValueType& root, const std::basic_string<Ch>& defaultValue, typename ValueType::AllocatorType& allocator) const {
+ bool alreadyExist;
+ Value& v = Create(root, allocator, &alreadyExist);
+ return alreadyExist ? v : v.SetString(defaultValue, allocator);
+ }
+#endif
+
+ //! Query a value in a subtree with default primitive value.
+ /*!
+ \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
+ GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const {
+ return GetWithDefault(root, ValueType(defaultValue).Move(), allocator);
+ }
+
+ //! Query a value in a document with default value.
+ template <typename stackAllocator>
+ ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& defaultValue) const {
+ return GetWithDefault(document, defaultValue, document.GetAllocator());
+ }
+
+ //! Query a value in a document with default null-terminated string.
+ template <typename stackAllocator>
+ ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* defaultValue) const {
+ return GetWithDefault(document, defaultValue, document.GetAllocator());
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Query a value in a document with default std::basic_string.
+ template <typename stackAllocator>
+ ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& defaultValue) const {
+ return GetWithDefault(document, defaultValue, document.GetAllocator());
+ }
+#endif
+
+ //! Query a value in a document with default primitive value.
+ /*!
+ \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
+ */
+ template <typename T, typename stackAllocator>
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
+ GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T defaultValue) const {
+ return GetWithDefault(document, defaultValue, document.GetAllocator());
+ }
+
+ //@}
+
+ //!@name Set a value
+ //@{
+
+ //! Set a value in a subtree, with move semantics.
+ /*!
+ It creates all parents if they are not exist or types are different to the tokens.
+ So this function always succeeds but potentially remove existing values.
+
+ \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
+ \param value Value to be set.
+ \param allocator Allocator for creating the values if the specified value or its parents are not exist.
+ \see Create()
+ */
+ ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {
+ return Create(root, allocator) = value;
+ }
+
+ //! Set a value in a subtree, with copy semantics.
+ ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const {
+ return Create(root, allocator).CopyFrom(value, allocator);
+ }
+
+ //! Set a null-terminated string in a subtree.
+ ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const {
+ return Create(root, allocator) = ValueType(value, allocator).Move();
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Set a std::basic_string in a subtree.
+ ValueType& Set(ValueType& root, const std::basic_string<Ch>& value, typename ValueType::AllocatorType& allocator) const {
+ return Create(root, allocator) = ValueType(value, allocator).Move();
+ }
+#endif
+
+ //! Set a primitive value in a subtree.
+ /*!
+ \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
+ Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const {
+ return Create(root, allocator) = ValueType(value).Move();
+ }
+
+ //! Set a value in a document, with move semantics.
+ template <typename stackAllocator>
+ ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const {
+ return Create(document) = value;
+ }
+
+ //! Set a value in a document, with copy semantics.
+ template <typename stackAllocator>
+ ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& value) const {
+ return Create(document).CopyFrom(value, document.GetAllocator());
+ }
+
+ //! Set a null-terminated string in a document.
+ template <typename stackAllocator>
+ ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* value) const {
+ return Create(document) = ValueType(value, document.GetAllocator()).Move();
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Sets a std::basic_string in a document.
+ template <typename stackAllocator>
+ ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& value) const {
+ return Create(document) = ValueType(value, document.GetAllocator()).Move();
+ }
+#endif
+
+ //! Set a primitive value in a document.
+ /*!
+ \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
+ */
+ template <typename T, typename stackAllocator>
+ RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
+ Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T value) const {
+ return Create(document) = value;
+ }
+
+ //@}
+
+ //!@name Swap a value
+ //@{
+
+ //! Swap a value with a value in a subtree.
+ /*!
+ It creates all parents if they are not exist or types are different to the tokens.
+ So this function always succeeds but potentially remove existing values.
+
+ \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
+ \param value Value to be swapped.
+ \param allocator Allocator for creating the values if the specified value or its parents are not exist.
+ \see Create()
+ */
+ ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {
+ return Create(root, allocator).Swap(value);
+ }
+
+ //! Swap a value with a value in a document.
+ template <typename stackAllocator>
+ ValueType& Swap(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const {
+ return Create(document).Swap(value);
+ }
+
+ //@}
+
+ //! Erase a value in a subtree.
+ /*!
+ \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
+ \return Whether the resolved value is found and erased.
+
+ \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false.
+ */
+ bool Erase(ValueType& root) const {
+ RAPIDJSON_ASSERT(IsValid());
+ if (tokenCount_ == 0) // Cannot erase the root
+ return false;
+
+ ValueType* v = &root;
+ const Token* last = tokens_ + (tokenCount_ - 1);
+ for (const Token *t = tokens_; t != last; ++t) {
+ switch (v->GetType()) {
+ case kObjectType:
+ {
+ typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
+ if (m == v->MemberEnd())
+ return false;
+ v = &m->value;
+ }
+ break;
+ case kArrayType:
+ if (t->index == kPointerInvalidIndex || t->index >= v->Size())
+ return false;
+ v = &((*v)[t->index]);
+ break;
+ default:
+ return false;
+ }
+ }
+
+ switch (v->GetType()) {
+ case kObjectType:
+ return v->EraseMember(GenericStringRef<Ch>(last->name, last->length));
+ case kArrayType:
+ if (last->index == kPointerInvalidIndex || last->index >= v->Size())
+ return false;
+ v->Erase(v->Begin() + last->index);
+ return true;
+ default:
+ return false;
+ }
+ }
+
+private:
+ //! Clone the content from rhs to this.
+ /*!
+ \param rhs Source pointer.
+ \param extraToken Extra tokens to be allocated.
+ \param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated.
+ \return Start of non-occupied name buffer, for storing extra names.
+ */
+ Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) {
+ if (!allocator_) // allocator is independently owned.
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+
+ size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens
+ for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t)
+ nameBufferSize += t->length;
+
+ tokenCount_ = rhs.tokenCount_ + extraToken;
+ tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch)));
+ nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);
+ std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token));
+ std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));
+
+ // Adjust pointers to name buffer
+ std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;
+ for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t)
+ t->name += diff;
+
+ return nameBuffer_ + nameBufferSize;
+ }
+
+ //! Check whether a character should be percent-encoded.
+ /*!
+ According to RFC 3986 2.3 Unreserved Characters.
+ \param c The character (code unit) to be tested.
+ */
+ bool NeedPercentEncode(Ch c) const {
+ return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~');
+ }
+
+ //! Parse a JSON String or its URI fragment representation into tokens.
+#ifndef __clang__ // -Wdocumentation
+ /*!
+ \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated.
+ \param length Length of the source string.
+ \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped.
+ */
+#endif
+ void Parse(const Ch* source, size_t length) {
+ RAPIDJSON_ASSERT(source != NULL);
+ RAPIDJSON_ASSERT(nameBuffer_ == 0);
+ RAPIDJSON_ASSERT(tokens_ == 0);
+
+ // Create own allocator if user did not supply.
+ if (!allocator_)
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+
+ // Count number of '/' as tokenCount
+ tokenCount_ = 0;
+ for (const Ch* s = source; s != source + length; s++)
+ if (*s == '/')
+ tokenCount_++;
+
+ Token* token = tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch)));
+ Ch* name = nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);
+ size_t i = 0;
+
+ // Detect if it is a URI fragment
+ bool uriFragment = false;
+ if (source[i] == '#') {
+ uriFragment = true;
+ i++;
+ }
+
+ if (i != length && source[i] != '/') {
+ parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus;
+ goto error;
+ }
+
+ while (i < length) {
+ RAPIDJSON_ASSERT(source[i] == '/');
+ i++; // consumes '/'
+
+ token->name = name;
+ bool isNumber = true;
+
+ while (i < length && source[i] != '/') {
+ Ch c = source[i];
+ if (uriFragment) {
+ // Decoding percent-encoding for URI fragment
+ if (c == '%') {
+ PercentDecodeStream is(&source[i], source + length);
+ GenericInsituStringStream<EncodingType> os(name);
+ Ch* begin = os.PutBegin();
+ if (!Transcoder<UTF8<>, EncodingType>().Validate(is, os) || !is.IsValid()) {
+ parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding;
+ goto error;
+ }
+ size_t len = os.PutEnd(begin);
+ i += is.Tell() - 1;
+ if (len == 1)
+ c = *name;
+ else {
+ name += len;
+ isNumber = false;
+ i++;
+ continue;
+ }
+ }
+ else if (NeedPercentEncode(c)) {
+ parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode;
+ goto error;
+ }
+ }
+
+ i++;
+
+ // Escaping "~0" -> '~', "~1" -> '/'
+ if (c == '~') {
+ if (i < length) {
+ c = source[i];
+ if (c == '0') c = '~';
+ else if (c == '1') c = '/';
+ else {
+ parseErrorCode_ = kPointerParseErrorInvalidEscape;
+ goto error;
+ }
+ i++;
+ }
+ else {
+ parseErrorCode_ = kPointerParseErrorInvalidEscape;
+ goto error;
+ }
+ }
+
+ // First check for index: all of characters are digit
+ if (c < '0' || c > '9')
+ isNumber = false;
+
+ *name++ = c;
+ }
+ token->length = static_cast<SizeType>(name - token->name);
+ if (token->length == 0)
+ isNumber = false;
+ *name++ = '\0'; // Null terminator
+
+ // Second check for index: more than one digit cannot have leading zero
+ if (isNumber && token->length > 1 && token->name[0] == '0')
+ isNumber = false;
+
+ // String to SizeType conversion
+ SizeType n = 0;
+ if (isNumber) {
+ for (size_t j = 0; j < token->length; j++) {
+ SizeType m = n * 10 + static_cast<SizeType>(token->name[j] - '0');
+ if (m < n) { // overflow detection
+ isNumber = false;
+ break;
+ }
+ n = m;
+ }
+ }
+
+ token->index = isNumber ? n : kPointerInvalidIndex;
+ token++;
+ }
+
+ RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer
+ parseErrorCode_ = kPointerParseErrorNone;
+ return;
+
+ error:
+ Allocator::Free(tokens_);
+ nameBuffer_ = 0;
+ tokens_ = 0;
+ tokenCount_ = 0;
+ parseErrorOffset_ = i;
+ return;
+ }
+
+ //! Stringify to string or URI fragment representation.
+ /*!
+ \tparam uriFragment True for stringifying to URI fragment representation. False for string representation.
+ \tparam OutputStream type of output stream.
+ \param os The output stream.
+ */
+ template<bool uriFragment, typename OutputStream>
+ bool Stringify(OutputStream& os) const {
+ RAPIDJSON_ASSERT(IsValid());
+
+ if (uriFragment)
+ os.Put('#');
+
+ for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
+ os.Put('/');
+ for (size_t j = 0; j < t->length; j++) {
+ Ch c = t->name[j];
+ if (c == '~') {
+ os.Put('~');
+ os.Put('0');
+ }
+ else if (c == '/') {
+ os.Put('~');
+ os.Put('1');
+ }
+ else if (uriFragment && NeedPercentEncode(c)) {
+ // Transcode to UTF8 sequence
+ GenericStringStream<typename ValueType::EncodingType> source(&t->name[j]);
+ PercentEncodeStream<OutputStream> target(os);
+ if (!Transcoder<EncodingType, UTF8<> >().Validate(source, target))
+ return false;
+ j += source.Tell() - 1;
+ }
+ else
+ os.Put(c);
+ }
+ }
+ return true;
+ }
+
+ //! A helper stream for decoding a percent-encoded sequence into code unit.
+ /*!
+ This stream decodes %XY triplet into code unit (0-255).
+ If it encounters invalid characters, it sets output code unit as 0 and
+ mark invalid, and to be checked by IsValid().
+ */
+ class PercentDecodeStream {
+ public:
+ typedef typename ValueType::Ch Ch;
+
+ //! Constructor
+ /*!
+ \param source Start of the stream
+ \param end Past-the-end of the stream.
+ */
+ PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {}
+
+ Ch Take() {
+ if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet
+ valid_ = false;
+ return 0;
+ }
+ src_++;
+ Ch c = 0;
+ for (int j = 0; j < 2; j++) {
+ c <<= 4;
+ Ch h = *src_;
+ if (h >= '0' && h <= '9') c += h - '0';
+ else if (h >= 'A' && h <= 'F') c += h - 'A' + 10;
+ else if (h >= 'a' && h <= 'f') c += h - 'a' + 10;
+ else {
+ valid_ = false;
+ return 0;
+ }
+ src_++;
+ }
+ return c;
+ }
+
+ size_t Tell() const { return static_cast<size_t>(src_ - head_); }
+ bool IsValid() const { return valid_; }
+
+ private:
+ const Ch* src_; //!< Current read position.
+ const Ch* head_; //!< Original head of the string.
+ const Ch* end_; //!< Past-the-end position.
+ bool valid_; //!< Whether the parsing is valid.
+ };
+
+ //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence.
+ template <typename OutputStream>
+ class PercentEncodeStream {
+ public:
+ PercentEncodeStream(OutputStream& os) : os_(os) {}
+ void Put(char c) { // UTF-8 must be byte
+ unsigned char u = static_cast<unsigned char>(c);
+ static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+ os_.Put('%');
+ os_.Put(hexDigits[u >> 4]);
+ os_.Put(hexDigits[u & 15]);
+ }
+ private:
+ OutputStream& os_;
+ };
+
+ Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_.
+ Allocator* ownAllocator_; //!< Allocator owned by this Pointer.
+ Ch* nameBuffer_; //!< A buffer containing all names in tokens.
+ Token* tokens_; //!< A list of tokens.
+ size_t tokenCount_; //!< Number of tokens in tokens_.
+ size_t parseErrorOffset_; //!< Offset in code unit when parsing fail.
+ PointerParseErrorCode parseErrorCode_; //!< Parsing error code.
+};
+
+//! GenericPointer for Value (UTF-8, default allocator).
+typedef GenericPointer<Value> Pointer;
+
+//!@name Helper functions for GenericPointer
+//@{
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::AllocatorType& a) {
+ return pointer.Create(root, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Create(root, a);
+}
+
+// No allocator parameter
+
+template <typename DocumentType>
+typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer) {
+ return pointer.Create(document);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Create(document);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+typename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
+ return pointer.Get(root, unresolvedTokenIndex);
+}
+
+template <typename T>
+const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
+ return pointer.Get(root, unresolvedTokenIndex);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
+}
+
+template <typename T, typename CharType, size_t N>
+const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {
+ return pointer.GetWithDefault(root, defaultValue, a);
+}
+
+template <typename T>
+typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) {
+ return pointer.GetWithDefault(root, defaultValue, a);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename T>
+typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {
+ return pointer.GetWithDefault(root, defaultValue, a);
+}
+#endif
+
+template <typename T, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
+GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 defaultValue, typename T::AllocatorType& a) {
+ return pointer.GetWithDefault(root, defaultValue, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
+}
+#endif
+
+template <typename T, typename CharType, size_t N, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
+GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
+}
+
+// No allocator parameter
+
+template <typename DocumentType>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& defaultValue) {
+ return pointer.GetWithDefault(document, defaultValue);
+}
+
+template <typename DocumentType>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* defaultValue) {
+ return pointer.GetWithDefault(document, defaultValue);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename DocumentType>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& defaultValue) {
+ return pointer.GetWithDefault(document, defaultValue);
+}
+#endif
+
+template <typename DocumentType, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
+GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 defaultValue) {
+ return pointer.GetWithDefault(document, defaultValue);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& defaultValue) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
+}
+#endif
+
+template <typename DocumentType, typename CharType, size_t N, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
+GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) {
+ return pointer.Set(root, value, a);
+}
+
+template <typename T>
+typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) {
+ return pointer.Set(root, value, a);
+}
+
+template <typename T>
+typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* value, typename T::AllocatorType& a) {
+ return pointer.Set(root, value, a);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename T>
+typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {
+ return pointer.Set(root, value, a);
+}
+#endif
+
+template <typename T, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
+SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 value, typename T::AllocatorType& a) {
+ return pointer.Set(root, value, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
+}
+#endif
+
+template <typename T, typename CharType, size_t N, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
+SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
+}
+
+// No allocator parameter
+
+template <typename DocumentType>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {
+ return pointer.Set(document, value);
+}
+
+template <typename DocumentType>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& value) {
+ return pointer.Set(document, value);
+}
+
+template <typename DocumentType>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* value) {
+ return pointer.Set(document, value);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename DocumentType>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& value) {
+ return pointer.Set(document, value);
+}
+#endif
+
+template <typename DocumentType, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
+SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 value) {
+ return pointer.Set(document, value);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& value) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
+}
+#endif
+
+template <typename DocumentType, typename CharType, size_t N, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
+SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+typename T::ValueType& SwapValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) {
+ return pointer.Swap(root, value, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Swap(root, value, a);
+}
+
+template <typename DocumentType>
+typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {
+ return pointer.Swap(document, value);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Swap(document, value);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+bool EraseValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) {
+ return pointer.Erase(root);
+}
+
+template <typename T, typename CharType, size_t N>
+bool EraseValueByPointer(T& root, const CharType(&source)[N]) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Erase(root);
+}
+
+//@}
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_POINTER_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/prettywriter.h b/3rdparty/rapidjson/include/rapidjson/prettywriter.h
new file mode 100644
index 00000000000..c74e1f10b01
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/prettywriter.h
@@ -0,0 +1,223 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_PRETTYWRITER_H_
+#define RAPIDJSON_PRETTYWRITER_H_
+
+#include "writer.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Writer with indentation and spacing.
+/*!
+ \tparam OutputStream Type of ouptut os.
+ \tparam SourceEncoding Encoding of source string.
+ \tparam TargetEncoding Encoding of output stream.
+ \tparam StackAllocator Type of allocator for allocating memory of stack.
+*/
+template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
+class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {
+public:
+ typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base;
+ typedef typename Base::Ch Ch;
+
+ //! Constructor
+ /*! \param os Output stream.
+ \param allocator User supplied allocator. If it is null, it will create a private one.
+ \param levelDepth Initial capacity of stack.
+ */
+ explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
+ Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
+
+
+ explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
+ Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
+
+ //! Set custom indentation.
+ /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
+ \param indentCharCount Number of indent characters for each indentation level.
+ \note The default indentation is 4 spaces.
+ */
+ PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
+ RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
+ indentChar_ = indentChar;
+ indentCharCount_ = indentCharCount;
+ return *this;
+ }
+
+ /*! @name Implementation of Handler
+ \see Handler
+ */
+ //@{
+
+ bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); }
+ bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); }
+ bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); }
+ bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); }
+ bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); }
+ bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
+ bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
+
+ bool String(const Ch* str, SizeType length, bool copy = false) {
+ (void)copy;
+ PrettyPrefix(kStringType);
+ return Base::WriteString(str, length);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ bool String(const std::basic_string<Ch>& str) {
+ return String(str.data(), SizeType(str.size()));
+ }
+#endif
+
+ bool StartObject() {
+ PrettyPrefix(kObjectType);
+ new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
+ return Base::WriteStartObject();
+ }
+
+ bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
+
+ bool EndObject(SizeType memberCount = 0) {
+ (void)memberCount;
+ RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
+ RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
+ bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
+
+ if (!empty) {
+ Base::os_->Put('\n');
+ WriteIndent();
+ }
+ bool ret = Base::WriteEndObject();
+ (void)ret;
+ RAPIDJSON_ASSERT(ret == true);
+ if (Base::level_stack_.Empty()) // end of json text
+ Base::os_->Flush();
+ return true;
+ }
+
+ bool StartArray() {
+ PrettyPrefix(kArrayType);
+ new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
+ return Base::WriteStartArray();
+ }
+
+ bool EndArray(SizeType memberCount = 0) {
+ (void)memberCount;
+ RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
+ RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
+ bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
+
+ if (!empty) {
+ Base::os_->Put('\n');
+ WriteIndent();
+ }
+ bool ret = Base::WriteEndArray();
+ (void)ret;
+ RAPIDJSON_ASSERT(ret == true);
+ if (Base::level_stack_.Empty()) // end of json text
+ Base::os_->Flush();
+ return true;
+ }
+
+ //@}
+
+ /*! @name Convenience extensions */
+ //@{
+
+ //! Simpler but slower overload.
+ bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
+ bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
+
+ //@}
+
+ //! Write a raw JSON value.
+ /*!
+ For user to write a stringified JSON as a value.
+
+ \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
+ \param length Length of the json.
+ \param type Type of the root of json.
+ \note When using PrettyWriter::RawValue(), the result json may not be indented correctly.
+ */
+ bool RawValue(const Ch* json, size_t length, Type type) { PrettyPrefix(type); return Base::WriteRawValue(json, length); }
+
+protected:
+ void PrettyPrefix(Type type) {
+ (void)type;
+ if (Base::level_stack_.GetSize() != 0) { // this value is not at root
+ typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
+
+ if (level->inArray) {
+ if (level->valueCount > 0) {
+ Base::os_->Put(','); // add comma if it is not the first element in array
+ Base::os_->Put('\n');
+ }
+ else
+ Base::os_->Put('\n');
+ WriteIndent();
+ }
+ else { // in object
+ if (level->valueCount > 0) {
+ if (level->valueCount % 2 == 0) {
+ Base::os_->Put(',');
+ Base::os_->Put('\n');
+ }
+ else {
+ Base::os_->Put(':');
+ Base::os_->Put(' ');
+ }
+ }
+ else
+ Base::os_->Put('\n');
+
+ if (level->valueCount % 2 == 0)
+ WriteIndent();
+ }
+ if (!level->inArray && level->valueCount % 2 == 0)
+ RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
+ level->valueCount++;
+ }
+ else {
+ RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root.
+ Base::hasRoot_ = true;
+ }
+ }
+
+ void WriteIndent() {
+ size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
+ PutN(*Base::os_, static_cast<typename TargetEncoding::Ch>(indentChar_), count);
+ }
+
+ Ch indentChar_;
+ unsigned indentCharCount_;
+
+private:
+ // Prohibit copy constructor & assignment operator.
+ PrettyWriter(const PrettyWriter&);
+ PrettyWriter& operator=(const PrettyWriter&);
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_RAPIDJSON_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/rapidjson.h b/3rdparty/rapidjson/include/rapidjson/rapidjson.h
new file mode 100644
index 00000000000..7a5db71bd0a
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/rapidjson.h
@@ -0,0 +1,569 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_RAPIDJSON_H_
+#define RAPIDJSON_RAPIDJSON_H_
+
+/*!\file rapidjson.h
+ \brief common definitions and configuration
+
+ \see RAPIDJSON_CONFIG
+ */
+
+/*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration
+ \brief Configuration macros for library features
+
+ Some RapidJSON features are configurable to adapt the library to a wide
+ variety of platforms, environments and usage scenarios. Most of the
+ features can be configured in terms of overriden or predefined
+ preprocessor macros at compile-time.
+
+ Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs.
+
+ \note These macros should be given on the compiler command-line
+ (where applicable) to avoid inconsistent values when compiling
+ different translation units of a single application.
+ */
+
+#include <cstdlib> // malloc(), realloc(), free(), size_t
+#include <cstring> // memset(), memcpy(), memmove(), memcmp()
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_VERSION_STRING
+//
+// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt.
+//
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+// token stringification
+#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)
+#define RAPIDJSON_DO_STRINGIFY(x) #x
+//!@endcond
+
+/*! \def RAPIDJSON_MAJOR_VERSION
+ \ingroup RAPIDJSON_CONFIG
+ \brief Major version of RapidJSON in integer.
+*/
+/*! \def RAPIDJSON_MINOR_VERSION
+ \ingroup RAPIDJSON_CONFIG
+ \brief Minor version of RapidJSON in integer.
+*/
+/*! \def RAPIDJSON_PATCH_VERSION
+ \ingroup RAPIDJSON_CONFIG
+ \brief Patch version of RapidJSON in integer.
+*/
+/*! \def RAPIDJSON_VERSION_STRING
+ \ingroup RAPIDJSON_CONFIG
+ \brief Version of RapidJSON in "<major>.<minor>.<patch>" string format.
+*/
+#define RAPIDJSON_MAJOR_VERSION 1
+#define RAPIDJSON_MINOR_VERSION 0
+#define RAPIDJSON_PATCH_VERSION 2
+#define RAPIDJSON_VERSION_STRING \
+ RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION)
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NAMESPACE_(BEGIN|END)
+/*! \def RAPIDJSON_NAMESPACE
+ \ingroup RAPIDJSON_CONFIG
+ \brief provide custom rapidjson namespace
+
+ In order to avoid symbol clashes and/or "One Definition Rule" errors
+ between multiple inclusions of (different versions of) RapidJSON in
+ a single binary, users can customize the name of the main RapidJSON
+ namespace.
+
+ In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE
+ to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple
+ levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref
+ RAPIDJSON_NAMESPACE_END need to be defined as well:
+
+ \code
+ // in some .cpp file
+ #define RAPIDJSON_NAMESPACE my::rapidjson
+ #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson {
+ #define RAPIDJSON_NAMESPACE_END } }
+ #include "rapidjson/..."
+ \endcode
+
+ \see rapidjson
+ */
+/*! \def RAPIDJSON_NAMESPACE_BEGIN
+ \ingroup RAPIDJSON_CONFIG
+ \brief provide custom rapidjson namespace (opening expression)
+ \see RAPIDJSON_NAMESPACE
+*/
+/*! \def RAPIDJSON_NAMESPACE_END
+ \ingroup RAPIDJSON_CONFIG
+ \brief provide custom rapidjson namespace (closing expression)
+ \see RAPIDJSON_NAMESPACE
+*/
+#ifndef RAPIDJSON_NAMESPACE
+#define RAPIDJSON_NAMESPACE rapidjson
+#endif
+#ifndef RAPIDJSON_NAMESPACE_BEGIN
+#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE {
+#endif
+#ifndef RAPIDJSON_NAMESPACE_END
+#define RAPIDJSON_NAMESPACE_END }
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_HAS_STDSTRING
+
+#ifndef RAPIDJSON_HAS_STDSTRING
+#ifdef RAPIDJSON_DOXYGEN_RUNNING
+#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation
+#else
+#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default
+#endif
+/*! \def RAPIDJSON_HAS_STDSTRING
+ \ingroup RAPIDJSON_CONFIG
+ \brief Enable RapidJSON support for \c std::string
+
+ By defining this preprocessor symbol to \c 1, several convenience functions for using
+ \ref rapidjson::GenericValue with \c std::string are enabled, especially
+ for construction and comparison.
+
+ \hideinitializer
+*/
+#endif // !defined(RAPIDJSON_HAS_STDSTRING)
+
+#if RAPIDJSON_HAS_STDSTRING
+#include <string>
+#endif // RAPIDJSON_HAS_STDSTRING
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NO_INT64DEFINE
+
+/*! \def RAPIDJSON_NO_INT64DEFINE
+ \ingroup RAPIDJSON_CONFIG
+ \brief Use external 64-bit integer types.
+
+ RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types
+ to be available at global scope.
+
+ If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to
+ prevent RapidJSON from defining its own types.
+*/
+#ifndef RAPIDJSON_NO_INT64DEFINE
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#ifdef _MSC_VER
+#include "msinttypes/stdint.h"
+#include "msinttypes/inttypes.h"
+#else
+// Other compilers should have this.
+#include <stdint.h>
+#include <inttypes.h>
+#endif
+//!@endcond
+#ifdef RAPIDJSON_DOXYGEN_RUNNING
+#define RAPIDJSON_NO_INT64DEFINE
+#endif
+#endif // RAPIDJSON_NO_INT64TYPEDEF
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_FORCEINLINE
+
+#ifndef RAPIDJSON_FORCEINLINE
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#if defined(_MSC_VER) && defined(NDEBUG)
+#define RAPIDJSON_FORCEINLINE __forceinline
+#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG)
+#define RAPIDJSON_FORCEINLINE __attribute__((always_inline))
+#else
+#define RAPIDJSON_FORCEINLINE
+#endif
+//!@endcond
+#endif // RAPIDJSON_FORCEINLINE
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ENDIAN
+#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine
+#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine
+
+//! Endianness of the machine.
+/*!
+ \def RAPIDJSON_ENDIAN
+ \ingroup RAPIDJSON_CONFIG
+
+ GCC 4.6 provided macro for detecting endianness of the target machine. But other
+ compilers may not have this. User can define RAPIDJSON_ENDIAN to either
+ \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN.
+
+ Default detection implemented with reference to
+ \li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html
+ \li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp
+*/
+#ifndef RAPIDJSON_ENDIAN
+// Detect with GCC 4.6's macro
+# ifdef __BYTE_ORDER__
+# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+# else
+# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
+# endif // __BYTE_ORDER__
+// Detect with GLIBC's endian.h
+# elif defined(__GLIBC__)
+# include <endian.h>
+# if (__BYTE_ORDER == __LITTLE_ENDIAN)
+# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+# elif (__BYTE_ORDER == __BIG_ENDIAN)
+# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+# else
+# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
+# endif // __GLIBC__
+// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro
+# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
+# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
+# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+// Detect with architecture macros
+# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__)
+# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
+# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+# elif defined(_MSC_VER) && defined(_M_ARM)
+# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+# elif defined(RAPIDJSON_DOXYGEN_RUNNING)
+# define RAPIDJSON_ENDIAN
+# else
+# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
+# endif
+#endif // RAPIDJSON_ENDIAN
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_64BIT
+
+//! Whether using 64-bit architecture
+#ifndef RAPIDJSON_64BIT
+#if defined(__LP64__) || defined(_WIN64) || defined(__EMSCRIPTEN__)
+#define RAPIDJSON_64BIT 1
+#else
+#define RAPIDJSON_64BIT 0
+#endif
+#endif // RAPIDJSON_64BIT
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ALIGN
+
+//! Data alignment of the machine.
+/*! \ingroup RAPIDJSON_CONFIG
+ \param x pointer to align
+
+ Some machines require strict data alignment. Currently the default uses 4 bytes
+ alignment. User can customize by defining the RAPIDJSON_ALIGN function macro.
+*/
+#ifndef RAPIDJSON_ALIGN
+#if RAPIDJSON_64BIT == 1
+#define RAPIDJSON_ALIGN(x) (((x) + static_cast<uint64_t>(7u)) & ~static_cast<uint64_t>(7u))
+#else
+#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u)
+#endif
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_UINT64_C2
+
+//! Construct a 64-bit literal by a pair of 32-bit integer.
+/*!
+ 64-bit literal with or without ULL suffix is prone to compiler warnings.
+ UINT64_C() is C macro which cause compilation problems.
+ Use this macro to define 64-bit constants by a pair of 32-bit integer.
+*/
+#ifndef RAPIDJSON_UINT64_C2
+#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
+
+/*! \def RAPIDJSON_SIMD
+ \ingroup RAPIDJSON_CONFIG
+ \brief Enable SSE2/SSE4.2 optimization.
+
+ RapidJSON supports optimized implementations for some parsing operations
+ based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible
+ processors.
+
+ To enable these optimizations, two different symbols can be defined;
+ \code
+ // Enable SSE2 optimization.
+ #define RAPIDJSON_SSE2
+
+ // Enable SSE4.2 optimization.
+ #define RAPIDJSON_SSE42
+ \endcode
+
+ \c RAPIDJSON_SSE42 takes precedence, if both are defined.
+
+ If any of these symbols is defined, RapidJSON defines the macro
+ \c RAPIDJSON_SIMD to indicate the availability of the optimized code.
+*/
+#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \
+ || defined(RAPIDJSON_DOXYGEN_RUNNING)
+#define RAPIDJSON_SIMD
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NO_SIZETYPEDEFINE
+
+#ifndef RAPIDJSON_NO_SIZETYPEDEFINE
+/*! \def RAPIDJSON_NO_SIZETYPEDEFINE
+ \ingroup RAPIDJSON_CONFIG
+ \brief User-provided \c SizeType definition.
+
+ In order to avoid using 32-bit size types for indexing strings and arrays,
+ define this preprocessor symbol and provide the type rapidjson::SizeType
+ before including RapidJSON:
+ \code
+ #define RAPIDJSON_NO_SIZETYPEDEFINE
+ namespace rapidjson { typedef ::std::size_t SizeType; }
+ #include "rapidjson/..."
+ \endcode
+
+ \see rapidjson::SizeType
+*/
+#ifdef RAPIDJSON_DOXYGEN_RUNNING
+#define RAPIDJSON_NO_SIZETYPEDEFINE
+#endif
+RAPIDJSON_NAMESPACE_BEGIN
+//! Size type (for string lengths, array sizes, etc.)
+/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms,
+ instead of using \c size_t. Users may override the SizeType by defining
+ \ref RAPIDJSON_NO_SIZETYPEDEFINE.
+*/
+typedef unsigned SizeType;
+RAPIDJSON_NAMESPACE_END
+#endif
+
+// always import std::size_t to rapidjson namespace
+RAPIDJSON_NAMESPACE_BEGIN
+using std::size_t;
+RAPIDJSON_NAMESPACE_END
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ASSERT
+
+//! Assertion.
+/*! \ingroup RAPIDJSON_CONFIG
+ By default, rapidjson uses C \c assert() for internal assertions.
+ User can override it by defining RAPIDJSON_ASSERT(x) macro.
+
+ \note Parsing errors are handled and can be customized by the
+ \ref RAPIDJSON_ERRORS APIs.
+*/
+#ifndef RAPIDJSON_ASSERT
+#include <cassert>
+#define RAPIDJSON_ASSERT(x) assert(x)
+#endif // RAPIDJSON_ASSERT
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_STATIC_ASSERT
+
+// Adopt from boost
+#ifndef RAPIDJSON_STATIC_ASSERT
+#ifndef __clang__
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#endif
+RAPIDJSON_NAMESPACE_BEGIN
+template <bool x> struct STATIC_ASSERTION_FAILURE;
+template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
+template<int x> struct StaticAssertTest {};
+RAPIDJSON_NAMESPACE_END
+
+#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)
+#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)
+#define RAPIDJSON_DO_JOIN2(X, Y) X##Y
+
+#if defined(__GNUC__)
+#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
+#else
+#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
+#endif
+#ifndef __clang__
+//!@endcond
+#endif
+
+/*! \def RAPIDJSON_STATIC_ASSERT
+ \brief (Internal) macro to check for conditions at compile-time
+ \param x compile-time condition
+ \hideinitializer
+ */
+#define RAPIDJSON_STATIC_ASSERT(x) \
+ typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \
+ sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \
+ RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY
+
+//! Compiler branching hint for expression with high probability to be true.
+/*!
+ \ingroup RAPIDJSON_CONFIG
+ \param x Boolean expression likely to be true.
+*/
+#ifndef RAPIDJSON_LIKELY
+#if defined(__GNUC__) || defined(__clang__)
+#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
+#else
+#define RAPIDJSON_LIKELY(x) x
+#endif
+#endif
+
+//! Compiler branching hint for expression with low probability to be true.
+/*!
+ \ingroup RAPIDJSON_CONFIG
+ \param x Boolean expression unlikely to be true.
+*/
+#ifndef RAPIDJSON_UNLIKELY
+#if defined(__GNUC__) || defined(__clang__)
+#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+#define RAPIDJSON_UNLIKELY(x) x
+#endif
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Helpers
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+
+#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
+#define RAPIDJSON_MULTILINEMACRO_END \
+} while((void)0, 0)
+
+// adopted from Boost
+#define RAPIDJSON_VERSION_CODE(x,y,z) \
+ (((x)*100000) + ((y)*100) + (z))
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
+
+#if defined(__GNUC__)
+#define RAPIDJSON_GNUC \
+ RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__)
+#endif
+
+#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0))
+
+#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x))
+#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x)
+#define RAPIDJSON_DIAG_OFF(x) \
+ RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x)))
+
+// push/pop support in Clang and GCC>=4.6
+#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0))
+#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
+#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
+#else // GCC >= 4.2, < 4.6
+#define RAPIDJSON_DIAG_PUSH /* ignored */
+#define RAPIDJSON_DIAG_POP /* ignored */
+#endif
+
+#elif defined(_MSC_VER)
+
+// pragma (MSVC specific)
+#define RAPIDJSON_PRAGMA(x) __pragma(x)
+#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x))
+
+#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x)
+#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
+#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
+
+#else
+
+#define RAPIDJSON_DIAG_OFF(x) /* ignored */
+#define RAPIDJSON_DIAG_PUSH /* ignored */
+#define RAPIDJSON_DIAG_POP /* ignored */
+
+#endif // RAPIDJSON_DIAG_*
+
+///////////////////////////////////////////////////////////////////////////////
+// C++11 features
+
+#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#if defined(__clang__)
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS __has_feature(cxx_rvalue_references) && \
+ (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
+#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
+ (defined(_MSC_VER) && _MSC_VER >= 1600)
+
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
+#else
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
+#endif
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT
+#if defined(__clang__)
+#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
+#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__))
+// (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported
+#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
+#else
+#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
+#endif
+#endif
+#if RAPIDJSON_HAS_CXX11_NOEXCEPT
+#define RAPIDJSON_NOEXCEPT noexcept
+#else
+#define RAPIDJSON_NOEXCEPT /* noexcept */
+#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
+
+// no automatic detection, yet
+#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS
+#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0
+#endif
+
+//!@endcond
+
+///////////////////////////////////////////////////////////////////////////////
+// new/delete
+
+#ifndef RAPIDJSON_NEW
+///! customization point for global \c new
+#define RAPIDJSON_NEW(x) new x
+#endif
+#ifndef RAPIDJSON_DELETE
+///! customization point for global \c delete
+#define RAPIDJSON_DELETE(x) delete x
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Type
+
+/*! \namespace rapidjson
+ \brief main RapidJSON namespace
+ \see RAPIDJSON_NAMESPACE
+*/
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Type of JSON value
+enum Type {
+ kNullType = 0, //!< null
+ kFalseType = 1, //!< false
+ kTrueType = 2, //!< true
+ kObjectType = 3, //!< object
+ kArrayType = 4, //!< array
+ kStringType = 5, //!< string
+ kNumberType = 6 //!< number
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_RAPIDJSON_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/reader.h b/3rdparty/rapidjson/include/rapidjson/reader.h
new file mode 100644
index 00000000000..ed6a1e77cc4
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/reader.h
@@ -0,0 +1,1696 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_READER_H_
+#define RAPIDJSON_READER_H_
+
+/*! \file reader.h */
+
+#include "allocators.h"
+#include "stream.h"
+#include "internal/meta.h"
+#include "internal/stack.h"
+#include "internal/strtod.h"
+
+#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
+#include <intrin.h>
+#pragma intrinsic(_BitScanForward)
+#endif
+#ifdef RAPIDJSON_SSE42
+#include <nmmintrin.h>
+#elif defined(RAPIDJSON_SSE2)
+#include <emmintrin.h>
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+RAPIDJSON_DIAG_OFF(4702) // unreachable code
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(switch-enum)
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#define RAPIDJSON_NOTHING /* deliberately empty */
+#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN
+#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \
+ RAPIDJSON_MULTILINEMACRO_BEGIN \
+ if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
+ RAPIDJSON_MULTILINEMACRO_END
+#endif
+#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
+//!@endcond
+
+/*! \def RAPIDJSON_PARSE_ERROR_NORETURN
+ \ingroup RAPIDJSON_ERRORS
+ \brief Macro to indicate a parse error.
+ \param parseErrorCode \ref rapidjson::ParseErrorCode of the error
+ \param offset position of the error in JSON input (\c size_t)
+
+ This macros can be used as a customization point for the internal
+ error handling mechanism of RapidJSON.
+
+ A common usage model is to throw an exception instead of requiring the
+ caller to explicitly check the \ref rapidjson::GenericReader::Parse's
+ return value:
+
+ \code
+ #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \
+ throw ParseException(parseErrorCode, #parseErrorCode, offset)
+
+ #include <stdexcept> // std::runtime_error
+ #include "rapidjson/error/error.h" // rapidjson::ParseResult
+
+ struct ParseException : std::runtime_error, rapidjson::ParseResult {
+ ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset)
+ : std::runtime_error(msg), ParseResult(code, offset) {}
+ };
+
+ #include "rapidjson/reader.h"
+ \endcode
+
+ \see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse
+ */
+#ifndef RAPIDJSON_PARSE_ERROR_NORETURN
+#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \
+ RAPIDJSON_MULTILINEMACRO_BEGIN \
+ RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
+ SetParseError(parseErrorCode, offset); \
+ RAPIDJSON_MULTILINEMACRO_END
+#endif
+
+/*! \def RAPIDJSON_PARSE_ERROR
+ \ingroup RAPIDJSON_ERRORS
+ \brief (Internal) macro to indicate and handle a parse error.
+ \param parseErrorCode \ref rapidjson::ParseErrorCode of the error
+ \param offset position of the error in JSON input (\c size_t)
+
+ Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing.
+
+ \see RAPIDJSON_PARSE_ERROR_NORETURN
+ \hideinitializer
+ */
+#ifndef RAPIDJSON_PARSE_ERROR
+#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \
+ RAPIDJSON_MULTILINEMACRO_BEGIN \
+ RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
+ RAPIDJSON_MULTILINEMACRO_END
+#endif
+
+#include "error/error.h" // ParseErrorCode, ParseResult
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseFlag
+
+/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS
+ \ingroup RAPIDJSON_CONFIG
+ \brief User-defined kParseDefaultFlags definition.
+
+ User can define this as any \c ParseFlag combinations.
+*/
+#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS
+#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags
+#endif
+
+//! Combination of parseFlags
+/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream
+ */
+enum ParseFlag {
+ kParseNoFlags = 0, //!< No flags are set.
+ kParseInsituFlag = 1, //!< In-situ(destructive) parsing.
+ kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings.
+ kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing.
+ kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error.
+ kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower).
+ kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments.
+ kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Handler
+
+/*! \class rapidjson::Handler
+ \brief Concept for receiving events from GenericReader upon parsing.
+ The functions return true if no error occurs. If they return false,
+ the event publisher should terminate the process.
+\code
+concept Handler {
+ typename Ch;
+
+ bool Null();
+ bool Bool(bool b);
+ bool Int(int i);
+ bool Uint(unsigned i);
+ bool Int64(int64_t i);
+ bool Uint64(uint64_t i);
+ bool Double(double d);
+ bool String(const Ch* str, SizeType length, bool copy);
+ bool StartObject();
+ bool Key(const Ch* str, SizeType length, bool copy);
+ bool EndObject(SizeType memberCount);
+ bool StartArray();
+ bool EndArray(SizeType elementCount);
+};
+\endcode
+*/
+///////////////////////////////////////////////////////////////////////////////
+// BaseReaderHandler
+
+//! Default implementation of Handler.
+/*! This can be used as base class of any reader handler.
+ \note implements Handler concept
+*/
+template<typename Encoding = UTF8<>, typename Derived = void>
+struct BaseReaderHandler {
+ typedef typename Encoding::Ch Ch;
+
+ typedef typename internal::SelectIf<internal::IsSame<Derived, void>, BaseReaderHandler, Derived>::Type Override;
+
+ bool Default() { return true; }
+ bool Null() { return static_cast<Override&>(*this).Default(); }
+ bool Bool(bool) { return static_cast<Override&>(*this).Default(); }
+ bool Int(int) { return static_cast<Override&>(*this).Default(); }
+ bool Uint(unsigned) { return static_cast<Override&>(*this).Default(); }
+ bool Int64(int64_t) { return static_cast<Override&>(*this).Default(); }
+ bool Uint64(uint64_t) { return static_cast<Override&>(*this).Default(); }
+ bool Double(double) { return static_cast<Override&>(*this).Default(); }
+ bool String(const Ch*, SizeType, bool) { return static_cast<Override&>(*this).Default(); }
+ bool StartObject() { return static_cast<Override&>(*this).Default(); }
+ bool Key(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); }
+ bool EndObject(SizeType) { return static_cast<Override&>(*this).Default(); }
+ bool StartArray() { return static_cast<Override&>(*this).Default(); }
+ bool EndArray(SizeType) { return static_cast<Override&>(*this).Default(); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// StreamLocalCopy
+
+namespace internal {
+
+template<typename Stream, int = StreamTraits<Stream>::copyOptimization>
+class StreamLocalCopy;
+
+//! Do copy optimization.
+template<typename Stream>
+class StreamLocalCopy<Stream, 1> {
+public:
+ StreamLocalCopy(Stream& original) : s(original), original_(original) {}
+ ~StreamLocalCopy() { original_ = s; }
+
+ Stream s;
+
+private:
+ StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */;
+
+ Stream& original_;
+};
+
+//! Keep reference.
+template<typename Stream>
+class StreamLocalCopy<Stream, 0> {
+public:
+ StreamLocalCopy(Stream& original) : s(original) {}
+
+ Stream& s;
+
+private:
+ StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */;
+};
+
+} // namespace internal
+
+///////////////////////////////////////////////////////////////////////////////
+// SkipWhitespace
+
+//! Skip the JSON white spaces in a stream.
+/*! \param is A input stream for skipping white spaces.
+ \note This function has SSE2/SSE4.2 specialization.
+*/
+template<typename InputStream>
+void SkipWhitespace(InputStream& is) {
+ internal::StreamLocalCopy<InputStream> copy(is);
+ InputStream& s(copy.s);
+
+ while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
+ s.Take();
+}
+
+#ifdef RAPIDJSON_SSE42
+//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.
+inline const char *SkipWhitespace_SIMD(const char* p) {
+ // Fast return for single non-whitespace
+ if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+ ++p;
+ else
+ return p;
+
+ // 16-byte align to the next boundary
+ const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ while (p != nextAligned)
+ if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+ ++p;
+ else
+ return p;
+
+ // The rest of string using SIMD
+ static const char whitespace[16] = " \n\r\t";
+ const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0]));
+
+ for (;; p += 16) {
+ const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
+ const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
+ if (r != 0) { // some of characters is non-whitespace
+#ifdef _MSC_VER // Find the index of first non-whitespace
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ return p + offset;
+#else
+ return p + __builtin_ffs(r) - 1;
+#endif
+ }
+ }
+}
+
+#elif defined(RAPIDJSON_SSE2)
+
+//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.
+inline const char *SkipWhitespace_SIMD(const char* p) {
+ // Fast return for single non-whitespace
+ if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+ ++p;
+ else
+ return p;
+
+ // 16-byte align to the next boundary
+ const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ while (p != nextAligned)
+ if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+ ++p;
+ else
+ return p;
+
+ // The rest of string
+ #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c }
+ static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') };
+ #undef C16
+
+ const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0]));
+ const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0]));
+ const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0]));
+ const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0]));
+
+ for (;; p += 16) {
+ const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
+ __m128i x = _mm_cmpeq_epi8(s, w0);
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
+ unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));
+ if (r != 0) { // some of characters may be non-whitespace
+#ifdef _MSC_VER // Find the index of first non-whitespace
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ return p + offset;
+#else
+ return p + __builtin_ffs(r) - 1;
+#endif
+ }
+ }
+}
+
+#endif // RAPIDJSON_SSE2
+
+#ifdef RAPIDJSON_SIMD
+//! Template function specialization for InsituStringStream
+template<> inline void SkipWhitespace(InsituStringStream& is) {
+ is.src_ = const_cast<char*>(SkipWhitespace_SIMD(is.src_));
+}
+
+//! Template function specialization for StringStream
+template<> inline void SkipWhitespace(StringStream& is) {
+ is.src_ = SkipWhitespace_SIMD(is.src_);
+}
+#endif // RAPIDJSON_SIMD
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericReader
+
+//! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator.
+/*! GenericReader parses JSON text from a stream, and send events synchronously to an
+ object implementing Handler concept.
+
+ It needs to allocate a stack for storing a single decoded string during
+ non-destructive parsing.
+
+ For in-situ parsing, the decoded string is directly written to the source
+ text string, no temporary buffer is required.
+
+ A GenericReader object can be reused for parsing multiple JSON text.
+
+ \tparam SourceEncoding Encoding of the input stream.
+ \tparam TargetEncoding Encoding of the parse output.
+ \tparam StackAllocator Allocator type for stack.
+*/
+template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator = CrtAllocator>
+class GenericReader {
+public:
+ typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type
+
+ //! Constructor.
+ /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
+ \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing)
+ */
+ GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {}
+
+ //! Parse JSON text.
+ /*! \tparam parseFlags Combination of \ref ParseFlag.
+ \tparam InputStream Type of input stream, implementing Stream concept.
+ \tparam Handler Type of handler, implementing Handler concept.
+ \param is Input stream to be parsed.
+ \param handler The handler to receive events.
+ \return Whether the parsing is successful.
+ */
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ ParseResult Parse(InputStream& is, Handler& handler) {
+ if (parseFlags & kParseIterativeFlag)
+ return IterativeParse<parseFlags>(is, handler);
+
+ parseResult_.Clear();
+
+ ClearStackOnExit scope(*this);
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+
+ if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+ }
+ else {
+ ParseValue<parseFlags>(is, handler);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+
+ if (!(parseFlags & kParseStopWhenDoneFlag)) {
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+
+ if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+ }
+ }
+ }
+
+ return parseResult_;
+ }
+
+ //! Parse JSON text (with \ref kParseDefaultFlags)
+ /*! \tparam InputStream Type of input stream, implementing Stream concept
+ \tparam Handler Type of handler, implementing Handler concept.
+ \param is Input stream to be parsed.
+ \param handler The handler to receive events.
+ \return Whether the parsing is successful.
+ */
+ template <typename InputStream, typename Handler>
+ ParseResult Parse(InputStream& is, Handler& handler) {
+ return Parse<kParseDefaultFlags>(is, handler);
+ }
+
+ //! Whether a parse error has occured in the last parsing.
+ bool HasParseError() const { return parseResult_.IsError(); }
+
+ //! Get the \ref ParseErrorCode of last parsing.
+ ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); }
+
+ //! Get the position of last parsing error in input, 0 otherwise.
+ size_t GetErrorOffset() const { return parseResult_.Offset(); }
+
+protected:
+ void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); }
+
+private:
+ // Prohibit copy constructor & assignment operator.
+ GenericReader(const GenericReader&);
+ GenericReader& operator=(const GenericReader&);
+
+ void ClearStack() { stack_.Clear(); }
+
+ // clear stack on any exit from ParseStream, e.g. due to exception
+ struct ClearStackOnExit {
+ explicit ClearStackOnExit(GenericReader& r) : r_(r) {}
+ ~ClearStackOnExit() { r_.ClearStack(); }
+ private:
+ GenericReader& r_;
+ ClearStackOnExit(const ClearStackOnExit&);
+ ClearStackOnExit& operator=(const ClearStackOnExit&);
+ };
+
+ template<unsigned parseFlags, typename InputStream>
+ void SkipWhitespaceAndComments(InputStream& is) {
+ SkipWhitespace(is);
+
+ if (parseFlags & kParseCommentsFlag) {
+ while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) {
+ if (Consume(is, '*')) {
+ while (true) {
+ if (RAPIDJSON_UNLIKELY(is.Peek() == '\0'))
+ RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
+ else if (Consume(is, '*')) {
+ if (Consume(is, '/'))
+ break;
+ }
+ else
+ is.Take();
+ }
+ }
+ else if (RAPIDJSON_LIKELY(Consume(is, '/')))
+ while (is.Peek() != '\0' && is.Take() != '\n');
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
+
+ SkipWhitespace(is);
+ }
+ }
+ }
+
+ // Parse object: { string : value, ... }
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseObject(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == '{');
+ is.Take(); // Skip '{'
+
+ if (RAPIDJSON_UNLIKELY(!handler.StartObject()))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ if (Consume(is, '}')) {
+ if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ return;
+ }
+
+ for (SizeType memberCount = 0;;) {
+ if (RAPIDJSON_UNLIKELY(is.Peek() != '"'))
+ RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
+
+ ParseString<parseFlags>(is, handler, true);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ if (RAPIDJSON_UNLIKELY(!Consume(is, ':')))
+ RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ ParseValue<parseFlags>(is, handler);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ ++memberCount;
+
+ switch (is.Peek()) {
+ case ',':
+ is.Take();
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ break;
+ case '}':
+ is.Take();
+ if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ return;
+ default:
+ RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
+ break;
+ }
+ }
+ }
+
+ // Parse array: [ value, ... ]
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseArray(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == '[');
+ is.Take(); // Skip '['
+
+ if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ if (Consume(is, ']')) {
+ if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ return;
+ }
+
+ for (SizeType elementCount = 0;;) {
+ ParseValue<parseFlags>(is, handler);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ ++elementCount;
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ if (Consume(is, ',')) {
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ }
+ else if (Consume(is, ']')) {
+ if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ return;
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
+ }
+ }
+
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseNull(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == 'n');
+ is.Take();
+
+ if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) {
+ if (RAPIDJSON_UNLIKELY(!handler.Null()))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
+ }
+
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseTrue(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == 't');
+ is.Take();
+
+ if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) {
+ if (RAPIDJSON_UNLIKELY(!handler.Bool(true)))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
+ }
+
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseFalse(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == 'f');
+ is.Take();
+
+ if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) {
+ if (RAPIDJSON_UNLIKELY(!handler.Bool(false)))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
+ }
+
+ template<typename InputStream>
+ RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) {
+ if (RAPIDJSON_LIKELY(is.Peek() == expect)) {
+ is.Take();
+ return true;
+ }
+ else
+ return false;
+ }
+
+ // Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
+ template<typename InputStream>
+ unsigned ParseHex4(InputStream& is, size_t escapeOffset) {
+ unsigned codepoint = 0;
+ for (int i = 0; i < 4; i++) {
+ Ch c = is.Peek();
+ codepoint <<= 4;
+ codepoint += static_cast<unsigned>(c);
+ if (c >= '0' && c <= '9')
+ codepoint -= '0';
+ else if (c >= 'A' && c <= 'F')
+ codepoint -= 'A' - 10;
+ else if (c >= 'a' && c <= 'f')
+ codepoint -= 'a' - 10;
+ else {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0);
+ }
+ is.Take();
+ }
+ return codepoint;
+ }
+
+ template <typename CharType>
+ class StackStream {
+ public:
+ typedef CharType Ch;
+
+ StackStream(internal::Stack<StackAllocator>& stack) : stack_(stack), length_(0) {}
+ RAPIDJSON_FORCEINLINE void Put(Ch c) {
+ *stack_.template Push<Ch>() = c;
+ ++length_;
+ }
+
+ RAPIDJSON_FORCEINLINE void* Push(SizeType count) {
+ length_ += count;
+ return stack_.template Push<Ch>(count);
+ }
+
+ size_t Length() const { return length_; }
+
+ Ch* Pop() {
+ return stack_.template Pop<Ch>(length_);
+ }
+
+ private:
+ StackStream(const StackStream&);
+ StackStream& operator=(const StackStream&);
+
+ internal::Stack<StackAllocator>& stack_;
+ SizeType length_;
+ };
+
+ // Parse string and generate String event. Different code paths for kParseInsituFlag.
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseString(InputStream& is, Handler& handler, bool isKey = false) {
+ internal::StreamLocalCopy<InputStream> copy(is);
+ InputStream& s(copy.s);
+
+ RAPIDJSON_ASSERT(s.Peek() == '\"');
+ s.Take(); // Skip '\"'
+
+ bool success = false;
+ if (parseFlags & kParseInsituFlag) {
+ typename InputStream::Ch *head = s.PutBegin();
+ ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ size_t length = s.PutEnd(head) - 1;
+ RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
+ const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head);
+ success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false));
+ }
+ else {
+ StackStream<typename TargetEncoding::Ch> stackStream(stack_);
+ ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ SizeType length = static_cast<SizeType>(stackStream.Length()) - 1;
+ const typename TargetEncoding::Ch* const str = stackStream.Pop();
+ success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true));
+ }
+ if (RAPIDJSON_UNLIKELY(!success))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
+ }
+
+ // Parse string to an output is
+ // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation.
+ template<unsigned parseFlags, typename SEncoding, typename TEncoding, typename InputStream, typename OutputStream>
+ RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) {
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+ static const char escape[256] = {
+ Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',
+ Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
+ 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
+ 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
+ };
+#undef Z16
+//!@endcond
+
+ for (;;) {
+ // Scan and copy string before "\\\"" or < 0x20. This is an optional optimzation.
+ if (!(parseFlags & kParseValidateEncodingFlag))
+ ScanCopyUnescapedString(is, os);
+
+ Ch c = is.Peek();
+ if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape
+ size_t escapeOffset = is.Tell(); // For invalid escaping, report the inital '\\' as error offset
+ is.Take();
+ Ch e = is.Peek();
+ if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast<unsigned char>(e)])) {
+ is.Take();
+ os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)]));
+ }
+ else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode
+ is.Take();
+ unsigned codepoint = ParseHex4(is, escapeOffset);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) {
+ // Handle UTF-16 surrogate pair
+ if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u')))
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
+ unsigned codepoint2 = ParseHex4(is, escapeOffset);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
+ codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
+ }
+ TEncoding::Encode(os, codepoint);
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset);
+ }
+ else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote
+ is.Take();
+ os.Put('\0'); // null-terminate the string
+ return;
+ }
+ else if (RAPIDJSON_UNLIKELY(static_cast<unsigned>(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
+ if (c == '\0')
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell());
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell());
+ }
+ else {
+ size_t offset = is.Tell();
+ if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ?
+ !Transcoder<SEncoding, TEncoding>::Validate(is, os) :
+ !Transcoder<SEncoding, TEncoding>::Transcode(is, os))))
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset);
+ }
+ }
+ }
+
+ template<typename InputStream, typename OutputStream>
+ static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) {
+ // Do nothing for generic version
+ }
+
+#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
+ // StringStream -> StackStream<char>
+ static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream<char>& os) {
+ const char* p = is.src_;
+
+ // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
+ const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ while (p != nextAligned)
+ if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
+ is.src_ = p;
+ return;
+ }
+ else
+ os.Put(*p++);
+
+ // The rest of string using SIMD
+ static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
+ static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
+ static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
+ const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
+ const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
+ const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
+
+ for (;; p += 16) {
+ const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
+ const __m128i t1 = _mm_cmpeq_epi8(s, dq);
+ const __m128i t2 = _mm_cmpeq_epi8(s, bs);
+ const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
+ const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
+ unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
+ if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
+ SizeType length;
+ #ifdef _MSC_VER // Find the index of first escaped
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ length = offset;
+ #else
+ length = static_cast<SizeType>(__builtin_ffs(r) - 1);
+ #endif
+ char* q = reinterpret_cast<char*>(os.Push(length));
+ for (size_t i = 0; i < length; i++)
+ q[i] = p[i];
+
+ p += length;
+ break;
+ }
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s);
+ }
+
+ is.src_ = p;
+ }
+
+ // InsituStringStream -> InsituStringStream
+ static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) {
+ RAPIDJSON_ASSERT(&is == &os);
+ (void)os;
+
+ if (is.src_ == is.dst_) {
+ SkipUnescapedString(is);
+ return;
+ }
+
+ char* p = is.src_;
+ char *q = is.dst_;
+
+ // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
+ const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ while (p != nextAligned)
+ if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
+ is.src_ = p;
+ is.dst_ = q;
+ return;
+ }
+ else
+ *q++ = *p++;
+
+ // The rest of string using SIMD
+ static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
+ static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
+ static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
+ const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
+ const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
+ const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
+
+ for (;; p += 16, q += 16) {
+ const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
+ const __m128i t1 = _mm_cmpeq_epi8(s, dq);
+ const __m128i t2 = _mm_cmpeq_epi8(s, bs);
+ const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
+ const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
+ unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
+ if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
+ size_t length;
+#ifdef _MSC_VER // Find the index of first escaped
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ length = offset;
+#else
+ length = static_cast<size_t>(__builtin_ffs(r) - 1);
+#endif
+ for (const char* pend = p + length; p != pend; )
+ *q++ = *p++;
+ break;
+ }
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(q), s);
+ }
+
+ is.src_ = p;
+ is.dst_ = q;
+ }
+
+ // When read/write pointers are the same for insitu stream, just skip unescaped characters
+ static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) {
+ RAPIDJSON_ASSERT(is.src_ == is.dst_);
+ char* p = is.src_;
+
+ // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
+ const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ for (; p != nextAligned; p++)
+ if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
+ is.src_ = is.dst_ = p;
+ return;
+ }
+
+ // The rest of string using SIMD
+ static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
+ static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
+ static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
+ const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
+ const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
+ const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
+
+ for (;; p += 16) {
+ const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
+ const __m128i t1 = _mm_cmpeq_epi8(s, dq);
+ const __m128i t2 = _mm_cmpeq_epi8(s, bs);
+ const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
+ const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
+ unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
+ if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
+ size_t length;
+#ifdef _MSC_VER // Find the index of first escaped
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ length = offset;
+#else
+ length = static_cast<size_t>(__builtin_ffs(r) - 1);
+#endif
+ p += length;
+ break;
+ }
+ }
+
+ is.src_ = is.dst_ = p;
+ }
+#endif
+
+ template<typename InputStream, bool backup>
+ class NumberStream;
+
+ template<typename InputStream>
+ class NumberStream<InputStream, false> {
+ public:
+ typedef typename InputStream::Ch Ch;
+
+ NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; }
+ ~NumberStream() {}
+
+ RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }
+ RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }
+ RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }
+ size_t Tell() { return is.Tell(); }
+ size_t Length() { return 0; }
+ const char* Pop() { return 0; }
+
+ protected:
+ NumberStream& operator=(const NumberStream&);
+
+ InputStream& is;
+ };
+
+ template<typename InputStream>
+ class NumberStream<InputStream, true> : public NumberStream<InputStream, false> {
+ typedef NumberStream<InputStream, false> Base;
+ public:
+ NumberStream(GenericReader& reader, InputStream& is) : NumberStream<InputStream, false>(reader, is), stackStream(reader.stack_) {}
+ ~NumberStream() {}
+
+ RAPIDJSON_FORCEINLINE Ch TakePush() {
+ stackStream.Put(static_cast<char>(Base::is.Peek()));
+ return Base::is.Take();
+ }
+
+ size_t Length() { return stackStream.Length(); }
+
+ const char* Pop() {
+ stackStream.Put('\0');
+ return stackStream.Pop();
+ }
+
+ private:
+ StackStream<char> stackStream;
+ };
+
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseNumber(InputStream& is, Handler& handler) {
+ internal::StreamLocalCopy<InputStream> copy(is);
+ NumberStream<InputStream, (parseFlags & kParseFullPrecisionFlag) != 0> s(*this, copy.s);
+ size_t startOffset = s.Tell();
+
+ // Parse minus
+ bool minus = Consume(s, '-');
+
+ // Parse int: zero / ( digit1-9 *DIGIT )
+ unsigned i = 0;
+ uint64_t i64 = 0;
+ bool use64bit = false;
+ int significandDigit = 0;
+ if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) {
+ i = 0;
+ s.TakePush();
+ }
+ else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) {
+ i = static_cast<unsigned>(s.TakePush() - '0');
+
+ if (minus)
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648
+ if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) {
+ i64 = i;
+ use64bit = true;
+ break;
+ }
+ }
+ i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
+ significandDigit++;
+ }
+ else
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295
+ if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) {
+ i64 = i;
+ use64bit = true;
+ break;
+ }
+ }
+ i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
+ significandDigit++;
+ }
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
+
+ // Parse 64bit int
+ bool useDouble = false;
+ double d = 0.0;
+ if (use64bit) {
+ if (minus)
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808
+ if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) {
+ d = static_cast<double>(i64);
+ useDouble = true;
+ break;
+ }
+ i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
+ significandDigit++;
+ }
+ else
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615
+ if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) {
+ d = static_cast<double>(i64);
+ useDouble = true;
+ break;
+ }
+ i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
+ significandDigit++;
+ }
+ }
+
+ // Force double for big integer
+ if (useDouble) {
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0
+ RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
+ d = d * 10 + (s.TakePush() - '0');
+ }
+ }
+
+ // Parse frac = decimal-point 1*DIGIT
+ int expFrac = 0;
+ size_t decimalPosition;
+ if (Consume(s, '.')) {
+ decimalPosition = s.Length();
+
+ if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9')))
+ RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell());
+
+ if (!useDouble) {
+#if RAPIDJSON_64BIT
+ // Use i64 to store significand in 64-bit architecture
+ if (!use64bit)
+ i64 = i;
+
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path
+ break;
+ else {
+ i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
+ --expFrac;
+ if (i64 != 0)
+ significandDigit++;
+ }
+ }
+
+ d = static_cast<double>(i64);
+#else
+ // Use double to store significand in 32-bit architecture
+ d = static_cast<double>(use64bit ? i64 : i);
+#endif
+ useDouble = true;
+ }
+
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (significandDigit < 17) {
+ d = d * 10.0 + (s.TakePush() - '0');
+ --expFrac;
+ if (RAPIDJSON_LIKELY(d > 0.0))
+ significandDigit++;
+ }
+ else
+ s.TakePush();
+ }
+ }
+ else
+ decimalPosition = s.Length(); // decimal position at the end of integer.
+
+ // Parse exp = e [ minus / plus ] 1*DIGIT
+ int exp = 0;
+ if (Consume(s, 'e') || Consume(s, 'E')) {
+ if (!useDouble) {
+ d = static_cast<double>(use64bit ? i64 : i);
+ useDouble = true;
+ }
+
+ bool expMinus = false;
+ if (Consume(s, '+'))
+ ;
+ else if (Consume(s, '-'))
+ expMinus = true;
+
+ if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ exp = static_cast<int>(s.Take() - '0');
+ if (expMinus) {
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ exp = exp * 10 + static_cast<int>(s.Take() - '0');
+ if (exp >= 214748364) { // Issue #313: prevent overflow exponent
+ while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent
+ s.Take();
+ }
+ }
+ }
+ else { // positive exp
+ int maxExp = 308 - expFrac;
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ exp = exp * 10 + static_cast<int>(s.Take() - '0');
+ if (RAPIDJSON_UNLIKELY(exp > maxExp))
+ RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
+ }
+ }
+ }
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell());
+
+ if (expMinus)
+ exp = -exp;
+ }
+
+ // Finish parsing, call event according to the type of number.
+ bool cont = true;
+ size_t length = s.Length();
+ const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not.
+
+ if (useDouble) {
+ int p = exp + expFrac;
+ if (parseFlags & kParseFullPrecisionFlag)
+ d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp);
+ else
+ d = internal::StrtodNormalPrecision(d, p);
+
+ cont = handler.Double(minus ? -d : d);
+ }
+ else {
+ if (use64bit) {
+ if (minus)
+ cont = handler.Int64(static_cast<int64_t>(~i64 + 1));
+ else
+ cont = handler.Uint64(i64);
+ }
+ else {
+ if (minus)
+ cont = handler.Int(static_cast<int32_t>(~i + 1));
+ else
+ cont = handler.Uint(i);
+ }
+ }
+ if (RAPIDJSON_UNLIKELY(!cont))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset);
+ }
+
+ // Parse any JSON value
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseValue(InputStream& is, Handler& handler) {
+ switch (is.Peek()) {
+ case 'n': ParseNull <parseFlags>(is, handler); break;
+ case 't': ParseTrue <parseFlags>(is, handler); break;
+ case 'f': ParseFalse <parseFlags>(is, handler); break;
+ case '"': ParseString<parseFlags>(is, handler); break;
+ case '{': ParseObject<parseFlags>(is, handler); break;
+ case '[': ParseArray <parseFlags>(is, handler); break;
+ default :
+ ParseNumber<parseFlags>(is, handler);
+ break;
+
+ }
+ }
+
+ // Iterative Parsing
+
+ // States
+ enum IterativeParsingState {
+ IterativeParsingStartState = 0,
+ IterativeParsingFinishState,
+ IterativeParsingErrorState,
+
+ // Object states
+ IterativeParsingObjectInitialState,
+ IterativeParsingMemberKeyState,
+ IterativeParsingKeyValueDelimiterState,
+ IterativeParsingMemberValueState,
+ IterativeParsingMemberDelimiterState,
+ IterativeParsingObjectFinishState,
+
+ // Array states
+ IterativeParsingArrayInitialState,
+ IterativeParsingElementState,
+ IterativeParsingElementDelimiterState,
+ IterativeParsingArrayFinishState,
+
+ // Single value state
+ IterativeParsingValueState
+ };
+
+ enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 };
+
+ // Tokens
+ enum Token {
+ LeftBracketToken = 0,
+ RightBracketToken,
+
+ LeftCurlyBracketToken,
+ RightCurlyBracketToken,
+
+ CommaToken,
+ ColonToken,
+
+ StringToken,
+ FalseToken,
+ TrueToken,
+ NullToken,
+ NumberToken,
+
+ kTokenCount
+ };
+
+ RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) {
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#define N NumberToken
+#define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N
+ // Maps from ASCII to Token
+ static const unsigned char tokenMap[256] = {
+ N16, // 00~0F
+ N16, // 10~1F
+ N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F
+ N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F
+ N16, // 40~4F
+ N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F
+ N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F
+ N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F
+ N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF
+ };
+#undef N
+#undef N16
+//!@endcond
+
+ if (sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256)
+ return static_cast<Token>(tokenMap[static_cast<unsigned char>(c)]);
+ else
+ return NumberToken;
+ }
+
+ RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) {
+ // current state x one lookahead token -> new state
+ static const char G[cIterativeParsingStateCount][kTokenCount] = {
+ // Start
+ {
+ IterativeParsingArrayInitialState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingObjectInitialState, // Left curly bracket
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingValueState, // String
+ IterativeParsingValueState, // False
+ IterativeParsingValueState, // True
+ IterativeParsingValueState, // Null
+ IterativeParsingValueState // Number
+ },
+ // Finish(sink state)
+ {
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState
+ },
+ // Error(sink state)
+ {
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState
+ },
+ // ObjectInitial
+ {
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingObjectFinishState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingMemberKeyState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
+ },
+ // MemberKey
+ {
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingKeyValueDelimiterState, // Colon
+ IterativeParsingErrorState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
+ },
+ // KeyValueDelimiter
+ {
+ IterativeParsingArrayInitialState, // Left bracket(push MemberValue state)
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state)
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingMemberValueState, // String
+ IterativeParsingMemberValueState, // False
+ IterativeParsingMemberValueState, // True
+ IterativeParsingMemberValueState, // Null
+ IterativeParsingMemberValueState // Number
+ },
+ // MemberValue
+ {
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingObjectFinishState, // Right curly bracket
+ IterativeParsingMemberDelimiterState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingErrorState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
+ },
+ // MemberDelimiter
+ {
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingMemberKeyState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
+ },
+ // ObjectFinish(sink state)
+ {
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState
+ },
+ // ArrayInitial
+ {
+ IterativeParsingArrayInitialState, // Left bracket(push Element state)
+ IterativeParsingArrayFinishState, // Right bracket
+ IterativeParsingObjectInitialState, // Left curly bracket(push Element state)
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingElementState, // String
+ IterativeParsingElementState, // False
+ IterativeParsingElementState, // True
+ IterativeParsingElementState, // Null
+ IterativeParsingElementState // Number
+ },
+ // Element
+ {
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingArrayFinishState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingElementDelimiterState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingErrorState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
+ },
+ // ElementDelimiter
+ {
+ IterativeParsingArrayInitialState, // Left bracket(push Element state)
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingObjectInitialState, // Left curly bracket(push Element state)
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingElementState, // String
+ IterativeParsingElementState, // False
+ IterativeParsingElementState, // True
+ IterativeParsingElementState, // Null
+ IterativeParsingElementState // Number
+ },
+ // ArrayFinish(sink state)
+ {
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState
+ },
+ // Single Value (sink state)
+ {
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState
+ }
+ }; // End of G
+
+ return static_cast<IterativeParsingState>(G[state][token]);
+ }
+
+ // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit().
+ // May return a new state on state pop.
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) {
+ (void)token;
+
+ switch (dst) {
+ case IterativeParsingErrorState:
+ return dst;
+
+ case IterativeParsingObjectInitialState:
+ case IterativeParsingArrayInitialState:
+ {
+ // Push the state(Element or MemeberValue) if we are nested in another array or value of member.
+ // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop.
+ IterativeParsingState n = src;
+ if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState)
+ n = IterativeParsingElementState;
+ else if (src == IterativeParsingKeyValueDelimiterState)
+ n = IterativeParsingMemberValueState;
+ // Push current state.
+ *stack_.template Push<SizeType>(1) = n;
+ // Initialize and push the member/element count.
+ *stack_.template Push<SizeType>(1) = 0;
+ // Call handler
+ bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray();
+ // On handler short circuits the parsing.
+ if (!hr) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
+ return IterativeParsingErrorState;
+ }
+ else {
+ is.Take();
+ return dst;
+ }
+ }
+
+ case IterativeParsingMemberKeyState:
+ ParseString<parseFlags>(is, handler, true);
+ if (HasParseError())
+ return IterativeParsingErrorState;
+ else
+ return dst;
+
+ case IterativeParsingKeyValueDelimiterState:
+ RAPIDJSON_ASSERT(token == ColonToken);
+ is.Take();
+ return dst;
+
+ case IterativeParsingMemberValueState:
+ // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
+ ParseValue<parseFlags>(is, handler);
+ if (HasParseError()) {
+ return IterativeParsingErrorState;
+ }
+ return dst;
+
+ case IterativeParsingElementState:
+ // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
+ ParseValue<parseFlags>(is, handler);
+ if (HasParseError()) {
+ return IterativeParsingErrorState;
+ }
+ return dst;
+
+ case IterativeParsingMemberDelimiterState:
+ case IterativeParsingElementDelimiterState:
+ is.Take();
+ // Update member/element count.
+ *stack_.template Top<SizeType>() = *stack_.template Top<SizeType>() + 1;
+ return dst;
+
+ case IterativeParsingObjectFinishState:
+ {
+ // Get member count.
+ SizeType c = *stack_.template Pop<SizeType>(1);
+ // If the object is not empty, count the last member.
+ if (src == IterativeParsingMemberValueState)
+ ++c;
+ // Restore the state.
+ IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1));
+ // Transit to Finish state if this is the topmost scope.
+ if (n == IterativeParsingStartState)
+ n = IterativeParsingFinishState;
+ // Call handler
+ bool hr = handler.EndObject(c);
+ // On handler short circuits the parsing.
+ if (!hr) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
+ return IterativeParsingErrorState;
+ }
+ else {
+ is.Take();
+ return n;
+ }
+ }
+
+ case IterativeParsingArrayFinishState:
+ {
+ // Get element count.
+ SizeType c = *stack_.template Pop<SizeType>(1);
+ // If the array is not empty, count the last element.
+ if (src == IterativeParsingElementState)
+ ++c;
+ // Restore the state.
+ IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1));
+ // Transit to Finish state if this is the topmost scope.
+ if (n == IterativeParsingStartState)
+ n = IterativeParsingFinishState;
+ // Call handler
+ bool hr = handler.EndArray(c);
+ // On handler short circuits the parsing.
+ if (!hr) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
+ return IterativeParsingErrorState;
+ }
+ else {
+ is.Take();
+ return n;
+ }
+ }
+
+ default:
+ // This branch is for IterativeParsingValueState actually.
+ // Use `default:` rather than
+ // `case IterativeParsingValueState:` is for code coverage.
+
+ // The IterativeParsingStartState is not enumerated in this switch-case.
+ // It is impossible for that case. And it can be caught by following assertion.
+
+ // The IterativeParsingFinishState is not enumerated in this switch-case either.
+ // It is a "derivative" state which cannot triggered from Predict() directly.
+ // Therefore it cannot happen here. And it can be caught by following assertion.
+ RAPIDJSON_ASSERT(dst == IterativeParsingValueState);
+
+ // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
+ ParseValue<parseFlags>(is, handler);
+ if (HasParseError()) {
+ return IterativeParsingErrorState;
+ }
+ return IterativeParsingFinishState;
+ }
+ }
+
+ template <typename InputStream>
+ void HandleError(IterativeParsingState src, InputStream& is) {
+ if (HasParseError()) {
+ // Error flag has been set.
+ return;
+ }
+
+ switch (src) {
+ case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return;
+ case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return;
+ case IterativeParsingObjectInitialState:
+ case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return;
+ case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return;
+ case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return;
+ case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return;
+ default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); return;
+ }
+ }
+
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ ParseResult IterativeParse(InputStream& is, Handler& handler) {
+ parseResult_.Clear();
+ ClearStackOnExit scope(*this);
+ IterativeParsingState state = IterativeParsingStartState;
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+ while (is.Peek() != '\0') {
+ Token t = Tokenize(is.Peek());
+ IterativeParsingState n = Predict(state, t);
+ IterativeParsingState d = Transit<parseFlags>(state, t, n, is, handler);
+
+ if (d == IterativeParsingErrorState) {
+ HandleError(state, is);
+ break;
+ }
+
+ state = d;
+
+ // Do not further consume streams if a root JSON has been parsed.
+ if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)
+ break;
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+ }
+
+ // Handle the end of file.
+ if (state != IterativeParsingFinishState)
+ HandleError(state, is);
+
+ return parseResult_;
+ }
+
+ static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
+ internal::Stack<StackAllocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing.
+ ParseResult parseResult_;
+}; // class GenericReader
+
+//! Reader with UTF8 encoding and default allocator.
+typedef GenericReader<UTF8<>, UTF8<> > Reader;
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_READER_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/schema.h b/3rdparty/rapidjson/include/rapidjson/schema.h
new file mode 100644
index 00000000000..e47f89aa3ba
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/schema.h
@@ -0,0 +1,1979 @@
+// Tencent is pleased to support the open source community by making RapidJSON available->
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved->
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License-> You may obtain a copy of the License at
+//
+// http://opensource->org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied-> See the License for the
+// specific language governing permissions and limitations under the License->
+
+#ifndef RAPIDJSON_SCHEMA_H_
+#define RAPIDJSON_SCHEMA_H_
+
+#include "document.h"
+#include "pointer.h"
+#include <cmath> // abs, floor
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(weak-vtables)
+RAPIDJSON_DIAG_OFF(exit-time-destructors)
+RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
+#endif
+
+#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
+#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
+#else
+#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0
+#endif
+
+#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
+#define RAPIDJSON_SCHEMA_USE_STDREGEX 1
+#else
+#define RAPIDJSON_SCHEMA_USE_STDREGEX 0
+#endif
+
+#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
+#include "internal/regex.h"
+#elif RAPIDJSON_SCHEMA_USE_STDREGEX
+#include <regex>
+#endif
+
+#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
+#define RAPIDJSON_SCHEMA_HAS_REGEX 1
+#else
+#define RAPIDJSON_SCHEMA_HAS_REGEX 0
+#endif
+
+#ifndef RAPIDJSON_SCHEMA_VERBOSE
+#define RAPIDJSON_SCHEMA_VERBOSE 0
+#endif
+
+#if RAPIDJSON_SCHEMA_VERBOSE
+#include "stringbuffer.h"
+#endif
+
+#if defined(__GNUC__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(variadic-macros)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Verbose Utilities
+
+#if RAPIDJSON_SCHEMA_VERBOSE
+
+namespace internal {
+
+inline void PrintInvalidKeyword(const char* keyword) {
+ printf("Fail keyword: %s\n", keyword);
+}
+
+inline void PrintInvalidKeyword(const wchar_t* keyword) {
+ wprintf(L"Fail keyword: %ls\n", keyword);
+}
+
+inline void PrintInvalidDocument(const char* document) {
+ printf("Fail document: %s\n\n", document);
+}
+
+inline void PrintInvalidDocument(const wchar_t* document) {
+ wprintf(L"Fail document: %ls\n\n", document);
+}
+
+inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) {
+ printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d);
+}
+
+inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) {
+ wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d);
+}
+
+} // namespace internal
+
+#endif // RAPIDJSON_SCHEMA_VERBOSE
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_INVALID_KEYWORD_RETURN
+
+#if RAPIDJSON_SCHEMA_VERBOSE
+#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)
+#else
+#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
+#endif
+
+#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\
+RAPIDJSON_MULTILINEMACRO_BEGIN\
+ context.invalidKeyword = keyword.GetString();\
+ RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\
+ return false;\
+RAPIDJSON_MULTILINEMACRO_END
+
+///////////////////////////////////////////////////////////////////////////////
+// Forward declarations
+
+template <typename ValueType, typename Allocator>
+class GenericSchemaDocument;
+
+namespace internal {
+
+template <typename SchemaDocumentType>
+class Schema;
+
+///////////////////////////////////////////////////////////////////////////////
+// ISchemaValidator
+
+class ISchemaValidator {
+public:
+ virtual ~ISchemaValidator() {}
+ virtual bool IsValid() const = 0;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// ISchemaStateFactory
+
+template <typename SchemaType>
+class ISchemaStateFactory {
+public:
+ virtual ~ISchemaStateFactory() {}
+ virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0;
+ virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
+ virtual void* CreateHasher() = 0;
+ virtual uint64_t GetHashCode(void* hasher) = 0;
+ virtual void DestroryHasher(void* hasher) = 0;
+ virtual void* MallocState(size_t size) = 0;
+ virtual void* ReallocState(void* originalPtr, size_t originalSize, size_t newSize) = 0;
+ virtual void FreeState(void* p) = 0;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Hasher
+
+// For comparison of compound value
+template<typename Encoding, typename Allocator>
+class Hasher {
+public:
+ typedef typename Encoding::Ch Ch;
+
+ Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}
+
+ bool Null() { return WriteType(kNullType); }
+ bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); }
+ bool Int(int i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
+ bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
+ bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
+ bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
+ bool Double(double d) {
+ Number n;
+ if (d < 0) n.u.i = static_cast<int64_t>(d);
+ else n.u.u = static_cast<uint64_t>(d);
+ n.d = d;
+ return WriteNumber(n);
+ }
+
+ bool String(const Ch* str, SizeType len, bool) {
+ WriteBuffer(kStringType, str, len * sizeof(Ch));
+ return true;
+ }
+
+ bool StartObject() { return true; }
+ bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); }
+ bool EndObject(SizeType memberCount) {
+ uint64_t h = Hash(0, kObjectType);
+ uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
+ for (SizeType i = 0; i < memberCount; i++)
+ h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive
+ *stack_.template Push<uint64_t>() = h;
+ return true;
+ }
+
+ bool StartArray() { return true; }
+ bool EndArray(SizeType elementCount) {
+ uint64_t h = Hash(0, kArrayType);
+ uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
+ for (SizeType i = 0; i < elementCount; i++)
+ h = Hash(h, e[i]); // Use hash to achieve element order sensitive
+ *stack_.template Push<uint64_t>() = h;
+ return true;
+ }
+
+ bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); }
+
+ uint64_t GetHashCode() const {
+ RAPIDJSON_ASSERT(IsValid());
+ return *stack_.template Top<uint64_t>();
+ }
+
+private:
+ static const size_t kDefaultSize = 256;
+ struct Number {
+ union U {
+ uint64_t u;
+ int64_t i;
+ }u;
+ double d;
+ };
+
+ bool WriteType(Type type) { return WriteBuffer(type, 0, 0); }
+
+ bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); }
+
+ bool WriteBuffer(Type type, const void* data, size_t len) {
+ // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/
+ uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type);
+ const unsigned char* d = static_cast<const unsigned char*>(data);
+ for (size_t i = 0; i < len; i++)
+ h = Hash(h, d[i]);
+ *stack_.template Push<uint64_t>() = h;
+ return true;
+ }
+
+ static uint64_t Hash(uint64_t h, uint64_t d) {
+ static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3);
+ h ^= d;
+ h *= kPrime;
+ return h;
+ }
+
+ Stack<Allocator> stack_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// SchemaValidationContext
+
+template <typename SchemaDocumentType>
+struct SchemaValidationContext {
+ typedef Schema<SchemaDocumentType> SchemaType;
+ typedef ISchemaStateFactory<SchemaType> SchemaValidatorFactoryType;
+ typedef typename SchemaType::ValueType ValueType;
+ typedef typename ValueType::Ch Ch;
+
+ enum PatternValidatorType {
+ kPatternValidatorOnly,
+ kPatternValidatorWithProperty,
+ kPatternValidatorWithAdditionalProperty
+ };
+
+ SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s) :
+ factory(f),
+ schema(s),
+ valueSchema(),
+ invalidKeyword(),
+ hasher(),
+ arrayElementHashCodes(),
+ validators(),
+ validatorCount(),
+ patternPropertiesValidators(),
+ patternPropertiesValidatorCount(),
+ patternPropertiesSchemas(),
+ patternPropertiesSchemaCount(),
+ valuePatternValidatorType(kPatternValidatorOnly),
+ objectDependencies(),
+ inArray(false),
+ valueUniqueness(false),
+ arrayUniqueness(false)
+ {
+ }
+
+ ~SchemaValidationContext() {
+ if (hasher)
+ factory.DestroryHasher(hasher);
+ if (validators) {
+ for (SizeType i = 0; i < validatorCount; i++)
+ factory.DestroySchemaValidator(validators[i]);
+ factory.FreeState(validators);
+ }
+ if (patternPropertiesValidators) {
+ for (SizeType i = 0; i < patternPropertiesValidatorCount; i++)
+ factory.DestroySchemaValidator(patternPropertiesValidators[i]);
+ factory.FreeState(patternPropertiesValidators);
+ }
+ if (patternPropertiesSchemas)
+ factory.FreeState(patternPropertiesSchemas);
+ if (objectDependencies)
+ factory.FreeState(objectDependencies);
+ }
+
+ SchemaValidatorFactoryType& factory;
+ const SchemaType* schema;
+ const SchemaType* valueSchema;
+ const Ch* invalidKeyword;
+ void* hasher; // Only validator access
+ void* arrayElementHashCodes; // Only validator access this
+ ISchemaValidator** validators;
+ SizeType validatorCount;
+ ISchemaValidator** patternPropertiesValidators;
+ SizeType patternPropertiesValidatorCount;
+ const SchemaType** patternPropertiesSchemas;
+ SizeType patternPropertiesSchemaCount;
+ PatternValidatorType valuePatternValidatorType;
+ PatternValidatorType objectPatternValidatorType;
+ SizeType objectRequiredCount;
+ SizeType arrayElementIndex;
+ bool* objectDependencies;
+ bool inArray;
+ bool valueUniqueness;
+ bool arrayUniqueness;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Schema
+
+template <typename SchemaDocumentType>
+class Schema {
+public:
+ typedef typename SchemaDocumentType::ValueType ValueType;
+ typedef typename SchemaDocumentType::AllocatorType AllocatorType;
+ typedef typename SchemaDocumentType::PointerType PointerType;
+ typedef typename ValueType::EncodingType EncodingType;
+ typedef typename EncodingType::Ch Ch;
+ typedef SchemaValidationContext<SchemaDocumentType> Context;
+ typedef Schema<SchemaDocumentType> SchemaType;
+ typedef GenericValue<EncodingType, AllocatorType> SValue;
+ friend class GenericSchemaDocument<ValueType, AllocatorType>;
+
+ Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) :
+ allocator_(allocator),
+ enum_(),
+ enumCount_(),
+ not_(),
+ type_((1 << kTotalSchemaType) - 1), // typeless
+ validatorCount_(),
+ properties_(),
+ additionalPropertiesSchema_(),
+ patternProperties_(),
+ patternPropertyCount_(),
+ propertyCount_(),
+ requiredCount_(),
+ minProperties_(),
+ maxProperties_(SizeType(~0)),
+ additionalProperties_(true),
+ hasDependencies_(),
+ hasSchemaDependencies_(),
+ additionalItemsSchema_(),
+ itemsList_(),
+ itemsTuple_(),
+ itemsTupleCount_(),
+ minItems_(),
+ maxItems_(SizeType(~0)),
+ additionalItems_(true),
+ uniqueItems_(false),
+ pattern_(),
+ minLength_(0),
+ maxLength_(~SizeType(0)),
+ exclusiveMinimum_(false),
+ exclusiveMaximum_(false)
+ {
+ typedef typename SchemaDocumentType::ValueType ValueType;
+ typedef typename ValueType::ConstValueIterator ConstValueIterator;
+ typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
+
+ if (!value.IsObject())
+ return;
+
+ if (const ValueType* v = GetMember(value, GetTypeString())) {
+ type_ = 0;
+ if (v->IsString())
+ AddType(*v);
+ else if (v->IsArray())
+ for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
+ AddType(*itr);
+ }
+
+ if (const ValueType* v = GetMember(value, GetEnumString()))
+ if (v->IsArray() && v->Size() > 0) {
+ enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
+ for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
+ typedef Hasher<EncodingType, MemoryPoolAllocator<> > EnumHasherType;
+ char buffer[256 + 24];
+ MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer));
+ EnumHasherType h(&hasherAllocator, 256);
+ itr->Accept(h);
+ enum_[enumCount_++] = h.GetHashCode();
+ }
+ }
+
+ AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
+ AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
+ AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
+
+ if (const ValueType* v = GetMember(value, GetNotString())) {
+ schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_), *v, document);
+ notValidatorIndex_ = validatorCount_;
+ validatorCount_++;
+ }
+
+ // Object
+
+ const ValueType* properties = GetMember(value, GetPropertiesString());
+ const ValueType* required = GetMember(value, GetRequiredString());
+ const ValueType* dependencies = GetMember(value, GetDependenciesString());
+ {
+ // Gather properties from properties/required/dependencies
+ SValue allProperties(kArrayType);
+
+ if (properties && properties->IsObject())
+ for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
+ AddUniqueElement(allProperties, itr->name);
+
+ if (required && required->IsArray())
+ for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
+ if (itr->IsString())
+ AddUniqueElement(allProperties, *itr);
+
+ if (dependencies && dependencies->IsObject())
+ for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
+ AddUniqueElement(allProperties, itr->name);
+ if (itr->value.IsArray())
+ for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
+ if (i->IsString())
+ AddUniqueElement(allProperties, *i);
+ }
+
+ if (allProperties.Size() > 0) {
+ propertyCount_ = allProperties.Size();
+ properties_ = static_cast<Property*>(allocator_->Malloc(sizeof(Property) * propertyCount_));
+ for (SizeType i = 0; i < propertyCount_; i++) {
+ new (&properties_[i]) Property();
+ properties_[i].name = allProperties[i];
+ properties_[i].schema = GetTypeless();
+ }
+ }
+ }
+
+ if (properties && properties->IsObject()) {
+ PointerType q = p.Append(GetPropertiesString(), allocator_);
+ for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
+ SizeType index;
+ if (FindPropertyIndex(itr->name, &index))
+ schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);
+ }
+ }
+
+ if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
+ PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
+ patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));
+ patternPropertyCount_ = 0;
+
+ for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
+ new (&patternProperties_[patternPropertyCount_]) PatternProperty();
+ patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
+ schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document);
+ patternPropertyCount_++;
+ }
+ }
+
+ if (required && required->IsArray())
+ for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
+ if (itr->IsString()) {
+ SizeType index;
+ if (FindPropertyIndex(*itr, &index)) {
+ properties_[index].required = true;
+ requiredCount_++;
+ }
+ }
+
+ if (dependencies && dependencies->IsObject()) {
+ PointerType q = p.Append(GetDependenciesString(), allocator_);
+ hasDependencies_ = true;
+ for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
+ SizeType sourceIndex;
+ if (FindPropertyIndex(itr->name, &sourceIndex)) {
+ if (itr->value.IsArray()) {
+ properties_[sourceIndex].dependencies = static_cast<bool*>(allocator_->Malloc(sizeof(bool) * propertyCount_));
+ std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_);
+ for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
+ SizeType targetIndex;
+ if (FindPropertyIndex(*targetItr, &targetIndex))
+ properties_[sourceIndex].dependencies[targetIndex] = true;
+ }
+ }
+ else if (itr->value.IsObject()) {
+ hasSchemaDependencies_ = true;
+ schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document);
+ properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
+ validatorCount_++;
+ }
+ }
+ }
+ }
+
+ if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
+ if (v->IsBool())
+ additionalProperties_ = v->GetBool();
+ else if (v->IsObject())
+ schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);
+ }
+
+ AssignIfExist(minProperties_, value, GetMinPropertiesString());
+ AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
+
+ // Array
+ if (const ValueType* v = GetMember(value, GetItemsString())) {
+ PointerType q = p.Append(GetItemsString(), allocator_);
+ if (v->IsObject()) // List validation
+ schemaDocument->CreateSchema(&itemsList_, q, *v, document);
+ else if (v->IsArray()) { // Tuple validation
+ itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(sizeof(const Schema*) * v->Size()));
+ SizeType index = 0;
+ for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
+ schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);
+ }
+ }
+
+ AssignIfExist(minItems_, value, GetMinItemsString());
+ AssignIfExist(maxItems_, value, GetMaxItemsString());
+
+ if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
+ if (v->IsBool())
+ additionalItems_ = v->GetBool();
+ else if (v->IsObject())
+ schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);
+ }
+
+ AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
+
+ // String
+ AssignIfExist(minLength_, value, GetMinLengthString());
+ AssignIfExist(maxLength_, value, GetMaxLengthString());
+
+ if (const ValueType* v = GetMember(value, GetPatternString()))
+ pattern_ = CreatePattern(*v);
+
+ // Number
+ if (const ValueType* v = GetMember(value, GetMinimumString()))
+ if (v->IsNumber())
+ minimum_.CopyFrom(*v, *allocator_);
+
+ if (const ValueType* v = GetMember(value, GetMaximumString()))
+ if (v->IsNumber())
+ maximum_.CopyFrom(*v, *allocator_);
+
+ AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
+ AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
+
+ if (const ValueType* v = GetMember(value, GetMultipleOfString()))
+ if (v->IsNumber() && v->GetDouble() > 0.0)
+ multipleOf_.CopyFrom(*v, *allocator_);
+ }
+
+ ~Schema() {
+ allocator_->Free(enum_);
+ if (properties_) {
+ for (SizeType i = 0; i < propertyCount_; i++)
+ properties_[i].~Property();
+ AllocatorType::Free(properties_);
+ }
+ if (patternProperties_) {
+ for (SizeType i = 0; i < patternPropertyCount_; i++)
+ patternProperties_[i].~PatternProperty();
+ AllocatorType::Free(patternProperties_);
+ }
+ AllocatorType::Free(itemsTuple_);
+#if RAPIDJSON_SCHEMA_HAS_REGEX
+ if (pattern_) {
+ pattern_->~RegexType();
+ allocator_->Free(pattern_);
+ }
+#endif
+ }
+
+ bool BeginValue(Context& context) const {
+ if (context.inArray) {
+ if (uniqueItems_)
+ context.valueUniqueness = true;
+
+ if (itemsList_)
+ context.valueSchema = itemsList_;
+ else if (itemsTuple_) {
+ if (context.arrayElementIndex < itemsTupleCount_)
+ context.valueSchema = itemsTuple_[context.arrayElementIndex];
+ else if (additionalItemsSchema_)
+ context.valueSchema = additionalItemsSchema_;
+ else if (additionalItems_)
+ context.valueSchema = GetTypeless();
+ else
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());
+ }
+ else
+ context.valueSchema = GetTypeless();
+
+ context.arrayElementIndex++;
+ }
+ return true;
+ }
+
+ RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {
+ if (context.patternPropertiesValidatorCount > 0) {
+ bool otherValid = false;
+ SizeType count = context.patternPropertiesValidatorCount;
+ if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)
+ otherValid = context.patternPropertiesValidators[--count]->IsValid();
+
+ bool patternValid = true;
+ for (SizeType i = 0; i < count; i++)
+ if (!context.patternPropertiesValidators[i]->IsValid()) {
+ patternValid = false;
+ break;
+ }
+
+ if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
+ if (!patternValid)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
+ }
+ else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
+ if (!patternValid || !otherValid)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
+ }
+ else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
+ }
+
+ if (enum_) {
+ const uint64_t h = context.factory.GetHashCode(context.hasher);
+ for (SizeType i = 0; i < enumCount_; i++)
+ if (enum_[i] == h)
+ goto foundEnum;
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());
+ foundEnum:;
+ }
+
+ if (allOf_.schemas)
+ for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
+ if (!context.validators[i]->IsValid())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString());
+
+ if (anyOf_.schemas) {
+ for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
+ if (context.validators[i]->IsValid())
+ goto foundAny;
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());
+ foundAny:;
+ }
+
+ if (oneOf_.schemas) {
+ bool oneValid = false;
+ for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
+ if (context.validators[i]->IsValid()) {
+ if (oneValid)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
+ else
+ oneValid = true;
+ }
+ if (!oneValid)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
+ }
+
+ if (not_ && context.validators[notValidatorIndex_]->IsValid())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());
+
+ return true;
+ }
+
+ bool Null(Context& context) const {
+ if (!(type_ & (1 << kNullSchemaType)))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+ return CreateParallelValidator(context);
+ }
+
+ bool Bool(Context& context, bool) const {
+ if (!(type_ & (1 << kBooleanSchemaType)))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+ return CreateParallelValidator(context);
+ }
+
+ bool Int(Context& context, int i) const {
+ if (!CheckInt(context, i))
+ return false;
+ return CreateParallelValidator(context);
+ }
+
+ bool Uint(Context& context, unsigned u) const {
+ if (!CheckUint(context, u))
+ return false;
+ return CreateParallelValidator(context);
+ }
+
+ bool Int64(Context& context, int64_t i) const {
+ if (!CheckInt(context, i))
+ return false;
+ return CreateParallelValidator(context);
+ }
+
+ bool Uint64(Context& context, uint64_t u) const {
+ if (!CheckUint(context, u))
+ return false;
+ return CreateParallelValidator(context);
+ }
+
+ bool Double(Context& context, double d) const {
+ if (!(type_ & (1 << kNumberSchemaType)))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+ if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
+ return false;
+
+ if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
+ return false;
+
+ if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
+ return false;
+
+ return CreateParallelValidator(context);
+ }
+
+ bool String(Context& context, const Ch* str, SizeType length, bool) const {
+ if (!(type_ & (1 << kStringSchemaType)))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+ if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
+ SizeType count;
+ if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
+ if (count < minLength_)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString());
+ if (count > maxLength_)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());
+ }
+ }
+
+ if (pattern_ && !IsPatternMatch(pattern_, str, length))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());
+
+ return CreateParallelValidator(context);
+ }
+
+ bool StartObject(Context& context) const {
+ if (!(type_ & (1 << kObjectSchemaType)))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+ context.objectRequiredCount = 0;
+ if (hasDependencies_) {
+ context.objectDependencies = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));
+ std::memset(context.objectDependencies, 0, sizeof(bool) * propertyCount_);
+ }
+
+ if (patternProperties_) { // pre-allocate schema array
+ SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType
+ context.patternPropertiesSchemas = static_cast<const SchemaType**>(context.factory.MallocState(sizeof(const SchemaType*) * count));
+ context.patternPropertiesSchemaCount = 0;
+ std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count);
+ }
+
+ return CreateParallelValidator(context);
+ }
+
+ bool Key(Context& context, const Ch* str, SizeType len, bool) const {
+ if (patternProperties_) {
+ context.patternPropertiesSchemaCount = 0;
+ for (SizeType i = 0; i < patternPropertyCount_; i++)
+ if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len))
+ context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
+ }
+
+ SizeType index;
+ if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
+ if (context.patternPropertiesSchemaCount > 0) {
+ context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
+ context.valueSchema = GetTypeless();
+ context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;
+ }
+ else
+ context.valueSchema = properties_[index].schema;
+
+ if (properties_[index].required)
+ context.objectRequiredCount++;
+
+ if (hasDependencies_)
+ context.objectDependencies[index] = true;
+
+ return true;
+ }
+
+ if (additionalPropertiesSchema_) {
+ if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) {
+ context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
+ context.valueSchema = GetTypeless();
+ context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
+ }
+ else
+ context.valueSchema = additionalPropertiesSchema_;
+ return true;
+ }
+ else if (additionalProperties_) {
+ context.valueSchema = GetTypeless();
+ return true;
+ }
+
+ if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());
+
+ return true;
+ }
+
+ bool EndObject(Context& context, SizeType memberCount) const {
+ if (context.objectRequiredCount != requiredCount_)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
+
+ if (memberCount < minProperties_)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
+
+ if (memberCount > maxProperties_)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());
+
+ if (hasDependencies_) {
+ for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
+ if (context.objectDependencies[sourceIndex]) {
+ if (properties_[sourceIndex].dependencies) {
+ for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
+ if (properties_[sourceIndex].dependencies[targetIndex] && !context.objectDependencies[targetIndex])
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
+ }
+ else if (properties_[sourceIndex].dependenciesSchema)
+ if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
+ }
+ }
+
+ return true;
+ }
+
+ bool StartArray(Context& context) const {
+ if (!(type_ & (1 << kArraySchemaType)))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+ context.arrayElementIndex = 0;
+ context.inArray = true;
+
+ return CreateParallelValidator(context);
+ }
+
+ bool EndArray(Context& context, SizeType elementCount) const {
+ context.inArray = false;
+
+ if (elementCount < minItems_)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());
+
+ if (elementCount > maxItems_)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());
+
+ return true;
+ }
+
+ // Generate functions for string literal according to Ch
+#define RAPIDJSON_STRING_(name, ...) \
+ static const ValueType& Get##name##String() {\
+ static const Ch s[] = { __VA_ARGS__, '\0' };\
+ static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1);\
+ return v;\
+ }
+
+ RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
+ RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n')
+ RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't')
+ RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y')
+ RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g')
+ RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r')
+ RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r')
+ RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e')
+ RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm')
+ RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f')
+ RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f')
+ RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f')
+ RAPIDJSON_STRING_(Not, 'n', 'o', 't')
+ RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
+ RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd')
+ RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')
+ RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
+ RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
+ RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
+ RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
+ RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's')
+ RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's')
+ RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's')
+ RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's')
+ RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')
+ RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h')
+ RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h')
+ RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n')
+ RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm')
+ RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm')
+ RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')
+ RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
+ RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
+
+#undef RAPIDJSON_STRING_
+
+private:
+ enum SchemaValueType {
+ kNullSchemaType,
+ kBooleanSchemaType,
+ kObjectSchemaType,
+ kArraySchemaType,
+ kStringSchemaType,
+ kNumberSchemaType,
+ kIntegerSchemaType,
+ kTotalSchemaType
+ };
+
+#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
+ typedef internal::GenericRegex<EncodingType> RegexType;
+#elif RAPIDJSON_SCHEMA_USE_STDREGEX
+ typedef std::basic_regex<Ch> RegexType;
+#else
+ typedef char RegexType;
+#endif
+
+ struct SchemaArray {
+ SchemaArray() : schemas(), count() {}
+ ~SchemaArray() { AllocatorType::Free(schemas); }
+ const SchemaType** schemas;
+ SizeType begin; // begin index of context.validators
+ SizeType count;
+ };
+
+ static const SchemaType* GetTypeless() {
+ static SchemaType typeless(0, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0);
+ return &typeless;
+ }
+
+ template <typename V1, typename V2>
+ void AddUniqueElement(V1& a, const V2& v) {
+ for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
+ if (*itr == v)
+ return;
+ V1 c(v, *allocator_);
+ a.PushBack(c, *allocator_);
+ }
+
+ static const ValueType* GetMember(const ValueType& value, const ValueType& name) {
+ typename ValueType::ConstMemberIterator itr = value.FindMember(name);
+ return itr != value.MemberEnd() ? &(itr->value) : 0;
+ }
+
+ static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) {
+ if (const ValueType* v = GetMember(value, name))
+ if (v->IsBool())
+ out = v->GetBool();
+ }
+
+ static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) {
+ if (const ValueType* v = GetMember(value, name))
+ if (v->IsUint64() && v->GetUint64() <= SizeType(~0))
+ out = static_cast<SizeType>(v->GetUint64());
+ }
+
+ void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) {
+ if (const ValueType* v = GetMember(value, name)) {
+ if (v->IsArray() && v->Size() > 0) {
+ PointerType q = p.Append(name, allocator_);
+ out.count = v->Size();
+ out.schemas = static_cast<const Schema**>(allocator_->Malloc(out.count * sizeof(const Schema*)));
+ memset(out.schemas, 0, sizeof(Schema*)* out.count);
+ for (SizeType i = 0; i < out.count; i++)
+ schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document);
+ out.begin = validatorCount_;
+ validatorCount_ += out.count;
+ }
+ }
+ }
+
+#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
+ template <typename ValueType>
+ RegexType* CreatePattern(const ValueType& value) {
+ if (value.IsString()) {
+ RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString());
+ if (!r->IsValid()) {
+ r->~RegexType();
+ r = 0;
+ }
+ return r;
+ }
+ return 0;
+ }
+
+ static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) {
+ return pattern->Search(str);
+ }
+#elif RAPIDJSON_SCHEMA_USE_STDREGEX
+ template <typename ValueType>
+ RegexType* CreatePattern(const ValueType& value) {
+ if (value.IsString())
+ try {
+ return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
+ }
+ catch (const std::regex_error&) {
+ }
+ return 0;
+ }
+
+ static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) {
+ std::match_results<const Ch*> r;
+ return std::regex_search(str, str + length, r, *pattern);
+ }
+#else
+ template <typename ValueType>
+ RegexType* CreatePattern(const ValueType&) { return 0; }
+
+ static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; }
+#endif // RAPIDJSON_SCHEMA_USE_STDREGEX
+
+ void AddType(const ValueType& type) {
+ if (type == GetNullString() ) type_ |= 1 << kNullSchemaType;
+ else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
+ else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
+ else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType;
+ else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
+ else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
+ else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
+ }
+
+ bool CreateParallelValidator(Context& context) const {
+ if (enum_ || context.arrayUniqueness)
+ context.hasher = context.factory.CreateHasher();
+
+ if (validatorCount_) {
+ RAPIDJSON_ASSERT(context.validators == 0);
+ context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_));
+ context.validatorCount = validatorCount_;
+
+ if (allOf_.schemas)
+ CreateSchemaValidators(context, allOf_);
+
+ if (anyOf_.schemas)
+ CreateSchemaValidators(context, anyOf_);
+
+ if (oneOf_.schemas)
+ CreateSchemaValidators(context, oneOf_);
+
+ if (not_)
+ context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_);
+
+ if (hasSchemaDependencies_) {
+ for (SizeType i = 0; i < propertyCount_; i++)
+ if (properties_[i].dependenciesSchema)
+ context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema);
+ }
+ }
+
+ return true;
+ }
+
+ void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const {
+ for (SizeType i = 0; i < schemas.count; i++)
+ context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]);
+ }
+
+ // O(n)
+ bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const {
+ SizeType len = name.GetStringLength();
+ const Ch* str = name.GetString();
+ for (SizeType index = 0; index < propertyCount_; index++)
+ if (properties_[index].name.GetStringLength() == len &&
+ (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0))
+ {
+ *outIndex = index;
+ return true;
+ }
+ return false;
+ }
+
+ bool CheckInt(Context& context, int64_t i) const {
+ if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+ if (!minimum_.IsNull()) {
+ if (minimum_.IsInt64()) {
+ if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
+ }
+ else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
+ return false;
+ }
+
+ if (!maximum_.IsNull()) {
+ if (maximum_.IsInt64()) {
+ if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
+ }
+ else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
+ return false;
+ }
+
+ if (!multipleOf_.IsNull()) {
+ if (multipleOf_.IsUint64()) {
+ if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
+ }
+ else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
+ return false;
+ }
+
+ return true;
+ }
+
+ bool CheckUint(Context& context, uint64_t i) const {
+ if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+ if (!minimum_.IsNull()) {
+ if (minimum_.IsUint64()) {
+ if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
+ }
+ else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
+ return false;
+ }
+
+ if (!maximum_.IsNull()) {
+ if (maximum_.IsUint64()) {
+ if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
+ }
+ else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
+ return false;
+ }
+
+ if (!multipleOf_.IsNull()) {
+ if (multipleOf_.IsUint64()) {
+ if (i % multipleOf_.GetUint64() != 0)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
+ }
+ else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
+ return false;
+ }
+
+ return true;
+ }
+
+ bool CheckDoubleMinimum(Context& context, double d) const {
+ if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
+ return true;
+ }
+
+ bool CheckDoubleMaximum(Context& context, double d) const {
+ if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
+ return true;
+ }
+
+ bool CheckDoubleMultipleOf(Context& context, double d) const {
+ double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
+ double q = std::floor(a / b);
+ double r = a - q * b;
+ if (r > 0.0)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
+ return true;
+ }
+
+ struct Property {
+ Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {}
+ ~Property() { AllocatorType::Free(dependencies); }
+ SValue name;
+ const SchemaType* schema;
+ const SchemaType* dependenciesSchema;
+ SizeType dependenciesValidatorIndex;
+ bool* dependencies;
+ bool required;
+ };
+
+ struct PatternProperty {
+ PatternProperty() : schema(), pattern() {}
+ ~PatternProperty() {
+ if (pattern) {
+ pattern->~RegexType();
+ AllocatorType::Free(pattern);
+ }
+ }
+ const SchemaType* schema;
+ RegexType* pattern;
+ };
+
+ AllocatorType* allocator_;
+ uint64_t* enum_;
+ SizeType enumCount_;
+ SchemaArray allOf_;
+ SchemaArray anyOf_;
+ SchemaArray oneOf_;
+ const SchemaType* not_;
+ unsigned type_; // bitmask of kSchemaType
+ SizeType validatorCount_;
+ SizeType notValidatorIndex_;
+
+ Property* properties_;
+ const SchemaType* additionalPropertiesSchema_;
+ PatternProperty* patternProperties_;
+ SizeType patternPropertyCount_;
+ SizeType propertyCount_;
+ SizeType requiredCount_;
+ SizeType minProperties_;
+ SizeType maxProperties_;
+ bool additionalProperties_;
+ bool hasDependencies_;
+ bool hasSchemaDependencies_;
+
+ const SchemaType* additionalItemsSchema_;
+ const SchemaType* itemsList_;
+ const SchemaType** itemsTuple_;
+ SizeType itemsTupleCount_;
+ SizeType minItems_;
+ SizeType maxItems_;
+ bool additionalItems_;
+ bool uniqueItems_;
+
+ RegexType* pattern_;
+ SizeType minLength_;
+ SizeType maxLength_;
+
+ SValue minimum_;
+ SValue maximum_;
+ SValue multipleOf_;
+ bool exclusiveMinimum_;
+ bool exclusiveMaximum_;
+};
+
+template<typename Stack, typename Ch>
+struct TokenHelper {
+ RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
+ *documentStack.template Push<Ch>() = '/';
+ char buffer[21];
+ size_t length = static_cast<size_t>((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);
+ for (size_t i = 0; i < length; i++)
+ *documentStack.template Push<Ch>() = buffer[i];
+ }
+};
+
+// Partial specialized version for char to prevent buffer copying.
+template <typename Stack>
+struct TokenHelper<Stack, char> {
+ RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
+ if (sizeof(SizeType) == 4) {
+ char *buffer = documentStack.template Push<char>(1 + 10); // '/' + uint
+ *buffer++ = '/';
+ const char* end = internal::u32toa(index, buffer);
+ documentStack.template Pop<char>(static_cast<size_t>(10 - (end - buffer)));
+ }
+ else {
+ char *buffer = documentStack.template Push<char>(1 + 20); // '/' + uint64
+ *buffer++ = '/';
+ const char* end = internal::u64toa(index, buffer);
+ documentStack.template Pop<char>(static_cast<size_t>(20 - (end - buffer)));
+ }
+ }
+};
+
+} // namespace internal
+
+///////////////////////////////////////////////////////////////////////////////
+// IGenericRemoteSchemaDocumentProvider
+
+template <typename SchemaDocumentType>
+class IGenericRemoteSchemaDocumentProvider {
+public:
+ typedef typename SchemaDocumentType::Ch Ch;
+
+ virtual ~IGenericRemoteSchemaDocumentProvider() {}
+ virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericSchemaDocument
+
+//! JSON schema document.
+/*!
+ A JSON schema document is a compiled version of a JSON schema.
+ It is basically a tree of internal::Schema.
+
+ \note This is an immutable class (i.e. its instance cannot be modified after construction).
+ \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding.
+ \tparam Allocator Allocator type for allocating memory of this document.
+*/
+template <typename ValueT, typename Allocator = CrtAllocator>
+class GenericSchemaDocument {
+public:
+ typedef ValueT ValueType;
+ typedef IGenericRemoteSchemaDocumentProvider<GenericSchemaDocument> IRemoteSchemaDocumentProviderType;
+ typedef Allocator AllocatorType;
+ typedef typename ValueType::EncodingType EncodingType;
+ typedef typename EncodingType::Ch Ch;
+ typedef internal::Schema<GenericSchemaDocument> SchemaType;
+ typedef GenericPointer<ValueType, Allocator> PointerType;
+ friend class internal::Schema<GenericSchemaDocument>;
+ template <typename, typename, typename>
+ friend class GenericSchemaValidator;
+
+ //! Constructor.
+ /*!
+ Compile a JSON document into schema document.
+
+ \param document A JSON document as source.
+ \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.
+ \param allocator An optional allocator instance for allocating memory. Can be null.
+ */
+ GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
+ remoteProvider_(remoteProvider),
+ allocator_(allocator),
+ ownAllocator_(),
+ root_(),
+ schemaMap_(allocator, kInitialSchemaMapSize),
+ schemaRef_(allocator, kInitialSchemaRefSize)
+ {
+ if (!allocator_)
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+
+ // Generate root schema, it will call CreateSchema() to create sub-schemas,
+ // And call AddRefSchema() if there are $ref.
+ CreateSchemaRecursive(&root_, PointerType(), document, document);
+
+ // Resolve $ref
+ while (!schemaRef_.Empty()) {
+ SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1);
+ if (const SchemaType* s = GetSchema(refEntry->target)) {
+ if (refEntry->schema)
+ *refEntry->schema = s;
+
+ // Create entry in map if not exist
+ if (!GetSchema(refEntry->source)) {
+ new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s), false, allocator_);
+ }
+ }
+ refEntry->~SchemaRefEntry();
+ }
+
+ RAPIDJSON_ASSERT(root_ != 0);
+
+ schemaRef_.ShrinkToFit(); // Deallocate all memory for ref
+ }
+
+ //! Destructor
+ ~GenericSchemaDocument() {
+ while (!schemaMap_.Empty())
+ schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
+
+ RAPIDJSON_DELETE(ownAllocator_);
+ }
+
+ //! Get the root schema.
+ const SchemaType& GetRoot() const { return *root_; }
+
+private:
+ struct SchemaRefEntry {
+ SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}
+ PointerType source;
+ PointerType target;
+ const SchemaType** schema;
+ };
+
+ struct SchemaEntry {
+ SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
+ ~SchemaEntry() {
+ if (owned) {
+ schema->~SchemaType();
+ Allocator::Free(schema);
+ }
+ }
+ PointerType pointer;
+ SchemaType* schema;
+ bool owned;
+ };
+
+ void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
+ if (schema)
+ *schema = SchemaType::GetTypeless();
+
+ if (v.GetType() == kObjectType) {
+ const SchemaType* s = GetSchema(pointer);
+ if (!s)
+ CreateSchema(schema, pointer, v, document);
+ else if (schema)
+ *schema = s;
+
+ for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
+ CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document);
+ }
+ else if (v.GetType() == kArrayType)
+ for (SizeType i = 0; i < v.Size(); i++)
+ CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document);
+ }
+
+ void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
+ RAPIDJSON_ASSERT(pointer.IsValid());
+ if (v.IsObject()) {
+ if (!HandleRefSchema(pointer, schema, v, document)) {
+ SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_);
+ new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(pointer, s, true, allocator_);
+ if (schema)
+ *schema = s;
+ }
+ }
+ }
+
+ bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) {
+ static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' };
+ static const ValueType kRefValue(kRefString, 4);
+
+ typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue);
+ if (itr == v.MemberEnd())
+ return false;
+
+ if (itr->value.IsString()) {
+ SizeType len = itr->value.GetStringLength();
+ if (len > 0) {
+ const Ch* s = itr->value.GetString();
+ SizeType i = 0;
+ while (i < len && s[i] != '#') // Find the first #
+ i++;
+
+ if (i > 0) { // Remote reference, resolve immediately
+ if (remoteProvider_) {
+ if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i - 1)) {
+ PointerType pointer(&s[i], len - i, allocator_);
+ if (pointer.IsValid()) {
+ if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) {
+ if (schema)
+ *schema = sc;
+ return true;
+ }
+ }
+ }
+ }
+ }
+ else if (s[i] == '#') { // Local reference, defer resolution
+ PointerType pointer(&s[i], len - i, allocator_);
+ if (pointer.IsValid()) {
+ if (const ValueType* nv = pointer.Get(document))
+ if (HandleRefSchema(source, schema, *nv, document))
+ return true;
+
+ new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(source, pointer, schema, allocator_);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ const SchemaType* GetSchema(const PointerType& pointer) const {
+ for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
+ if (pointer == target->pointer)
+ return target->schema;
+ return 0;
+ }
+
+ PointerType GetPointer(const SchemaType* schema) const {
+ for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
+ if (schema == target->schema)
+ return target->pointer;
+ return PointerType();
+ }
+
+ static const size_t kInitialSchemaMapSize = 64;
+ static const size_t kInitialSchemaRefSize = 64;
+
+ IRemoteSchemaDocumentProviderType* remoteProvider_;
+ Allocator *allocator_;
+ Allocator *ownAllocator_;
+ const SchemaType* root_; //!< Root schema.
+ internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas
+ internal::Stack<Allocator> schemaRef_; // Stores Pointer from $ref and schema which holds the $ref
+};
+
+//! GenericSchemaDocument using Value type.
+typedef GenericSchemaDocument<Value> SchemaDocument;
+//! IGenericRemoteSchemaDocumentProvider using SchemaDocument.
+typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericSchemaValidator
+
+//! JSON Schema Validator.
+/*!
+ A SAX style JSON schema validator.
+ It uses a \c GenericSchemaDocument to validate SAX events.
+ It delegates the incoming SAX events to an output handler.
+ The default output handler does nothing.
+ It can be reused multiple times by calling \c Reset().
+
+ \tparam SchemaDocumentType Type of schema document.
+ \tparam OutputHandler Type of output handler. Default handler does nothing.
+ \tparam StateAllocator Allocator for storing the internal validation states.
+*/
+template <
+ typename SchemaDocumentType,
+ typename OutputHandler = BaseReaderHandler<typename SchemaDocumentType::SchemaType::EncodingType>,
+ typename StateAllocator = CrtAllocator>
+class GenericSchemaValidator :
+ public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>,
+ public internal::ISchemaValidator
+{
+public:
+ typedef typename SchemaDocumentType::SchemaType SchemaType;
+ typedef typename SchemaDocumentType::PointerType PointerType;
+ typedef typename SchemaType::EncodingType EncodingType;
+ typedef typename EncodingType::Ch Ch;
+
+ //! Constructor without output handler.
+ /*!
+ \param schemaDocument The schema document to conform to.
+ \param allocator Optional allocator for storing internal validation states.
+ \param schemaStackCapacity Optional initial capacity of schema path stack.
+ \param documentStackCapacity Optional initial capacity of document path stack.
+ */
+ GenericSchemaValidator(
+ const SchemaDocumentType& schemaDocument,
+ StateAllocator* allocator = 0,
+ size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
+ size_t documentStackCapacity = kDefaultDocumentStackCapacity)
+ :
+ schemaDocument_(&schemaDocument),
+ root_(schemaDocument.GetRoot()),
+ outputHandler_(GetNullHandler()),
+ stateAllocator_(allocator),
+ ownStateAllocator_(0),
+ schemaStack_(allocator, schemaStackCapacity),
+ documentStack_(allocator, documentStackCapacity),
+ valid_(true)
+#if RAPIDJSON_SCHEMA_VERBOSE
+ , depth_(0)
+#endif
+ {
+ }
+
+ //! Constructor with output handler.
+ /*!
+ \param schemaDocument The schema document to conform to.
+ \param allocator Optional allocator for storing internal validation states.
+ \param schemaStackCapacity Optional initial capacity of schema path stack.
+ \param documentStackCapacity Optional initial capacity of document path stack.
+ */
+ GenericSchemaValidator(
+ const SchemaDocumentType& schemaDocument,
+ OutputHandler& outputHandler,
+ StateAllocator* allocator = 0,
+ size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
+ size_t documentStackCapacity = kDefaultDocumentStackCapacity)
+ :
+ schemaDocument_(&schemaDocument),
+ root_(schemaDocument.GetRoot()),
+ outputHandler_(outputHandler),
+ stateAllocator_(allocator),
+ ownStateAllocator_(0),
+ schemaStack_(allocator, schemaStackCapacity),
+ documentStack_(allocator, documentStackCapacity),
+ valid_(true)
+#if RAPIDJSON_SCHEMA_VERBOSE
+ , depth_(0)
+#endif
+ {
+ }
+
+ //! Destructor.
+ ~GenericSchemaValidator() {
+ Reset();
+ RAPIDJSON_DELETE(ownStateAllocator_);
+ }
+
+ //! Reset the internal states.
+ void Reset() {
+ while (!schemaStack_.Empty())
+ PopSchema();
+ documentStack_.Clear();
+ valid_ = true;
+ }
+
+ //! Checks whether the current state is valid.
+ // Implementation of ISchemaValidator
+ virtual bool IsValid() const { return valid_; }
+
+ //! Gets the JSON pointer pointed to the invalid schema.
+ PointerType GetInvalidSchemaPointer() const {
+ return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema());
+ }
+
+ //! Gets the keyword of invalid schema.
+ const Ch* GetInvalidSchemaKeyword() const {
+ return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
+ }
+
+ //! Gets the JSON pointer pointed to the invalid value.
+ PointerType GetInvalidDocumentPointer() const {
+ return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() / sizeof(Ch));
+ }
+
+#if RAPIDJSON_SCHEMA_VERBOSE
+#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \
+RAPIDJSON_MULTILINEMACRO_BEGIN\
+ *documentStack_.template Push<Ch>() = '\0';\
+ documentStack_.template Pop<Ch>(1);\
+ internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\
+RAPIDJSON_MULTILINEMACRO_END
+#else
+#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
+#endif
+
+#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
+ if (!valid_) return false; \
+ if (!BeginValue() || !CurrentSchema().method arg1) {\
+ RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\
+ return valid_ = false;\
+ }
+
+#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
+ for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
+ if (context->hasher)\
+ static_cast<HasherType*>(context->hasher)->method arg2;\
+ if (context->validators)\
+ for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\
+ static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\
+ if (context->patternPropertiesValidators)\
+ for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
+ static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\
+ }
+
+#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
+ return valid_ = EndValue() && outputHandler_.method arg2
+
+#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
+ RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\
+ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
+ RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2)
+
+ bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext() ), ( )); }
+ bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); }
+ bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); }
+ bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); }
+ bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); }
+ bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
+ bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
+ bool String(const Ch* str, SizeType length, bool copy)
+ { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
+
+ bool StartObject() {
+ RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
+ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
+ return valid_ = outputHandler_.StartObject();
+ }
+
+ bool Key(const Ch* str, SizeType len, bool copy) {
+ if (!valid_) return false;
+ AppendToken(str, len);
+ if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false;
+ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
+ return valid_ = outputHandler_.Key(str, len, copy);
+ }
+
+ bool EndObject(SizeType memberCount) {
+ if (!valid_) return false;
+ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
+ if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false;
+ RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
+ }
+
+ bool StartArray() {
+ RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
+ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
+ return valid_ = outputHandler_.StartArray();
+ }
+
+ bool EndArray(SizeType elementCount) {
+ if (!valid_) return false;
+ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
+ if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false;
+ RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
+ }
+
+#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_
+#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
+#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
+#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
+
+ // Implementation of ISchemaStateFactory<SchemaType>
+ virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) {
+ return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root,
+#if RAPIDJSON_SCHEMA_VERBOSE
+ depth_ + 1,
+#endif
+ &GetStateAllocator());
+ }
+
+ virtual void DestroySchemaValidator(ISchemaValidator* validator) {
+ GenericSchemaValidator* v = static_cast<GenericSchemaValidator*>(validator);
+ v->~GenericSchemaValidator();
+ StateAllocator::Free(v);
+ }
+
+ virtual void* CreateHasher() {
+ return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator());
+ }
+
+ virtual uint64_t GetHashCode(void* hasher) {
+ return static_cast<HasherType*>(hasher)->GetHashCode();
+ }
+
+ virtual void DestroryHasher(void* hasher) {
+ HasherType* h = static_cast<HasherType*>(hasher);
+ h->~HasherType();
+ StateAllocator::Free(h);
+ }
+
+ virtual void* MallocState(size_t size) {
+ return GetStateAllocator().Malloc(size);
+ }
+
+ virtual void* ReallocState(void* originalPtr, size_t originalSize, size_t newSize) {
+ return GetStateAllocator().Realloc(originalPtr, originalSize, newSize);
+ }
+
+ virtual void FreeState(void* p) {
+ return StateAllocator::Free(p);
+ }
+
+private:
+ typedef typename SchemaType::Context Context;
+ typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;
+ typedef internal::Hasher<EncodingType, StateAllocator> HasherType;
+
+ GenericSchemaValidator(
+ const SchemaDocumentType& schemaDocument,
+ const SchemaType& root,
+#if RAPIDJSON_SCHEMA_VERBOSE
+ unsigned depth,
+#endif
+ StateAllocator* allocator = 0,
+ size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
+ size_t documentStackCapacity = kDefaultDocumentStackCapacity)
+ :
+ schemaDocument_(&schemaDocument),
+ root_(root),
+ outputHandler_(GetNullHandler()),
+ stateAllocator_(allocator),
+ ownStateAllocator_(0),
+ schemaStack_(allocator, schemaStackCapacity),
+ documentStack_(allocator, documentStackCapacity),
+ valid_(true)
+#if RAPIDJSON_SCHEMA_VERBOSE
+ , depth_(depth)
+#endif
+ {
+ }
+
+ StateAllocator& GetStateAllocator() {
+ if (!stateAllocator_)
+ stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator());
+ return *stateAllocator_;
+ }
+
+ bool BeginValue() {
+ if (schemaStack_.Empty())
+ PushSchema(root_);
+ else {
+ if (CurrentContext().inArray)
+ internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);
+
+ if (!CurrentSchema().BeginValue(CurrentContext()))
+ return false;
+
+ SizeType count = CurrentContext().patternPropertiesSchemaCount;
+ const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
+ typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
+ bool valueUniqueness = CurrentContext().valueUniqueness;
+ if (CurrentContext().valueSchema)
+ PushSchema(*CurrentContext().valueSchema);
+
+ if (count > 0) {
+ CurrentContext().objectPatternValidatorType = patternValidatorType;
+ ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
+ SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
+ va = static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count));
+ for (SizeType i = 0; i < count; i++)
+ va[validatorCount++] = CreateSchemaValidator(*sa[i]);
+ }
+
+ CurrentContext().arrayUniqueness = valueUniqueness;
+ }
+ return true;
+ }
+
+ bool EndValue() {
+ if (!CurrentSchema().EndValue(CurrentContext()))
+ return false;
+
+#if RAPIDJSON_SCHEMA_VERBOSE
+ GenericStringBuffer<EncodingType> sb;
+ schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
+
+ *documentStack_.template Push<Ch>() = '\0';
+ documentStack_.template Pop<Ch>(1);
+ internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());
+#endif
+
+ uint64_t h = CurrentContext().arrayUniqueness ? static_cast<HasherType*>(CurrentContext().hasher)->GetHashCode() : 0;
+
+ PopSchema();
+
+ if (!schemaStack_.Empty()) {
+ Context& context = CurrentContext();
+ if (context.valueUniqueness) {
+ HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);
+ if (!a)
+ CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType);
+ for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)
+ if (itr->GetUint64() == h)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString());
+ a->PushBack(h, GetStateAllocator());
+ }
+ }
+
+ // Remove the last token of document pointer
+ while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/')
+ ;
+
+ return true;
+ }
+
+ void AppendToken(const Ch* str, SizeType len) {
+ documentStack_.template Reserve<Ch>(1 + len * 2); // worst case all characters are escaped as two characters
+ *documentStack_.template PushUnsafe<Ch>() = '/';
+ for (SizeType i = 0; i < len; i++) {
+ if (str[i] == '~') {
+ *documentStack_.template PushUnsafe<Ch>() = '~';
+ *documentStack_.template PushUnsafe<Ch>() = '0';
+ }
+ else if (str[i] == '/') {
+ *documentStack_.template PushUnsafe<Ch>() = '~';
+ *documentStack_.template PushUnsafe<Ch>() = '1';
+ }
+ else
+ *documentStack_.template PushUnsafe<Ch>() = str[i];
+ }
+ }
+
+ RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, &schema); }
+
+ RAPIDJSON_FORCEINLINE void PopSchema() {
+ Context* c = schemaStack_.template Pop<Context>(1);
+ if (HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes)) {
+ a->~HashCodeArray();
+ StateAllocator::Free(a);
+ }
+ c->~Context();
+ }
+
+ const SchemaType& CurrentSchema() const { return *schemaStack_.template Top<Context>()->schema; }
+ Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }
+ const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); }
+
+ static OutputHandler& GetNullHandler() {
+ static OutputHandler nullHandler;
+ return nullHandler;
+ }
+
+ static const size_t kDefaultSchemaStackCapacity = 1024;
+ static const size_t kDefaultDocumentStackCapacity = 256;
+ const SchemaDocumentType* schemaDocument_;
+ const SchemaType& root_;
+ OutputHandler& outputHandler_;
+ StateAllocator* stateAllocator_;
+ StateAllocator* ownStateAllocator_;
+ internal::Stack<StateAllocator> schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *)
+ internal::Stack<StateAllocator> documentStack_; //!< stack to store the current path of validating document (Ch)
+ bool valid_;
+#if RAPIDJSON_SCHEMA_VERBOSE
+ unsigned depth_;
+#endif
+};
+
+typedef GenericSchemaValidator<SchemaDocument> SchemaValidator;
+
+///////////////////////////////////////////////////////////////////////////////
+// SchemaValidatingReader
+
+//! A helper class for parsing with validation.
+/*!
+ This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate().
+
+ \tparam parseFlags Combination of \ref ParseFlag.
+ \tparam InputStream Type of input stream, implementing Stream concept.
+ \tparam SourceEncoding Encoding of the input stream.
+ \tparam SchemaDocumentType Type of schema document.
+ \tparam StackAllocator Allocator type for stack.
+*/
+template <
+ unsigned parseFlags,
+ typename InputStream,
+ typename SourceEncoding,
+ typename SchemaDocumentType = SchemaDocument,
+ typename StackAllocator = CrtAllocator>
+class SchemaValidatingReader {
+public:
+ typedef typename SchemaDocumentType::PointerType PointerType;
+ typedef typename InputStream::Ch Ch;
+
+ //! Constructor
+ /*!
+ \param is Input stream.
+ \param sd Schema document.
+ */
+ SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {}
+
+ template <typename Handler>
+ bool operator()(Handler& handler) {
+ GenericReader<SourceEncoding, typename SchemaDocumentType::EncodingType, StackAllocator> reader;
+ GenericSchemaValidator<SchemaDocumentType, Handler> validator(sd_, handler);
+ parseResult_ = reader.template Parse<parseFlags>(is_, validator);
+
+ if ((isValid_ = validator.IsValid())) {
+ invalidSchemaPointer_ = PointerType();
+ invalidSchemaKeyword_ = 0;
+ invalidDocumentPointer_ = PointerType();
+ }
+ else {
+ invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
+ invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
+ invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
+ }
+
+ return parseResult_;
+ }
+
+ const ParseResult& GetParseResult() const { return parseResult_; }
+ bool IsValid() const { return isValid_; }
+ const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; }
+ const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }
+ const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }
+
+private:
+ InputStream& is_;
+ const SchemaDocumentType& sd_;
+
+ ParseResult parseResult_;
+ PointerType invalidSchemaPointer_;
+ const Ch* invalidSchemaKeyword_;
+ PointerType invalidDocumentPointer_;
+ bool isValid_;
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__GNUC__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_SCHEMA_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/stream.h b/3rdparty/rapidjson/include/rapidjson/stream.h
new file mode 100644
index 00000000000..dd2783b4134
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/stream.h
@@ -0,0 +1,179 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "rapidjson.h"
+
+#ifndef RAPIDJSON_STREAM_H_
+#define RAPIDJSON_STREAM_H_
+
+#include "encodings.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Stream
+
+/*! \class rapidjson::Stream
+ \brief Concept for reading and writing characters.
+
+ For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd().
+
+ For write-only stream, only need to implement Put() and Flush().
+
+\code
+concept Stream {
+ typename Ch; //!< Character type of the stream.
+
+ //! Read the current character from stream without moving the read cursor.
+ Ch Peek() const;
+
+ //! Read the current character from stream and moving the read cursor to next character.
+ Ch Take();
+
+ //! Get the current read cursor.
+ //! \return Number of characters read from start.
+ size_t Tell();
+
+ //! Begin writing operation at the current read pointer.
+ //! \return The begin writer pointer.
+ Ch* PutBegin();
+
+ //! Write a character.
+ void Put(Ch c);
+
+ //! Flush the buffer.
+ void Flush();
+
+ //! End the writing operation.
+ //! \param begin The begin write pointer returned by PutBegin().
+ //! \return Number of characters written.
+ size_t PutEnd(Ch* begin);
+}
+\endcode
+*/
+
+//! Provides additional information for stream.
+/*!
+ By using traits pattern, this type provides a default configuration for stream.
+ For custom stream, this type can be specialized for other configuration.
+ See TEST(Reader, CustomStringStream) in readertest.cpp for example.
+*/
+template<typename Stream>
+struct StreamTraits {
+ //! Whether to make local copy of stream for optimization during parsing.
+ /*!
+ By default, for safety, streams do not use local copy optimization.
+ Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.
+ */
+ enum { copyOptimization = 0 };
+};
+
+//! Reserve n characters for writing to a stream.
+template<typename Stream>
+inline void PutReserve(Stream& stream, size_t count) {
+ (void)stream;
+ (void)count;
+}
+
+//! Write character to a stream, presuming buffer is reserved.
+template<typename Stream>
+inline void PutUnsafe(Stream& stream, typename Stream::Ch c) {
+ stream.Put(c);
+}
+
+//! Put N copies of a character to a stream.
+template<typename Stream, typename Ch>
+inline void PutN(Stream& stream, Ch c, size_t n) {
+ PutReserve<Stream>(stream, n);
+ for (size_t i = 0; i < n; i++)
+ PutUnsafe(stream, c);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// StringStream
+
+//! Read-only string stream.
+/*! \note implements Stream concept
+*/
+template <typename Encoding>
+struct GenericStringStream {
+ typedef typename Encoding::Ch Ch;
+
+ GenericStringStream(const Ch *src) : src_(src), head_(src) {}
+
+ Ch Peek() const { return *src_; }
+ Ch Take() { return *src_++; }
+ size_t Tell() const { return static_cast<size_t>(src_ - head_); }
+
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
+ void Flush() { RAPIDJSON_ASSERT(false); }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+ const Ch* src_; //!< Current read position.
+ const Ch* head_; //!< Original head of the string.
+};
+
+template <typename Encoding>
+struct StreamTraits<GenericStringStream<Encoding> > {
+ enum { copyOptimization = 1 };
+};
+
+//! String stream with UTF8 encoding.
+typedef GenericStringStream<UTF8<> > StringStream;
+
+///////////////////////////////////////////////////////////////////////////////
+// InsituStringStream
+
+//! A read-write string stream.
+/*! This string stream is particularly designed for in-situ parsing.
+ \note implements Stream concept
+*/
+template <typename Encoding>
+struct GenericInsituStringStream {
+ typedef typename Encoding::Ch Ch;
+
+ GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}
+
+ // Read
+ Ch Peek() { return *src_; }
+ Ch Take() { return *src_++; }
+ size_t Tell() { return static_cast<size_t>(src_ - head_); }
+
+ // Write
+ void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
+
+ Ch* PutBegin() { return dst_ = src_; }
+ size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }
+ void Flush() {}
+
+ Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; }
+ void Pop(size_t count) { dst_ -= count; }
+
+ Ch* src_;
+ Ch* dst_;
+ Ch* head_;
+};
+
+template <typename Encoding>
+struct StreamTraits<GenericInsituStringStream<Encoding> > {
+ enum { copyOptimization = 1 };
+};
+
+//! Insitu string stream with UTF8 encoding.
+typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_STREAM_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/stringbuffer.h b/3rdparty/rapidjson/include/rapidjson/stringbuffer.h
new file mode 100644
index 00000000000..78f34d2098e
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/stringbuffer.h
@@ -0,0 +1,117 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_STRINGBUFFER_H_
+#define RAPIDJSON_STRINGBUFFER_H_
+
+#include "stream.h"
+#include "internal/stack.h"
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#include <utility> // std::move
+#endif
+
+#include "internal/stack.h"
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Represents an in-memory output stream.
+/*!
+ \tparam Encoding Encoding of the stream.
+ \tparam Allocator type for allocating memory buffer.
+ \note implements Stream concept
+*/
+template <typename Encoding, typename Allocator = CrtAllocator>
+class GenericStringBuffer {
+public:
+ typedef typename Encoding::Ch Ch;
+
+ GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {}
+ GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {
+ if (&rhs != this)
+ stack_ = std::move(rhs.stack_);
+ return *this;
+ }
+#endif
+
+ void Put(Ch c) { *stack_.template Push<Ch>() = c; }
+ void PutUnsafe(Ch c) { *stack_.template PushUnsafe<Ch>() = c; }
+ void Flush() {}
+
+ void Clear() { stack_.Clear(); }
+ void ShrinkToFit() {
+ // Push and pop a null terminator. This is safe.
+ *stack_.template Push<Ch>() = '\0';
+ stack_.ShrinkToFit();
+ stack_.template Pop<Ch>(1);
+ }
+
+ void Reserve(size_t count) { stack_.template Reserve<Ch>(count); }
+ Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
+ Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe<Ch>(count); }
+ void Pop(size_t count) { stack_.template Pop<Ch>(count); }
+
+ const Ch* GetString() const {
+ // Push and pop a null terminator. This is safe.
+ *stack_.template Push<Ch>() = '\0';
+ stack_.template Pop<Ch>(1);
+
+ return stack_.template Bottom<Ch>();
+ }
+
+ size_t GetSize() const { return stack_.GetSize(); }
+
+ static const size_t kDefaultCapacity = 256;
+ mutable internal::Stack<Allocator> stack_;
+
+private:
+ // Prohibit copy constructor & assignment operator.
+ GenericStringBuffer(const GenericStringBuffer&);
+ GenericStringBuffer& operator=(const GenericStringBuffer&);
+};
+
+//! String buffer with UTF8 encoding
+typedef GenericStringBuffer<UTF8<> > StringBuffer;
+
+template<typename Encoding, typename Allocator>
+inline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) {
+ stream.Reserve(count);
+}
+
+template<typename Encoding, typename Allocator>
+inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) {
+ stream.PutUnsafe(c);
+}
+
+//! Implement specialized version of PutN() with memset() for better performance.
+template<>
+inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
+ std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_STRINGBUFFER_H_
diff --git a/3rdparty/rapidjson/include/rapidjson/writer.h b/3rdparty/rapidjson/include/rapidjson/writer.h
new file mode 100644
index 00000000000..a64c79fe245
--- /dev/null
+++ b/3rdparty/rapidjson/include/rapidjson/writer.h
@@ -0,0 +1,558 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_WRITER_H_
+#define RAPIDJSON_WRITER_H_
+
+#include "stream.h"
+#include "internal/stack.h"
+#include "internal/strfunc.h"
+#include "internal/dtoa.h"
+#include "internal/itoa.h"
+#include "stringbuffer.h"
+#include <new> // placement new
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// WriteFlag
+
+/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS
+ \ingroup RAPIDJSON_CONFIG
+ \brief User-defined kWriteDefaultFlags definition.
+
+ User can define this as any \c WriteFlag combinations.
+*/
+#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
+#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags
+#endif
+
+//! Combination of writeFlags
+enum WriteFlag {
+ kWriteNoFlags = 0, //!< No flags are set.
+ kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.
+ kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS
+};
+
+//! JSON writer
+/*! Writer implements the concept Handler.
+ It generates JSON text by events to an output os.
+
+ User may programmatically calls the functions of a writer to generate JSON text.
+
+ On the other side, a writer can also be passed to objects that generates events,
+
+ for example Reader::Parse() and Document::Accept().
+
+ \tparam OutputStream Type of output stream.
+ \tparam SourceEncoding Encoding of source string.
+ \tparam TargetEncoding Encoding of output stream.
+ \tparam StackAllocator Type of allocator for allocating memory of stack.
+ \note implements Handler concept
+*/
+template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
+class Writer {
+public:
+ typedef typename SourceEncoding::Ch Ch;
+
+ static const int kDefaultMaxDecimalPlaces = 324;
+
+ //! Constructor
+ /*! \param os Output stream.
+ \param stackAllocator User supplied allocator. If it is null, it will create a private one.
+ \param levelDepth Initial capacity of stack.
+ */
+ explicit
+ Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :
+ os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
+
+ explicit
+ Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
+ os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
+
+ //! Reset the writer with a new stream.
+ /*!
+ This function reset the writer with a new stream and default settings,
+ in order to make a Writer object reusable for output multiple JSONs.
+
+ \param os New output stream.
+ \code
+ Writer<OutputStream> writer(os1);
+ writer.StartObject();
+ // ...
+ writer.EndObject();
+
+ writer.Reset(os2);
+ writer.StartObject();
+ // ...
+ writer.EndObject();
+ \endcode
+ */
+ void Reset(OutputStream& os) {
+ os_ = &os;
+ hasRoot_ = false;
+ level_stack_.Clear();
+ }
+
+ //! Checks whether the output is a complete JSON.
+ /*!
+ A complete JSON has a complete root object or array.
+ */
+ bool IsComplete() const {
+ return hasRoot_ && level_stack_.Empty();
+ }
+
+ int GetMaxDecimalPlaces() const {
+ return maxDecimalPlaces_;
+ }
+
+ //! Sets the maximum number of decimal places for double output.
+ /*!
+ This setting truncates the output with specified number of decimal places.
+
+ For example,
+
+ \code
+ writer.SetMaxDecimalPlaces(3);
+ writer.StartArray();
+ writer.Double(0.12345); // "0.123"
+ writer.Double(0.0001); // "0.0"
+ writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent)
+ writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent)
+ writer.EndArray();
+ \endcode
+
+ The default setting does not truncate any decimal places. You can restore to this setting by calling
+ \code
+ writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces);
+ \endcode
+ */
+ void SetMaxDecimalPlaces(int maxDecimalPlaces) {
+ maxDecimalPlaces_ = maxDecimalPlaces;
+ }
+
+ /*!@name Implementation of Handler
+ \see Handler
+ */
+ //@{
+
+ bool Null() { Prefix(kNullType); return WriteNull(); }
+ bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return WriteBool(b); }
+ bool Int(int i) { Prefix(kNumberType); return WriteInt(i); }
+ bool Uint(unsigned u) { Prefix(kNumberType); return WriteUint(u); }
+ bool Int64(int64_t i64) { Prefix(kNumberType); return WriteInt64(i64); }
+ bool Uint64(uint64_t u64) { Prefix(kNumberType); return WriteUint64(u64); }
+
+ //! Writes the given \c double value to the stream
+ /*!
+ \param d The value to be written.
+ \return Whether it is succeed.
+ */
+ bool Double(double d) { Prefix(kNumberType); return WriteDouble(d); }
+
+ bool String(const Ch* str, SizeType length, bool copy = false) {
+ (void)copy;
+ Prefix(kStringType);
+ return WriteString(str, length);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ bool String(const std::basic_string<Ch>& str) {
+ return String(str.data(), SizeType(str.size()));
+ }
+#endif
+
+ bool StartObject() {
+ Prefix(kObjectType);
+ new (level_stack_.template Push<Level>()) Level(false);
+ return WriteStartObject();
+ }
+
+ bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
+
+ bool EndObject(SizeType memberCount = 0) {
+ (void)memberCount;
+ RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
+ RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
+ level_stack_.template Pop<Level>(1);
+ bool ret = WriteEndObject();
+ if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
+ os_->Flush();
+ return ret;
+ }
+
+ bool StartArray() {
+ Prefix(kArrayType);
+ new (level_stack_.template Push<Level>()) Level(true);
+ return WriteStartArray();
+ }
+
+ bool EndArray(SizeType elementCount = 0) {
+ (void)elementCount;
+ RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
+ RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
+ level_stack_.template Pop<Level>(1);
+ bool ret = WriteEndArray();
+ if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
+ os_->Flush();
+ return ret;
+ }
+ //@}
+
+ /*! @name Convenience extensions */
+ //@{
+
+ //! Simpler but slower overload.
+ bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
+ bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
+
+ //@}
+
+ //! Write a raw JSON value.
+ /*!
+ For user to write a stringified JSON as a value.
+
+ \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
+ \param length Length of the json.
+ \param type Type of the root of json.
+ */
+ bool RawValue(const Ch* json, size_t length, Type type) { Prefix(type); return WriteRawValue(json, length); }
+
+protected:
+ //! Information for each nested level
+ struct Level {
+ Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
+ size_t valueCount; //!< number of values in this level
+ bool inArray; //!< true if in array, otherwise in object
+ };
+
+ static const size_t kDefaultLevelDepth = 32;
+
+ bool WriteNull() {
+ PutReserve(*os_, 4);
+ PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
+ }
+
+ bool WriteBool(bool b) {
+ if (b) {
+ PutReserve(*os_, 4);
+ PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e');
+ }
+ else {
+ PutReserve(*os_, 5);
+ PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e');
+ }
+ return true;
+ }
+
+ bool WriteInt(int i) {
+ char buffer[11];
+ const char* end = internal::i32toa(i, buffer);
+ PutReserve(*os_, static_cast<size_t>(end - buffer));
+ for (const char* p = buffer; p != end; ++p)
+ PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+ return true;
+ }
+
+ bool WriteUint(unsigned u) {
+ char buffer[10];
+ const char* end = internal::u32toa(u, buffer);
+ PutReserve(*os_, static_cast<size_t>(end - buffer));
+ for (const char* p = buffer; p != end; ++p)
+ PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+ return true;
+ }
+
+ bool WriteInt64(int64_t i64) {
+ char buffer[21];
+ const char* end = internal::i64toa(i64, buffer);
+ PutReserve(*os_, static_cast<size_t>(end - buffer));
+ for (const char* p = buffer; p != end; ++p)
+ PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+ return true;
+ }
+
+ bool WriteUint64(uint64_t u64) {
+ char buffer[20];
+ char* end = internal::u64toa(u64, buffer);
+ PutReserve(*os_, static_cast<size_t>(end - buffer));
+ for (char* p = buffer; p != end; ++p)
+ PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+ return true;
+ }
+
+ bool WriteDouble(double d) {
+ if (internal::Double(d).IsNanOrInf())
+ return false;
+
+ char buffer[25];
+ char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
+ PutReserve(*os_, static_cast<size_t>(end - buffer));
+ for (char* p = buffer; p != end; ++p)
+ PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+ return true;
+ }
+
+ bool WriteString(const Ch* str, SizeType length) {
+ static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+ static const char escape[256] = {
+#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+ //0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
+ 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
+ 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
+ Z16, Z16, // 30~4F
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
+ Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
+#undef Z16
+ };
+
+ if (TargetEncoding::supportUnicode)
+ PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
+ else
+ PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..."
+
+ PutUnsafe(*os_, '\"');
+ GenericStringStream<SourceEncoding> is(str);
+ while (ScanWriteUnescapedString(is, length)) {
+ const Ch c = is.Peek();
+ if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {
+ // Unicode escaping
+ unsigned codepoint;
+ if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))
+ return false;
+ PutUnsafe(*os_, '\\');
+ PutUnsafe(*os_, 'u');
+ if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
+ PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);
+ PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]);
+ PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]);
+ PutUnsafe(*os_, hexDigits[(codepoint ) & 15]);
+ }
+ else {
+ RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
+ // Surrogate pair
+ unsigned s = codepoint - 0x010000;
+ unsigned lead = (s >> 10) + 0xD800;
+ unsigned trail = (s & 0x3FF) + 0xDC00;
+ PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);
+ PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]);
+ PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]);
+ PutUnsafe(*os_, hexDigits[(lead ) & 15]);
+ PutUnsafe(*os_, '\\');
+ PutUnsafe(*os_, 'u');
+ PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);
+ PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]);
+ PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]);
+ PutUnsafe(*os_, hexDigits[(trail ) & 15]);
+ }
+ }
+ else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) {
+ is.Take();
+ PutUnsafe(*os_, '\\');
+ PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(escape[static_cast<unsigned char>(c)]));
+ if (escape[static_cast<unsigned char>(c)] == 'u') {
+ PutUnsafe(*os_, '0');
+ PutUnsafe(*os_, '0');
+ PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);
+ PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
+ }
+ }
+ else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
+ Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
+ Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
+ return false;
+ }
+ PutUnsafe(*os_, '\"');
+ return true;
+ }
+
+ bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {
+ return RAPIDJSON_LIKELY(is.Tell() < length);
+ }
+
+ bool WriteStartObject() { os_->Put('{'); return true; }
+ bool WriteEndObject() { os_->Put('}'); return true; }
+ bool WriteStartArray() { os_->Put('['); return true; }
+ bool WriteEndArray() { os_->Put(']'); return true; }
+
+ bool WriteRawValue(const Ch* json, size_t length) {
+ PutReserve(*os_, length);
+ for (size_t i = 0; i < length; i++) {
+ RAPIDJSON_ASSERT(json[i] != '\0');
+ PutUnsafe(*os_, json[i]);
+ }
+ return true;
+ }
+
+ void Prefix(Type type) {
+ (void)type;
+ if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
+ Level* level = level_stack_.template Top<Level>();
+ if (level->valueCount > 0) {
+ if (level->inArray)
+ os_->Put(','); // add comma if it is not the first element in array
+ else // in object
+ os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
+ }
+ if (!level->inArray && level->valueCount % 2 == 0)
+ RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
+ level->valueCount++;
+ }
+ else {
+ RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
+ hasRoot_ = true;
+ }
+ }
+
+ OutputStream* os_;
+ internal::Stack<StackAllocator> level_stack_;
+ int maxDecimalPlaces_;
+ bool hasRoot_;
+
+private:
+ // Prohibit copy constructor & assignment operator.
+ Writer(const Writer&);
+ Writer& operator=(const Writer&);
+};
+
+// Full specialization for StringStream to prevent memory copying
+
+template<>
+inline bool Writer<StringBuffer>::WriteInt(int i) {
+ char *buffer = os_->Push(11);
+ const char* end = internal::i32toa(i, buffer);
+ os_->Pop(static_cast<size_t>(11 - (end - buffer)));
+ return true;
+}
+
+template<>
+inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
+ char *buffer = os_->Push(10);
+ const char* end = internal::u32toa(u, buffer);
+ os_->Pop(static_cast<size_t>(10 - (end - buffer)));
+ return true;
+}
+
+template<>
+inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
+ char *buffer = os_->Push(21);
+ const char* end = internal::i64toa(i64, buffer);
+ os_->Pop(static_cast<size_t>(21 - (end - buffer)));
+ return true;
+}
+
+template<>
+inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
+ char *buffer = os_->Push(20);
+ const char* end = internal::u64toa(u, buffer);
+ os_->Pop(static_cast<size_t>(20 - (end - buffer)));
+ return true;
+}
+
+template<>
+inline bool Writer<StringBuffer>::WriteDouble(double d) {
+ if (internal::Double(d).IsNanOrInf())
+ return false;
+
+ char *buffer = os_->Push(25);
+ char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
+ os_->Pop(static_cast<size_t>(25 - (end - buffer)));
+ return true;
+}
+
+#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
+template<>
+inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
+ if (length < 16)
+ return RAPIDJSON_LIKELY(is.Tell() < length);
+
+ if (!RAPIDJSON_LIKELY(is.Tell() < length))
+ return false;
+
+ const char* p = is.src_;
+ const char* end = is.head_ + length;
+ const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
+ if (nextAligned > end)
+ return true;
+
+ while (p != nextAligned)
+ if (*p < 0x20 || *p == '\"' || *p == '\\') {
+ is.src_ = p;
+ return RAPIDJSON_LIKELY(is.Tell() < length);
+ }
+ else
+ os_->PutUnsafe(*p++);
+
+ // The rest of string using SIMD
+ static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
+ static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
+ static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
+ const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
+ const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
+ const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
+
+ for (; p != endAligned; p += 16) {
+ const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
+ const __m128i t1 = _mm_cmpeq_epi8(s, dq);
+ const __m128i t2 = _mm_cmpeq_epi8(s, bs);
+ const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
+ const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
+ unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
+ if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
+ SizeType len;
+#ifdef _MSC_VER // Find the index of first escaped
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ len = offset;
+#else
+ len = static_cast<SizeType>(__builtin_ffs(r) - 1);
+#endif
+ char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
+ for (size_t i = 0; i < len; i++)
+ q[i] = p[i];
+
+ p += len;
+ break;
+ }
+ _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s);
+ }
+
+ is.src_ = p;
+ return RAPIDJSON_LIKELY(is.Tell() < length);
+}
+#endif // defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_RAPIDJSON_H_
diff --git a/3rdparty/rapidjson/library.json b/3rdparty/rapidjson/library.json
new file mode 100644
index 00000000000..47fd352ac7e
--- /dev/null
+++ b/3rdparty/rapidjson/library.json
@@ -0,0 +1,12 @@
+{
+ "name": "RapidJSON",
+ "keywords": "json, sax, dom, parser, generator",
+ "description": "A fast JSON parser/generator for C++ with both SAX/DOM style API",
+ "include": "include",
+ "examples": "example/*/*.cpp",
+ "repository":
+ {
+ "type": "git",
+ "url": "https://github.com/miloyip/rapidjson"
+ }
+}
diff --git a/3rdparty/rapidjson/license.txt b/3rdparty/rapidjson/license.txt
new file mode 100644
index 00000000000..7ccc161c84b
--- /dev/null
+++ b/3rdparty/rapidjson/license.txt
@@ -0,0 +1,57 @@
+Tencent is pleased to support the open source community by making RapidJSON available.
+
+Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+
+If you have downloaded a copy of the RapidJSON binary from Tencent, please note that the RapidJSON binary is licensed under the MIT License.
+If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON. To avoid the problematic JSON license in your own projects, it's sufficient to exclude the bin/jsonchecker/ directory, as it's the only code under the JSON license.
+A copy of the MIT License is included in this file.
+
+Other dependencies and licenses:
+
+Open Source Software Licensed Under the BSD License:
+--------------------------------------------------------------------
+
+The msinttypes r29
+Copyright (c) 2006-2013 Alexander Chemeris
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+* Neither the name of copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Open Source Software Licensed Under the JSON License:
+--------------------------------------------------------------------
+
+json.org
+Copyright (c) 2002 JSON.org
+All Rights Reserved.
+
+JSON_checker
+Copyright (c) 2002 JSON.org
+All Rights Reserved.
+
+
+Terms of the JSON License:
+---------------------------------------------------
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+Terms of the MIT License:
+--------------------------------------------------------------------
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/3rdparty/rapidjson/rapidjson.autopkg b/3rdparty/rapidjson/rapidjson.autopkg
new file mode 100644
index 00000000000..d91aaeff681
--- /dev/null
+++ b/3rdparty/rapidjson/rapidjson.autopkg
@@ -0,0 +1,75 @@
+nuget {
+ //Usage: Write-NuGetPackage rapidjson.autopkg -defines:MYVERSION=1.0.2
+ //Be sure you are running Powershell 3.0 and have the CoApp powershell extensions installed properly.
+ nuspec {
+ id = rapidjson;
+ version : ${MYVERSION};
+ title: "rapidjson";
+ authors: {"https://github.com/miloyip/rapidjson/releases/tag/v1.0.2"};
+ owners: {"@lsantos (github)"};
+ licenseUrl: "https://github.com/miloyip/rapidjson/blob/master/license.txt";
+ projectUrl: "https://github.com/miloyip/rapidjson/";
+ iconUrl: "https://cdn1.iconfinder.com/data/icons/fatcow/32x32/json.png";
+ requireLicenseAcceptance:false;
+ summary: @"A fast JSON parser/generator for C++ with both SAX/DOM style API";
+
+ // if you need to span several lines you can prefix a string with an @ symbol (exactly like c# does).
+ description: @"Rapidjson is an attempt to create the fastest JSON parser and generator.
+
+ - Small but complete. Supports both SAX and DOM style API. SAX parser only a few hundred lines of code.
+ - Fast. In the order of magnitude of strlen(). Optionally supports SSE2/SSE4.2 for acceleration.
+ - Self-contained. Minimal dependency on standard libraries. No BOOST, not even STL.
+ - Compact. Each JSON value is 16 or 20 bytes for 32 or 64-bit machines respectively (excluding text string storage). With the custom memory allocator, parser allocates memory compactly during parsing.
+ - Full RFC4627 compliance. Supports UTF-8, UTF-16 and UTF-32.
+ - Support both in-situ parsing (directly decode strings into the source JSON text) and non-destructive parsing (decode strings into new buffers).
+ - Parse number to int/unsigned/int64_t/uint64_t/double depending on input
+ - Support custom memory allocation. Also, the default memory pool allocator can also be supplied with a user buffer (such as a buffer allocated on user's heap or - programme stack) to minimize allocation.
+
+ As the name implies, rapidjson is inspired by rapidxml.";
+
+ releaseNotes: @"
+Added
+ Add Value::XXXMember(...) overloads for std::string (#335)
+
+Fixed
+ Include rapidjson.h for all internal/error headers.
+ Parsing some numbers incorrectly in full-precision mode (kFullPrecisionParseFlag) (#342)
+ Fix alignment of 64bit platforms (#328)
+ Fix MemoryPoolAllocator::Clear() to clear user-buffer (0691502)
+
+Changed
+ CMakeLists for include as a thirdparty in projects (#334, #337)
+ Change Document::ParseStream() to use stack allocator for Reader (ffbe386)";
+
+ copyright: "Copyright 2015";
+ tags: { native, coapp, JSON, nativepackage };
+ language: en-US;
+ };
+
+ dependencies {
+ packages : {
+ //TODO: Add dependecies here in [pkg.name]/[version] form per newline
+ //zlib/[1.2.8],
+ };
+ }
+
+ // the files that go into the content folders
+ files {
+ #defines {
+ SDK_ROOT = .\;
+ }
+
+ // grab all the files in the include folder
+ // the folder that contains all the .h files will
+ // automatically get added to the Includes path.
+ nestedinclude += {
+ #destination = ${d_include}rapidjson;
+ "${SDK_ROOT}include\rapidjson\**\*.h"
+ };
+ };
+
+ targets {
+ // We're trying to be standard about these sorts of thing. (Will help with config.h later :D)
+ //Defines += HAS_EQCORE;
+ };
+} \ No newline at end of file
diff --git a/3rdparty/rapidjson/readme.md b/3rdparty/rapidjson/readme.md
new file mode 100644
index 00000000000..9a3d6a7b5be
--- /dev/null
+++ b/3rdparty/rapidjson/readme.md
@@ -0,0 +1,129 @@
+![](doc/logo/rapidjson.png)
+
+![](https://img.shields.io/badge/release-v1.0.2-blue.png)
+
+## A fast JSON parser/generator for C++ with both SAX/DOM style API
+
+Tencent is pleased to support the open source community by making RapidJSON available.
+
+Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+
+* [RapidJSON GitHub](https://github.com/miloyip/rapidjson/)
+* RapidJSON Documentation
+ * [English](http://rapidjson.org/)
+ * [简体中文](http://rapidjson.org/zh-cn/)
+ * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) with downloadable PDF/EPUB/MOBI, without API reference.
+
+## Build status
+
+| [Linux][lin-link] | [Windows][win-link] | [Coveralls][cov-link] |
+| :---------------: | :-----------------: | :-------------------: |
+| ![lin-badge] | ![win-badge] | ![cov-badge] |
+
+[lin-badge]: https://travis-ci.org/miloyip/rapidjson.png?branch=master "Travis build status"
+[lin-link]: https://travis-ci.org/miloyip/rapidjson "Travis build status"
+[win-badge]: https://ci.appveyor.com/api/projects/status/u658dcuwxo14a8m9/branch/master "AppVeyor build status"
+[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson/branch/master "AppVeyor build status"
+[cov-badge]: https://coveralls.io/repos/miloyip/rapidjson/badge.png?branch=master
+[cov-link]: https://coveralls.io/r/miloyip/rapidjson?branch=master
+
+## Introduction
+
+RapidJSON is a JSON parser and generator for C++. It was inspired by [RapidXml](http://rapidxml.sourceforge.net/).
+
+* RapidJSON is **small** but **complete**. It supports both SAX and DOM style API. The SAX parser is only a half thousand lines of code.
+
+* RapidJSON is **fast**. Its performance can be comparable to `strlen()`. It also optionally supports SSE2/SSE4.2 for acceleration.
+
+* RapidJSON is **self-contained** and **header-only**. It does not depend on external libraries such as BOOST. It even does not depend on STL.
+
+* RapidJSON is **memory-friendly**. Each JSON value occupies exactly 16/20 bytes for most 32/64-bit machines (excluding text string). By default it uses a fast memory allocator, and the parser allocates memory compactly during parsing.
+
+* RapidJSON is **Unicode-friendly**. It supports UTF-8, UTF-16, UTF-32 (LE & BE), and their detection, validation and transcoding internally. For example, you can read a UTF-8 file and let RapidJSON transcode the JSON strings into UTF-16 in the DOM. It also supports surrogates and "\u0000" (null character).
+
+More features can be read [here](doc/features.md).
+
+JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in fully compliance with RFC7159/ECMA-404. More information about JSON can be obtained at
+* [Introducing JSON](http://json.org/)
+* [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](http://www.ietf.org/rfc/rfc7159.txt)
+* [Standard ECMA-404: The JSON Data Interchange Format](http://www.ecma-international.org/publications/standards/Ecma-404.htm)
+
+## Compatibility
+
+RapidJSON is cross-platform. Some platform/compiler combinations which have been tested are shown as follows.
+* Visual C++ 2008/2010/2013 on Windows (32/64-bit)
+* GNU C++ 3.8.x on Cygwin
+* Clang 3.4 on Mac OS X (32/64-bit) and iOS
+* Clang 3.4 on Android NDK
+
+Users can build and run the unit tests on their platform/compiler.
+
+## Installation
+
+RapidJSON is a header-only C++ library. Just copy the `include/rapidjson` folder to system or project's include path.
+
+RapidJSON uses following software as its dependencies:
+* [CMake](https://cmake.org/) as a general build tool
+* (optional)[Doxygen](http://www.doxygen.org) to build documentation
+* (optional)[googletest](https://github.com/google/googletest) for unit and performance testing
+
+To generate user documentation and run tests please proceed with the steps below:
+
+1. Execute `git submodule update --init` to get the files of thirdparty submodules (google test).
+2. Create directory called `build` in rapidjson source directory.
+3. Change to `build` directory and run `cmake ..` command to configure your build. Windows users can do the same with cmake-gui application.
+4. On Windows, build the solution found in the build directory. On Linux, run `make` from the build directory.
+
+On successfull build you will find compiled test and example binaries in `bin`
+directory. The generated documentation will be available in `doc/html`
+directory of the build tree. To run tests after finished build please run `make
+test` or `ctest` from your build tree. You can get detailed output using `ctest
+-V` command.
+
+It is possible to install library system-wide by running `make install` command
+from the build tree with administrative privileges. This will install all files
+according to system preferences. Once RapidJSON is installed, it is possible
+to use it from other CMake projects by adding `find_package(RapidJSON)` line to
+your CMakeLists.txt.
+
+## Usage at a glance
+
+This simple example parses a JSON string into a document (DOM), make a simple modification of the DOM, and finally stringify the DOM to a JSON string.
+
+~~~~~~~~~~cpp
+// rapidjson/example/simpledom/simpledom.cpp`
+#include "rapidjson/document.h"
+#include "rapidjson/writer.h"
+#include "rapidjson/stringbuffer.h"
+#include <iostream>
+
+using namespace rapidjson;
+
+int main() {
+ // 1. Parse a JSON string into DOM.
+ const char* json = "{\"project\":\"rapidjson\",\"stars\":10}";
+ Document d;
+ d.Parse(json);
+
+ // 2. Modify it by DOM.
+ Value& s = d["stars"];
+ s.SetInt(s.GetInt() + 1);
+
+ // 3. Stringify the DOM
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ d.Accept(writer);
+
+ // Output {"project":"rapidjson","stars":11}
+ std::cout << buffer.GetString() << std::endl;
+ return 0;
+}
+~~~~~~~~~~
+
+Note that this example did not handle potential errors.
+
+The following diagram shows the process.
+
+![simpledom](doc/diagram/simpledom.png)
+
+More [examples](https://github.com/miloyip/rapidjson/tree/master/example) are available.
diff --git a/3rdparty/rapidjson/readme.zh-cn.md b/3rdparty/rapidjson/readme.zh-cn.md
new file mode 100644
index 00000000000..5124f8eedef
--- /dev/null
+++ b/3rdparty/rapidjson/readme.zh-cn.md
@@ -0,0 +1,121 @@
+![](doc/logo/rapidjson.png)
+
+![](https://img.shields.io/badge/release-v1.0.2-blue.png)
+
+## 高效的C++ JSONè§£æžï¼ç”Ÿæˆå™¨ï¼Œæä¾›SAXåŠDOM风格API
+
+Tencent is pleased to support the open source community by making RapidJSON available.
+
+Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+
+* [RapidJSON GitHub](https://github.com/miloyip/rapidjson/)
+* RapidJSON 文档
+ * [English](http://rapidjson.org/)
+ * [简体中文](http://rapidjson.org/zh-cn/)
+ * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/)å¯ä¸‹è½½PDF/EPUB/MOBI,但ä¸å«APIå‚考手册。
+
+## Build 状æ€
+
+| [Linux][lin-link] | [Windows][win-link] | [Coveralls][cov-link] |
+| :---------------: | :-----------------: | :-------------------: |
+| ![lin-badge] | ![win-badge] | ![cov-badge] |
+
+[lin-badge]: https://travis-ci.org/miloyip/rapidjson.png?branch=master "Travis build status"
+[lin-link]: https://travis-ci.org/miloyip/rapidjson "Travis build status"
+[win-badge]: https://ci.appveyor.com/api/projects/status/u658dcuwxo14a8m9/branch/master "AppVeyor build status"
+[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson/branch/master "AppVeyor build status"
+[cov-badge]: https://coveralls.io/repos/miloyip/rapidjson/badge.png?branch=master
+[cov-link]: https://coveralls.io/r/miloyip/rapidjson?branch=master
+
+## 简介
+
+RapidJSON是一个C++çš„JSONè§£æžå™¨åŠç”Ÿæˆå™¨ã€‚å®ƒçš„çµæ„Ÿæ¥è‡ª[RapidXml](http://rapidxml.sourceforge.net/)。
+
+* RapidJSONå°è€Œå…¨ã€‚å®ƒåŒæ—¶æ”¯æŒSAXå’ŒDOM风格的API。SAXè§£æžå™¨åªæœ‰çº¦500行代ç ã€‚
+
+* RapidJSON快。它的性能å¯ä¸Ž`strlen()`ç›¸æ¯”ã€‚å¯æ”¯æŒSSE2/SSE4.2加速。
+
+* RapidJSON独立。它ä¸ä¾èµ–于BOOST等外部库。它甚至ä¸ä¾èµ–于STL。
+
+* RapidJSON对内存å‹å¥½ã€‚在大部分32/64使œºå™¨ä¸Šï¼Œæ¯ä¸ªJSON值åªå 16或20字节(除字符串外)。它预设使用一个快速的内存分é…器,令分æžå™¨å¯ä»¥ç´§å‡‘地分é…内存。
+
+* RapidJSON对Unicodeå‹å¥½ã€‚它支æŒUTF-8ã€UTF-16ã€UTF-32 (大端åºï¼å°ç«¯åº),并内部支æŒè¿™äº›ç¼–ç çš„æ£€æµ‹ã€æ ¡éªŒåŠè½¬ç ã€‚例如,RapidJSONå¯ä»¥åœ¨åˆ†æžä¸€ä¸ªUTF-8文件至DOM时,把当中的JSON字符串转ç è‡³UTF-16。它也支æŒä»£ç†å¯¹ï¼ˆsurrogate pair)åŠ`"\u0000"`(空字符)。
+
+在[这里](doc/features.md)å¯è¯»å–更多特点。
+
+JSON(JavaScript Object Notation)是一个轻é‡çš„æ•°æ®äº¤æ¢æ ¼å¼ã€‚RapidJSON应该完全éµä»ŽRFC7159/ECMA-404。 关于JSON的更多信æ¯å¯å‚考:
+* [Introducing JSON](http://json.org/)
+* [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](http://www.ietf.org/rfc/rfc7159.txt)
+* [Standard ECMA-404: The JSON Data Interchange Format](http://www.ecma-international.org/publications/standards/Ecma-404.htm)
+
+## 兼容性
+
+RapidJSON是跨平å°çš„。以下是一些曾测试的平å°ï¼ç¼–译器组åˆï¼š
+* Visual C++ 2008/2010/2013 在 Windows (32/64-bit)
+* GNU C++ 3.8.x 在 Cygwin
+* Clang 3.4 在 Mac OS X (32/64-bit) åŠ iOS
+* Clang 3.4 在 Android NDK
+
+用户也å¯ä»¥åœ¨ä»–们的平å°ä¸Šç”ŸæˆåŠæ‰§è¡Œå•元测试。
+
+## 安装
+
+RapidJSONæ˜¯åªæœ‰å¤´æ–‡ä»¶çš„C++库。åªéœ€æŠŠ`include/rapidjson`目录å¤åˆ¶è‡³ç³»ç»Ÿæˆ–项目的include目录中。
+
+RapidJSONä¾èµ–于以下软件:
+* [CMake](http://www.cmake.org) 作为通用生æˆå·¥å…·
+* (optional)[Doxygen](http://www.doxygen.org)ç”¨äºŽç”Ÿæˆæ–‡æ¡£
+* (optional)[googletest](https://code.google.com/p/googletest/)用于å•å…ƒåŠæ€§èƒ½æµ‹è¯•
+
+ç”Ÿæˆæµ‹è¯•åŠä¾‹å­çš„æ­¥éª¤ï¼š
+
+1. 执行 `git submodule update --init` åŽ»èŽ·å– thirdparty submodules (google test)。
+2. 在rapidjson目渌下,建立一个`build`目录。
+3. 在`build`目录下执行`cmake ..`命令以设置生æˆã€‚Windows用户å¯ä½¿ç”¨cmake-gui应用程åºã€‚
+4. 在Windows下,编译生æˆåœ¨build目录中的solution。在Linux下,于build目录è¿è¡Œ`make`。
+
+æˆåŠŸç”ŸæˆåŽï¼Œä½ ä¼šåœ¨`bin`的目录下找到编译åŽçš„æµ‹è¯•åŠä¾‹å­å¯æ‰§è¡Œæ–‡ä»¶ã€‚而生æˆçš„æ–‡æ¡£å°†ä½äºŽbuild下的`doc/html`ç›®å½•ã€‚è¦æ‰§è¡Œæµ‹è¯•,请在build下执行`make test`或`ctest`。使用`ctest -V`命令å¯èŽ·å–详细的输出。
+
+我们也å¯ä»¥æŠŠç¨‹åºåº“安装至全系统中,åªè¦åœ¨å…·ç®¡ç†æ¬Šé™ä¸‹ä»Žbuild目录执行`make install`命令。这样会按系统的å好设置安装所有文件。当安装RapidJSONåŽï¼Œå…¶ä»–çš„CMake项目需è¦ä½¿ç”¨å®ƒæ—¶ï¼Œå¯ä»¥é€šè¿‡åœ¨`CMakeLists.txt`加入一å¥`find_package(RapidJSON)`。
+
+## 用法一览
+
+此简å•例å­è§£æžä¸€ä¸ªJSON字符串至一个document (DOM),对DOM作出简å•修改,最终把DOM转æ¢ï¼ˆstringify)至JSON字符串。
+
+~~~~~~~~~~cpp
+// rapidjson/example/simpledom/simpledom.cpp`
+#include "rapidjson/document.h"
+#include "rapidjson/writer.h"
+#include "rapidjson/stringbuffer.h"
+#include <iostream>
+
+using namespace rapidjson;
+
+int main() {
+ // 1. 把JSONè§£æžè‡³DOM。
+ const char* json = "{\"project\":\"rapidjson\",\"stars\":10}";
+ Document d;
+ d.Parse(json);
+
+ // 2. 利用DOM作出修改。
+ Value& s = d["stars"];
+ s.SetInt(s.GetInt() + 1);
+
+ // 3. 把DOM转æ¢ï¼ˆstringify)æˆJSON。
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ d.Accept(writer);
+
+ // Output {"project":"rapidjson","stars":11}
+ std::cout << buffer.GetString() << std::endl;
+ return 0;
+}
+~~~~~~~~~~
+
+æ³¨æ„æ­¤ä¾‹å­å¹¶æ²¡æœ‰å¤„ç†æ½œåœ¨é”™è¯¯ã€‚
+
+下图展示执行过程。
+
+![simpledom](doc/diagram/simpledom.png)
+
+还有许多[例å­](https://github.com/miloyip/rapidjson/tree/master/example)å¯ä¾›å‚考。
diff --git a/3rdparty/rapidjson/test/CMakeLists.txt b/3rdparty/rapidjson/test/CMakeLists.txt
new file mode 100644
index 00000000000..11c1b04c7d1
--- /dev/null
+++ b/3rdparty/rapidjson/test/CMakeLists.txt
@@ -0,0 +1,20 @@
+find_package(GTestSrc)
+
+IF(GTESTSRC_FOUND)
+ enable_testing()
+
+ if (WIN32 AND (NOT CYGWIN) AND (NOT MINGW))
+ set(gtest_disable_pthreads ON)
+ set(gtest_force_shared_crt ON)
+ endif()
+
+ add_subdirectory(${GTEST_SOURCE_DIR} ${CMAKE_BINARY_DIR}/googletest)
+ include_directories(SYSTEM ${GTEST_INCLUDE_DIR})
+
+ set(TEST_LIBRARIES gtest gtest_main)
+
+ add_custom_target(tests ALL)
+ add_subdirectory(perftest)
+ add_subdirectory(unittest)
+
+ENDIF(GTESTSRC_FOUND)
diff --git a/3rdparty/rapidjson/test/perftest/CMakeLists.txt b/3rdparty/rapidjson/test/perftest/CMakeLists.txt
new file mode 100644
index 00000000000..c88cf707451
--- /dev/null
+++ b/3rdparty/rapidjson/test/perftest/CMakeLists.txt
@@ -0,0 +1,17 @@
+set(PERFTEST_SOURCES
+ misctest.cpp
+ perftest.cpp
+ platformtest.cpp
+ rapidjsontest.cpp
+ schematest.cpp)
+
+add_executable(perftest ${PERFTEST_SOURCES})
+target_link_libraries(perftest ${TEST_LIBRARIES})
+
+add_dependencies(tests perftest)
+
+IF(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug"))
+add_test(NAME perftest
+ COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/perftest
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
+ENDIF()
diff --git a/3rdparty/rapidjson/test/perftest/misctest.cpp b/3rdparty/rapidjson/test/perftest/misctest.cpp
new file mode 100644
index 00000000000..aac84778429
--- /dev/null
+++ b/3rdparty/rapidjson/test/perftest/misctest.cpp
@@ -0,0 +1,974 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "perftest.h"
+
+#if TEST_MISC
+
+#define __STDC_FORMAT_MACROS
+#include "rapidjson/stringbuffer.h"
+
+#define protected public
+#include "rapidjson/writer.h"
+#undef private
+
+class Misc : public PerfTest {
+};
+
+// Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
+// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
+
+#define UTF8_ACCEPT 0
+#define UTF8_REJECT 12
+
+static const unsigned char utf8d[] = {
+ // The first part of the table maps bytes to character classes that
+ // to reduce the size of the transition table and create bitmasks.
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
+
+ // The second part is a transition table that maps a combination
+ // of a state of the automaton and a character class to a state.
+ 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
+ 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
+ 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
+ 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
+ 12,36,12,12,12,12,12,12,12,12,12,12,
+};
+
+static unsigned inline decode(unsigned* state, unsigned* codep, unsigned byte) {
+ unsigned type = utf8d[byte];
+
+ *codep = (*state != UTF8_ACCEPT) ?
+ (byte & 0x3fu) | (*codep << 6) :
+ (0xff >> type) & (byte);
+
+ *state = utf8d[256 + *state + type];
+ return *state;
+}
+
+static bool IsUTF8(unsigned char* s) {
+ unsigned codepoint, state = 0;
+
+ while (*s)
+ decode(&state, &codepoint, *s++);
+
+ return state == UTF8_ACCEPT;
+}
+
+TEST_F(Misc, Hoehrmann_IsUTF8) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ EXPECT_TRUE(IsUTF8((unsigned char*)json_));
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CountDecimalDigit: Count number of decimal places
+
+inline unsigned CountDecimalDigit_naive(unsigned n) {
+ unsigned count = 1;
+ while (n >= 10) {
+ n /= 10;
+ count++;
+ }
+ return count;
+}
+
+inline unsigned CountDecimalDigit_enroll4(unsigned n) {
+ unsigned count = 1;
+ while (n >= 10000) {
+ n /= 10000u;
+ count += 4;
+ }
+ if (n < 10) return count;
+ if (n < 100) return count + 1;
+ if (n < 1000) return count + 2;
+ return count + 3;
+}
+
+inline unsigned CountDecimalDigit64_enroll4(uint64_t n) {
+ unsigned count = 1;
+ while (n >= 10000) {
+ n /= 10000u;
+ count += 4;
+ }
+ if (n < 10) return count;
+ if (n < 100) return count + 1;
+ if (n < 1000) return count + 2;
+ return count + 3;
+}
+
+inline unsigned CountDecimalDigit_fast(unsigned n) {
+ static const uint32_t powers_of_10[] = {
+ 0,
+ 10,
+ 100,
+ 1000,
+ 10000,
+ 100000,
+ 1000000,
+ 10000000,
+ 100000000,
+ 1000000000
+ };
+
+#if defined(_M_IX86) || defined(_M_X64)
+ unsigned long i = 0;
+ _BitScanReverse(&i, n | 1);
+ uint32_t t = (i + 1) * 1233 >> 12;
+#elif defined(__GNUC__)
+ uint32_t t = (32 - __builtin_clz(n | 1)) * 1233 >> 12;
+#else
+#error
+#endif
+ return t - (n < powers_of_10[t]) + 1;
+}
+
+inline unsigned CountDecimalDigit64_fast(uint64_t n) {
+ static const uint64_t powers_of_10[] = {
+ 0,
+ 10,
+ 100,
+ 1000,
+ 10000,
+ 100000,
+ 1000000,
+ 10000000,
+ 100000000,
+ 1000000000,
+ 10000000000,
+ 100000000000,
+ 1000000000000,
+ 10000000000000,
+ 100000000000000,
+ 1000000000000000,
+ 10000000000000000,
+ 100000000000000000,
+ 1000000000000000000,
+ 10000000000000000000U
+ };
+
+#if defined(_M_IX86)
+ uint64_t m = n | 1;
+ unsigned long i = 0;
+ if (_BitScanReverse(&i, m >> 32))
+ i += 32;
+ else
+ _BitScanReverse(&i, m & 0xFFFFFFFF);
+ uint32_t t = (i + 1) * 1233 >> 12;
+#elif defined(_M_X64)
+ unsigned long i = 0;
+ _BitScanReverse64(&i, n | 1);
+ uint32_t t = (i + 1) * 1233 >> 12;
+#elif defined(__GNUC__)
+ uint32_t t = (64 - __builtin_clzll(n | 1)) * 1233 >> 12;
+#else
+#error
+#endif
+
+ return t - (n < powers_of_10[t]) + 1;
+}
+
+#if 0
+// Exhaustive, very slow
+TEST_F(Misc, CountDecimalDigit_Verify) {
+ unsigned i = 0;
+ do {
+ if (i % (65536 * 256) == 0)
+ printf("%u\n", i);
+ ASSERT_EQ(CountDecimalDigit_enroll4(i), CountDecimalDigit_fast(i));
+ i++;
+ } while (i != 0);
+}
+
+static const unsigned kDigits10Trial = 1000000000u;
+TEST_F(Misc, CountDecimalDigit_naive) {
+ unsigned sum = 0;
+ for (unsigned i = 0; i < kDigits10Trial; i++)
+ sum += CountDecimalDigit_naive(i);
+ printf("%u\n", sum);
+}
+
+TEST_F(Misc, CountDecimalDigit_enroll4) {
+ unsigned sum = 0;
+ for (unsigned i = 0; i < kDigits10Trial; i++)
+ sum += CountDecimalDigit_enroll4(i);
+ printf("%u\n", sum);
+}
+
+TEST_F(Misc, CountDecimalDigit_fast) {
+ unsigned sum = 0;
+ for (unsigned i = 0; i < kDigits10Trial; i++)
+ sum += CountDecimalDigit_fast(i);
+ printf("%u\n", sum);
+}
+#endif
+
+TEST_F(Misc, CountDecimalDigit64_VerifyFast) {
+ uint64_t i = 1, j;
+ do {
+ //printf("%" PRIu64 "\n", i);
+ ASSERT_EQ(CountDecimalDigit64_enroll4(i), CountDecimalDigit64_fast(i));
+ j = i;
+ i *= 3;
+ } while (j < i);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// integer-to-string conversion
+
+// https://gist.github.com/anonymous/7179097
+static const int randval[] ={
+ 936116, 369532, 453755, -72860, 209713, 268347, 435278, -360266, -416287, -182064,
+ -644712, 944969, 640463, -366588, 471577, -69401, -744294, -505829, 923883, 831785,
+ -601136, -636767, -437054, 591718, 100758, 231907, -719038, 973540, -605220, 506659,
+ -871653, 462533, 764843, -919138, 404305, -630931, -288711, -751454, -173726, -718208,
+ 432689, -281157, 360737, 659827, 19174, -376450, 769984, -858198, 439127, 734703,
+ -683426, 7, 386135, 186997, -643900, -744422, -604708, -629545, 42313, -933592,
+ -635566, 182308, 439024, -367219, -73924, -516649, 421935, -470515, 413507, -78952,
+ -427917, -561158, 737176, 94538, 572322, 405217, 709266, -357278, -908099, -425447,
+ 601119, 750712, -862285, -177869, 900102, 384877, 157859, -641680, 503738, -702558,
+ 278225, 463290, 268378, -212840, 580090, 347346, -473985, -950968, -114547, -839893,
+ -738032, -789424, 409540, 493495, 432099, 119755, 905004, -174834, 338266, 234298,
+ 74641, -965136, -754593, 685273, 466924, 920560, 385062, 796402, -67229, 994864,
+ 376974, 299869, -647540, -128724, 469890, -163167, -547803, -743363, 486463, -621028,
+ 612288, 27459, -514224, 126342, -66612, 803409, -777155, -336453, -284002, 472451,
+ 342390, -163630, 908356, -456147, -825607, 268092, -974715, 287227, 227890, -524101,
+ 616370, -782456, 922098, -624001, -813690, 171605, -192962, 796151, 707183, -95696,
+ -23163, -721260, 508892, 430715, 791331, 482048, -996102, 863274, 275406, -8279,
+ -556239, -902076, 268647, -818565, 260069, -798232, -172924, -566311, -806503, -885992,
+ 813969, -78468, 956632, 304288, 494867, -508784, 381751, 151264, 762953, 76352,
+ 594902, 375424, 271700, -743062, 390176, 924237, 772574, 676610, 435752, -153847,
+ 3959, -971937, -294181, -538049, -344620, -170136, 19120, -703157, 868152, -657961,
+ -818631, 219015, -872729, -940001, -956570, 880727, -345910, 942913, -942271, -788115,
+ 225294, 701108, -517736, -416071, 281940, 488730, 942698, 711494, 838382, -892302,
+ -533028, 103052, 528823, 901515, 949577, 159364, 718227, -241814, -733661, -462928,
+ -495829, 165170, 513580, -629188, -509571, -459083, 198437, 77198, -644612, 811276,
+ -422298, -860842, -52584, 920369, 686424, -530667, -243476, 49763, 345866, -411960,
+ -114863, 470810, -302860, 683007, -509080, 2, -174981, -772163, -48697, 447770,
+ -268246, 213268, 269215, 78810, -236340, -639140, -864323, 505113, -986569, -325215,
+ 541859, 163070, -819998, -645161, -583336, 573414, 696417, -132375, 3, -294501,
+ 320435, 682591, 840008, 351740, 426951, 609354, 898154, -943254, 227321, -859793,
+ -727993, 44137, -497965, -782239, 14955, -746080, -243366, 9837, -233083, 606507,
+ -995864, -615287, -994307, 602715, 770771, -315040, 610860, 446102, -307120, 710728,
+ -590392, -230474, -762625, -637525, 134963, -202700, -766902, -985541, 218163, 682009,
+ 926051, 525156, -61195, 403211, -810098, 245539, -431733, 179998, -806533, 745943,
+ 447597, 131973, -187130, 826019, 286107, -937230, -577419, 20254, 681802, -340500,
+ 323080, 266283, -667617, 309656, 416386, 611863, 759991, -534257, 523112, -634892,
+ -169913, -204905, -909867, -882185, -944908, 741811, -717675, 967007, -317396, 407230,
+ -412805, 792905, 994873, 744793, -456797, 713493, 355232, 116900, -945199, 880539,
+ 342505, -580824, -262273, 982968, -349497, -735488, 311767, -455191, 570918, 389734,
+ -958386, 10262, -99267, 155481, 304210, 204724, 704367, -144893, -233664, -671441,
+ 896849, 408613, 762236, 322697, 981321, 688476, 13663, -970704, -379507, 896412,
+ 977084, 348869, 875948, 341348, 318710, 512081, 6163, 669044, 833295, 811883,
+ 708756, -802534, -536057, 608413, -389625, -694603, 541106, -110037, 720322, -540581,
+ 645420, 32980, 62442, 510157, -981870, -87093, -325960, -500494, -718291, -67889,
+ 991501, 374804, 769026, -978869, 294747, 714623, 413327, -199164, 671368, 804789,
+ -362507, 798196, -170790, -568895, -869379, 62020, -316693, -837793, 644994, -39341,
+ -417504, -243068, -957756, 99072, 622234, -739992, 225668, 8863, -505910, 82483,
+ -559244, 241572, 1315, -36175, -54990, 376813, -11, 162647, -688204, -486163,
+ -54934, -197470, 744223, -762707, 732540, 996618, 351561, -445933, -898491, 486531,
+ 456151, 15276, 290186, -817110, -52995, 313046, -452533, -96267, 94470, -500176,
+ -818026, -398071, -810548, -143325, -819741, 1338, -897676, -101577, -855445, 37309,
+ 285742, 953804, -777927, -926962, -811217, -936744, -952245, -802300, -490188, -964953,
+ -552279, 329142, -570048, -505756, 682898, -381089, -14352, 175138, 152390, -582268,
+ -485137, 717035, 805329, 239572, -730409, 209643, -184403, -385864, 675086, 819648,
+ 629058, -527109, -488666, -171981, 532788, 552441, 174666, 984921, 766514, 758787,
+ 716309, 338801, -978004, -412163, 876079, -734212, 789557, -160491, -522719, 56644,
+ -991, -286038, -53983, 663740, 809812, 919889, -717502, -137704, 220511, 184396,
+ -825740, -588447, 430870, 124309, 135956, 558662, -307087, -788055, -451328, 812260,
+ 931601, 324347, -482989, -117858, -278861, 189068, -172774, 929057, 293787, 198161,
+ -342386, -47173, 906555, -759955, -12779, 777604, -97869, 899320, 927486, -25284,
+ -848550, 259450, -485856, -17820, 88, 171400, 235492, -326783, -340793, 886886,
+ 112428, -246280, 5979, 648444, -114982, 991013, -56489, -9497, 419706, 632820,
+ -341664, 393926, -848977, -22538, 257307, 773731, -905319, 491153, 734883, -868212,
+ -951053, 644458, -580758, 764735, 584316, 297077, 28852, -397710, -953669, 201772,
+ 879050, -198237, -588468, 448102, -116837, 770007, -231812, 642906, -582166, -885828,
+ 9, 305082, -996577, 303559, 75008, -772956, -447960, 599825, -295552, 870739,
+ -386278, -950300, 485359, -457081, 629461, -850276, 550496, -451755, -620841, -11766,
+ -950137, 832337, 28711, -273398, -507197, 91921, -271360, -705991, -753220, -388968,
+ 967945, 340434, -320883, -662793, -554617, -574568, 477946, -6148, -129519, 689217,
+ 920020, -656315, -974523, -212525, 80921, -612532, 645096, 545655, 655713, -591631,
+ -307385, -816688, -618823, -113713, 526430, 673063, 735916, -809095, -850417, 639004,
+ 432281, -388185, 270708, 860146, -39902, -786157, -258180, -246169, -966720, -264957,
+ 548072, -306010, -57367, -635665, 933824, 70553, -989936, -488741, 72411, -452509,
+ 529831, 956277, 449019, -577850, -360986, -803418, 48833, 296073, 203430, 609591,
+ 715483, 470964, 658106, -718254, -96424, 790163, 334739, 181070, -373578, 5,
+ -435088, 329841, 330939, -256602, 394355, 912412, 231910, 927278, -661933, 788539,
+ -769664, -893274, -96856, 298205, 901043, -608122, -527430, 183618, -553963, -35246,
+ -393924, 948832, -483198, 594501, 35460, -407007, 93494, -336881, -634072, 984205,
+ -812161, 944664, -31062, 753872, 823933, -69566, 50445, 290147, 85134, 34706,
+ 551902, 405202, -991246, -84642, 154341, 316432, -695101, -651588, -5030, 137564,
+ -294665, 332541, 528307, -90572, -344923, 523766, -758498, -968047, 339028, 494578,
+ 593129, -725773, 31834, -718406, -208638, 159665, -2043, 673344, -442767, 75816,
+ 755442, 769257, -158730, -410272, 691688, 589550, -878398, -184121, 460679, 346312,
+ 294163, -544602, 653308, 254167, -276979, 52073, -892684, 887653, -41222, 983065,
+ -68258, -408799, -99069, -674069, -863635, -32890, 622757, -743862, 40872, -4837,
+ -967228, 522370, -903951, -818669, 524459, 514702, 925801, 20007, -299229, 579348,
+ 626021, 430089, 348139, -562692, -607728, -130606, -928451, -424793, -458647, -448892,
+ -312230, 143337, 109746, 880042, -339658, -785614, 938995, 540916, 118429, 661351,
+ -402967, 404729, -40918, -976535, 743230, 713110, 440182, -381314, -499252, 74613,
+ 193652, 912717, 491323, 583633, 324691, 459397, 281253, 195540, -2764, -888651,
+ 892449, 132663, -478373, -430002, -314551, 527826, 247165, 557966, 554778, 481531,
+ -946634, 431685, -769059, -348371, 174046, 184597, -354867, 584422, 227390, -850397,
+ -542924, -849093, -737769, 325359, 736314, 269101, 767940, 674809, 81413, -447458,
+ 445076, 189072, 906218, 502688, -718476, -863827, -731381, 100660, 623249, 710008,
+ 572060, 922203, 685740, 55096, 263394, -243695, -353910, -516788, 388471, 455165,
+ 844103, -643772, 363976, 268875, -899450, 104470, 104029, -238874, -274659, 732969,
+ -676443, 953291, -916289, -861849, -242344, 958083, -479593, -970395, 799831, 277841,
+ -243236, -283462, -201510, 166263, -259105, -575706, 878926, 891064, 895297, 655262,
+ -34807, -809833, -89281, 342585, 554920, 1, 902141, -333425, 139703, 852318,
+ -618438, 329498, -932596, -692836, -513372, 733656, -523411, 85779, 500478, -682697,
+ -502836, 138776, 156341, -420037, -557964, -556378, 710993, -50383, -877159, 916334,
+ 132996, 583516, -603392, -111615, -12288, -780214, 476780, 123327, 137607, 519956,
+ 745837, 17358, -158581, -53490
+};
+static const size_t randvalCount = sizeof(randval) / sizeof(randval[0]);
+static const size_t kItoaTrialCount = 10000;
+
+static const char digits[201] =
+"0001020304050607080910111213141516171819"
+"2021222324252627282930313233343536373839"
+"4041424344454647484950515253545556575859"
+"6061626364656667686970717273747576777879"
+"8081828384858687888990919293949596979899";
+
+// Prevent code being optimized out
+//#define OUTPUT_LENGTH(length) printf("", length)
+#define OUTPUT_LENGTH(length) printf("%u\n", (unsigned)length)
+
+template<typename OutputStream>
+class Writer1 {
+public:
+ Writer1() : os_() {}
+ Writer1(OutputStream& os) : os_(&os) {}
+
+ void Reset(OutputStream& os) {
+ os_ = &os;
+ }
+
+ bool WriteInt(int i) {
+ if (i < 0) {
+ os_->Put('-');
+ i = -i;
+ }
+ return WriteUint((unsigned)i);
+ }
+
+ bool WriteUint(unsigned u) {
+ char buffer[10];
+ char *p = buffer;
+ do {
+ *p++ = char(u % 10) + '0';
+ u /= 10;
+ } while (u > 0);
+
+ do {
+ --p;
+ os_->Put(*p);
+ } while (p != buffer);
+ return true;
+ }
+
+ bool WriteInt64(int64_t i64) {
+ if (i64 < 0) {
+ os_->Put('-');
+ i64 = -i64;
+ }
+ WriteUint64((uint64_t)i64);
+ return true;
+ }
+
+ bool WriteUint64(uint64_t u64) {
+ char buffer[20];
+ char *p = buffer;
+ do {
+ *p++ = char(u64 % 10) + '0';
+ u64 /= 10;
+ } while (u64 > 0);
+
+ do {
+ --p;
+ os_->Put(*p);
+ } while (p != buffer);
+ return true;
+ }
+
+private:
+ OutputStream* os_;
+};
+
+template<>
+bool Writer1<rapidjson::StringBuffer>::WriteUint(unsigned u) {
+ char buffer[10];
+ char* p = buffer;
+ do {
+ *p++ = char(u % 10) + '0';
+ u /= 10;
+ } while (u > 0);
+
+ char* d = os_->Push(p - buffer);
+ do {
+ --p;
+ *d++ = *p;
+ } while (p != buffer);
+ return true;
+}
+
+// Using digits LUT to reduce divsion/modulo
+template<typename OutputStream>
+class Writer2 {
+public:
+ Writer2() : os_() {}
+ Writer2(OutputStream& os) : os_(&os) {}
+
+ void Reset(OutputStream& os) {
+ os_ = &os;
+ }
+
+ bool WriteInt(int i) {
+ if (i < 0) {
+ os_->Put('-');
+ i = -i;
+ }
+ return WriteUint((unsigned)i);
+ }
+
+ bool WriteUint(unsigned u) {
+ char buffer[10];
+ char* p = buffer;
+ while (u >= 100) {
+ const unsigned i = (u % 100) << 1;
+ u /= 100;
+ *p++ = digits[i + 1];
+ *p++ = digits[i];
+ }
+ if (u < 10)
+ *p++ = char(u) + '0';
+ else {
+ const unsigned i = u << 1;
+ *p++ = digits[i + 1];
+ *p++ = digits[i];
+ }
+
+ do {
+ --p;
+ os_->Put(*p);
+ } while (p != buffer);
+ return true;
+ }
+
+ bool WriteInt64(int64_t i64) {
+ if (i64 < 0) {
+ os_->Put('-');
+ i64 = -i64;
+ }
+ WriteUint64((uint64_t)i64);
+ return true;
+ }
+
+ bool WriteUint64(uint64_t u64) {
+ char buffer[20];
+ char* p = buffer;
+ while (u64 >= 100) {
+ const unsigned i = static_cast<unsigned>(u64 % 100) << 1;
+ u64 /= 100;
+ *p++ = digits[i + 1];
+ *p++ = digits[i];
+ }
+ if (u64 < 10)
+ *p++ = char(u64) + '0';
+ else {
+ const unsigned i = static_cast<unsigned>(u64) << 1;
+ *p++ = digits[i + 1];
+ *p++ = digits[i];
+ }
+
+ do {
+ --p;
+ os_->Put(*p);
+ } while (p != buffer);
+ return true;
+ }
+
+private:
+ OutputStream* os_;
+};
+
+// First pass to count digits
+template<typename OutputStream>
+class Writer3 {
+public:
+ Writer3() : os_() {}
+ Writer3(OutputStream& os) : os_(&os) {}
+
+ void Reset(OutputStream& os) {
+ os_ = &os;
+ }
+
+ bool WriteInt(int i) {
+ if (i < 0) {
+ os_->Put('-');
+ i = -i;
+ }
+ return WriteUint((unsigned)i);
+ }
+
+ bool WriteUint(unsigned u) {
+ char buffer[10];
+ char *p = buffer;
+ do {
+ *p++ = char(u % 10) + '0';
+ u /= 10;
+ } while (u > 0);
+
+ do {
+ --p;
+ os_->Put(*p);
+ } while (p != buffer);
+ return true;
+ }
+
+ bool WriteInt64(int64_t i64) {
+ if (i64 < 0) {
+ os_->Put('-');
+ i64 = -i64;
+ }
+ WriteUint64((uint64_t)i64);
+ return true;
+ }
+
+ bool WriteUint64(uint64_t u64) {
+ char buffer[20];
+ char *p = buffer;
+ do {
+ *p++ = char(u64 % 10) + '0';
+ u64 /= 10;
+ } while (u64 > 0);
+
+ do {
+ --p;
+ os_->Put(*p);
+ } while (p != buffer);
+ return true;
+ }
+
+private:
+ void WriteUintReverse(char* d, unsigned u) {
+ do {
+ *--d = char(u % 10) + '0';
+ u /= 10;
+ } while (u > 0);
+ }
+
+ void WriteUint64Reverse(char* d, uint64_t u) {
+ do {
+ *--d = char(u % 10) + '0';
+ u /= 10;
+ } while (u > 0);
+ }
+
+ OutputStream* os_;
+};
+
+template<>
+inline bool Writer3<rapidjson::StringBuffer>::WriteUint(unsigned u) {
+ unsigned digit = CountDecimalDigit_fast(u);
+ WriteUintReverse(os_->Push(digit) + digit, u);
+ return true;
+}
+
+template<>
+inline bool Writer3<rapidjson::InsituStringStream>::WriteUint(unsigned u) {
+ unsigned digit = CountDecimalDigit_fast(u);
+ WriteUintReverse(os_->Push(digit) + digit, u);
+ return true;
+}
+
+template<>
+inline bool Writer3<rapidjson::StringBuffer>::WriteUint64(uint64_t u) {
+ unsigned digit = CountDecimalDigit64_fast(u);
+ WriteUint64Reverse(os_->Push(digit) + digit, u);
+ return true;
+}
+
+template<>
+inline bool Writer3<rapidjson::InsituStringStream>::WriteUint64(uint64_t u) {
+ unsigned digit = CountDecimalDigit64_fast(u);
+ WriteUint64Reverse(os_->Push(digit) + digit, u);
+ return true;
+}
+
+// Using digits LUT to reduce divsion/modulo, two passes
+template<typename OutputStream>
+class Writer4 {
+public:
+ Writer4() : os_() {}
+ Writer4(OutputStream& os) : os_(&os) {}
+
+ void Reset(OutputStream& os) {
+ os_ = &os;
+ }
+
+ bool WriteInt(int i) {
+ if (i < 0) {
+ os_->Put('-');
+ i = -i;
+ }
+ return WriteUint((unsigned)i);
+ }
+
+ bool WriteUint(unsigned u) {
+ char buffer[10];
+ char* p = buffer;
+ while (u >= 100) {
+ const unsigned i = (u % 100) << 1;
+ u /= 100;
+ *p++ = digits[i + 1];
+ *p++ = digits[i];
+ }
+ if (u < 10)
+ *p++ = char(u) + '0';
+ else {
+ const unsigned i = u << 1;
+ *p++ = digits[i + 1];
+ *p++ = digits[i];
+ }
+
+ do {
+ --p;
+ os_->Put(*p);
+ } while (p != buffer);
+ return true;
+ }
+
+ bool WriteInt64(int64_t i64) {
+ if (i64 < 0) {
+ os_->Put('-');
+ i64 = -i64;
+ }
+ WriteUint64((uint64_t)i64);
+ return true;
+ }
+
+ bool WriteUint64(uint64_t u64) {
+ char buffer[20];
+ char* p = buffer;
+ while (u64 >= 100) {
+ const unsigned i = static_cast<unsigned>(u64 % 100) << 1;
+ u64 /= 100;
+ *p++ = digits[i + 1];
+ *p++ = digits[i];
+ }
+ if (u64 < 10)
+ *p++ = char(u64) + '0';
+ else {
+ const unsigned i = static_cast<unsigned>(u64) << 1;
+ *p++ = digits[i + 1];
+ *p++ = digits[i];
+ }
+
+ do {
+ --p;
+ os_->Put(*p);
+ } while (p != buffer);
+ return true;
+ }
+
+private:
+ void WriteUintReverse(char* d, unsigned u) {
+ while (u >= 100) {
+ const unsigned i = (u % 100) << 1;
+ u /= 100;
+ *--d = digits[i + 1];
+ *--d = digits[i];
+ }
+ if (u < 10) {
+ *--d = char(u) + '0';
+ }
+ else {
+ const unsigned i = u << 1;
+ *--d = digits[i + 1];
+ *--d = digits[i];
+ }
+ }
+
+ void WriteUint64Reverse(char* d, uint64_t u) {
+ while (u >= 100) {
+ const unsigned i = (u % 100) << 1;
+ u /= 100;
+ *--d = digits[i + 1];
+ *--d = digits[i];
+ }
+ if (u < 10) {
+ *--d = char(u) + '0';
+ }
+ else {
+ const unsigned i = u << 1;
+ *--d = digits[i + 1];
+ *--d = digits[i];
+ }
+ }
+
+ OutputStream* os_;
+};
+
+template<>
+inline bool Writer4<rapidjson::StringBuffer>::WriteUint(unsigned u) {
+ unsigned digit = CountDecimalDigit_fast(u);
+ WriteUintReverse(os_->Push(digit) + digit, u);
+ return true;
+}
+
+template<>
+inline bool Writer4<rapidjson::InsituStringStream>::WriteUint(unsigned u) {
+ unsigned digit = CountDecimalDigit_fast(u);
+ WriteUintReverse(os_->Push(digit) + digit, u);
+ return true;
+}
+
+template<>
+inline bool Writer4<rapidjson::StringBuffer>::WriteUint64(uint64_t u) {
+ unsigned digit = CountDecimalDigit64_fast(u);
+ WriteUint64Reverse(os_->Push(digit) + digit, u);
+ return true;
+}
+
+template<>
+inline bool Writer4<rapidjson::InsituStringStream>::WriteUint64(uint64_t u) {
+ unsigned digit = CountDecimalDigit64_fast(u);
+ WriteUint64Reverse(os_->Push(digit) + digit, u);
+ return true;
+}
+
+template <typename Writer>
+void itoa_Writer_StringBufferVerify() {
+ rapidjson::StringBuffer sb;
+ Writer writer(sb);
+ for (size_t j = 0; j < randvalCount; j++) {
+ char buffer[32];
+ sprintf(buffer, "%d", randval[j]);
+ writer.WriteInt(randval[j]);
+ ASSERT_STREQ(buffer, sb.GetString());
+ sb.Clear();
+ }
+}
+
+template <typename Writer>
+void itoa_Writer_InsituStringStreamVerify() {
+ Writer writer;
+ for (size_t j = 0; j < randvalCount; j++) {
+ char buffer[32];
+ sprintf(buffer, "%d", randval[j]);
+ char buffer2[32];
+ rapidjson::InsituStringStream ss(buffer2);
+ writer.Reset(ss);
+ char* begin = ss.PutBegin();
+ writer.WriteInt(randval[j]);
+ ss.Put('\0');
+ ss.PutEnd(begin);
+ ASSERT_STREQ(buffer, buffer2);
+ }
+}
+
+template <typename Writer>
+void itoa_Writer_StringBuffer() {
+ size_t length = 0;
+
+ rapidjson::StringBuffer sb;
+ Writer writer(sb);
+
+ for (size_t i = 0; i < kItoaTrialCount; i++) {
+ for (size_t j = 0; j < randvalCount; j++) {
+ writer.WriteInt(randval[j]);
+ length += sb.GetSize();
+ sb.Clear();
+ }
+ }
+ OUTPUT_LENGTH(length);
+}
+
+template <typename Writer>
+void itoa_Writer_InsituStringStream() {
+ size_t length = 0;
+
+ char buffer[32];
+ Writer writer;
+ for (size_t i = 0; i < kItoaTrialCount; i++) {
+ for (size_t j = 0; j < randvalCount; j++) {
+ rapidjson::InsituStringStream ss(buffer);
+ writer.Reset(ss);
+ char* begin = ss.PutBegin();
+ writer.WriteInt(randval[j]);
+ length += ss.PutEnd(begin);
+ }
+ }
+ OUTPUT_LENGTH(length);
+};
+
+template <typename Writer>
+void itoa64_Writer_StringBufferVerify() {
+ rapidjson::StringBuffer sb;
+ Writer writer(sb);
+ for (size_t j = 0; j < randvalCount; j++) {
+ char buffer[32];
+ int64_t x = randval[j] * randval[j];
+ sprintf(buffer, "%" PRIi64, x);
+ writer.WriteInt64(x);
+ ASSERT_STREQ(buffer, sb.GetString());
+ sb.Clear();
+ }
+}
+
+template <typename Writer>
+void itoa64_Writer_InsituStringStreamVerify() {
+ Writer writer;
+ for (size_t j = 0; j < randvalCount; j++) {
+ char buffer[32];
+ int64_t x = randval[j] * randval[j];
+ sprintf(buffer, "%" PRIi64, x);
+ char buffer2[32];
+ rapidjson::InsituStringStream ss(buffer2);
+ writer.Reset(ss);
+ char* begin = ss.PutBegin();
+ writer.WriteInt64(x);
+ ss.Put('\0');
+ ss.PutEnd(begin);
+ ASSERT_STREQ(buffer, buffer2);
+ }
+}
+
+template <typename Writer>
+void itoa64_Writer_StringBuffer() {
+ size_t length = 0;
+
+ rapidjson::StringBuffer sb;
+ Writer writer(sb);
+
+ for (size_t i = 0; i < kItoaTrialCount; i++) {
+ for (size_t j = 0; j < randvalCount; j++) {
+ writer.WriteInt64(randval[j] * randval[j]);
+ length += sb.GetSize();
+ sb.Clear();
+ }
+ }
+ OUTPUT_LENGTH(length);
+}
+
+template <typename Writer>
+void itoa64_Writer_InsituStringStream() {
+ size_t length = 0;
+
+ char buffer[32];
+ Writer writer;
+ for (size_t i = 0; i < kItoaTrialCount; i++) {
+ for (size_t j = 0; j < randvalCount; j++) {
+ rapidjson::InsituStringStream ss(buffer);
+ writer.Reset(ss);
+ char* begin = ss.PutBegin();
+ writer.WriteInt64(randval[j] * randval[j]);
+ length += ss.PutEnd(begin);
+ }
+ }
+ OUTPUT_LENGTH(length);
+};
+
+// Full specialization for InsituStringStream to prevent memory copying
+// (normally we will not use InsituStringStream for writing, just for testing)
+
+namespace rapidjson {
+
+template<>
+bool rapidjson::Writer<InsituStringStream>::WriteInt(int i) {
+ char *buffer = os_->Push(11);
+ const char* end = internal::i32toa(i, buffer);
+ os_->Pop(11 - (end - buffer));
+ return true;
+}
+
+template<>
+bool Writer<InsituStringStream>::WriteUint(unsigned u) {
+ char *buffer = os_->Push(10);
+ const char* end = internal::u32toa(u, buffer);
+ os_->Pop(10 - (end - buffer));
+ return true;
+}
+
+template<>
+bool Writer<InsituStringStream>::WriteInt64(int64_t i64) {
+ char *buffer = os_->Push(21);
+ const char* end = internal::i64toa(i64, buffer);
+ os_->Pop(21 - (end - buffer));
+ return true;
+}
+
+template<>
+bool Writer<InsituStringStream>::WriteUint64(uint64_t u) {
+ char *buffer = os_->Push(20);
+ const char* end = internal::u64toa(u, buffer);
+ os_->Pop(20 - (end - buffer));
+ return true;
+}
+
+} // namespace rapidjson
+
+TEST_F(Misc, itoa_Writer_StringBufferVerify) { itoa_Writer_StringBufferVerify<rapidjson::Writer<rapidjson::StringBuffer> >(); }
+TEST_F(Misc, itoa_Writer1_StringBufferVerify) { itoa_Writer_StringBufferVerify<Writer1<rapidjson::StringBuffer> >(); }
+TEST_F(Misc, itoa_Writer2_StringBufferVerify) { itoa_Writer_StringBufferVerify<Writer2<rapidjson::StringBuffer> >(); }
+TEST_F(Misc, itoa_Writer3_StringBufferVerify) { itoa_Writer_StringBufferVerify<Writer3<rapidjson::StringBuffer> >(); }
+TEST_F(Misc, itoa_Writer4_StringBufferVerify) { itoa_Writer_StringBufferVerify<Writer4<rapidjson::StringBuffer> >(); }
+TEST_F(Misc, itoa_Writer_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify<rapidjson::Writer<rapidjson::InsituStringStream> >(); }
+TEST_F(Misc, itoa_Writer1_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify<Writer1<rapidjson::InsituStringStream> >(); }
+TEST_F(Misc, itoa_Writer2_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify<Writer2<rapidjson::InsituStringStream> >(); }
+TEST_F(Misc, itoa_Writer3_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify<Writer3<rapidjson::InsituStringStream> >(); }
+TEST_F(Misc, itoa_Writer4_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify<Writer4<rapidjson::InsituStringStream> >(); }
+TEST_F(Misc, itoa_Writer_StringBuffer) { itoa_Writer_StringBuffer<rapidjson::Writer<rapidjson::StringBuffer> >(); }
+TEST_F(Misc, itoa_Writer1_StringBuffer) { itoa_Writer_StringBuffer<Writer1<rapidjson::StringBuffer> >(); }
+TEST_F(Misc, itoa_Writer2_StringBuffer) { itoa_Writer_StringBuffer<Writer2<rapidjson::StringBuffer> >(); }
+TEST_F(Misc, itoa_Writer3_StringBuffer) { itoa_Writer_StringBuffer<Writer3<rapidjson::StringBuffer> >(); }
+TEST_F(Misc, itoa_Writer4_StringBuffer) { itoa_Writer_StringBuffer<Writer4<rapidjson::StringBuffer> >(); }
+TEST_F(Misc, itoa_Writer_InsituStringStream) { itoa_Writer_InsituStringStream<rapidjson::Writer<rapidjson::InsituStringStream> >(); }
+TEST_F(Misc, itoa_Writer1_InsituStringStream) { itoa_Writer_InsituStringStream<Writer1<rapidjson::InsituStringStream> >(); }
+TEST_F(Misc, itoa_Writer2_InsituStringStream) { itoa_Writer_InsituStringStream<Writer2<rapidjson::InsituStringStream> >(); }
+TEST_F(Misc, itoa_Writer3_InsituStringStream) { itoa_Writer_InsituStringStream<Writer3<rapidjson::InsituStringStream> >(); }
+TEST_F(Misc, itoa_Writer4_InsituStringStream) { itoa_Writer_InsituStringStream<Writer4<rapidjson::InsituStringStream> >(); }
+
+TEST_F(Misc, itoa64_Writer_StringBufferVerify) { itoa64_Writer_StringBufferVerify<rapidjson::Writer<rapidjson::StringBuffer> >(); }
+TEST_F(Misc, itoa64_Writer1_StringBufferVerify) { itoa64_Writer_StringBufferVerify<Writer1<rapidjson::StringBuffer> >(); }
+TEST_F(Misc, itoa64_Writer2_StringBufferVerify) { itoa64_Writer_StringBufferVerify<Writer2<rapidjson::StringBuffer> >(); }
+TEST_F(Misc, itoa64_Writer3_StringBufferVerify) { itoa64_Writer_StringBufferVerify<Writer3<rapidjson::StringBuffer> >(); }
+TEST_F(Misc, itoa64_Writer4_StringBufferVerify) { itoa64_Writer_StringBufferVerify<Writer4<rapidjson::StringBuffer> >(); }
+TEST_F(Misc, itoa64_Writer_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify<rapidjson::Writer<rapidjson::InsituStringStream> >(); }
+TEST_F(Misc, itoa64_Writer1_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify<Writer1<rapidjson::InsituStringStream> >(); }
+TEST_F(Misc, itoa64_Writer2_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify<Writer2<rapidjson::InsituStringStream> >(); }
+TEST_F(Misc, itoa64_Writer3_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify<Writer3<rapidjson::InsituStringStream> >(); }
+TEST_F(Misc, itoa64_Writer4_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify<Writer4<rapidjson::InsituStringStream> >(); }
+TEST_F(Misc, itoa64_Writer_StringBuffer) { itoa64_Writer_StringBuffer<rapidjson::Writer<rapidjson::StringBuffer> >(); }
+TEST_F(Misc, itoa64_Writer1_StringBuffer) { itoa64_Writer_StringBuffer<Writer1<rapidjson::StringBuffer> >(); }
+TEST_F(Misc, itoa64_Writer2_StringBuffer) { itoa64_Writer_StringBuffer<Writer2<rapidjson::StringBuffer> >(); }
+TEST_F(Misc, itoa64_Writer3_StringBuffer) { itoa64_Writer_StringBuffer<Writer3<rapidjson::StringBuffer> >(); }
+TEST_F(Misc, itoa64_Writer4_StringBuffer) { itoa64_Writer_StringBuffer<Writer4<rapidjson::StringBuffer> >(); }
+TEST_F(Misc, itoa64_Writer_InsituStringStream) { itoa64_Writer_InsituStringStream<rapidjson::Writer<rapidjson::InsituStringStream> >(); }
+TEST_F(Misc, itoa64_Writer1_InsituStringStream) { itoa64_Writer_InsituStringStream<Writer1<rapidjson::InsituStringStream> >(); }
+TEST_F(Misc, itoa64_Writer2_InsituStringStream) { itoa64_Writer_InsituStringStream<Writer2<rapidjson::InsituStringStream> >(); }
+TEST_F(Misc, itoa64_Writer3_InsituStringStream) { itoa64_Writer_InsituStringStream<Writer3<rapidjson::InsituStringStream> >(); }
+TEST_F(Misc, itoa64_Writer4_InsituStringStream) { itoa64_Writer_InsituStringStream<Writer4<rapidjson::InsituStringStream> >(); }
+
+#endif // TEST_MISC
diff --git a/3rdparty/rapidjson/test/perftest/perftest.cpp b/3rdparty/rapidjson/test/perftest/perftest.cpp
new file mode 100644
index 00000000000..4e79f1f5180
--- /dev/null
+++ b/3rdparty/rapidjson/test/perftest/perftest.cpp
@@ -0,0 +1,24 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "perftest.h"
+
+int main(int argc, char **argv) {
+#if _MSC_VER
+ _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
+ //void *testWhetherMemoryLeakDetectionWorks = malloc(1);
+#endif
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/3rdparty/rapidjson/test/perftest/perftest.h b/3rdparty/rapidjson/test/perftest/perftest.h
new file mode 100644
index 00000000000..029940934c7
--- /dev/null
+++ b/3rdparty/rapidjson/test/perftest/perftest.h
@@ -0,0 +1,180 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef PERFTEST_H_
+#define PERFTEST_H_
+
+#define TEST_RAPIDJSON 1
+#define TEST_PLATFORM 0
+#define TEST_MISC 0
+
+#define TEST_VERSION_CODE(x,y,z) \
+ (((x)*100000) + ((y)*100) + (z))
+
+// __SSE2__ and __SSE4_2__ are recognized by gcc, clang, and the Intel compiler.
+// We use -march=native with gmake to enable -msse2 and -msse4.2, if supported.
+#if defined(__SSE4_2__)
+# define RAPIDJSON_SSE42
+#elif defined(__SSE2__)
+# define RAPIDJSON_SSE2
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Google Test
+
+#ifdef __cplusplus
+
+// gtest indirectly included inttypes.h, without __STDC_CONSTANT_MACROS.
+#ifndef __STDC_CONSTANT_MACROS
+# define __STDC_CONSTANT_MACROS 1 // required by C++ standard
+#endif
+
+#if defined(__clang__) || defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
+#if defined(__clang__) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+#pragma GCC diagnostic push
+#endif
+#pragma GCC diagnostic ignored "-Weffc++"
+#endif
+
+#include "gtest/gtest.h"
+
+#if defined(__clang__) || defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+#pragma GCC diagnostic pop
+#endif
+
+#ifdef _MSC_VER
+#define _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#pragma warning(disable : 4996) // 'function': was declared deprecated
+#endif
+
+//! Base class for all performance tests
+class PerfTest : public ::testing::Test {
+public:
+ PerfTest() : filename_(), json_(), length_(), whitespace_(), whitespace_length_() {}
+
+ virtual void SetUp() {
+ {
+ const char *paths[] = {
+ "data/sample.json",
+ "bin/data/sample.json",
+ "../bin/data/sample.json",
+ "../../bin/data/sample.json",
+ "../../../bin/data/sample.json"
+ };
+
+ FILE *fp = 0;
+ for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
+ fp = fopen(filename_ = paths[i], "rb");
+ if (fp)
+ break;
+ }
+ ASSERT_TRUE(fp != 0);
+
+ fseek(fp, 0, SEEK_END);
+ length_ = (size_t)ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+ json_ = (char*)malloc(length_ + 1);
+ ASSERT_EQ(length_, fread(json_, 1, length_, fp));
+ json_[length_] = '\0';
+ fclose(fp);
+ }
+
+ // whitespace test
+ {
+ whitespace_length_ = 1024 * 1024;
+ whitespace_ = (char *)malloc(whitespace_length_ + 4);
+ char *p = whitespace_;
+ for (size_t i = 0; i < whitespace_length_; i += 4) {
+ *p++ = ' ';
+ *p++ = '\n';
+ *p++ = '\r';
+ *p++ = '\t';
+ }
+ *p++ = '[';
+ *p++ = '0';
+ *p++ = ']';
+ *p++ = '\0';
+ }
+
+ // types test
+ {
+ const char *typespaths[] = {
+ "data/types",
+ "bin/types",
+ "../bin/types",
+ "../../bin/types/",
+ "../../../bin/types"
+ };
+
+ const char* typesfilenames[] = {
+ "booleans.json",
+ "floats.json",
+ "guids.json",
+ "integers.json",
+ "mixed.json",
+ "nulls.json",
+ "paragraphs.json"
+ };
+
+ for (size_t j = 0; j < sizeof(typesfilenames) / sizeof(typesfilenames[0]); j++) {
+ types_[j] = 0;
+ for (size_t i = 0; i < sizeof(typespaths) / sizeof(typespaths[0]); i++) {
+ char filename[256];
+ sprintf(filename, "%s/%s", typespaths[i], typesfilenames[j]);
+ if (FILE* fp = fopen(filename, "rb")) {
+ fseek(fp, 0, SEEK_END);
+ typesLength_[j] = (size_t)ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+ types_[j] = (char*)malloc(typesLength_[j] + 1);
+ ASSERT_EQ(typesLength_[j], fread(types_[j], 1, typesLength_[j], fp));
+ types_[j][typesLength_[j]] = '\0';
+ fclose(fp);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ virtual void TearDown() {
+ free(json_);
+ free(whitespace_);
+ json_ = 0;
+ whitespace_ = 0;
+ for (size_t i = 0; i < 7; i++) {
+ free(types_[i]);
+ types_[i] = 0;
+ }
+ }
+
+private:
+ PerfTest(const PerfTest&);
+ PerfTest& operator=(const PerfTest&);
+
+protected:
+ const char* filename_;
+ char *json_;
+ size_t length_;
+ char *whitespace_;
+ size_t whitespace_length_;
+ char *types_[7];
+ size_t typesLength_[7];
+
+ static const size_t kTrialCount = 1000;
+};
+
+#endif // __cplusplus
+
+#endif // PERFTEST_H_
diff --git a/3rdparty/rapidjson/test/perftest/platformtest.cpp b/3rdparty/rapidjson/test/perftest/platformtest.cpp
new file mode 100644
index 00000000000..bb905ca73be
--- /dev/null
+++ b/3rdparty/rapidjson/test/perftest/platformtest.cpp
@@ -0,0 +1,166 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "perftest.h"
+
+// This file is for giving the performance characteristics of the platform (compiler/OS/CPU).
+
+#if TEST_PLATFORM
+
+#include <cmath>
+#include <fcntl.h>
+
+// Windows
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+// UNIX
+#if defined(unix) || defined(__unix__) || defined(__unix)
+#include <unistd.h>
+#ifdef _POSIX_MAPPED_FILES
+#include <sys/mman.h>
+#endif
+#endif
+
+class Platform : public PerfTest {
+public:
+ virtual void SetUp() {
+ PerfTest::SetUp();
+
+ // temp buffer for testing
+ temp_ = (char *)malloc(length_ + 1);
+ memcpy(temp_, json_, length_);
+ checkSum_ = CheckSum();
+ }
+
+ char CheckSum() {
+ char c = 0;
+ for (size_t i = 0; i < length_; ++i)
+ c += temp_[i];
+ return c;
+ }
+
+ virtual void TearDown() {
+ PerfTest::TearDown();
+ free(temp_);
+ }
+
+protected:
+ char *temp_;
+ char checkSum_;
+};
+
+TEST_F(Platform, CheckSum) {
+ for (int i = 0; i < kTrialCount; i++)
+ EXPECT_EQ(checkSum_, CheckSum());
+}
+
+TEST_F(Platform, strlen) {
+ for (int i = 0; i < kTrialCount; i++) {
+ size_t l = strlen(json_);
+ EXPECT_EQ(length_, l);
+ }
+}
+
+TEST_F(Platform, memcmp) {
+ for (int i = 0; i < kTrialCount; i++) {
+ EXPECT_EQ(0, memcmp(temp_, json_, length_));
+ }
+}
+
+TEST_F(Platform, pow) {
+ double sum = 0;
+ for (int i = 0; i < kTrialCount * kTrialCount; i++)
+ sum += pow(10.0, i & 255);
+ EXPECT_GT(sum, 0.0);
+}
+
+TEST_F(Platform, Whitespace_strlen) {
+ for (int i = 0; i < kTrialCount; i++) {
+ size_t l = strlen(whitespace_);
+ EXPECT_GT(l, whitespace_length_);
+ }
+}
+
+TEST_F(Platform, Whitespace_strspn) {
+ for (int i = 0; i < kTrialCount; i++) {
+ size_t l = strspn(whitespace_, " \n\r\t");
+ EXPECT_EQ(whitespace_length_, l);
+ }
+}
+
+TEST_F(Platform, fread) {
+ for (int i = 0; i < kTrialCount; i++) {
+ FILE *fp = fopen(filename_, "rb");
+ ASSERT_EQ(length_, fread(temp_, 1, length_, fp));
+ EXPECT_EQ(checkSum_, CheckSum());
+ fclose(fp);
+ }
+}
+
+#ifdef _MSC_VER
+TEST_F(Platform, read) {
+ for (int i = 0; i < kTrialCount; i++) {
+ int fd = _open(filename_, _O_BINARY | _O_RDONLY);
+ ASSERT_NE(-1, fd);
+ ASSERT_EQ(length_, _read(fd, temp_, length_));
+ EXPECT_EQ(checkSum_, CheckSum());
+ _close(fd);
+ }
+}
+#else
+TEST_F(Platform, read) {
+ for (int i = 0; i < kTrialCount; i++) {
+ int fd = open(filename_, O_RDONLY);
+ ASSERT_NE(-1, fd);
+ ASSERT_EQ(length_, read(fd, temp_, length_));
+ EXPECT_EQ(checkSum_, CheckSum());
+ close(fd);
+ }
+}
+#endif
+
+#ifdef _WIN32
+TEST_F(Platform, MapViewOfFile) {
+ for (int i = 0; i < kTrialCount; i++) {
+ HANDLE file = CreateFile(filename_, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ ASSERT_NE(INVALID_HANDLE_VALUE, file);
+ HANDLE mapObject = CreateFileMapping(file, NULL, PAGE_READONLY, 0, length_, NULL);
+ ASSERT_NE(INVALID_HANDLE_VALUE, mapObject);
+ void *p = MapViewOfFile(mapObject, FILE_MAP_READ, 0, 0, length_);
+ ASSERT_TRUE(p != NULL);
+ EXPECT_EQ(checkSum_, CheckSum());
+ ASSERT_TRUE(UnmapViewOfFile(p) == TRUE);
+ ASSERT_TRUE(CloseHandle(mapObject) == TRUE);
+ ASSERT_TRUE(CloseHandle(file) == TRUE);
+ }
+}
+#endif
+
+#ifdef _POSIX_MAPPED_FILES
+TEST_F(Platform, mmap) {
+ for (int i = 0; i < kTrialCount; i++) {
+ int fd = open(filename_, O_RDONLY);
+ ASSERT_NE(-1, fd);
+ void *p = mmap(NULL, length_, PROT_READ, MAP_PRIVATE, fd, 0);
+ ASSERT_TRUE(p != NULL);
+ EXPECT_EQ(checkSum_, CheckSum());
+ munmap(p, length_);
+ close(fd);
+ }
+}
+#endif
+
+#endif // TEST_PLATFORM
diff --git a/3rdparty/rapidjson/test/perftest/rapidjsontest.cpp b/3rdparty/rapidjson/test/perftest/rapidjsontest.cpp
new file mode 100644
index 00000000000..74424ac332b
--- /dev/null
+++ b/3rdparty/rapidjson/test/perftest/rapidjsontest.cpp
@@ -0,0 +1,422 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "perftest.h"
+
+#if TEST_RAPIDJSON
+
+#include "rapidjson/rapidjson.h"
+#include "rapidjson/document.h"
+#include "rapidjson/prettywriter.h"
+#include "rapidjson/stringbuffer.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/encodedstream.h"
+#include "rapidjson/memorystream.h"
+
+#ifdef RAPIDJSON_SSE2
+#define SIMD_SUFFIX(name) name##_SSE2
+#elif defined(RAPIDJSON_SSE42)
+#define SIMD_SUFFIX(name) name##_SSE42
+#else
+#define SIMD_SUFFIX(name) name
+#endif
+
+using namespace rapidjson;
+
+class RapidJson : public PerfTest {
+public:
+ RapidJson() : temp_(), doc_() {}
+
+ virtual void SetUp() {
+ PerfTest::SetUp();
+
+ // temp buffer for insitu parsing.
+ temp_ = (char *)malloc(length_ + 1);
+
+ // Parse as a document
+ EXPECT_FALSE(doc_.Parse(json_).HasParseError());
+
+ for (size_t i = 0; i < 7; i++)
+ EXPECT_FALSE(typesDoc_[i].Parse(types_[i]).HasParseError());
+ }
+
+ virtual void TearDown() {
+ PerfTest::TearDown();
+ free(temp_);
+ }
+
+private:
+ RapidJson(const RapidJson&);
+ RapidJson& operator=(const RapidJson&);
+
+protected:
+ char *temp_;
+ Document doc_;
+ Document typesDoc_[7];
+};
+
+TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseInsitu_DummyHandler)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ memcpy(temp_, json_, length_ + 1);
+ InsituStringStream s(temp_);
+ BaseReaderHandler<> h;
+ Reader reader;
+ EXPECT_TRUE(reader.Parse<kParseInsituFlag>(s, h));
+ }
+}
+
+TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseInsitu_DummyHandler_ValidateEncoding)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ memcpy(temp_, json_, length_ + 1);
+ InsituStringStream s(temp_);
+ BaseReaderHandler<> h;
+ Reader reader;
+ EXPECT_TRUE(reader.Parse<kParseInsituFlag | kParseValidateEncodingFlag>(s, h));
+ }
+}
+
+TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ StringStream s(json_);
+ BaseReaderHandler<> h;
+ Reader reader;
+ EXPECT_TRUE(reader.Parse(s, h));
+ }
+}
+
+#define TEST_TYPED(index, Name)\
+TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_##Name)) {\
+ for (size_t i = 0; i < kTrialCount * 10; i++) {\
+ StringStream s(types_[index]);\
+ BaseReaderHandler<> h;\
+ Reader reader;\
+ EXPECT_TRUE(reader.Parse(s, h));\
+ }\
+}\
+TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseInsitu_DummyHandler_##Name)) {\
+ for (size_t i = 0; i < kTrialCount * 10; i++) {\
+ memcpy(temp_, types_[index], typesLength_[index] + 1);\
+ InsituStringStream s(temp_);\
+ BaseReaderHandler<> h;\
+ Reader reader;\
+ EXPECT_TRUE(reader.Parse<kParseInsituFlag>(s, h));\
+ }\
+}
+
+TEST_TYPED(0, Booleans)
+TEST_TYPED(1, Floats)
+TEST_TYPED(2, Guids)
+TEST_TYPED(3, Integers)
+TEST_TYPED(4, Mixed)
+TEST_TYPED(5, Nulls)
+TEST_TYPED(6, Paragraphs)
+
+#undef TEST_TYPED
+
+TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FullPrecision)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ StringStream s(json_);
+ BaseReaderHandler<> h;
+ Reader reader;
+ EXPECT_TRUE(reader.Parse<kParseFullPrecisionFlag>(s, h));
+ }
+}
+
+TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseIterative_DummyHandler)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ StringStream s(json_);
+ BaseReaderHandler<> h;
+ Reader reader;
+ EXPECT_TRUE(reader.Parse<kParseIterativeFlag>(s, h));
+ }
+}
+
+TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseIterativeInsitu_DummyHandler)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ memcpy(temp_, json_, length_ + 1);
+ InsituStringStream s(temp_);
+ BaseReaderHandler<> h;
+ Reader reader;
+ EXPECT_TRUE(reader.Parse<kParseIterativeFlag|kParseInsituFlag>(s, h));
+ }
+}
+
+TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_ValidateEncoding)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ StringStream s(json_);
+ BaseReaderHandler<> h;
+ Reader reader;
+ EXPECT_TRUE(reader.Parse<kParseValidateEncodingFlag>(s, h));
+ }
+}
+
+TEST_F(RapidJson, SIMD_SUFFIX(DocumentParseInsitu_MemoryPoolAllocator)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ memcpy(temp_, json_, length_ + 1);
+ Document doc;
+ doc.ParseInsitu(temp_);
+ ASSERT_TRUE(doc.IsObject());
+ }
+}
+
+TEST_F(RapidJson, SIMD_SUFFIX(DocumentParseIterativeInsitu_MemoryPoolAllocator)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ memcpy(temp_, json_, length_ + 1);
+ Document doc;
+ doc.ParseInsitu<kParseIterativeFlag>(temp_);
+ ASSERT_TRUE(doc.IsObject());
+ }
+}
+
+TEST_F(RapidJson, SIMD_SUFFIX(DocumentParse_MemoryPoolAllocator)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ Document doc;
+ doc.Parse(json_);
+ ASSERT_TRUE(doc.IsObject());
+ }
+}
+
+TEST_F(RapidJson, SIMD_SUFFIX(DocumentParseIterative_MemoryPoolAllocator)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ Document doc;
+ doc.Parse<kParseIterativeFlag>(json_);
+ ASSERT_TRUE(doc.IsObject());
+ }
+}
+
+TEST_F(RapidJson, SIMD_SUFFIX(DocumentParse_CrtAllocator)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ memcpy(temp_, json_, length_ + 1);
+ GenericDocument<UTF8<>, CrtAllocator> doc;
+ doc.Parse(temp_);
+ ASSERT_TRUE(doc.IsObject());
+ }
+}
+
+TEST_F(RapidJson, SIMD_SUFFIX(DocumentParseEncodedInputStream_MemoryStream)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ MemoryStream ms(json_, length_);
+ EncodedInputStream<UTF8<>, MemoryStream> is(ms);
+ Document doc;
+ doc.ParseStream<0, UTF8<> >(is);
+ ASSERT_TRUE(doc.IsObject());
+ }
+}
+
+TEST_F(RapidJson, SIMD_SUFFIX(DocumentParseAutoUTFInputStream_MemoryStream)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ MemoryStream ms(json_, length_);
+ AutoUTFInputStream<unsigned, MemoryStream> is(ms);
+ Document doc;
+ doc.ParseStream<0, AutoUTF<unsigned> >(is);
+ ASSERT_TRUE(doc.IsObject());
+ }
+}
+
+template<typename T>
+size_t Traverse(const T& value) {
+ size_t count = 1;
+ switch(value.GetType()) {
+ case kObjectType:
+ for (typename T::ConstMemberIterator itr = value.MemberBegin(); itr != value.MemberEnd(); ++itr) {
+ count++; // name
+ count += Traverse(itr->value);
+ }
+ break;
+
+ case kArrayType:
+ for (typename T::ConstValueIterator itr = value.Begin(); itr != value.End(); ++itr)
+ count += Traverse(*itr);
+ break;
+
+ default:
+ // Do nothing.
+ break;
+ }
+ return count;
+}
+
+TEST_F(RapidJson, DocumentTraverse) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ size_t count = Traverse(doc_);
+ EXPECT_EQ(4339u, count);
+ //if (i == 0)
+ // std::cout << count << std::endl;
+ }
+}
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+struct ValueCounter : public BaseReaderHandler<> {
+ ValueCounter() : count_(1) {} // root
+
+ bool EndObject(SizeType memberCount) { count_ += memberCount * 2; return true; }
+ bool EndArray(SizeType elementCount) { count_ += elementCount; return true; }
+
+ SizeType count_;
+};
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+TEST_F(RapidJson, DocumentAccept) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ ValueCounter counter;
+ doc_.Accept(counter);
+ EXPECT_EQ(4339u, counter.count_);
+ }
+}
+
+struct NullStream {
+ typedef char Ch;
+
+ NullStream() /*: length_(0)*/ {}
+ void Put(Ch) { /*++length_;*/ }
+ void Flush() {}
+ //size_t length_;
+};
+
+TEST_F(RapidJson, Writer_NullStream) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ NullStream s;
+ Writer<NullStream> writer(s);
+ doc_.Accept(writer);
+ //if (i == 0)
+ // std::cout << s.length_ << std::endl;
+ }
+}
+
+TEST_F(RapidJson, SIMD_SUFFIX(Writer_StringBuffer)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ StringBuffer s(0, 1024 * 1024);
+ Writer<StringBuffer> writer(s);
+ doc_.Accept(writer);
+ const char* str = s.GetString();
+ (void)str;
+ //if (i == 0)
+ // std::cout << strlen(str) << std::endl;
+ }
+}
+
+#define TEST_TYPED(index, Name)\
+TEST_F(RapidJson, SIMD_SUFFIX(Writer_StringBuffer_##Name)) {\
+ for (size_t i = 0; i < kTrialCount * 10; i++) {\
+ StringBuffer s(0, 1024 * 1024);\
+ Writer<StringBuffer> writer(s);\
+ typesDoc_[index].Accept(writer);\
+ const char* str = s.GetString();\
+ (void)str;\
+ }\
+}
+
+TEST_TYPED(0, Booleans)
+TEST_TYPED(1, Floats)
+TEST_TYPED(2, Guids)
+TEST_TYPED(3, Integers)
+TEST_TYPED(4, Mixed)
+TEST_TYPED(5, Nulls)
+TEST_TYPED(6, Paragraphs)
+
+#undef TEST_TYPED
+
+TEST_F(RapidJson, SIMD_SUFFIX(PrettyWriter_StringBuffer)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ StringBuffer s(0, 2048 * 1024);
+ PrettyWriter<StringBuffer> writer(s);
+ writer.SetIndent(' ', 1);
+ doc_.Accept(writer);
+ const char* str = s.GetString();
+ (void)str;
+ //if (i == 0)
+ // std::cout << strlen(str) << std::endl;
+ }
+}
+
+TEST_F(RapidJson, internal_Pow10) {
+ double sum = 0;
+ for (size_t i = 0; i < kTrialCount * kTrialCount; i++)
+ sum += internal::Pow10(int(i & 255));
+ EXPECT_GT(sum, 0.0);
+}
+
+TEST_F(RapidJson, SkipWhitespace_Basic) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ rapidjson::StringStream s(whitespace_);
+ while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
+ s.Take();
+ ASSERT_EQ('[', s.Peek());
+ }
+}
+
+TEST_F(RapidJson, SIMD_SUFFIX(SkipWhitespace)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ rapidjson::StringStream s(whitespace_);
+ rapidjson::SkipWhitespace(s);
+ ASSERT_EQ('[', s.Peek());
+ }
+}
+
+TEST_F(RapidJson, SkipWhitespace_strspn) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ const char* s = whitespace_ + std::strspn(whitespace_, " \t\r\n");
+ ASSERT_EQ('[', *s);
+ }
+}
+
+TEST_F(RapidJson, UTF8_Validate) {
+ NullStream os;
+
+ for (size_t i = 0; i < kTrialCount; i++) {
+ StringStream is(json_);
+ bool result = true;
+ while (is.Peek() != '\0')
+ result &= UTF8<>::Validate(is, os);
+ EXPECT_TRUE(result);
+ }
+}
+
+TEST_F(RapidJson, FileReadStream) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ FILE *fp = fopen(filename_, "rb");
+ char buffer[65536];
+ FileReadStream s(fp, buffer, sizeof(buffer));
+ while (s.Take() != '\0')
+ ;
+ fclose(fp);
+ }
+}
+
+TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FileReadStream)) {
+ for (size_t i = 0; i < kTrialCount; i++) {
+ FILE *fp = fopen(filename_, "rb");
+ char buffer[65536];
+ FileReadStream s(fp, buffer, sizeof(buffer));
+ BaseReaderHandler<> h;
+ Reader reader;
+ reader.Parse(s, h);
+ fclose(fp);
+ }
+}
+
+TEST_F(RapidJson, StringBuffer) {
+ StringBuffer sb;
+ for (int i = 0; i < 32 * 1024 * 1024; i++)
+ sb.Put(i & 0x7f);
+}
+
+#endif // TEST_RAPIDJSON
diff --git a/3rdparty/rapidjson/test/perftest/schematest.cpp b/3rdparty/rapidjson/test/perftest/schematest.cpp
new file mode 100644
index 00000000000..468f5fe6f6a
--- /dev/null
+++ b/3rdparty/rapidjson/test/perftest/schematest.cpp
@@ -0,0 +1,216 @@
+#include "perftest.h"
+
+#if TEST_RAPIDJSON
+
+#include "rapidjson/schema.h"
+#include <ctime>
+#include <string>
+#include <vector>
+
+#define ARRAY_SIZE(a) sizeof(a) / sizeof(a[0])
+
+using namespace rapidjson;
+
+template <typename Allocator>
+static char* ReadFile(const char* filename, Allocator& allocator) {
+ const char *paths[] = {
+ "",
+ "bin/",
+ "../bin/",
+ "../../bin/",
+ "../../../bin/"
+ };
+ char buffer[1024];
+ FILE *fp = 0;
+ for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
+ sprintf(buffer, "%s%s", paths[i], filename);
+ fp = fopen(buffer, "rb");
+ if (fp)
+ break;
+ }
+
+ if (!fp)
+ return 0;
+
+ fseek(fp, 0, SEEK_END);
+ size_t length = static_cast<size_t>(ftell(fp));
+ fseek(fp, 0, SEEK_SET);
+ char* json = reinterpret_cast<char*>(allocator.Malloc(length + 1));
+ size_t readLength = fread(json, 1, length, fp);
+ json[readLength] = '\0';
+ fclose(fp);
+ return json;
+}
+
+class Schema : public PerfTest {
+public:
+ Schema() {}
+
+ virtual void SetUp() {
+ PerfTest::SetUp();
+
+ const char* filenames[] = {
+ "additionalItems.json",
+ "additionalProperties.json",
+ "allOf.json",
+ "anyOf.json",
+ "default.json",
+ "definitions.json",
+ "dependencies.json",
+ "enum.json",
+ "items.json",
+ "maximum.json",
+ "maxItems.json",
+ "maxLength.json",
+ "maxProperties.json",
+ "minimum.json",
+ "minItems.json",
+ "minLength.json",
+ "minProperties.json",
+ "multipleOf.json",
+ "not.json",
+ "oneOf.json",
+ "pattern.json",
+ "patternProperties.json",
+ "properties.json",
+ "ref.json",
+ "refRemote.json",
+ "required.json",
+ "type.json",
+ "uniqueItems.json"
+ };
+
+ char jsonBuffer[65536];
+ MemoryPoolAllocator<> jsonAllocator(jsonBuffer, sizeof(jsonBuffer));
+
+ for (size_t i = 0; i < ARRAY_SIZE(filenames); i++) {
+ char filename[FILENAME_MAX];
+ sprintf(filename, "jsonschema/tests/draft4/%s", filenames[i]);
+ char* json = ReadFile(filename, jsonAllocator);
+ if (!json) {
+ printf("json test suite file %s not found", filename);
+ return;
+ }
+
+ Document d;
+ d.Parse(json);
+ if (d.HasParseError()) {
+ printf("json test suite file %s has parse error", filename);
+ return;
+ }
+
+ for (Value::ConstValueIterator schemaItr = d.Begin(); schemaItr != d.End(); ++schemaItr) {
+ std::string schemaDescription = (*schemaItr)["description"].GetString();
+ if (IsExcludeTestSuite(schemaDescription))
+ continue;
+
+ TestSuite* ts = new TestSuite;
+ ts->schema = new SchemaDocument((*schemaItr)["schema"]);
+
+ const Value& tests = (*schemaItr)["tests"];
+ for (Value::ConstValueIterator testItr = tests.Begin(); testItr != tests.End(); ++testItr) {
+ if (IsExcludeTest(schemaDescription + ", " + (*testItr)["description"].GetString()))
+ continue;
+
+ Document* d2 = new Document;
+ d2->CopyFrom((*testItr)["data"], d2->GetAllocator());
+ ts->tests.push_back(d2);
+ }
+ testSuites.push_back(ts);
+ }
+ }
+ }
+
+ virtual void TearDown() {
+ PerfTest::TearDown();
+ for (TestSuiteList::const_iterator itr = testSuites.begin(); itr != testSuites.end(); ++itr)
+ delete *itr;
+ testSuites.clear();
+ }
+
+private:
+ // Using the same exclusion in https://github.com/json-schema/JSON-Schema-Test-Suite
+ static bool IsExcludeTestSuite(const std::string& description) {
+ const char* excludeTestSuites[] = {
+ //lost failing these tests
+ "remote ref",
+ "remote ref, containing refs itself",
+ "fragment within remote ref",
+ "ref within remote ref",
+ "change resolution scope",
+ // these below were added to get jsck in the benchmarks)
+ "uniqueItems validation",
+ "valid definition",
+ "invalid definition"
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE(excludeTestSuites); i++)
+ if (excludeTestSuites[i] == description)
+ return true;
+ return false;
+ }
+
+ // Using the same exclusion in https://github.com/json-schema/JSON-Schema-Test-Suite
+ static bool IsExcludeTest(const std::string& description) {
+ const char* excludeTests[] = {
+ //lots of validators fail these
+ "invalid definition, invalid definition schema",
+ "maxLength validation, two supplementary Unicode code points is long enough",
+ "minLength validation, one supplementary Unicode code point is not long enough",
+ //this is to get tv4 in the benchmarks
+ "heterogeneous enum validation, something else is invalid"
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE(excludeTests); i++)
+ if (excludeTests[i] == description)
+ return true;
+ return false;
+ }
+
+ Schema(const Schema&);
+ Schema& operator=(const Schema&);
+
+protected:
+ typedef std::vector<Document*> DocumentList;
+
+ struct TestSuite {
+ TestSuite() : schema() {}
+ ~TestSuite() {
+ delete schema;
+ for (DocumentList::iterator itr = tests.begin(); itr != tests.end(); ++itr)
+ delete *itr;
+ }
+ SchemaDocument* schema;
+ DocumentList tests;
+ };
+
+ typedef std::vector<TestSuite* > TestSuiteList;
+ TestSuiteList testSuites;
+};
+
+TEST_F(Schema, TestSuite) {
+ char validatorBuffer[65536];
+ MemoryPoolAllocator<> validatorAllocator(validatorBuffer, sizeof(validatorBuffer));
+
+ const int trialCount = 100000;
+ int testCount = 0;
+ clock_t start = clock();
+ for (int i = 0; i < trialCount; i++) {
+ for (TestSuiteList::const_iterator itr = testSuites.begin(); itr != testSuites.end(); ++itr) {
+ const TestSuite& ts = **itr;
+ GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > validator(*ts.schema, &validatorAllocator);
+ for (DocumentList::const_iterator testItr = ts.tests.begin(); testItr != ts.tests.end(); ++testItr) {
+ validator.Reset();
+ (*testItr)->Accept(validator);
+ testCount++;
+ }
+ validatorAllocator.Clear();
+ }
+ }
+ clock_t end = clock();
+ double duration = double(end - start) / CLOCKS_PER_SEC;
+ printf("%d trials in %f s -> %f trials per sec\n", trialCount, duration, trialCount / duration);
+ printf("%d tests per trial\n", testCount / trialCount);
+}
+
+#endif
diff --git a/3rdparty/rapidjson/test/unittest/CMakeLists.txt b/3rdparty/rapidjson/test/unittest/CMakeLists.txt
new file mode 100644
index 00000000000..0ae166282e5
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/CMakeLists.txt
@@ -0,0 +1,61 @@
+set(UNITTEST_SOURCES
+ allocatorstest.cpp
+ bigintegertest.cpp
+ documenttest.cpp
+ dtoatest.cpp
+ encodedstreamtest.cpp
+ encodingstest.cpp
+ fwdtest.cpp
+ filestreamtest.cpp
+ itoatest.cpp
+ istreamwrappertest.cpp
+ jsoncheckertest.cpp
+ namespacetest.cpp
+ pointertest.cpp
+ prettywritertest.cpp
+ ostreamwrappertest.cpp
+ readertest.cpp
+ regextest.cpp
+ schematest.cpp
+ simdtest.cpp
+ strfunctest.cpp
+ stringbuffertest.cpp
+ strtodtest.cpp
+ unittest.cpp
+ valuetest.cpp
+ writertest.cpp)
+
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal")
+elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal -Wimplicit-fallthrough -Weverything")
+elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
+endif()
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DRAPIDJSON_HAS_STDSTRING=1")
+
+add_library(namespacetest STATIC namespacetest.cpp)
+
+add_executable(unittest ${UNITTEST_SOURCES})
+target_link_libraries(unittest ${TEST_LIBRARIES} namespacetest)
+
+add_dependencies(tests unittest)
+
+add_test(NAME unittest
+ COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unittest
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
+
+if(NOT MSVC)
+ # Not running SIMD.* unit test cases for Valgrind
+ add_test(NAME valgrind_unittest
+ COMMAND valgrind --leak-check=full --error-exitcode=1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unittest --gtest_filter=-SIMD.*
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
+
+ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ add_test(NAME symbol_check
+ COMMAND sh -c "objdump -t -C libnamespacetest.a | grep rapidjson ; test $? -ne 0"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ endif(CMAKE_BUILD_TYPE STREQUAL "Debug")
+
+endif(NOT MSVC)
diff --git a/3rdparty/rapidjson/test/unittest/allocatorstest.cpp b/3rdparty/rapidjson/test/unittest/allocatorstest.cpp
new file mode 100644
index 00000000000..a5958de199e
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/allocatorstest.cpp
@@ -0,0 +1,102 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+
+#include "rapidjson/allocators.h"
+
+using namespace rapidjson;
+
+template <typename Allocator>
+void TestAllocator(Allocator& a) {
+ EXPECT_TRUE(a.Malloc(0) == 0);
+
+ uint8_t* p = static_cast<uint8_t*>(a.Malloc(100));
+ EXPECT_TRUE(p != 0);
+ for (size_t i = 0; i < 100; i++)
+ p[i] = static_cast<uint8_t>(i);
+
+ // Expand
+ uint8_t* q = static_cast<uint8_t*>(a.Realloc(p, 100, 200));
+ EXPECT_TRUE(q != 0);
+ for (size_t i = 0; i < 100; i++)
+ EXPECT_EQ(i, q[i]);
+ for (size_t i = 100; i < 200; i++)
+ q[i] = static_cast<uint8_t>(i);
+
+ // Shrink
+ uint8_t *r = static_cast<uint8_t*>(a.Realloc(q, 200, 150));
+ EXPECT_TRUE(r != 0);
+ for (size_t i = 0; i < 150; i++)
+ EXPECT_EQ(i, r[i]);
+
+ Allocator::Free(r);
+
+ // Realloc to zero size
+ EXPECT_TRUE(a.Realloc(a.Malloc(1), 1, 0) == 0);
+}
+
+TEST(Allocator, CrtAllocator) {
+ CrtAllocator a;
+ TestAllocator(a);
+}
+
+TEST(Allocator, MemoryPoolAllocator) {
+ MemoryPoolAllocator<> a;
+ TestAllocator(a);
+
+ for (size_t i = 1; i < 1000; i++) {
+ EXPECT_TRUE(a.Malloc(i) != 0);
+ EXPECT_LE(a.Size(), a.Capacity());
+ }
+}
+
+TEST(Allocator, Alignment) {
+#if RAPIDJSON_64BIT == 1
+ EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000000, 0x00000000), RAPIDJSON_ALIGN(0));
+ for (uint64_t i = 1; i < 8; i++) {
+ EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000000, 0x00000008), RAPIDJSON_ALIGN(i));
+ EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000000, 0x00000010), RAPIDJSON_ALIGN(RAPIDJSON_UINT64_C2(0x00000000, 0x00000008) + i));
+ EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000001, 0x00000000), RAPIDJSON_ALIGN(RAPIDJSON_UINT64_C2(0x00000000, 0xFFFFFFF8) + i));
+ EXPECT_EQ(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFF8), RAPIDJSON_ALIGN(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFF0) + i));
+ }
+#else
+ EXPECT_EQ(0u, RAPIDJSON_ALIGN(0u));
+ for (uint32_t i = 1; i < 4; i++) {
+ EXPECT_EQ(4u, RAPIDJSON_ALIGN(i));
+ EXPECT_EQ(8u, RAPIDJSON_ALIGN(4u + i));
+ EXPECT_EQ(0xFFFFFFF8u, RAPIDJSON_ALIGN(0xFFFFFFF4u + i));
+ EXPECT_EQ(0xFFFFFFFCu, RAPIDJSON_ALIGN(0xFFFFFFF8u + i));
+ }
+#endif
+}
+
+TEST(Allocator, Issue399) {
+ MemoryPoolAllocator<> a;
+ void* p = a.Malloc(100);
+ void* q = a.Realloc(p, 100, 200);
+ EXPECT_EQ(p, q);
+
+ // exhuasive testing
+ for (size_t j = 1; j < 32; j++) {
+ a.Clear();
+ a.Malloc(j); // some unaligned size
+ p = a.Malloc(1);
+ for (size_t i = 1; i < 1024; i++) {
+ q = a.Realloc(p, i, i + 1);
+ EXPECT_EQ(p, q);
+ p = q;
+ }
+ }
+}
diff --git a/3rdparty/rapidjson/test/unittest/bigintegertest.cpp b/3rdparty/rapidjson/test/unittest/bigintegertest.cpp
new file mode 100644
index 00000000000..a68e1444672
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/bigintegertest.cpp
@@ -0,0 +1,133 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+
+#include "rapidjson/internal/biginteger.h"
+
+using namespace rapidjson::internal;
+
+#define BIGINTEGER_LITERAL(s) BigInteger(s, sizeof(s) - 1)
+
+static const BigInteger kZero(0);
+static const BigInteger kOne(1);
+static const BigInteger kUint64Max = BIGINTEGER_LITERAL("18446744073709551615");
+static const BigInteger kTwo64 = BIGINTEGER_LITERAL("18446744073709551616");
+
+TEST(BigInteger, Constructor) {
+ EXPECT_TRUE(kZero.IsZero());
+ EXPECT_TRUE(kZero == kZero);
+ EXPECT_TRUE(kZero == BIGINTEGER_LITERAL("0"));
+ EXPECT_TRUE(kZero == BIGINTEGER_LITERAL("00"));
+
+ const BigInteger a(123);
+ EXPECT_TRUE(a == a);
+ EXPECT_TRUE(a == BIGINTEGER_LITERAL("123"));
+ EXPECT_TRUE(a == BIGINTEGER_LITERAL("0123"));
+
+ EXPECT_EQ(2u, kTwo64.GetCount());
+ EXPECT_EQ(0u, kTwo64.GetDigit(0));
+ EXPECT_EQ(1u, kTwo64.GetDigit(1));
+}
+
+TEST(BigInteger, AddUint64) {
+ BigInteger a = kZero;
+ a += 0u;
+ EXPECT_TRUE(kZero == a);
+
+ a += 1u;
+ EXPECT_TRUE(kOne == a);
+
+ a += 1u;
+ EXPECT_TRUE(BigInteger(2) == a);
+
+ EXPECT_TRUE(BigInteger(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF)) == kUint64Max);
+ BigInteger b = kUint64Max;
+ b += 1u;
+ EXPECT_TRUE(kTwo64 == b);
+ b += RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF);
+ EXPECT_TRUE(BIGINTEGER_LITERAL("36893488147419103231") == b);
+}
+
+TEST(BigInteger, MultiplyUint64) {
+ BigInteger a = kZero;
+ a *= static_cast <uint64_t>(0);
+ EXPECT_TRUE(kZero == a);
+ a *= static_cast <uint64_t>(123);
+ EXPECT_TRUE(kZero == a);
+
+ BigInteger b = kOne;
+ b *= static_cast<uint64_t>(1);
+ EXPECT_TRUE(kOne == b);
+ b *= static_cast<uint64_t>(0);
+ EXPECT_TRUE(kZero == b);
+
+ BigInteger c(123);
+ c *= static_cast<uint64_t>(456u);
+ EXPECT_TRUE(BigInteger(123u * 456u) == c);
+ c *= RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF);
+ EXPECT_TRUE(BIGINTEGER_LITERAL("1034640981606221330982120") == c);
+ c *= RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF);
+ EXPECT_TRUE(BIGINTEGER_LITERAL("19085757395861596536664473018420572782123800") == c);
+}
+
+TEST(BigInteger, MultiplyUint32) {
+ BigInteger a = kZero;
+ a *= static_cast <uint32_t>(0);
+ EXPECT_TRUE(kZero == a);
+ a *= static_cast <uint32_t>(123);
+ EXPECT_TRUE(kZero == a);
+
+ BigInteger b = kOne;
+ b *= static_cast<uint32_t>(1);
+ EXPECT_TRUE(kOne == b);
+ b *= static_cast<uint32_t>(0);
+ EXPECT_TRUE(kZero == b);
+
+ BigInteger c(123);
+ c *= static_cast<uint32_t>(456u);
+ EXPECT_TRUE(BigInteger(123u * 456u) == c);
+ c *= 0xFFFFFFFFu;
+ EXPECT_TRUE(BIGINTEGER_LITERAL("240896125641960") == c);
+ c *= 0xFFFFFFFFu;
+ EXPECT_TRUE(BIGINTEGER_LITERAL("1034640981124429079698200") == c);
+}
+
+TEST(BigInteger, LeftShift) {
+ BigInteger a = kZero;
+ a <<= 1;
+ EXPECT_TRUE(kZero == a);
+ a <<= 64;
+ EXPECT_TRUE(kZero == a);
+
+ a = BigInteger(123);
+ a <<= 0;
+ EXPECT_TRUE(BigInteger(123) == a);
+ a <<= 1;
+ EXPECT_TRUE(BigInteger(246) == a);
+ a <<= 64;
+ EXPECT_TRUE(BIGINTEGER_LITERAL("4537899042132549697536") == a);
+ a <<= 99;
+ EXPECT_TRUE(BIGINTEGER_LITERAL("2876235222267216943024851750785644982682875244576768") == a);
+}
+
+TEST(BigInteger, Compare) {
+ EXPECT_EQ(0, kZero.Compare(kZero));
+ EXPECT_EQ(1, kOne.Compare(kZero));
+ EXPECT_EQ(-1, kZero.Compare(kOne));
+ EXPECT_EQ(0, kUint64Max.Compare(kUint64Max));
+ EXPECT_EQ(0, kTwo64.Compare(kTwo64));
+ EXPECT_EQ(-1, kUint64Max.Compare(kTwo64));
+ EXPECT_EQ(1, kTwo64.Compare(kUint64Max));
+}
diff --git a/3rdparty/rapidjson/test/unittest/documenttest.cpp b/3rdparty/rapidjson/test/unittest/documenttest.cpp
new file mode 100644
index 00000000000..afe696a1e21
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/documenttest.cpp
@@ -0,0 +1,589 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+#include "rapidjson/document.h"
+#include "rapidjson/writer.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/encodedstream.h"
+#include "rapidjson/stringbuffer.h"
+#include <sstream>
+#include <algorithm>
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+RAPIDJSON_DIAG_OFF(missing-variable-declarations)
+#endif
+
+using namespace rapidjson;
+
+template <typename DocumentType>
+void ParseCheck(DocumentType& doc) {
+ typedef typename DocumentType::ValueType ValueType;
+
+ EXPECT_FALSE(doc.HasParseError());
+ EXPECT_TRUE(static_cast<ParseResult>(doc));
+
+ EXPECT_TRUE(doc.IsObject());
+
+ EXPECT_TRUE(doc.HasMember("hello"));
+ const ValueType& hello = doc["hello"];
+ EXPECT_TRUE(hello.IsString());
+ EXPECT_STREQ("world", hello.GetString());
+
+ EXPECT_TRUE(doc.HasMember("t"));
+ const ValueType& t = doc["t"];
+ EXPECT_TRUE(t.IsTrue());
+
+ EXPECT_TRUE(doc.HasMember("f"));
+ const ValueType& f = doc["f"];
+ EXPECT_TRUE(f.IsFalse());
+
+ EXPECT_TRUE(doc.HasMember("n"));
+ const ValueType& n = doc["n"];
+ EXPECT_TRUE(n.IsNull());
+
+ EXPECT_TRUE(doc.HasMember("i"));
+ const ValueType& i = doc["i"];
+ EXPECT_TRUE(i.IsNumber());
+ EXPECT_EQ(123, i.GetInt());
+
+ EXPECT_TRUE(doc.HasMember("pi"));
+ const ValueType& pi = doc["pi"];
+ EXPECT_TRUE(pi.IsNumber());
+ EXPECT_DOUBLE_EQ(3.1416, pi.GetDouble());
+
+ EXPECT_TRUE(doc.HasMember("a"));
+ const ValueType& a = doc["a"];
+ EXPECT_TRUE(a.IsArray());
+ EXPECT_EQ(4u, a.Size());
+ for (SizeType j = 0; j < 4; j++)
+ EXPECT_EQ(j + 1, a[j].GetUint());
+}
+
+template <typename Allocator, typename StackAllocator>
+void ParseTest() {
+ typedef GenericDocument<UTF8<>, Allocator, StackAllocator> DocumentType;
+ DocumentType doc;
+
+ const char* json = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";
+
+ doc.Parse(json);
+ ParseCheck(doc);
+
+ doc.SetNull();
+ StringStream s(json);
+ doc.template ParseStream<0>(s);
+ ParseCheck(doc);
+
+ doc.SetNull();
+ char *buffer = strdup(json);
+ doc.ParseInsitu(buffer);
+ ParseCheck(doc);
+ free(buffer);
+}
+
+TEST(Document, Parse) {
+ ParseTest<MemoryPoolAllocator<>, CrtAllocator>();
+ ParseTest<MemoryPoolAllocator<>, MemoryPoolAllocator<> >();
+ ParseTest<CrtAllocator, MemoryPoolAllocator<> >();
+ ParseTest<CrtAllocator, CrtAllocator>();
+}
+
+TEST(Document, UnchangedOnParseError) {
+ Document doc;
+ doc.SetArray().PushBack(0, doc.GetAllocator());
+
+ ParseResult err = doc.Parse("{]");
+ EXPECT_TRUE(doc.HasParseError());
+ EXPECT_EQ(err.Code(), doc.GetParseError());
+ EXPECT_EQ(err.Offset(), doc.GetErrorOffset());
+ EXPECT_TRUE(doc.IsArray());
+ EXPECT_EQ(doc.Size(), 1u);
+
+ err = doc.Parse("{}");
+ EXPECT_FALSE(doc.HasParseError());
+ EXPECT_FALSE(err.IsError());
+ EXPECT_EQ(err.Code(), doc.GetParseError());
+ EXPECT_EQ(err.Offset(), doc.GetErrorOffset());
+ EXPECT_TRUE(doc.IsObject());
+ EXPECT_EQ(doc.MemberCount(), 0u);
+}
+
+static FILE* OpenEncodedFile(const char* filename) {
+ const char *paths[] = {
+ "encodings",
+ "bin/encodings",
+ "../bin/encodings",
+ "../../bin/encodings",
+ "../../../bin/encodings"
+ };
+ char buffer[1024];
+ for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
+ sprintf(buffer, "%s/%s", paths[i], filename);
+ FILE *fp = fopen(buffer, "rb");
+ if (fp)
+ return fp;
+ }
+ return 0;
+}
+
+TEST(Document, ParseStream_EncodedInputStream) {
+ // UTF8 -> UTF16
+ FILE* fp = OpenEncodedFile("utf8.json");
+ char buffer[256];
+ FileReadStream bis(fp, buffer, sizeof(buffer));
+ EncodedInputStream<UTF8<>, FileReadStream> eis(bis);
+
+ GenericDocument<UTF16<> > d;
+ d.ParseStream<0, UTF8<> >(eis);
+ EXPECT_FALSE(d.HasParseError());
+
+ fclose(fp);
+
+ wchar_t expected[] = L"I can eat glass and it doesn't hurt me.";
+ GenericValue<UTF16<> >& v = d[L"en"];
+ EXPECT_TRUE(v.IsString());
+ EXPECT_EQ(sizeof(expected) / sizeof(wchar_t) - 1, v.GetStringLength());
+ EXPECT_EQ(0, StrCmp(expected, v.GetString()));
+
+ // UTF16 -> UTF8 in memory
+ StringBuffer bos;
+ typedef EncodedOutputStream<UTF8<>, StringBuffer> OutputStream;
+ OutputStream eos(bos, false); // Not writing BOM
+ {
+ Writer<OutputStream, UTF16<>, UTF8<> > writer(eos);
+ d.Accept(writer);
+ }
+
+ // Condense the original file and compare.
+ fp = OpenEncodedFile("utf8.json");
+ FileReadStream is(fp, buffer, sizeof(buffer));
+ Reader reader;
+ StringBuffer bos2;
+ Writer<StringBuffer> writer2(bos2);
+ reader.Parse(is, writer2);
+ fclose(fp);
+
+ EXPECT_EQ(bos.GetSize(), bos2.GetSize());
+ EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize()));
+}
+
+TEST(Document, ParseStream_AutoUTFInputStream) {
+ // Any -> UTF8
+ FILE* fp = OpenEncodedFile("utf32be.json");
+ char buffer[256];
+ FileReadStream bis(fp, buffer, sizeof(buffer));
+ AutoUTFInputStream<unsigned, FileReadStream> eis(bis);
+
+ Document d;
+ d.ParseStream<0, AutoUTF<unsigned> >(eis);
+ EXPECT_FALSE(d.HasParseError());
+
+ fclose(fp);
+
+ char expected[] = "I can eat glass and it doesn't hurt me.";
+ Value& v = d["en"];
+ EXPECT_TRUE(v.IsString());
+ EXPECT_EQ(sizeof(expected) - 1, v.GetStringLength());
+ EXPECT_EQ(0, StrCmp(expected, v.GetString()));
+
+ // UTF8 -> UTF8 in memory
+ StringBuffer bos;
+ Writer<StringBuffer> writer(bos);
+ d.Accept(writer);
+
+ // Condense the original file and compare.
+ fp = OpenEncodedFile("utf8.json");
+ FileReadStream is(fp, buffer, sizeof(buffer));
+ Reader reader;
+ StringBuffer bos2;
+ Writer<StringBuffer> writer2(bos2);
+ reader.Parse(is, writer2);
+ fclose(fp);
+
+ EXPECT_EQ(bos.GetSize(), bos2.GetSize());
+ EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize()));
+}
+
+TEST(Document, Swap) {
+ Document d1;
+ Document::AllocatorType& a = d1.GetAllocator();
+
+ d1.SetArray().PushBack(1, a).PushBack(2, a);
+
+ Value o;
+ o.SetObject().AddMember("a", 1, a);
+
+ // Swap between Document and Value
+ // d1.Swap(o); // doesn't compile
+ o.Swap(d1);
+ EXPECT_TRUE(d1.IsObject());
+ EXPECT_TRUE(o.IsArray());
+
+ // Swap between Document and Document
+ Document d2;
+ d2.SetArray().PushBack(3, a);
+ d1.Swap(d2);
+ EXPECT_TRUE(d1.IsArray());
+ EXPECT_TRUE(d2.IsObject());
+ EXPECT_EQ(&d2.GetAllocator(), &a);
+
+ // reset value
+ Value().Swap(d1);
+ EXPECT_TRUE(d1.IsNull());
+
+ // reset document, including allocator
+ Document().Swap(d2);
+ EXPECT_TRUE(d2.IsNull());
+ EXPECT_NE(&d2.GetAllocator(), &a);
+
+ // testing std::swap compatibility
+ d1.SetBool(true);
+ using std::swap;
+ swap(d1, d2);
+ EXPECT_TRUE(d1.IsNull());
+ EXPECT_TRUE(d2.IsTrue());
+
+ swap(o, d2);
+ EXPECT_TRUE(o.IsTrue());
+ EXPECT_TRUE(d2.IsArray());
+}
+
+
+// This should be slow due to assignment in inner-loop.
+struct OutputStringStream : public std::ostringstream {
+ typedef char Ch;
+
+ virtual ~OutputStringStream();
+
+ void Put(char c) {
+ put(c);
+ }
+ void Flush() {}
+};
+
+OutputStringStream::~OutputStringStream() {}
+
+TEST(Document, AcceptWriter) {
+ Document doc;
+ doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
+
+ OutputStringStream os;
+ Writer<OutputStringStream> writer(os);
+ doc.Accept(writer);
+
+ EXPECT_EQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3,4]}", os.str());
+}
+
+TEST(Document, UserBuffer) {
+ typedef GenericDocument<UTF8<>, MemoryPoolAllocator<>, MemoryPoolAllocator<> > DocumentType;
+ char valueBuffer[4096];
+ char parseBuffer[1024];
+ MemoryPoolAllocator<> valueAllocator(valueBuffer, sizeof(valueBuffer));
+ MemoryPoolAllocator<> parseAllocator(parseBuffer, sizeof(parseBuffer));
+ DocumentType doc(&valueAllocator, sizeof(parseBuffer) / 2, &parseAllocator);
+ doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
+ EXPECT_FALSE(doc.HasParseError());
+ EXPECT_LE(valueAllocator.Size(), sizeof(valueBuffer));
+ EXPECT_LE(parseAllocator.Size(), sizeof(parseBuffer));
+
+ // Cover MemoryPoolAllocator::Capacity()
+ EXPECT_LE(valueAllocator.Size(), valueAllocator.Capacity());
+ EXPECT_LE(parseAllocator.Size(), parseAllocator.Capacity());
+}
+
+// Issue 226: Value of string type should not point to NULL
+TEST(Document, AssertAcceptInvalidNameType) {
+ Document doc;
+ doc.SetObject();
+ doc.AddMember("a", 0, doc.GetAllocator());
+ doc.FindMember("a")->name.SetNull(); // Change name to non-string type.
+
+ OutputStringStream os;
+ Writer<OutputStringStream> writer(os);
+ ASSERT_THROW(doc.Accept(writer), AssertException);
+}
+
+// Issue 44: SetStringRaw doesn't work with wchar_t
+TEST(Document, UTF16_Document) {
+ GenericDocument< UTF16<> > json;
+ json.Parse<kParseValidateEncodingFlag>(L"[{\"created_at\":\"Wed Oct 30 17:13:20 +0000 2012\"}]");
+
+ ASSERT_TRUE(json.IsArray());
+ GenericValue< UTF16<> >& v = json[0];
+ ASSERT_TRUE(v.IsObject());
+
+ GenericValue< UTF16<> >& s = v[L"created_at"];
+ ASSERT_TRUE(s.IsString());
+
+ EXPECT_EQ(0, memcmp(L"Wed Oct 30 17:13:20 +0000 2012", s.GetString(), (s.GetStringLength() + 1) * sizeof(wchar_t)));
+}
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+#if 0 // Many old compiler does not support these. Turn it off temporaily.
+
+#include <type_traits>
+
+TEST(Document, Traits) {
+ static_assert(std::is_constructible<Document>::value, "");
+ static_assert(std::is_default_constructible<Document>::value, "");
+#ifndef _MSC_VER
+ static_assert(!std::is_copy_constructible<Document>::value, "");
+#endif
+ static_assert(std::is_move_constructible<Document>::value, "");
+
+ static_assert(!std::is_nothrow_constructible<Document>::value, "");
+ static_assert(!std::is_nothrow_default_constructible<Document>::value, "");
+#ifndef _MSC_VER
+ static_assert(!std::is_nothrow_copy_constructible<Document>::value, "");
+ static_assert(std::is_nothrow_move_constructible<Document>::value, "");
+#endif
+
+ static_assert(std::is_assignable<Document,Document>::value, "");
+#ifndef _MSC_VER
+ static_assert(!std::is_copy_assignable<Document>::value, "");
+#endif
+ static_assert(std::is_move_assignable<Document>::value, "");
+
+#ifndef _MSC_VER
+ static_assert(std::is_nothrow_assignable<Document, Document>::value, "");
+#endif
+ static_assert(!std::is_nothrow_copy_assignable<Document>::value, "");
+#ifndef _MSC_VER
+ static_assert(std::is_nothrow_move_assignable<Document>::value, "");
+#endif
+
+ static_assert( std::is_destructible<Document>::value, "");
+#ifndef _MSC_VER
+ static_assert(std::is_nothrow_destructible<Document>::value, "");
+#endif
+}
+
+#endif
+
+template <typename Allocator>
+struct DocumentMove: public ::testing::Test {
+};
+
+typedef ::testing::Types< CrtAllocator, MemoryPoolAllocator<> > MoveAllocatorTypes;
+TYPED_TEST_CASE(DocumentMove, MoveAllocatorTypes);
+
+TYPED_TEST(DocumentMove, MoveConstructor) {
+ typedef TypeParam Allocator;
+ typedef GenericDocument<UTF8<>, Allocator> Document;
+ Allocator allocator;
+
+ Document a(&allocator);
+ a.Parse("[\"one\", \"two\", \"three\"]");
+ EXPECT_FALSE(a.HasParseError());
+ EXPECT_TRUE(a.IsArray());
+ EXPECT_EQ(3u, a.Size());
+ EXPECT_EQ(&a.GetAllocator(), &allocator);
+
+ // Document b(a); // does not compile (!is_copy_constructible)
+ Document b(std::move(a));
+ EXPECT_TRUE(a.IsNull());
+ EXPECT_TRUE(b.IsArray());
+ EXPECT_EQ(3u, b.Size());
+ EXPECT_THROW(a.GetAllocator(), AssertException);
+ EXPECT_EQ(&b.GetAllocator(), &allocator);
+
+ b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}");
+ EXPECT_FALSE(b.HasParseError());
+ EXPECT_TRUE(b.IsObject());
+ EXPECT_EQ(2u, b.MemberCount());
+
+ // Document c = a; // does not compile (!is_copy_constructible)
+ Document c = std::move(b);
+ EXPECT_TRUE(b.IsNull());
+ EXPECT_TRUE(c.IsObject());
+ EXPECT_EQ(2u, c.MemberCount());
+ EXPECT_THROW(b.GetAllocator(), AssertException);
+ EXPECT_EQ(&c.GetAllocator(), &allocator);
+}
+
+TYPED_TEST(DocumentMove, MoveConstructorParseError) {
+ typedef TypeParam Allocator;
+ typedef GenericDocument<UTF8<>, Allocator> Document;
+
+ ParseResult noError;
+ Document a;
+ a.Parse("{ 4 = 4]");
+ ParseResult error(a.GetParseError(), a.GetErrorOffset());
+ EXPECT_TRUE(a.HasParseError());
+ EXPECT_NE(error.Code(), noError.Code());
+ EXPECT_NE(error.Offset(), noError.Offset());
+
+ Document b(std::move(a));
+ EXPECT_FALSE(a.HasParseError());
+ EXPECT_TRUE(b.HasParseError());
+ EXPECT_EQ(a.GetParseError(), noError.Code());
+ EXPECT_EQ(b.GetParseError(), error.Code());
+ EXPECT_EQ(a.GetErrorOffset(), noError.Offset());
+ EXPECT_EQ(b.GetErrorOffset(), error.Offset());
+
+ Document c(std::move(b));
+ EXPECT_FALSE(b.HasParseError());
+ EXPECT_TRUE(c.HasParseError());
+ EXPECT_EQ(b.GetParseError(), noError.Code());
+ EXPECT_EQ(c.GetParseError(), error.Code());
+ EXPECT_EQ(b.GetErrorOffset(), noError.Offset());
+ EXPECT_EQ(c.GetErrorOffset(), error.Offset());
+}
+
+// This test does not properly use parsing, just for testing.
+// It must call ClearStack() explicitly to prevent memory leak.
+// But here we cannot as ClearStack() is private.
+#if 0
+TYPED_TEST(DocumentMove, MoveConstructorStack) {
+ typedef TypeParam Allocator;
+ typedef UTF8<> Encoding;
+ typedef GenericDocument<Encoding, Allocator> Document;
+
+ Document a;
+ size_t defaultCapacity = a.GetStackCapacity();
+
+ // Trick Document into getting GetStackCapacity() to return non-zero
+ typedef GenericReader<Encoding, Encoding, Allocator> Reader;
+ Reader reader(&a.GetAllocator());
+ GenericStringStream<Encoding> is("[\"one\", \"two\", \"three\"]");
+ reader.template Parse<kParseDefaultFlags>(is, a);
+ size_t capacity = a.GetStackCapacity();
+ EXPECT_GT(capacity, 0u);
+
+ Document b(std::move(a));
+ EXPECT_EQ(a.GetStackCapacity(), defaultCapacity);
+ EXPECT_EQ(b.GetStackCapacity(), capacity);
+
+ Document c = std::move(b);
+ EXPECT_EQ(b.GetStackCapacity(), defaultCapacity);
+ EXPECT_EQ(c.GetStackCapacity(), capacity);
+}
+#endif
+
+TYPED_TEST(DocumentMove, MoveAssignment) {
+ typedef TypeParam Allocator;
+ typedef GenericDocument<UTF8<>, Allocator> Document;
+ Allocator allocator;
+
+ Document a(&allocator);
+ a.Parse("[\"one\", \"two\", \"three\"]");
+ EXPECT_FALSE(a.HasParseError());
+ EXPECT_TRUE(a.IsArray());
+ EXPECT_EQ(3u, a.Size());
+ EXPECT_EQ(&a.GetAllocator(), &allocator);
+
+ // Document b; b = a; // does not compile (!is_copy_assignable)
+ Document b;
+ b = std::move(a);
+ EXPECT_TRUE(a.IsNull());
+ EXPECT_TRUE(b.IsArray());
+ EXPECT_EQ(3u, b.Size());
+ EXPECT_THROW(a.GetAllocator(), AssertException);
+ EXPECT_EQ(&b.GetAllocator(), &allocator);
+
+ b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}");
+ EXPECT_FALSE(b.HasParseError());
+ EXPECT_TRUE(b.IsObject());
+ EXPECT_EQ(2u, b.MemberCount());
+
+ // Document c; c = a; // does not compile (see static_assert)
+ Document c;
+ c = std::move(b);
+ EXPECT_TRUE(b.IsNull());
+ EXPECT_TRUE(c.IsObject());
+ EXPECT_EQ(2u, c.MemberCount());
+ EXPECT_THROW(b.GetAllocator(), AssertException);
+ EXPECT_EQ(&c.GetAllocator(), &allocator);
+}
+
+TYPED_TEST(DocumentMove, MoveAssignmentParseError) {
+ typedef TypeParam Allocator;
+ typedef GenericDocument<UTF8<>, Allocator> Document;
+
+ ParseResult noError;
+ Document a;
+ a.Parse("{ 4 = 4]");
+ ParseResult error(a.GetParseError(), a.GetErrorOffset());
+ EXPECT_TRUE(a.HasParseError());
+ EXPECT_NE(error.Code(), noError.Code());
+ EXPECT_NE(error.Offset(), noError.Offset());
+
+ Document b;
+ b = std::move(a);
+ EXPECT_FALSE(a.HasParseError());
+ EXPECT_TRUE(b.HasParseError());
+ EXPECT_EQ(a.GetParseError(), noError.Code());
+ EXPECT_EQ(b.GetParseError(), error.Code());
+ EXPECT_EQ(a.GetErrorOffset(), noError.Offset());
+ EXPECT_EQ(b.GetErrorOffset(), error.Offset());
+
+ Document c;
+ c = std::move(b);
+ EXPECT_FALSE(b.HasParseError());
+ EXPECT_TRUE(c.HasParseError());
+ EXPECT_EQ(b.GetParseError(), noError.Code());
+ EXPECT_EQ(c.GetParseError(), error.Code());
+ EXPECT_EQ(b.GetErrorOffset(), noError.Offset());
+ EXPECT_EQ(c.GetErrorOffset(), error.Offset());
+}
+
+// This test does not properly use parsing, just for testing.
+// It must call ClearStack() explicitly to prevent memory leak.
+// But here we cannot as ClearStack() is private.
+#if 0
+TYPED_TEST(DocumentMove, MoveAssignmentStack) {
+ typedef TypeParam Allocator;
+ typedef UTF8<> Encoding;
+ typedef GenericDocument<Encoding, Allocator> Document;
+
+ Document a;
+ size_t defaultCapacity = a.GetStackCapacity();
+
+ // Trick Document into getting GetStackCapacity() to return non-zero
+ typedef GenericReader<Encoding, Encoding, Allocator> Reader;
+ Reader reader(&a.GetAllocator());
+ GenericStringStream<Encoding> is("[\"one\", \"two\", \"three\"]");
+ reader.template Parse<kParseDefaultFlags>(is, a);
+ size_t capacity = a.GetStackCapacity();
+ EXPECT_GT(capacity, 0u);
+
+ Document b;
+ b = std::move(a);
+ EXPECT_EQ(a.GetStackCapacity(), defaultCapacity);
+ EXPECT_EQ(b.GetStackCapacity(), capacity);
+
+ Document c;
+ c = std::move(b);
+ EXPECT_EQ(b.GetStackCapacity(), defaultCapacity);
+ EXPECT_EQ(c.GetStackCapacity(), capacity);
+}
+#endif
+
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+// Issue 22: Memory corruption via operator=
+// Fixed by making unimplemented assignment operator private.
+//TEST(Document, Assignment) {
+// Document d1;
+// Document d2;
+// d1 = d2;
+//}
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
diff --git a/3rdparty/rapidjson/test/unittest/dtoatest.cpp b/3rdparty/rapidjson/test/unittest/dtoatest.cpp
new file mode 100644
index 00000000000..da020957211
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/dtoatest.cpp
@@ -0,0 +1,91 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+#include "rapidjson/internal/dtoa.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(type-limits)
+#endif
+
+using namespace rapidjson::internal;
+
+TEST(dtoa, normal) {
+ char buffer[30];
+
+#define TEST_DTOA(d, a)\
+ *dtoa(d, buffer) = '\0';\
+ EXPECT_STREQ(a, buffer)
+
+ TEST_DTOA(0.0, "0.0");
+ TEST_DTOA(-0.0, "-0.0");
+ TEST_DTOA(1.0, "1.0");
+ TEST_DTOA(-1.0, "-1.0");
+ TEST_DTOA(1.2345, "1.2345");
+ TEST_DTOA(1.2345678, "1.2345678");
+ TEST_DTOA(0.123456789012, "0.123456789012");
+ TEST_DTOA(1234567.8, "1234567.8");
+ TEST_DTOA(0.000001, "0.000001");
+ TEST_DTOA(0.0000001, "1e-7");
+ TEST_DTOA(1e30, "1e30");
+ TEST_DTOA(1.234567890123456e30, "1.234567890123456e30");
+ TEST_DTOA(5e-324, "5e-324"); // Min subnormal positive double
+ TEST_DTOA(2.225073858507201e-308, "2.225073858507201e-308"); // Max subnormal positive double
+ TEST_DTOA(2.2250738585072014e-308, "2.2250738585072014e-308"); // Min normal positive double
+ TEST_DTOA(1.7976931348623157e308, "1.7976931348623157e308"); // Max double
+
+#undef TEST_DTOA
+}
+
+TEST(dtoa, maxDecimalPlaces) {
+ char buffer[30];
+
+#define TEST_DTOA(m, d, a)\
+ *dtoa(d, buffer, m) = '\0';\
+ EXPECT_STREQ(a, buffer)
+
+ TEST_DTOA(3, 0.0, "0.0");
+ TEST_DTOA(1, 0.0, "0.0");
+ TEST_DTOA(3, -0.0, "-0.0");
+ TEST_DTOA(3, 1.0, "1.0");
+ TEST_DTOA(3, -1.0, "-1.0");
+ TEST_DTOA(3, 1.2345, "1.234");
+ TEST_DTOA(2, 1.2345, "1.23");
+ TEST_DTOA(1, 1.2345, "1.2");
+ TEST_DTOA(3, 1.2345678, "1.234");
+ TEST_DTOA(3, 1.0001, "1.0");
+ TEST_DTOA(2, 1.0001, "1.0");
+ TEST_DTOA(1, 1.0001, "1.0");
+ TEST_DTOA(3, 0.123456789012, "0.123");
+ TEST_DTOA(2, 0.123456789012, "0.12");
+ TEST_DTOA(1, 0.123456789012, "0.1");
+ TEST_DTOA(4, 0.0001, "0.0001");
+ TEST_DTOA(3, 0.0001, "0.0");
+ TEST_DTOA(2, 0.0001, "0.0");
+ TEST_DTOA(1, 0.0001, "0.0");
+ TEST_DTOA(3, 1234567.8, "1234567.8");
+ TEST_DTOA(3, 1e30, "1e30");
+ TEST_DTOA(3, 5e-324, "0.0"); // Min subnormal positive double
+ TEST_DTOA(3, 2.225073858507201e-308, "0.0"); // Max subnormal positive double
+ TEST_DTOA(3, 2.2250738585072014e-308, "0.0"); // Min normal positive double
+ TEST_DTOA(3, 1.7976931348623157e308, "1.7976931348623157e308"); // Max double
+
+#undef TEST_DTOA
+}
+
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
diff --git a/3rdparty/rapidjson/test/unittest/encodedstreamtest.cpp b/3rdparty/rapidjson/test/unittest/encodedstreamtest.cpp
new file mode 100644
index 00000000000..bc234d3ba76
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/encodedstreamtest.cpp
@@ -0,0 +1,313 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/filewritestream.h"
+#include "rapidjson/encodedstream.h"
+#include "rapidjson/stringbuffer.h"
+#include "rapidjson/memorystream.h"
+#include "rapidjson/memorybuffer.h"
+
+using namespace rapidjson;
+
+class EncodedStreamTest : public ::testing::Test {
+public:
+ EncodedStreamTest() : json_(), length_() {}
+ virtual ~EncodedStreamTest();
+
+ virtual void SetUp() {
+ json_ = ReadFile("utf8.json", true, &length_);
+ }
+
+ virtual void TearDown() {
+ free(json_);
+ json_ = 0;
+ }
+
+private:
+ EncodedStreamTest(const EncodedStreamTest&);
+ EncodedStreamTest& operator=(const EncodedStreamTest&);
+
+protected:
+ static FILE* Open(const char* filename) {
+ const char *paths[] = {
+ "encodings",
+ "bin/encodings",
+ "../bin/encodings",
+ "../../bin/encodings",
+ "../../../bin/encodings"
+ };
+ char buffer[1024];
+ for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
+ sprintf(buffer, "%s/%s", paths[i], filename);
+ FILE *fp = fopen(buffer, "rb");
+ if (fp)
+ return fp;
+ }
+ return 0;
+ }
+
+ static char *ReadFile(const char* filename, bool appendPath, size_t* outLength) {
+ FILE *fp = appendPath ? Open(filename) : fopen(filename, "rb");
+
+ if (!fp) {
+ *outLength = 0;
+ return 0;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ *outLength = static_cast<size_t>(ftell(fp));
+ fseek(fp, 0, SEEK_SET);
+ char* buffer = static_cast<char*>(malloc(*outLength + 1));
+ size_t readLength = fread(buffer, 1, *outLength, fp);
+ buffer[readLength] = '\0';
+ fclose(fp);
+ return buffer;
+ }
+
+ template <typename FileEncoding, typename MemoryEncoding>
+ void TestEncodedInputStream(const char* filename) {
+ // Test FileReadStream
+ {
+ char buffer[16];
+ FILE *fp = Open(filename);
+ ASSERT_TRUE(fp != 0);
+ FileReadStream fs(fp, buffer, sizeof(buffer));
+ EncodedInputStream<FileEncoding, FileReadStream> eis(fs);
+ StringStream s(json_);
+
+ while (eis.Peek() != '\0') {
+ unsigned expected, actual;
+ EXPECT_TRUE(UTF8<>::Decode(s, &expected));
+ EXPECT_TRUE(MemoryEncoding::Decode(eis, &actual));
+ EXPECT_EQ(expected, actual);
+ }
+ EXPECT_EQ('\0', s.Peek());
+ fclose(fp);
+ }
+
+ // Test MemoryStream
+ {
+ size_t size;
+ char* data = ReadFile(filename, true, &size);
+ MemoryStream ms(data, size);
+ EncodedInputStream<FileEncoding, MemoryStream> eis(ms);
+ StringStream s(json_);
+
+ while (eis.Peek() != '\0') {
+ unsigned expected, actual;
+ EXPECT_TRUE(UTF8<>::Decode(s, &expected));
+ EXPECT_TRUE(MemoryEncoding::Decode(eis, &actual));
+ EXPECT_EQ(expected, actual);
+ }
+ EXPECT_EQ('\0', s.Peek());
+ free(data);
+ EXPECT_EQ(size, eis.Tell());
+ }
+ }
+
+ void TestAutoUTFInputStream(const char *filename, bool expectHasBOM) {
+ // Test FileReadStream
+ {
+ char buffer[16];
+ FILE *fp = Open(filename);
+ ASSERT_TRUE(fp != 0);
+ FileReadStream fs(fp, buffer, sizeof(buffer));
+ AutoUTFInputStream<unsigned, FileReadStream> eis(fs);
+ EXPECT_EQ(expectHasBOM, eis.HasBOM());
+ StringStream s(json_);
+ while (eis.Peek() != '\0') {
+ unsigned expected, actual;
+ EXPECT_TRUE(UTF8<>::Decode(s, &expected));
+ EXPECT_TRUE(AutoUTF<unsigned>::Decode(eis, &actual));
+ EXPECT_EQ(expected, actual);
+ }
+ EXPECT_EQ('\0', s.Peek());
+ fclose(fp);
+ }
+
+ // Test MemoryStream
+ {
+ size_t size;
+ char* data = ReadFile(filename, true, &size);
+ MemoryStream ms(data, size);
+ AutoUTFInputStream<unsigned, MemoryStream> eis(ms);
+ EXPECT_EQ(expectHasBOM, eis.HasBOM());
+ StringStream s(json_);
+
+ while (eis.Peek() != '\0') {
+ unsigned expected, actual;
+ EXPECT_TRUE(UTF8<>::Decode(s, &expected));
+ EXPECT_TRUE(AutoUTF<unsigned>::Decode(eis, &actual));
+ EXPECT_EQ(expected, actual);
+ }
+ EXPECT_EQ('\0', s.Peek());
+ free(data);
+ EXPECT_EQ(size, eis.Tell());
+ }
+ }
+
+ template <typename FileEncoding, typename MemoryEncoding>
+ void TestEncodedOutputStream(const char* expectedFilename, bool putBOM) {
+ // Test FileWriteStream
+ {
+ char filename[L_tmpnam];
+ FILE* fp = TempFile(filename);
+ char buffer[16];
+ FileWriteStream os(fp, buffer, sizeof(buffer));
+ EncodedOutputStream<FileEncoding, FileWriteStream> eos(os, putBOM);
+ StringStream s(json_);
+ while (s.Peek() != '\0') {
+ bool success = Transcoder<UTF8<>, MemoryEncoding>::Transcode(s, eos);
+ EXPECT_TRUE(success);
+ }
+ eos.Flush();
+ fclose(fp);
+ EXPECT_TRUE(CompareFile(filename, expectedFilename));
+ remove(filename);
+ }
+
+ // Test MemoryBuffer
+ {
+ MemoryBuffer mb;
+ EncodedOutputStream<FileEncoding, MemoryBuffer> eos(mb, putBOM);
+ StringStream s(json_);
+ while (s.Peek() != '\0') {
+ bool success = Transcoder<UTF8<>, MemoryEncoding>::Transcode(s, eos);
+ EXPECT_TRUE(success);
+ }
+ eos.Flush();
+ EXPECT_TRUE(CompareBufferFile(mb.GetBuffer(), mb.GetSize(), expectedFilename));
+ }
+ }
+
+ void TestAutoUTFOutputStream(UTFType type, bool putBOM, const char *expectedFilename) {
+ // Test FileWriteStream
+ {
+ char filename[L_tmpnam];
+ FILE* fp = TempFile(filename);
+
+ char buffer[16];
+ FileWriteStream os(fp, buffer, sizeof(buffer));
+ AutoUTFOutputStream<unsigned, FileWriteStream> eos(os, type, putBOM);
+ StringStream s(json_);
+ while (s.Peek() != '\0') {
+ bool success = Transcoder<UTF8<>, AutoUTF<unsigned> >::Transcode(s, eos);
+ EXPECT_TRUE(success);
+ }
+ eos.Flush();
+ fclose(fp);
+ EXPECT_TRUE(CompareFile(filename, expectedFilename));
+ remove(filename);
+ }
+
+ // Test MemoryBuffer
+ {
+ MemoryBuffer mb;
+ AutoUTFOutputStream<unsigned, MemoryBuffer> eos(mb, type, putBOM);
+ StringStream s(json_);
+ while (s.Peek() != '\0') {
+ bool success = Transcoder<UTF8<>, AutoUTF<unsigned> >::Transcode(s, eos);
+ EXPECT_TRUE(success);
+ }
+ eos.Flush();
+ EXPECT_TRUE(CompareBufferFile(mb.GetBuffer(), mb.GetSize(), expectedFilename));
+ }
+ }
+
+ bool CompareFile(const char* filename, const char* expectedFilename) {
+ size_t actualLength, expectedLength;
+ char* actualBuffer = ReadFile(filename, false, &actualLength);
+ char* expectedBuffer = ReadFile(expectedFilename, true, &expectedLength);
+ bool ret = (expectedLength == actualLength) && memcmp(expectedBuffer, actualBuffer, actualLength) == 0;
+ free(actualBuffer);
+ free(expectedBuffer);
+ return ret;
+ }
+
+ bool CompareBufferFile(const char* actualBuffer, size_t actualLength, const char* expectedFilename) {
+ size_t expectedLength;
+ char* expectedBuffer = ReadFile(expectedFilename, true, &expectedLength);
+ bool ret = (expectedLength == actualLength) && memcmp(expectedBuffer, actualBuffer, actualLength) == 0;
+ free(expectedBuffer);
+ return ret;
+ }
+
+ char *json_;
+ size_t length_;
+};
+
+EncodedStreamTest::~EncodedStreamTest() {}
+
+TEST_F(EncodedStreamTest, EncodedInputStream) {
+ TestEncodedInputStream<UTF8<>, UTF8<> >("utf8.json");
+ TestEncodedInputStream<UTF8<>, UTF8<> >("utf8bom.json");
+ TestEncodedInputStream<UTF16LE<>, UTF16<> >("utf16le.json");
+ TestEncodedInputStream<UTF16LE<>, UTF16<> >("utf16lebom.json");
+ TestEncodedInputStream<UTF16BE<>, UTF16<> >("utf16be.json");
+ TestEncodedInputStream<UTF16BE<>, UTF16<> >("utf16bebom.json");
+ TestEncodedInputStream<UTF32LE<>, UTF32<> >("utf32le.json");
+ TestEncodedInputStream<UTF32LE<>, UTF32<> >("utf32lebom.json");
+ TestEncodedInputStream<UTF32BE<>, UTF32<> >("utf32be.json");
+ TestEncodedInputStream<UTF32BE<>, UTF32<> >("utf32bebom.json");
+}
+
+TEST_F(EncodedStreamTest, AutoUTFInputStream) {
+ TestAutoUTFInputStream("utf8.json", false);
+ TestAutoUTFInputStream("utf8bom.json", true);
+ TestAutoUTFInputStream("utf16le.json", false);
+ TestAutoUTFInputStream("utf16lebom.json",true);
+ TestAutoUTFInputStream("utf16be.json", false);
+ TestAutoUTFInputStream("utf16bebom.json",true);
+ TestAutoUTFInputStream("utf32le.json", false);
+ TestAutoUTFInputStream("utf32lebom.json",true);
+ TestAutoUTFInputStream("utf32be.json", false);
+ TestAutoUTFInputStream("utf32bebom.json", true);
+
+ {
+ // Auto detection fail, use user defined UTF type
+ const char json[] = "{ }";
+ MemoryStream ms(json, sizeof(json));
+ AutoUTFInputStream<unsigned, MemoryStream> eis(ms, kUTF8);
+ EXPECT_FALSE(eis.HasBOM());
+ EXPECT_EQ(kUTF8, eis.GetType());
+ }
+}
+
+TEST_F(EncodedStreamTest, EncodedOutputStream) {
+ TestEncodedOutputStream<UTF8<>, UTF8<> >("utf8.json", false);
+ TestEncodedOutputStream<UTF8<>, UTF8<> >("utf8bom.json", true);
+ TestEncodedOutputStream<UTF16LE<>, UTF16<> >("utf16le.json", false);
+ TestEncodedOutputStream<UTF16LE<>, UTF16<> >("utf16lebom.json",true);
+ TestEncodedOutputStream<UTF16BE<>, UTF16<> >("utf16be.json", false);
+ TestEncodedOutputStream<UTF16BE<>, UTF16<> >("utf16bebom.json",true);
+ TestEncodedOutputStream<UTF32LE<>, UTF32<> >("utf32le.json", false);
+ TestEncodedOutputStream<UTF32LE<>, UTF32<> >("utf32lebom.json",true);
+ TestEncodedOutputStream<UTF32BE<>, UTF32<> >("utf32be.json", false);
+ TestEncodedOutputStream<UTF32BE<>, UTF32<> >("utf32bebom.json",true);
+}
+
+TEST_F(EncodedStreamTest, AutoUTFOutputStream) {
+ TestAutoUTFOutputStream(kUTF8, false, "utf8.json");
+ TestAutoUTFOutputStream(kUTF8, true, "utf8bom.json");
+ TestAutoUTFOutputStream(kUTF16LE, false, "utf16le.json");
+ TestAutoUTFOutputStream(kUTF16LE, true, "utf16lebom.json");
+ TestAutoUTFOutputStream(kUTF16BE, false, "utf16be.json");
+ TestAutoUTFOutputStream(kUTF16BE, true, "utf16bebom.json");
+ TestAutoUTFOutputStream(kUTF32LE, false, "utf32le.json");
+ TestAutoUTFOutputStream(kUTF32LE, true, "utf32lebom.json");
+ TestAutoUTFOutputStream(kUTF32BE, false, "utf32be.json");
+ TestAutoUTFOutputStream(kUTF32BE, true, "utf32bebom.json");
+}
diff --git a/3rdparty/rapidjson/test/unittest/encodingstest.cpp b/3rdparty/rapidjson/test/unittest/encodingstest.cpp
new file mode 100644
index 00000000000..b3cbb76607b
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/encodingstest.cpp
@@ -0,0 +1,425 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/filewritestream.h"
+#include "rapidjson/encodedstream.h"
+#include "rapidjson/stringbuffer.h"
+
+using namespace rapidjson;
+
+// Verification of encoders/decoders with Hoehrmann's UTF8 decoder
+
+// http://www.unicode.org/Public/UNIDATA/Blocks.txt
+static const unsigned kCodepointRanges[] = {
+ 0x0000, 0x007F, // Basic Latin
+ 0x0080, 0x00FF, // Latin-1 Supplement
+ 0x0100, 0x017F, // Latin Extended-A
+ 0x0180, 0x024F, // Latin Extended-B
+ 0x0250, 0x02AF, // IPA Extensions
+ 0x02B0, 0x02FF, // Spacing Modifier Letters
+ 0x0300, 0x036F, // Combining Diacritical Marks
+ 0x0370, 0x03FF, // Greek and Coptic
+ 0x0400, 0x04FF, // Cyrillic
+ 0x0500, 0x052F, // Cyrillic Supplement
+ 0x0530, 0x058F, // Armenian
+ 0x0590, 0x05FF, // Hebrew
+ 0x0600, 0x06FF, // Arabic
+ 0x0700, 0x074F, // Syriac
+ 0x0750, 0x077F, // Arabic Supplement
+ 0x0780, 0x07BF, // Thaana
+ 0x07C0, 0x07FF, // NKo
+ 0x0800, 0x083F, // Samaritan
+ 0x0840, 0x085F, // Mandaic
+ 0x0900, 0x097F, // Devanagari
+ 0x0980, 0x09FF, // Bengali
+ 0x0A00, 0x0A7F, // Gurmukhi
+ 0x0A80, 0x0AFF, // Gujarati
+ 0x0B00, 0x0B7F, // Oriya
+ 0x0B80, 0x0BFF, // Tamil
+ 0x0C00, 0x0C7F, // Telugu
+ 0x0C80, 0x0CFF, // Kannada
+ 0x0D00, 0x0D7F, // Malayalam
+ 0x0D80, 0x0DFF, // Sinhala
+ 0x0E00, 0x0E7F, // Thai
+ 0x0E80, 0x0EFF, // Lao
+ 0x0F00, 0x0FFF, // Tibetan
+ 0x1000, 0x109F, // Myanmar
+ 0x10A0, 0x10FF, // Georgian
+ 0x1100, 0x11FF, // Hangul Jamo
+ 0x1200, 0x137F, // Ethiopic
+ 0x1380, 0x139F, // Ethiopic Supplement
+ 0x13A0, 0x13FF, // Cherokee
+ 0x1400, 0x167F, // Unified Canadian Aboriginal Syllabics
+ 0x1680, 0x169F, // Ogham
+ 0x16A0, 0x16FF, // Runic
+ 0x1700, 0x171F, // Tagalog
+ 0x1720, 0x173F, // Hanunoo
+ 0x1740, 0x175F, // Buhid
+ 0x1760, 0x177F, // Tagbanwa
+ 0x1780, 0x17FF, // Khmer
+ 0x1800, 0x18AF, // Mongolian
+ 0x18B0, 0x18FF, // Unified Canadian Aboriginal Syllabics Extended
+ 0x1900, 0x194F, // Limbu
+ 0x1950, 0x197F, // Tai Le
+ 0x1980, 0x19DF, // New Tai Lue
+ 0x19E0, 0x19FF, // Khmer Symbols
+ 0x1A00, 0x1A1F, // Buginese
+ 0x1A20, 0x1AAF, // Tai Tham
+ 0x1B00, 0x1B7F, // Balinese
+ 0x1B80, 0x1BBF, // Sundanese
+ 0x1BC0, 0x1BFF, // Batak
+ 0x1C00, 0x1C4F, // Lepcha
+ 0x1C50, 0x1C7F, // Ol Chiki
+ 0x1CD0, 0x1CFF, // Vedic Extensions
+ 0x1D00, 0x1D7F, // Phonetic Extensions
+ 0x1D80, 0x1DBF, // Phonetic Extensions Supplement
+ 0x1DC0, 0x1DFF, // Combining Diacritical Marks Supplement
+ 0x1E00, 0x1EFF, // Latin Extended Additional
+ 0x1F00, 0x1FFF, // Greek Extended
+ 0x2000, 0x206F, // General Punctuation
+ 0x2070, 0x209F, // Superscripts and Subscripts
+ 0x20A0, 0x20CF, // Currency Symbols
+ 0x20D0, 0x20FF, // Combining Diacritical Marks for Symbols
+ 0x2100, 0x214F, // Letterlike Symbols
+ 0x2150, 0x218F, // Number Forms
+ 0x2190, 0x21FF, // Arrows
+ 0x2200, 0x22FF, // Mathematical Operators
+ 0x2300, 0x23FF, // Miscellaneous Technical
+ 0x2400, 0x243F, // Control Pictures
+ 0x2440, 0x245F, // Optical Character Recognition
+ 0x2460, 0x24FF, // Enclosed Alphanumerics
+ 0x2500, 0x257F, // Box Drawing
+ 0x2580, 0x259F, // Block Elements
+ 0x25A0, 0x25FF, // Geometric Shapes
+ 0x2600, 0x26FF, // Miscellaneous Symbols
+ 0x2700, 0x27BF, // Dingbats
+ 0x27C0, 0x27EF, // Miscellaneous Mathematical Symbols-A
+ 0x27F0, 0x27FF, // Supplemental Arrows-A
+ 0x2800, 0x28FF, // Braille Patterns
+ 0x2900, 0x297F, // Supplemental Arrows-B
+ 0x2980, 0x29FF, // Miscellaneous Mathematical Symbols-B
+ 0x2A00, 0x2AFF, // Supplemental Mathematical Operators
+ 0x2B00, 0x2BFF, // Miscellaneous Symbols and Arrows
+ 0x2C00, 0x2C5F, // Glagolitic
+ 0x2C60, 0x2C7F, // Latin Extended-C
+ 0x2C80, 0x2CFF, // Coptic
+ 0x2D00, 0x2D2F, // Georgian Supplement
+ 0x2D30, 0x2D7F, // Tifinagh
+ 0x2D80, 0x2DDF, // Ethiopic Extended
+ 0x2DE0, 0x2DFF, // Cyrillic Extended-A
+ 0x2E00, 0x2E7F, // Supplemental Punctuation
+ 0x2E80, 0x2EFF, // CJK Radicals Supplement
+ 0x2F00, 0x2FDF, // Kangxi Radicals
+ 0x2FF0, 0x2FFF, // Ideographic Description Characters
+ 0x3000, 0x303F, // CJK Symbols and Punctuation
+ 0x3040, 0x309F, // Hiragana
+ 0x30A0, 0x30FF, // Katakana
+ 0x3100, 0x312F, // Bopomofo
+ 0x3130, 0x318F, // Hangul Compatibility Jamo
+ 0x3190, 0x319F, // Kanbun
+ 0x31A0, 0x31BF, // Bopomofo Extended
+ 0x31C0, 0x31EF, // CJK Strokes
+ 0x31F0, 0x31FF, // Katakana Phonetic Extensions
+ 0x3200, 0x32FF, // Enclosed CJK Letters and Months
+ 0x3300, 0x33FF, // CJK Compatibility
+ 0x3400, 0x4DBF, // CJK Unified Ideographs Extension A
+ 0x4DC0, 0x4DFF, // Yijing Hexagram Symbols
+ 0x4E00, 0x9FFF, // CJK Unified Ideographs
+ 0xA000, 0xA48F, // Yi Syllables
+ 0xA490, 0xA4CF, // Yi Radicals
+ 0xA4D0, 0xA4FF, // Lisu
+ 0xA500, 0xA63F, // Vai
+ 0xA640, 0xA69F, // Cyrillic Extended-B
+ 0xA6A0, 0xA6FF, // Bamum
+ 0xA700, 0xA71F, // Modifier Tone Letters
+ 0xA720, 0xA7FF, // Latin Extended-D
+ 0xA800, 0xA82F, // Syloti Nagri
+ 0xA830, 0xA83F, // Common Indic Number Forms
+ 0xA840, 0xA87F, // Phags-pa
+ 0xA880, 0xA8DF, // Saurashtra
+ 0xA8E0, 0xA8FF, // Devanagari Extended
+ 0xA900, 0xA92F, // Kayah Li
+ 0xA930, 0xA95F, // Rejang
+ 0xA960, 0xA97F, // Hangul Jamo Extended-A
+ 0xA980, 0xA9DF, // Javanese
+ 0xAA00, 0xAA5F, // Cham
+ 0xAA60, 0xAA7F, // Myanmar Extended-A
+ 0xAA80, 0xAADF, // Tai Viet
+ 0xAB00, 0xAB2F, // Ethiopic Extended-A
+ 0xABC0, 0xABFF, // Meetei Mayek
+ 0xAC00, 0xD7AF, // Hangul Syllables
+ 0xD7B0, 0xD7FF, // Hangul Jamo Extended-B
+ //0xD800, 0xDB7F, // High Surrogates
+ //0xDB80, 0xDBFF, // High Private Use Surrogates
+ //0xDC00, 0xDFFF, // Low Surrogates
+ 0xE000, 0xF8FF, // Private Use Area
+ 0xF900, 0xFAFF, // CJK Compatibility Ideographs
+ 0xFB00, 0xFB4F, // Alphabetic Presentation Forms
+ 0xFB50, 0xFDFF, // Arabic Presentation Forms-A
+ 0xFE00, 0xFE0F, // Variation Selectors
+ 0xFE10, 0xFE1F, // Vertical Forms
+ 0xFE20, 0xFE2F, // Combining Half Marks
+ 0xFE30, 0xFE4F, // CJK Compatibility Forms
+ 0xFE50, 0xFE6F, // Small Form Variants
+ 0xFE70, 0xFEFF, // Arabic Presentation Forms-B
+ 0xFF00, 0xFFEF, // Halfwidth and Fullwidth Forms
+ 0xFFF0, 0xFFFF, // Specials
+ 0x10000, 0x1007F, // Linear B Syllabary
+ 0x10080, 0x100FF, // Linear B Ideograms
+ 0x10100, 0x1013F, // Aegean Numbers
+ 0x10140, 0x1018F, // Ancient Greek Numbers
+ 0x10190, 0x101CF, // Ancient Symbols
+ 0x101D0, 0x101FF, // Phaistos Disc
+ 0x10280, 0x1029F, // Lycian
+ 0x102A0, 0x102DF, // Carian
+ 0x10300, 0x1032F, // Old Italic
+ 0x10330, 0x1034F, // Gothic
+ 0x10380, 0x1039F, // Ugaritic
+ 0x103A0, 0x103DF, // Old Persian
+ 0x10400, 0x1044F, // Deseret
+ 0x10450, 0x1047F, // Shavian
+ 0x10480, 0x104AF, // Osmanya
+ 0x10800, 0x1083F, // Cypriot Syllabary
+ 0x10840, 0x1085F, // Imperial Aramaic
+ 0x10900, 0x1091F, // Phoenician
+ 0x10920, 0x1093F, // Lydian
+ 0x10A00, 0x10A5F, // Kharoshthi
+ 0x10A60, 0x10A7F, // Old South Arabian
+ 0x10B00, 0x10B3F, // Avestan
+ 0x10B40, 0x10B5F, // Inscriptional Parthian
+ 0x10B60, 0x10B7F, // Inscriptional Pahlavi
+ 0x10C00, 0x10C4F, // Old Turkic
+ 0x10E60, 0x10E7F, // Rumi Numeral Symbols
+ 0x11000, 0x1107F, // Brahmi
+ 0x11080, 0x110CF, // Kaithi
+ 0x12000, 0x123FF, // Cuneiform
+ 0x12400, 0x1247F, // Cuneiform Numbers and Punctuation
+ 0x13000, 0x1342F, // Egyptian Hieroglyphs
+ 0x16800, 0x16A3F, // Bamum Supplement
+ 0x1B000, 0x1B0FF, // Kana Supplement
+ 0x1D000, 0x1D0FF, // Byzantine Musical Symbols
+ 0x1D100, 0x1D1FF, // Musical Symbols
+ 0x1D200, 0x1D24F, // Ancient Greek Musical Notation
+ 0x1D300, 0x1D35F, // Tai Xuan Jing Symbols
+ 0x1D360, 0x1D37F, // Counting Rod Numerals
+ 0x1D400, 0x1D7FF, // Mathematical Alphanumeric Symbols
+ 0x1F000, 0x1F02F, // Mahjong Tiles
+ 0x1F030, 0x1F09F, // Domino Tiles
+ 0x1F0A0, 0x1F0FF, // Playing Cards
+ 0x1F100, 0x1F1FF, // Enclosed Alphanumeric Supplement
+ 0x1F200, 0x1F2FF, // Enclosed Ideographic Supplement
+ 0x1F300, 0x1F5FF, // Miscellaneous Symbols And Pictographs
+ 0x1F600, 0x1F64F, // Emoticons
+ 0x1F680, 0x1F6FF, // Transport And Map Symbols
+ 0x1F700, 0x1F77F, // Alchemical Symbols
+ 0x20000, 0x2A6DF, // CJK Unified Ideographs Extension B
+ 0x2A700, 0x2B73F, // CJK Unified Ideographs Extension C
+ 0x2B740, 0x2B81F, // CJK Unified Ideographs Extension D
+ 0x2F800, 0x2FA1F, // CJK Compatibility Ideographs Supplement
+ 0xE0000, 0xE007F, // Tags
+ 0xE0100, 0xE01EF, // Variation Selectors Supplement
+ 0xF0000, 0xFFFFF, // Supplementary Private Use Area-A
+ 0x100000, 0x10FFFF, // Supplementary Private Use Area-B
+ 0xFFFFFFFF
+};
+
+// Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
+// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
+
+#define UTF8_ACCEPT 0u
+
+static const unsigned char utf8d[] = {
+ // The first part of the table maps bytes to character classes that
+ // to reduce the size of the transition table and create bitmasks.
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
+
+ // The second part is a transition table that maps a combination
+ // of a state of the automaton and a character class to a state.
+ 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
+ 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
+ 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
+ 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
+ 12,36,12,12,12,12,12,12,12,12,12,12,
+};
+
+static unsigned inline decode(unsigned* state, unsigned* codep, unsigned byte) {
+ unsigned type = utf8d[byte];
+
+ *codep = (*state != UTF8_ACCEPT) ?
+ (byte & 0x3fu) | (*codep << 6) :
+ (0xff >> type) & (byte);
+
+ *state = utf8d[256 + *state + type];
+ return *state;
+}
+
+//static bool IsUTF8(unsigned char* s) {
+// unsigned codepoint, state = 0;
+//
+// while (*s)
+// decode(&state, &codepoint, *s++);
+//
+// return state == UTF8_ACCEPT;
+//}
+
+TEST(EncodingsTest, UTF8) {
+ StringBuffer os, os2;
+ for (const unsigned* range = kCodepointRanges; *range != 0xFFFFFFFF; range += 2) {
+ for (unsigned codepoint = range[0]; codepoint <= range[1]; ++codepoint) {
+ os.Clear();
+ UTF8<>::Encode(os, codepoint);
+ const char* encodedStr = os.GetString();
+
+ // Decode with Hoehrmann
+ {
+ unsigned decodedCodepoint = 0;
+ unsigned state = 0;
+
+ unsigned decodedCount = 0;
+ for (const char* s = encodedStr; *s; ++s)
+ if (!decode(&state, &decodedCodepoint, static_cast<unsigned char>(*s))) {
+ EXPECT_EQ(codepoint, decodedCodepoint);
+ decodedCount++;
+ }
+
+ if (*encodedStr) // This decoder cannot handle U+0000
+ EXPECT_EQ(1u, decodedCount); // Should only contain one code point
+
+ EXPECT_EQ(UTF8_ACCEPT, state);
+ if (UTF8_ACCEPT != state)
+ std::cout << std::hex << codepoint << " " << decodedCodepoint << std::endl;
+ }
+
+ // Decode
+ {
+ StringStream is(encodedStr);
+ unsigned decodedCodepoint;
+ bool result = UTF8<>::Decode(is, &decodedCodepoint);
+ EXPECT_TRUE(result);
+ EXPECT_EQ(codepoint, decodedCodepoint);
+ if (!result || codepoint != decodedCodepoint)
+ std::cout << std::hex << codepoint << " " << decodedCodepoint << std::endl;
+ }
+
+ // Validate
+ {
+ StringStream is(encodedStr);
+ os2.Clear();
+ bool result = UTF8<>::Validate(is, os2);
+ EXPECT_TRUE(result);
+ EXPECT_EQ(0, StrCmp(encodedStr, os2.GetString()));
+ }
+ }
+ }
+}
+
+TEST(EncodingsTest, UTF16) {
+ GenericStringBuffer<UTF16<> > os, os2;
+ GenericStringBuffer<UTF8<> > utf8os;
+ for (const unsigned* range = kCodepointRanges; *range != 0xFFFFFFFF; range += 2) {
+ for (unsigned codepoint = range[0]; codepoint <= range[1]; ++codepoint) {
+ os.Clear();
+ UTF16<>::Encode(os, codepoint);
+ const UTF16<>::Ch* encodedStr = os.GetString();
+
+ // Encode with Hoehrmann's code
+ if (codepoint != 0) // cannot handle U+0000
+ {
+ // encode with UTF8<> first
+ utf8os.Clear();
+ UTF8<>::Encode(utf8os, codepoint);
+
+ // transcode from UTF8 to UTF16 with Hoehrmann's code
+ unsigned decodedCodepoint = 0;
+ unsigned state = 0;
+ UTF16<>::Ch buffer[3], *p = &buffer[0];
+ for (const char* s = utf8os.GetString(); *s; ++s) {
+ if (!decode(&state, &decodedCodepoint, static_cast<unsigned char>(*s)))
+ break;
+ }
+
+ if (codepoint <= 0xFFFF)
+ *p++ = static_cast<UTF16<>::Ch>(decodedCodepoint);
+ else {
+ // Encode code points above U+FFFF as surrogate pair.
+ *p++ = static_cast<UTF16<>::Ch>(0xD7C0 + (decodedCodepoint >> 10));
+ *p++ = static_cast<UTF16<>::Ch>(0xDC00 + (decodedCodepoint & 0x3FF));
+ }
+ *p++ = '\0';
+
+ EXPECT_EQ(0, StrCmp(buffer, encodedStr));
+ }
+
+ // Decode
+ {
+ GenericStringStream<UTF16<> > is(encodedStr);
+ unsigned decodedCodepoint;
+ bool result = UTF16<>::Decode(is, &decodedCodepoint);
+ EXPECT_TRUE(result);
+ EXPECT_EQ(codepoint, decodedCodepoint);
+ if (!result || codepoint != decodedCodepoint)
+ std::cout << std::hex << codepoint << " " << decodedCodepoint << std::endl;
+ }
+
+ // Validate
+ {
+ GenericStringStream<UTF16<> > is(encodedStr);
+ os2.Clear();
+ bool result = UTF16<>::Validate(is, os2);
+ EXPECT_TRUE(result);
+ EXPECT_EQ(0, StrCmp(encodedStr, os2.GetString()));
+ }
+ }
+ }
+}
+
+TEST(EncodingsTest, UTF32) {
+ GenericStringBuffer<UTF32<> > os, os2;
+ for (const unsigned* range = kCodepointRanges; *range != 0xFFFFFFFF; range += 2) {
+ for (unsigned codepoint = range[0]; codepoint <= range[1]; ++codepoint) {
+ os.Clear();
+ UTF32<>::Encode(os, codepoint);
+ const UTF32<>::Ch* encodedStr = os.GetString();
+
+ // Decode
+ {
+ GenericStringStream<UTF32<> > is(encodedStr);
+ unsigned decodedCodepoint;
+ bool result = UTF32<>::Decode(is, &decodedCodepoint);
+ EXPECT_TRUE(result);
+ EXPECT_EQ(codepoint, decodedCodepoint);
+ if (!result || codepoint != decodedCodepoint)
+ std::cout << std::hex << codepoint << " " << decodedCodepoint << std::endl;
+ }
+
+ // Validate
+ {
+ GenericStringStream<UTF32<> > is(encodedStr);
+ os2.Clear();
+ bool result = UTF32<>::Validate(is, os2);
+ EXPECT_TRUE(result);
+ EXPECT_EQ(0, StrCmp(encodedStr, os2.GetString()));
+ }
+ }
+ }
+}
diff --git a/3rdparty/rapidjson/test/unittest/filestreamtest.cpp b/3rdparty/rapidjson/test/unittest/filestreamtest.cpp
new file mode 100644
index 00000000000..a38133fa7f6
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/filestreamtest.cpp
@@ -0,0 +1,112 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/filewritestream.h"
+#include "rapidjson/encodedstream.h"
+
+using namespace rapidjson;
+
+class FileStreamTest : public ::testing::Test {
+public:
+ FileStreamTest() : filename_(), json_(), length_() {}
+ virtual ~FileStreamTest();
+
+ virtual void SetUp() {
+ const char *paths[] = {
+ "data/sample.json",
+ "bin/data/sample.json",
+ "../bin/data/sample.json",
+ "../../bin/data/sample.json",
+ "../../../bin/data/sample.json"
+ };
+ FILE* fp = 0;
+ for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
+ fp = fopen(paths[i], "rb");
+ if (fp) {
+ filename_ = paths[i];
+ break;
+ }
+ }
+ ASSERT_TRUE(fp != 0);
+
+ fseek(fp, 0, SEEK_END);
+ length_ = static_cast<size_t>(ftell(fp));
+ fseek(fp, 0, SEEK_SET);
+ json_ = static_cast<char*>(malloc(length_ + 1));
+ size_t readLength = fread(json_, 1, length_, fp);
+ json_[readLength] = '\0';
+ fclose(fp);
+ }
+
+ virtual void TearDown() {
+ free(json_);
+ json_ = 0;
+ }
+
+private:
+ FileStreamTest(const FileStreamTest&);
+ FileStreamTest& operator=(const FileStreamTest&);
+
+protected:
+ const char* filename_;
+ char *json_;
+ size_t length_;
+};
+
+FileStreamTest::~FileStreamTest() {}
+
+TEST_F(FileStreamTest, FileReadStream) {
+ FILE *fp = fopen(filename_, "rb");
+ ASSERT_TRUE(fp != 0);
+ char buffer[65536];
+ FileReadStream s(fp, buffer, sizeof(buffer));
+
+ for (size_t i = 0; i < length_; i++) {
+ EXPECT_EQ(json_[i], s.Peek());
+ EXPECT_EQ(json_[i], s.Peek()); // 2nd time should be the same
+ EXPECT_EQ(json_[i], s.Take());
+ }
+
+ EXPECT_EQ(length_, s.Tell());
+ EXPECT_EQ('\0', s.Peek());
+
+ fclose(fp);
+}
+
+TEST_F(FileStreamTest, FileWriteStream) {
+ char filename[L_tmpnam];
+ FILE* fp = TempFile(filename);
+
+ char buffer[65536];
+ FileWriteStream os(fp, buffer, sizeof(buffer));
+ for (size_t i = 0; i < length_; i++)
+ os.Put(json_[i]);
+ os.Flush();
+ fclose(fp);
+
+ // Read it back to verify
+ fp = fopen(filename, "rb");
+ FileReadStream is(fp, buffer, sizeof(buffer));
+
+ for (size_t i = 0; i < length_; i++)
+ EXPECT_EQ(json_[i], is.Take());
+
+ EXPECT_EQ(length_, is.Tell());
+ fclose(fp);
+
+ //std::cout << filename << std::endl;
+ remove(filename);
+}
diff --git a/3rdparty/rapidjson/test/unittest/fwdtest.cpp b/3rdparty/rapidjson/test/unittest/fwdtest.cpp
new file mode 100644
index 00000000000..4f326846116
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/fwdtest.cpp
@@ -0,0 +1,227 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+
+// Using forward declared types here.
+
+#include "rapidjson/fwd.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+using namespace rapidjson;
+
+struct Foo {
+ Foo();
+ ~Foo();
+
+ // encodings.h
+ UTF8<char>* utf8;
+ UTF16<wchar_t>* utf16;
+ UTF16BE<wchar_t>* utf16be;
+ UTF16LE<wchar_t>* utf16le;
+ UTF32<unsigned>* utf32;
+ UTF32BE<unsigned>* utf32be;
+ UTF32LE<unsigned>* utf32le;
+ ASCII<char>* ascii;
+ AutoUTF<unsigned>* autoutf;
+ Transcoder<UTF8<char>, UTF8<char> >* transcoder;
+
+ // allocators.h
+ CrtAllocator* crtallocator;
+ MemoryPoolAllocator<CrtAllocator>* memorypoolallocator;
+
+ // stream.h
+ StringStream* stringstream;
+ InsituStringStream* insitustringstream;
+
+ // stringbuffer.h
+ StringBuffer* stringbuffer;
+
+ // // filereadstream.h
+ // FileReadStream* filereadstream;
+
+ // // filewritestream.h
+ // FileWriteStream* filewritestream;
+
+ // memorybuffer.h
+ MemoryBuffer* memorybuffer;
+
+ // memorystream.h
+ MemoryStream* memorystream;
+
+ // reader.h
+ BaseReaderHandler<UTF8<char>, void>* basereaderhandler;
+ Reader* reader;
+
+ // writer.h
+ Writer<StringBuffer, UTF8<char>, UTF8<char>, CrtAllocator, 0>* writer;
+
+ // prettywriter.h
+ PrettyWriter<StringBuffer, UTF8<char>, UTF8<char>, CrtAllocator, 0>* prettywriter;
+
+ // document.h
+ Value* value;
+ Document* document;
+
+ // pointer.h
+ Pointer* pointer;
+
+ // schema.h
+ SchemaDocument* schemadocument;
+ SchemaValidator* schemavalidator;
+
+ // char buffer[16];
+};
+
+// Using type definitions here.
+
+#include "rapidjson/stringbuffer.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/filewritestream.h"
+#include "rapidjson/memorybuffer.h"
+#include "rapidjson/memorystream.h"
+#include "rapidjson/document.h" // -> reader.h
+#include "rapidjson/writer.h"
+#include "rapidjson/prettywriter.h"
+#include "rapidjson/schema.h" // -> pointer.h
+
+Foo::Foo() :
+ // encodings.h
+ utf8(RAPIDJSON_NEW(UTF8<>)),
+ utf16(RAPIDJSON_NEW(UTF16<>)),
+ utf16be(RAPIDJSON_NEW(UTF16BE<>)),
+ utf16le(RAPIDJSON_NEW(UTF16LE<>)),
+ utf32(RAPIDJSON_NEW(UTF32<>)),
+ utf32be(RAPIDJSON_NEW(UTF32BE<>)),
+ utf32le(RAPIDJSON_NEW(UTF32LE<>)),
+ ascii(RAPIDJSON_NEW(ASCII<>)),
+ autoutf(RAPIDJSON_NEW(AutoUTF<unsigned>)),
+ transcoder(RAPIDJSON_NEW((Transcoder<UTF8<>, UTF8<> >))),
+
+ // allocators.h
+ crtallocator(RAPIDJSON_NEW(CrtAllocator)),
+ memorypoolallocator(RAPIDJSON_NEW(MemoryPoolAllocator<>)),
+
+ // stream.h
+ stringstream(RAPIDJSON_NEW(StringStream(0))),
+ insitustringstream(RAPIDJSON_NEW(InsituStringStream(0))),
+
+ // stringbuffer.h
+ stringbuffer(RAPIDJSON_NEW(StringBuffer)),
+
+ // // filereadstream.h
+ // filereadstream(RAPIDJSON_NEW(FileReadStream(stdout, buffer, sizeof(buffer)))),
+
+ // // filewritestream.h
+ // filewritestream(RAPIDJSON_NEW(FileWriteStream(stdout, buffer, sizeof(buffer)))),
+
+ // memorybuffer.h
+ memorybuffer(RAPIDJSON_NEW(MemoryBuffer)),
+
+ // memorystream.h
+ memorystream(RAPIDJSON_NEW(MemoryStream(0, 0))),
+
+ // reader.h
+ basereaderhandler(RAPIDJSON_NEW((BaseReaderHandler<UTF8<>, void>))),
+ reader(RAPIDJSON_NEW(Reader)),
+
+ // writer.h
+ writer(RAPIDJSON_NEW((Writer<StringBuffer>))),
+
+ // prettywriter.h
+ prettywriter(RAPIDJSON_NEW((PrettyWriter<StringBuffer>))),
+
+ // document.h
+ value(RAPIDJSON_NEW(Value)),
+ document(RAPIDJSON_NEW(Document)),
+
+ // pointer.h
+ pointer(RAPIDJSON_NEW(Pointer)),
+
+ // schema.h
+ schemadocument(RAPIDJSON_NEW(SchemaDocument(*document))),
+ schemavalidator(RAPIDJSON_NEW(SchemaValidator(*schemadocument)))
+{
+
+}
+
+Foo::~Foo() {
+ // encodings.h
+ RAPIDJSON_DELETE(utf8);
+ RAPIDJSON_DELETE(utf16);
+ RAPIDJSON_DELETE(utf16be);
+ RAPIDJSON_DELETE(utf16le);
+ RAPIDJSON_DELETE(utf32);
+ RAPIDJSON_DELETE(utf32be);
+ RAPIDJSON_DELETE(utf32le);
+ RAPIDJSON_DELETE(ascii);
+ RAPIDJSON_DELETE(autoutf);
+ RAPIDJSON_DELETE(transcoder);
+
+ // allocators.h
+ RAPIDJSON_DELETE(crtallocator);
+ RAPIDJSON_DELETE(memorypoolallocator);
+
+ // stream.h
+ RAPIDJSON_DELETE(stringstream);
+ RAPIDJSON_DELETE(insitustringstream);
+
+ // stringbuffer.h
+ RAPIDJSON_DELETE(stringbuffer);
+
+ // // filereadstream.h
+ // RAPIDJSON_DELETE(filereadstream);
+
+ // // filewritestream.h
+ // RAPIDJSON_DELETE(filewritestream);
+
+ // memorybuffer.h
+ RAPIDJSON_DELETE(memorybuffer);
+
+ // memorystream.h
+ RAPIDJSON_DELETE(memorystream);
+
+ // reader.h
+ RAPIDJSON_DELETE(basereaderhandler);
+ RAPIDJSON_DELETE(reader);
+
+ // writer.h
+ RAPIDJSON_DELETE(writer);
+
+ // prettywriter.h
+ RAPIDJSON_DELETE(prettywriter);
+
+ // document.h
+ RAPIDJSON_DELETE(value);
+ RAPIDJSON_DELETE(document);
+
+ // pointer.h
+ RAPIDJSON_DELETE(pointer);
+
+ // schema.h
+ RAPIDJSON_DELETE(schemadocument);
+ RAPIDJSON_DELETE(schemavalidator);
+}
+
+TEST(Fwd, Fwd) {
+ Foo f;
+}
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
diff --git a/3rdparty/rapidjson/test/unittest/istreamwrappertest.cpp b/3rdparty/rapidjson/test/unittest/istreamwrappertest.cpp
new file mode 100644
index 00000000000..f6b0fa916e2
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/istreamwrappertest.cpp
@@ -0,0 +1,171 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+
+#include "rapidjson/istreamwrapper.h"
+#include "rapidjson/encodedstream.h"
+#include "rapidjson/document.h"
+#include <sstream>
+#include <fstream>
+
+using namespace rapidjson;
+using namespace std;
+
+template <typename StringStreamType>
+static void TestStringStream() {
+ typedef typename StringStreamType::char_type Ch;
+
+ {
+ StringStreamType iss;
+ BasicIStreamWrapper<StringStreamType> is(iss);
+ EXPECT_EQ(0, is.Tell());
+ if (sizeof(Ch) == 1) {
+ EXPECT_EQ(0, is.Peek4());
+ EXPECT_EQ(0, is.Tell());
+ }
+ EXPECT_EQ(0, is.Peek());
+ EXPECT_EQ(0, is.Take());
+ EXPECT_EQ(0, is.Tell());
+ }
+
+ {
+ Ch s[] = { 'A', 'B', 'C', '\0' };
+ StringStreamType iss(s);
+ BasicIStreamWrapper<StringStreamType> is(iss);
+ EXPECT_EQ(0, is.Tell());
+ if (sizeof(Ch) == 1)
+ EXPECT_EQ(0, is.Peek4()); // less than 4 bytes
+ for (int i = 0; i < 3; i++) {
+ EXPECT_EQ(static_cast<size_t>(i), is.Tell());
+ EXPECT_EQ('A' + i, is.Peek());
+ EXPECT_EQ('A' + i, is.Peek());
+ EXPECT_EQ('A' + i, is.Take());
+ }
+ EXPECT_EQ(3, is.Tell());
+ EXPECT_EQ(0, is.Peek());
+ EXPECT_EQ(0, is.Take());
+ }
+
+ {
+ Ch s[] = { 'A', 'B', 'C', 'D', 'E', '\0' };
+ StringStreamType iss(s);
+ BasicIStreamWrapper<StringStreamType> is(iss);
+ if (sizeof(Ch) == 1) {
+ const Ch* c = is.Peek4();
+ for (int i = 0; i < 4; i++)
+ EXPECT_EQ('A' + i, c[i]);
+ EXPECT_EQ(0, is.Tell());
+ }
+ for (int i = 0; i < 5; i++) {
+ EXPECT_EQ(static_cast<size_t>(i), is.Tell());
+ EXPECT_EQ('A' + i, is.Peek());
+ EXPECT_EQ('A' + i, is.Peek());
+ EXPECT_EQ('A' + i, is.Take());
+ }
+ EXPECT_EQ(5, is.Tell());
+ EXPECT_EQ(0, is.Peek());
+ EXPECT_EQ(0, is.Take());
+ }
+}
+
+TEST(IStreamWrapper, istringstream) {
+ TestStringStream<istringstream>();
+}
+
+TEST(IStreamWrapper, stringstream) {
+ TestStringStream<stringstream>();
+}
+
+TEST(IStreamWrapper, wistringstream) {
+ TestStringStream<wistringstream>();
+}
+
+TEST(IStreamWrapper, wstringstream) {
+ TestStringStream<wstringstream>();
+}
+
+template <typename FileStreamType>
+static bool Open(FileStreamType& fs, const char* filename) {
+ const char *paths[] = {
+ "encodings",
+ "bin/encodings",
+ "../bin/encodings",
+ "../../bin/encodings",
+ "../../../bin/encodings"
+ };
+ char buffer[1024];
+ for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
+ sprintf(buffer, "%s/%s", paths[i], filename);
+ fs.open(buffer, ios_base::in | ios_base::binary);
+ if (fs.is_open())
+ return true;
+ }
+ return false;
+}
+
+TEST(IStreamWrapper, ifstream) {
+ ifstream ifs;
+ ASSERT_TRUE(Open(ifs, "utf8bom.json"));
+ IStreamWrapper isw(ifs);
+ EncodedInputStream<UTF8<>, IStreamWrapper> eis(isw);
+ Document d;
+ EXPECT_TRUE(!d.ParseStream(eis).HasParseError());
+ EXPECT_TRUE(d.IsObject());
+ EXPECT_EQ(5, d.MemberCount());
+}
+
+TEST(IStreamWrapper, fstream) {
+ fstream fs;
+ ASSERT_TRUE(Open(fs, "utf8bom.json"));
+ IStreamWrapper isw(fs);
+ EncodedInputStream<UTF8<>, IStreamWrapper> eis(isw);
+ Document d;
+ EXPECT_TRUE(!d.ParseStream(eis).HasParseError());
+ EXPECT_TRUE(d.IsObject());
+ EXPECT_EQ(5, d.MemberCount());
+}
+
+// wifstream/wfstream only works on C++11 with codecvt_utf16
+// But many C++11 library still not have it.
+#if 0
+#include <codecvt>
+
+TEST(IStreamWrapper, wifstream) {
+ wifstream ifs;
+ ASSERT_TRUE(Open(ifs, "utf16bebom.json"));
+ ifs.imbue(std::locale(ifs.getloc(),
+ new std::codecvt_utf16<wchar_t, 0x10ffff, std::consume_header>));
+ WIStreamWrapper isw(ifs);
+ GenericDocument<UTF16<> > d;
+ d.ParseStream<kParseDefaultFlags, UTF16<>, WIStreamWrapper>(isw);
+ EXPECT_TRUE(!d.HasParseError());
+ EXPECT_TRUE(d.IsObject());
+ EXPECT_EQ(5, d.MemberCount());
+}
+
+TEST(IStreamWrapper, wfstream) {
+ wfstream fs;
+ ASSERT_TRUE(Open(fs, "utf16bebom.json"));
+ fs.imbue(std::locale(fs.getloc(),
+ new std::codecvt_utf16<wchar_t, 0x10ffff, std::consume_header>));
+ WIStreamWrapper isw(fs);
+ GenericDocument<UTF16<> > d;
+ d.ParseStream<kParseDefaultFlags, UTF16<>, WIStreamWrapper>(isw);
+ EXPECT_TRUE(!d.HasParseError());
+ EXPECT_TRUE(d.IsObject());
+ EXPECT_EQ(5, d.MemberCount());
+}
+
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
diff --git a/3rdparty/rapidjson/test/unittest/itoatest.cpp b/3rdparty/rapidjson/test/unittest/itoatest.cpp
new file mode 100644
index 00000000000..9c3107d4178
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/itoatest.cpp
@@ -0,0 +1,158 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+#include "rapidjson/internal/itoa.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(type-limits)
+#endif
+
+using namespace rapidjson::internal;
+
+template <typename T>
+struct Traits {
+};
+
+template <>
+struct Traits<uint32_t> {
+ enum { kBufferSize = 11 };
+ enum { kMaxDigit = 10 };
+ static uint32_t Negate(uint32_t x) { return x; }
+};
+
+template <>
+struct Traits<int32_t> {
+ enum { kBufferSize = 12 };
+ enum { kMaxDigit = 10 };
+ static int32_t Negate(int32_t x) { return -x; }
+};
+
+template <>
+struct Traits<uint64_t> {
+ enum { kBufferSize = 21 };
+ enum { kMaxDigit = 20 };
+ static uint64_t Negate(uint64_t x) { return x; }
+};
+
+template <>
+struct Traits<int64_t> {
+ enum { kBufferSize = 22 };
+ enum { kMaxDigit = 20 };
+ static int64_t Negate(int64_t x) { return -x; }
+};
+
+template <typename T>
+static void VerifyValue(T value, void(*f)(T, char*), char* (*g)(T, char*)) {
+ char buffer1[Traits<T>::kBufferSize];
+ char buffer2[Traits<T>::kBufferSize];
+
+ f(value, buffer1);
+ *g(value, buffer2) = '\0';
+
+
+ EXPECT_STREQ(buffer1, buffer2);
+}
+
+template <typename T>
+static void Verify(void(*f)(T, char*), char* (*g)(T, char*)) {
+ // Boundary cases
+ VerifyValue<T>(0, f, g);
+ VerifyValue<T>(std::numeric_limits<T>::min(), f, g);
+ VerifyValue<T>(std::numeric_limits<T>::max(), f, g);
+
+ // 2^n - 1, 2^n, 10^n - 1, 10^n until overflow
+ for (uint32_t power = 2; power <= 10; power += 8) {
+ T i = 1, last;
+ do {
+ VerifyValue<T>(i - 1, f, g);
+ VerifyValue<T>(i, f, g);
+ if (std::numeric_limits<T>::min() < 0) {
+ VerifyValue<T>(Traits<T>::Negate(i), f, g);
+ VerifyValue<T>(Traits<T>::Negate(i + 1), f, g);
+ }
+ last = i;
+ i *= power;
+ } while (last < i);
+ }
+}
+
+static void u32toa_naive(uint32_t value, char* buffer) {
+ char temp[10];
+ char *p = temp;
+ do {
+ *p++ = char(value % 10) + '0';
+ value /= 10;
+ } while (value > 0);
+
+ do {
+ *buffer++ = *--p;
+ } while (p != temp);
+
+ *buffer = '\0';
+}
+
+static void i32toa_naive(int32_t value, char* buffer) {
+ uint32_t u = static_cast<uint32_t>(value);
+ if (value < 0) {
+ *buffer++ = '-';
+ u = ~u + 1;
+ }
+ u32toa_naive(u, buffer);
+}
+
+static void u64toa_naive(uint64_t value, char* buffer) {
+ char temp[20];
+ char *p = temp;
+ do {
+ *p++ = char(value % 10) + '0';
+ value /= 10;
+ } while (value > 0);
+
+ do {
+ *buffer++ = *--p;
+ } while (p != temp);
+
+ *buffer = '\0';
+}
+
+static void i64toa_naive(int64_t value, char* buffer) {
+ uint64_t u = static_cast<uint64_t>(value);
+ if (value < 0) {
+ *buffer++ = '-';
+ u = ~u + 1;
+ }
+ u64toa_naive(u, buffer);
+}
+
+TEST(itoa, u32toa) {
+ Verify(u32toa_naive, u32toa);
+}
+
+TEST(itoa, i32toa) {
+ Verify(i32toa_naive, i32toa);
+}
+
+TEST(itoa, u64toa) {
+ Verify(u64toa_naive, u64toa);
+}
+
+TEST(itoa, i64toa) {
+ Verify(i64toa_naive, i64toa);
+}
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
diff --git a/3rdparty/rapidjson/test/unittest/jsoncheckertest.cpp b/3rdparty/rapidjson/test/unittest/jsoncheckertest.cpp
new file mode 100644
index 00000000000..bea788d26e3
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/jsoncheckertest.cpp
@@ -0,0 +1,99 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+
+#include "rapidjson/document.h"
+
+using namespace rapidjson;
+
+static char* ReadFile(const char* filename, size_t& length) {
+ const char *paths[] = {
+ "jsonchecker",
+ "bin/jsonchecker",
+ "../bin/jsonchecker",
+ "../../bin/jsonchecker",
+ "../../../bin/jsonchecker"
+ };
+ char buffer[1024];
+ FILE *fp = 0;
+ for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
+ sprintf(buffer, "%s/%s", paths[i], filename);
+ fp = fopen(buffer, "rb");
+ if (fp)
+ break;
+ }
+
+ if (!fp)
+ return 0;
+
+ fseek(fp, 0, SEEK_END);
+ length = static_cast<size_t>(ftell(fp));
+ fseek(fp, 0, SEEK_SET);
+ char* json = static_cast<char*>(malloc(length + 1));
+ size_t readLength = fread(json, 1, length, fp);
+ json[readLength] = '\0';
+ fclose(fp);
+ return json;
+}
+
+TEST(JsonChecker, Reader) {
+ char filename[256];
+
+ // jsonchecker/failXX.json
+ for (int i = 1; i <= 33; i++) {
+ if (i == 1) // fail1.json is valid in rapidjson, which has no limitation on type of root element (RFC 7159).
+ continue;
+ if (i == 18) // fail18.json is valid in rapidjson, which has no limitation on depth of nesting.
+ continue;
+
+ sprintf(filename, "fail%d.json", i);
+ size_t length;
+ char* json = ReadFile(filename, length);
+ if (!json) {
+ printf("jsonchecker file %s not found", filename);
+ ADD_FAILURE();
+ continue;
+ }
+
+ GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
+ document.Parse(json);
+ EXPECT_TRUE(document.HasParseError());
+
+ document.Parse<kParseIterativeFlag>(json);
+ EXPECT_TRUE(document.HasParseError());
+
+ free(json);
+ }
+
+ // passX.json
+ for (int i = 1; i <= 3; i++) {
+ sprintf(filename, "pass%d.json", i);
+ size_t length;
+ char* json = ReadFile(filename, length);
+ if (!json) {
+ printf("jsonchecker file %s not found", filename);
+ continue;
+ }
+
+ GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
+ document.Parse(json);
+ EXPECT_FALSE(document.HasParseError());
+
+ document.Parse<kParseIterativeFlag>(json);
+ EXPECT_FALSE(document.HasParseError());
+
+ free(json);
+ }
+}
diff --git a/3rdparty/rapidjson/test/unittest/namespacetest.cpp b/3rdparty/rapidjson/test/unittest/namespacetest.cpp
new file mode 100644
index 00000000000..1814724aec6
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/namespacetest.cpp
@@ -0,0 +1,70 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+
+// test another instantiation of RapidJSON in a different namespace
+
+#define RAPIDJSON_NAMESPACE my::rapid::json
+#define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapid { namespace json {
+#define RAPIDJSON_NAMESPACE_END } } }
+
+// include lots of RapidJSON files
+
+#include "rapidjson/document.h"
+#include "rapidjson/writer.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/filewritestream.h"
+#include "rapidjson/encodedstream.h"
+#include "rapidjson/stringbuffer.h"
+
+static const char json[] = "{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3,4]}";
+
+TEST(NamespaceTest,Using) {
+ using namespace RAPIDJSON_NAMESPACE;
+ typedef GenericDocument<UTF8<>, CrtAllocator> DocumentType;
+ DocumentType doc;
+
+ doc.Parse(json);
+ EXPECT_TRUE(!doc.HasParseError());
+}
+
+TEST(NamespaceTest,Direct) {
+ typedef RAPIDJSON_NAMESPACE::Document Document;
+ typedef RAPIDJSON_NAMESPACE::Reader Reader;
+ typedef RAPIDJSON_NAMESPACE::StringStream StringStream;
+ typedef RAPIDJSON_NAMESPACE::StringBuffer StringBuffer;
+ typedef RAPIDJSON_NAMESPACE::Writer<StringBuffer> WriterType;
+
+ StringStream s(json);
+ StringBuffer buffer;
+ WriterType writer(buffer);
+ buffer.ShrinkToFit();
+ Reader reader;
+ reader.Parse(s, writer);
+
+ EXPECT_STREQ(json, buffer.GetString());
+ EXPECT_EQ(sizeof(json)-1, buffer.GetSize());
+ EXPECT_TRUE(writer.IsComplete());
+
+ Document doc;
+ doc.Parse(buffer.GetString());
+ EXPECT_TRUE(!doc.HasParseError());
+
+ buffer.Clear();
+ writer.Reset(buffer);
+ doc.Accept(writer);
+ EXPECT_STREQ(json, buffer.GetString());
+ EXPECT_TRUE(writer.IsComplete());
+}
diff --git a/3rdparty/rapidjson/test/unittest/ostreamwrappertest.cpp b/3rdparty/rapidjson/test/unittest/ostreamwrappertest.cpp
new file mode 100644
index 00000000000..b1d1cd827fc
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/ostreamwrappertest.cpp
@@ -0,0 +1,91 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+
+#include "rapidjson/ostreamwrapper.h"
+#include "rapidjson/encodedstream.h"
+#include "rapidjson/document.h"
+#include <sstream>
+#include <fstream>
+
+using namespace rapidjson;
+using namespace std;
+
+template <typename StringStreamType>
+static void TestStringStream() {
+ typedef typename StringStreamType::char_type Ch;
+
+ Ch s[] = { 'A', 'B', 'C', '\0' };
+ StringStreamType oss(s);
+ BasicOStreamWrapper<StringStreamType> os(oss);
+ for (size_t i = 0; i < 3; i++)
+ os.Put(s[i]);
+ os.Flush();
+ for (size_t i = 0; i < 3; i++)
+ EXPECT_EQ(s[i], oss.str()[i]);
+}
+
+TEST(OStreamWrapper, ostringstream) {
+ TestStringStream<ostringstream>();
+}
+
+TEST(OStreamWrapper, stringstream) {
+ TestStringStream<stringstream>();
+}
+
+TEST(OStreamWrapper, wostringstream) {
+ TestStringStream<wostringstream>();
+}
+
+TEST(OStreamWrapper, wstringstream) {
+ TestStringStream<wstringstream>();
+}
+
+TEST(OStreamWrapper, cout) {
+ OStreamWrapper os(cout);
+ const char* s = "Hello World!\n";
+ while (*s)
+ os.Put(*s++);
+ os.Flush();
+}
+
+template <typename FileStreamType>
+static void TestFileStream() {
+ char filename[L_tmpnam];
+ FILE* fp = TempFile(filename);
+ fclose(fp);
+
+ const char* s = "Hello World!\n";
+ {
+ ofstream ofs(filename, ios::out | ios::binary);
+ BasicOStreamWrapper<ofstream> osw(ofs);
+ for (const char* p = s; *p; p++)
+ osw.Put(*p);
+ osw.Flush();
+ }
+
+ fp = fopen(filename, "r");
+ for (const char* p = s; *p; p++)
+ EXPECT_EQ(*p, static_cast<char>(fgetc(fp)));
+ fclose(fp);
+}
+
+TEST(OStreamWrapper, ofstream) {
+ TestFileStream<ofstream>();
+}
+
+TEST(OStreamWrapper, fstream) {
+ TestFileStream<fstream>();
+}
diff --git a/3rdparty/rapidjson/test/unittest/pointertest.cpp b/3rdparty/rapidjson/test/unittest/pointertest.cpp
new file mode 100644
index 00000000000..dbddbedee25
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/pointertest.cpp
@@ -0,0 +1,1524 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+#include "rapidjson/pointer.h"
+#include "rapidjson/stringbuffer.h"
+#include <sstream>
+
+using namespace rapidjson;
+
+static const char kJson[] = "{\n"
+" \"foo\":[\"bar\", \"baz\"],\n"
+" \"\" : 0,\n"
+" \"a/b\" : 1,\n"
+" \"c%d\" : 2,\n"
+" \"e^f\" : 3,\n"
+" \"g|h\" : 4,\n"
+" \"i\\\\j\" : 5,\n"
+" \"k\\\"l\" : 6,\n"
+" \" \" : 7,\n"
+" \"m~n\" : 8\n"
+"}";
+
+TEST(Pointer, DefaultConstructor) {
+ Pointer p;
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(0u, p.GetTokenCount());
+}
+
+TEST(Pointer, Parse) {
+ {
+ Pointer p("");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(0u, p.GetTokenCount());
+ }
+
+ {
+ Pointer p("/");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_EQ(0u, p.GetTokens()[0].length);
+ EXPECT_STREQ("", p.GetTokens()[0].name);
+ EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
+ }
+
+ {
+ Pointer p("/foo");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_EQ(3u, p.GetTokens()[0].length);
+ EXPECT_STREQ("foo", p.GetTokens()[0].name);
+ EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
+ }
+
+ #if RAPIDJSON_HAS_STDSTRING
+ {
+ Pointer p(std::string("/foo"));
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_EQ(3u, p.GetTokens()[0].length);
+ EXPECT_STREQ("foo", p.GetTokens()[0].name);
+ EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
+ }
+ #endif
+
+ {
+ Pointer p("/foo/0");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(2u, p.GetTokenCount());
+ EXPECT_EQ(3u, p.GetTokens()[0].length);
+ EXPECT_STREQ("foo", p.GetTokens()[0].name);
+ EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
+ EXPECT_EQ(1u, p.GetTokens()[1].length);
+ EXPECT_STREQ("0", p.GetTokens()[1].name);
+ EXPECT_EQ(0u, p.GetTokens()[1].index);
+ }
+
+ {
+ // Unescape ~1
+ Pointer p("/a~1b");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_EQ(3u, p.GetTokens()[0].length);
+ EXPECT_STREQ("a/b", p.GetTokens()[0].name);
+ }
+
+ {
+ // Unescape ~0
+ Pointer p("/m~0n");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_EQ(3u, p.GetTokens()[0].length);
+ EXPECT_STREQ("m~n", p.GetTokens()[0].name);
+ }
+
+ {
+ // empty name
+ Pointer p("/");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_EQ(0u, p.GetTokens()[0].length);
+ EXPECT_STREQ("", p.GetTokens()[0].name);
+ }
+
+ {
+ // empty and non-empty name
+ Pointer p("//a");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(2u, p.GetTokenCount());
+ EXPECT_EQ(0u, p.GetTokens()[0].length);
+ EXPECT_STREQ("", p.GetTokens()[0].name);
+ EXPECT_EQ(1u, p.GetTokens()[1].length);
+ EXPECT_STREQ("a", p.GetTokens()[1].name);
+ }
+
+ {
+ // Null characters
+ Pointer p("/\0\0", 3);
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_EQ(2u, p.GetTokens()[0].length);
+ EXPECT_EQ('\0', p.GetTokens()[0].name[0]);
+ EXPECT_EQ('\0', p.GetTokens()[0].name[1]);
+ EXPECT_EQ('\0', p.GetTokens()[0].name[2]);
+ }
+
+ {
+ // Valid index
+ Pointer p("/123");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_STREQ("123", p.GetTokens()[0].name);
+ EXPECT_EQ(123u, p.GetTokens()[0].index);
+ }
+
+ {
+ // Invalid index (with leading zero)
+ Pointer p("/01");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_STREQ("01", p.GetTokens()[0].name);
+ EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
+ }
+
+ if (sizeof(SizeType) == 4) {
+ // Invalid index (overflow)
+ Pointer p("/4294967296");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_STREQ("4294967296", p.GetTokens()[0].name);
+ EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
+ }
+
+ {
+ // kPointerParseErrorTokenMustBeginWithSolidus
+ Pointer p(" ");
+ EXPECT_FALSE(p.IsValid());
+ EXPECT_EQ(kPointerParseErrorTokenMustBeginWithSolidus, p.GetParseErrorCode());
+ EXPECT_EQ(0u, p.GetParseErrorOffset());
+ }
+
+ {
+ // kPointerParseErrorInvalidEscape
+ Pointer p("/~");
+ EXPECT_FALSE(p.IsValid());
+ EXPECT_EQ(kPointerParseErrorInvalidEscape, p.GetParseErrorCode());
+ EXPECT_EQ(2u, p.GetParseErrorOffset());
+ }
+
+ {
+ // kPointerParseErrorInvalidEscape
+ Pointer p("/~2");
+ EXPECT_FALSE(p.IsValid());
+ EXPECT_EQ(kPointerParseErrorInvalidEscape, p.GetParseErrorCode());
+ EXPECT_EQ(2u, p.GetParseErrorOffset());
+ }
+}
+
+TEST(Pointer, Parse_URIFragment) {
+ {
+ Pointer p("#");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(0u, p.GetTokenCount());
+ }
+
+ {
+ Pointer p("#/foo");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_EQ(3u, p.GetTokens()[0].length);
+ EXPECT_STREQ("foo", p.GetTokens()[0].name);
+ }
+
+ {
+ Pointer p("#/foo/0");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(2u, p.GetTokenCount());
+ EXPECT_EQ(3u, p.GetTokens()[0].length);
+ EXPECT_STREQ("foo", p.GetTokens()[0].name);
+ EXPECT_EQ(1u, p.GetTokens()[1].length);
+ EXPECT_STREQ("0", p.GetTokens()[1].name);
+ EXPECT_EQ(0u, p.GetTokens()[1].index);
+ }
+
+ {
+ // Unescape ~1
+ Pointer p("#/a~1b");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_EQ(3u, p.GetTokens()[0].length);
+ EXPECT_STREQ("a/b", p.GetTokens()[0].name);
+ }
+
+ {
+ // Unescape ~0
+ Pointer p("#/m~0n");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_EQ(3u, p.GetTokens()[0].length);
+ EXPECT_STREQ("m~n", p.GetTokens()[0].name);
+ }
+
+ {
+ // empty name
+ Pointer p("#/");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_EQ(0u, p.GetTokens()[0].length);
+ EXPECT_STREQ("", p.GetTokens()[0].name);
+ }
+
+ {
+ // empty and non-empty name
+ Pointer p("#//a");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(2u, p.GetTokenCount());
+ EXPECT_EQ(0u, p.GetTokens()[0].length);
+ EXPECT_STREQ("", p.GetTokens()[0].name);
+ EXPECT_EQ(1u, p.GetTokens()[1].length);
+ EXPECT_STREQ("a", p.GetTokens()[1].name);
+ }
+
+ {
+ // Null characters
+ Pointer p("#/%00%00");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_EQ(2u, p.GetTokens()[0].length);
+ EXPECT_EQ('\0', p.GetTokens()[0].name[0]);
+ EXPECT_EQ('\0', p.GetTokens()[0].name[1]);
+ EXPECT_EQ('\0', p.GetTokens()[0].name[2]);
+ }
+
+ {
+ // Percentage Escapes
+ EXPECT_STREQ("c%d", Pointer("#/c%25d").GetTokens()[0].name);
+ EXPECT_STREQ("e^f", Pointer("#/e%5Ef").GetTokens()[0].name);
+ EXPECT_STREQ("g|h", Pointer("#/g%7Ch").GetTokens()[0].name);
+ EXPECT_STREQ("i\\j", Pointer("#/i%5Cj").GetTokens()[0].name);
+ EXPECT_STREQ("k\"l", Pointer("#/k%22l").GetTokens()[0].name);
+ EXPECT_STREQ(" ", Pointer("#/%20").GetTokens()[0].name);
+ }
+
+ {
+ // Valid index
+ Pointer p("#/123");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_STREQ("123", p.GetTokens()[0].name);
+ EXPECT_EQ(123u, p.GetTokens()[0].index);
+ }
+
+ {
+ // Invalid index (with leading zero)
+ Pointer p("#/01");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_STREQ("01", p.GetTokens()[0].name);
+ EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
+ }
+
+ if (sizeof(SizeType) == 4) {
+ // Invalid index (overflow)
+ Pointer p("#/4294967296");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_STREQ("4294967296", p.GetTokens()[0].name);
+ EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
+ }
+
+ {
+ // Decode UTF-8 perecent encoding to UTF-8
+ Pointer p("#/%C2%A2");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_STREQ("\xC2\xA2", p.GetTokens()[0].name);
+ }
+
+ {
+ // Decode UTF-8 perecent encoding to UTF-16
+ GenericPointer<GenericValue<UTF16<> > > p(L"#/%C2%A2");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_EQ(static_cast<UTF16<>::Ch>(0x00A2), p.GetTokens()[0].name[0]);
+ EXPECT_EQ(1u, p.GetTokens()[0].length);
+ }
+
+ {
+ // Decode UTF-8 perecent encoding to UTF-16
+ GenericPointer<GenericValue<UTF16<> > > p(L"#/%E2%82%AC");
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(1u, p.GetTokenCount());
+ EXPECT_EQ(static_cast<UTF16<>::Ch>(0x20AC), p.GetTokens()[0].name[0]);
+ EXPECT_EQ(1u, p.GetTokens()[0].length);
+ }
+
+ {
+ // kPointerParseErrorTokenMustBeginWithSolidus
+ Pointer p("# ");
+ EXPECT_FALSE(p.IsValid());
+ EXPECT_EQ(kPointerParseErrorTokenMustBeginWithSolidus, p.GetParseErrorCode());
+ EXPECT_EQ(1u, p.GetParseErrorOffset());
+ }
+
+ {
+ // kPointerParseErrorInvalidEscape
+ Pointer p("#/~");
+ EXPECT_FALSE(p.IsValid());
+ EXPECT_EQ(kPointerParseErrorInvalidEscape, p.GetParseErrorCode());
+ EXPECT_EQ(3u, p.GetParseErrorOffset());
+ }
+
+ {
+ // kPointerParseErrorInvalidEscape
+ Pointer p("#/~2");
+ EXPECT_FALSE(p.IsValid());
+ EXPECT_EQ(kPointerParseErrorInvalidEscape, p.GetParseErrorCode());
+ EXPECT_EQ(3u, p.GetParseErrorOffset());
+ }
+
+ {
+ // kPointerParseErrorInvalidPercentEncoding
+ Pointer p("#/%");
+ EXPECT_FALSE(p.IsValid());
+ EXPECT_EQ(kPointerParseErrorInvalidPercentEncoding, p.GetParseErrorCode());
+ EXPECT_EQ(2u, p.GetParseErrorOffset());
+ }
+
+ {
+ // kPointerParseErrorInvalidPercentEncoding (invalid hex)
+ Pointer p("#/%g0");
+ EXPECT_FALSE(p.IsValid());
+ EXPECT_EQ(kPointerParseErrorInvalidPercentEncoding, p.GetParseErrorCode());
+ EXPECT_EQ(2u, p.GetParseErrorOffset());
+ }
+
+ {
+ // kPointerParseErrorInvalidPercentEncoding (invalid hex)
+ Pointer p("#/%0g");
+ EXPECT_FALSE(p.IsValid());
+ EXPECT_EQ(kPointerParseErrorInvalidPercentEncoding, p.GetParseErrorCode());
+ EXPECT_EQ(2u, p.GetParseErrorOffset());
+ }
+
+ {
+ // kPointerParseErrorInvalidPercentEncoding (incomplete UTF-8 sequence)
+ Pointer p("#/%C2");
+ EXPECT_FALSE(p.IsValid());
+ EXPECT_EQ(kPointerParseErrorInvalidPercentEncoding, p.GetParseErrorCode());
+ EXPECT_EQ(2u, p.GetParseErrorOffset());
+ }
+
+ {
+ // kPointerParseErrorCharacterMustPercentEncode
+ Pointer p("#/ ");
+ EXPECT_FALSE(p.IsValid());
+ EXPECT_EQ(kPointerParseErrorCharacterMustPercentEncode, p.GetParseErrorCode());
+ EXPECT_EQ(2u, p.GetParseErrorOffset());
+ }
+
+ {
+ // kPointerParseErrorCharacterMustPercentEncode
+ Pointer p("#/\n");
+ EXPECT_FALSE(p.IsValid());
+ EXPECT_EQ(kPointerParseErrorCharacterMustPercentEncode, p.GetParseErrorCode());
+ EXPECT_EQ(2u, p.GetParseErrorOffset());
+ }
+}
+
+TEST(Pointer, Stringify) {
+ // Test by roundtrip
+ const char* sources[] = {
+ "",
+ "/foo",
+ "/foo/0",
+ "/",
+ "/a~1b",
+ "/c%d",
+ "/e^f",
+ "/g|h",
+ "/i\\j",
+ "/k\"l",
+ "/ ",
+ "/m~0n",
+ "/\xC2\xA2",
+ "/\xE2\x82\xAC",
+ "/\xF0\x9D\x84\x9E"
+ };
+
+ for (size_t i = 0; i < sizeof(sources) / sizeof(sources[0]); i++) {
+ Pointer p(sources[i]);
+ StringBuffer s;
+ EXPECT_TRUE(p.Stringify(s));
+ EXPECT_STREQ(sources[i], s.GetString());
+
+ // Stringify to URI fragment
+ StringBuffer s2;
+ EXPECT_TRUE(p.StringifyUriFragment(s2));
+ Pointer p2(s2.GetString(), s2.GetSize());
+ EXPECT_TRUE(p2.IsValid());
+ EXPECT_TRUE(p == p2);
+ }
+
+ {
+ // Strigify to URI fragment with an invalid UTF-8 sequence
+ Pointer p("/\xC2");
+ StringBuffer s;
+ EXPECT_FALSE(p.StringifyUriFragment(s));
+ }
+}
+
+// Construct a Pointer with static tokens, no dynamic allocation involved.
+#define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex }
+#define INDEX(i) { #i, sizeof(#i) - 1, i }
+
+static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(0) }; // equivalent to "/foo/0"
+
+#undef NAME
+#undef INDEX
+
+TEST(Pointer, ConstructorWithToken) {
+ Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
+ EXPECT_TRUE(p.IsValid());
+ EXPECT_EQ(2u, p.GetTokenCount());
+ EXPECT_EQ(3u, p.GetTokens()[0].length);
+ EXPECT_STREQ("foo", p.GetTokens()[0].name);
+ EXPECT_EQ(1u, p.GetTokens()[1].length);
+ EXPECT_STREQ("0", p.GetTokens()[1].name);
+ EXPECT_EQ(0u, p.GetTokens()[1].index);
+}
+
+TEST(Pointer, CopyConstructor) {
+ {
+ Pointer p("/foo/0");
+ Pointer q(p);
+ EXPECT_TRUE(q.IsValid());
+ EXPECT_EQ(2u, q.GetTokenCount());
+ EXPECT_EQ(3u, q.GetTokens()[0].length);
+ EXPECT_STREQ("foo", q.GetTokens()[0].name);
+ EXPECT_EQ(1u, q.GetTokens()[1].length);
+ EXPECT_STREQ("0", q.GetTokens()[1].name);
+ EXPECT_EQ(0u, q.GetTokens()[1].index);
+ }
+
+ // Static tokens
+ {
+ Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
+ Pointer q(p);
+ EXPECT_TRUE(q.IsValid());
+ EXPECT_EQ(2u, q.GetTokenCount());
+ EXPECT_EQ(3u, q.GetTokens()[0].length);
+ EXPECT_STREQ("foo", q.GetTokens()[0].name);
+ EXPECT_EQ(1u, q.GetTokens()[1].length);
+ EXPECT_STREQ("0", q.GetTokens()[1].name);
+ EXPECT_EQ(0u, q.GetTokens()[1].index);
+ }
+}
+
+TEST(Pointer, Assignment) {
+ {
+ Pointer p("/foo/0");
+ Pointer q;
+ q = p;
+ EXPECT_TRUE(q.IsValid());
+ EXPECT_EQ(2u, q.GetTokenCount());
+ EXPECT_EQ(3u, q.GetTokens()[0].length);
+ EXPECT_STREQ("foo", q.GetTokens()[0].name);
+ EXPECT_EQ(1u, q.GetTokens()[1].length);
+ EXPECT_STREQ("0", q.GetTokens()[1].name);
+ EXPECT_EQ(0u, q.GetTokens()[1].index);
+ q = q;
+ EXPECT_TRUE(q.IsValid());
+ EXPECT_EQ(2u, q.GetTokenCount());
+ EXPECT_EQ(3u, q.GetTokens()[0].length);
+ EXPECT_STREQ("foo", q.GetTokens()[0].name);
+ EXPECT_EQ(1u, q.GetTokens()[1].length);
+ EXPECT_STREQ("0", q.GetTokens()[1].name);
+ EXPECT_EQ(0u, q.GetTokens()[1].index);
+ }
+
+ // Static tokens
+ {
+ Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
+ Pointer q;
+ q = p;
+ EXPECT_TRUE(q.IsValid());
+ EXPECT_EQ(2u, q.GetTokenCount());
+ EXPECT_EQ(3u, q.GetTokens()[0].length);
+ EXPECT_STREQ("foo", q.GetTokens()[0].name);
+ EXPECT_EQ(1u, q.GetTokens()[1].length);
+ EXPECT_STREQ("0", q.GetTokens()[1].name);
+ EXPECT_EQ(0u, q.GetTokens()[1].index);
+ }
+}
+
+TEST(Pointer, Append) {
+ {
+ Pointer p;
+ Pointer q = p.Append("foo");
+ EXPECT_TRUE(Pointer("/foo") == q);
+ q = q.Append(1234);
+ EXPECT_TRUE(Pointer("/foo/1234") == q);
+ q = q.Append("");
+ EXPECT_TRUE(Pointer("/foo/1234/") == q);
+ }
+
+ {
+ Pointer p;
+ Pointer q = p.Append(Value("foo").Move());
+ EXPECT_TRUE(Pointer("/foo") == q);
+ q = q.Append(Value(1234).Move());
+ EXPECT_TRUE(Pointer("/foo/1234") == q);
+ q = q.Append(Value(kStringType).Move());
+ EXPECT_TRUE(Pointer("/foo/1234/") == q);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ {
+ Pointer p;
+ Pointer q = p.Append(std::string("foo"));
+ EXPECT_TRUE(Pointer("/foo") == q);
+ }
+#endif
+}
+
+TEST(Pointer, Equality) {
+ EXPECT_TRUE(Pointer("/foo/0") == Pointer("/foo/0"));
+ EXPECT_FALSE(Pointer("/foo/0") == Pointer("/foo/1"));
+ EXPECT_FALSE(Pointer("/foo/0") == Pointer("/foo/0/1"));
+ EXPECT_FALSE(Pointer("/foo/0") == Pointer("a"));
+ EXPECT_FALSE(Pointer("a") == Pointer("a")); // Invalid always not equal
+}
+
+TEST(Pointer, Inequality) {
+ EXPECT_FALSE(Pointer("/foo/0") != Pointer("/foo/0"));
+ EXPECT_TRUE(Pointer("/foo/0") != Pointer("/foo/1"));
+ EXPECT_TRUE(Pointer("/foo/0") != Pointer("/foo/0/1"));
+ EXPECT_TRUE(Pointer("/foo/0") != Pointer("a"));
+ EXPECT_TRUE(Pointer("a") != Pointer("a")); // Invalid always not equal
+}
+
+TEST(Pointer, Create) {
+ Document d;
+ {
+ Value* v = &Pointer("").Create(d, d.GetAllocator());
+ EXPECT_EQ(&d, v);
+ }
+ {
+ Value* v = &Pointer("/foo").Create(d, d.GetAllocator());
+ EXPECT_EQ(&d["foo"], v);
+ }
+ {
+ Value* v = &Pointer("/foo/0").Create(d, d.GetAllocator());
+ EXPECT_EQ(&d["foo"][0], v);
+ }
+ {
+ Value* v = &Pointer("/foo/-").Create(d, d.GetAllocator());
+ EXPECT_EQ(&d["foo"][1], v);
+ }
+
+ {
+ Value* v = &Pointer("/foo/-/-").Create(d, d.GetAllocator());
+ // "foo/-" is a newly created null value x.
+ // "foo/-/-" finds that x is not an array, it converts x to empty object
+ // and treats - as "-" member name
+ EXPECT_EQ(&d["foo"][2]["-"], v);
+ }
+
+ {
+ // Document with no allocator
+ Value* v = &Pointer("/foo/-").Create(d);
+ EXPECT_EQ(&d["foo"][3], v);
+ }
+
+ {
+ // Value (not document) must give allocator
+ Value* v = &Pointer("/-").Create(d["foo"], d.GetAllocator());
+ EXPECT_EQ(&d["foo"][4], v);
+ }
+}
+
+TEST(Pointer, Get) {
+ Document d;
+ d.Parse(kJson);
+
+ EXPECT_EQ(&d, Pointer("").Get(d));
+ EXPECT_EQ(&d["foo"], Pointer("/foo").Get(d));
+ EXPECT_EQ(&d["foo"][0], Pointer("/foo/0").Get(d));
+ EXPECT_EQ(&d[""], Pointer("/").Get(d));
+ EXPECT_EQ(&d["a/b"], Pointer("/a~1b").Get(d));
+ EXPECT_EQ(&d["c%d"], Pointer("/c%d").Get(d));
+ EXPECT_EQ(&d["e^f"], Pointer("/e^f").Get(d));
+ EXPECT_EQ(&d["g|h"], Pointer("/g|h").Get(d));
+ EXPECT_EQ(&d["i\\j"], Pointer("/i\\j").Get(d));
+ EXPECT_EQ(&d["k\"l"], Pointer("/k\"l").Get(d));
+ EXPECT_EQ(&d[" "], Pointer("/ ").Get(d));
+ EXPECT_EQ(&d["m~n"], Pointer("/m~0n").Get(d));
+ EXPECT_TRUE(Pointer("/abc").Get(d) == 0);
+ size_t unresolvedTokenIndex;
+ EXPECT_TRUE(Pointer("/foo/2").Get(d, &unresolvedTokenIndex) == 0); // Out of boundary
+ EXPECT_EQ(1, unresolvedTokenIndex);
+ EXPECT_TRUE(Pointer("/foo/a").Get(d, &unresolvedTokenIndex) == 0); // "/foo" is an array, cannot query by "a"
+ EXPECT_EQ(1, unresolvedTokenIndex);
+ EXPECT_TRUE(Pointer("/foo/0/0").Get(d, &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query
+ EXPECT_EQ(2, unresolvedTokenIndex);
+ EXPECT_TRUE(Pointer("/foo/0/a").Get(d, &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query
+ EXPECT_EQ(2, unresolvedTokenIndex);
+}
+
+TEST(Pointer, GetWithDefault) {
+ Document d;
+ d.Parse(kJson);
+
+ // Value version
+ Document::AllocatorType& a = d.GetAllocator();
+ const Value v("qux");
+ EXPECT_TRUE(Value("bar") == Pointer("/foo/0").GetWithDefault(d, v, a));
+ EXPECT_TRUE(Value("baz") == Pointer("/foo/1").GetWithDefault(d, v, a));
+ EXPECT_TRUE(Value("qux") == Pointer("/foo/2").GetWithDefault(d, v, a));
+ EXPECT_TRUE(Value("last") == Pointer("/foo/-").GetWithDefault(d, Value("last").Move(), a));
+ EXPECT_STREQ("last", d["foo"][3].GetString());
+
+ EXPECT_TRUE(Pointer("/foo/null").GetWithDefault(d, Value().Move(), a).IsNull());
+ EXPECT_TRUE(Pointer("/foo/null").GetWithDefault(d, "x", a).IsNull());
+
+ // Generic version
+ EXPECT_EQ(-1, Pointer("/foo/int").GetWithDefault(d, -1, a).GetInt());
+ EXPECT_EQ(-1, Pointer("/foo/int").GetWithDefault(d, -2, a).GetInt());
+ EXPECT_EQ(0x87654321, Pointer("/foo/uint").GetWithDefault(d, 0x87654321, a).GetUint());
+ EXPECT_EQ(0x87654321, Pointer("/foo/uint").GetWithDefault(d, 0x12345678, a).GetUint());
+
+ const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
+ EXPECT_EQ(i64, Pointer("/foo/int64").GetWithDefault(d, i64, a).GetInt64());
+ EXPECT_EQ(i64, Pointer("/foo/int64").GetWithDefault(d, i64 + 1, a).GetInt64());
+
+ const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
+ EXPECT_EQ(u64, Pointer("/foo/uint64").GetWithDefault(d, u64, a).GetUint64());
+ EXPECT_EQ(u64, Pointer("/foo/uint64").GetWithDefault(d, u64 - 1, a).GetUint64());
+
+ EXPECT_TRUE(Pointer("/foo/true").GetWithDefault(d, true, a).IsTrue());
+ EXPECT_TRUE(Pointer("/foo/true").GetWithDefault(d, false, a).IsTrue());
+
+ EXPECT_TRUE(Pointer("/foo/false").GetWithDefault(d, false, a).IsFalse());
+ EXPECT_TRUE(Pointer("/foo/false").GetWithDefault(d, true, a).IsFalse());
+
+ // StringRef version
+ EXPECT_STREQ("Hello", Pointer("/foo/hello").GetWithDefault(d, "Hello", a).GetString());
+
+ // Copy string version
+ {
+ char buffer[256];
+ strcpy(buffer, "World");
+ EXPECT_STREQ("World", Pointer("/foo/world").GetWithDefault(d, buffer, a).GetString());
+ memset(buffer, 0, sizeof(buffer));
+ }
+ EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString());
+
+#if RAPIDJSON_HAS_STDSTRING
+ EXPECT_STREQ("C++", Pointer("/foo/C++").GetWithDefault(d, std::string("C++"), a).GetString());
+#endif
+}
+
+TEST(Pointer, GetWithDefault_NoAllocator) {
+ Document d;
+ d.Parse(kJson);
+
+ // Value version
+ const Value v("qux");
+ EXPECT_TRUE(Value("bar") == Pointer("/foo/0").GetWithDefault(d, v));
+ EXPECT_TRUE(Value("baz") == Pointer("/foo/1").GetWithDefault(d, v));
+ EXPECT_TRUE(Value("qux") == Pointer("/foo/2").GetWithDefault(d, v));
+ EXPECT_TRUE(Value("last") == Pointer("/foo/-").GetWithDefault(d, Value("last").Move()));
+ EXPECT_STREQ("last", d["foo"][3].GetString());
+
+ EXPECT_TRUE(Pointer("/foo/null").GetWithDefault(d, Value().Move()).IsNull());
+ EXPECT_TRUE(Pointer("/foo/null").GetWithDefault(d, "x").IsNull());
+
+ // Generic version
+ EXPECT_EQ(-1, Pointer("/foo/int").GetWithDefault(d, -1).GetInt());
+ EXPECT_EQ(-1, Pointer("/foo/int").GetWithDefault(d, -2).GetInt());
+ EXPECT_EQ(0x87654321, Pointer("/foo/uint").GetWithDefault(d, 0x87654321).GetUint());
+ EXPECT_EQ(0x87654321, Pointer("/foo/uint").GetWithDefault(d, 0x12345678).GetUint());
+
+ const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
+ EXPECT_EQ(i64, Pointer("/foo/int64").GetWithDefault(d, i64).GetInt64());
+ EXPECT_EQ(i64, Pointer("/foo/int64").GetWithDefault(d, i64 + 1).GetInt64());
+
+ const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
+ EXPECT_EQ(u64, Pointer("/foo/uint64").GetWithDefault(d, u64).GetUint64());
+ EXPECT_EQ(u64, Pointer("/foo/uint64").GetWithDefault(d, u64 - 1).GetUint64());
+
+ EXPECT_TRUE(Pointer("/foo/true").GetWithDefault(d, true).IsTrue());
+ EXPECT_TRUE(Pointer("/foo/true").GetWithDefault(d, false).IsTrue());
+
+ EXPECT_TRUE(Pointer("/foo/false").GetWithDefault(d, false).IsFalse());
+ EXPECT_TRUE(Pointer("/foo/false").GetWithDefault(d, true).IsFalse());
+
+ // StringRef version
+ EXPECT_STREQ("Hello", Pointer("/foo/hello").GetWithDefault(d, "Hello").GetString());
+
+ // Copy string version
+ {
+ char buffer[256];
+ strcpy(buffer, "World");
+ EXPECT_STREQ("World", Pointer("/foo/world").GetWithDefault(d, buffer).GetString());
+ memset(buffer, 0, sizeof(buffer));
+ }
+ EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString());
+
+#if RAPIDJSON_HAS_STDSTRING
+ EXPECT_STREQ("C++", Pointer("/foo/C++").GetWithDefault(d, std::string("C++")).GetString());
+#endif
+}
+
+TEST(Pointer, Set) {
+ Document d;
+ d.Parse(kJson);
+ Document::AllocatorType& a = d.GetAllocator();
+
+ // Value version
+ Pointer("/foo/0").Set(d, Value(123).Move(), a);
+ EXPECT_EQ(123, d["foo"][0].GetInt());
+
+ Pointer("/foo/-").Set(d, Value(456).Move(), a);
+ EXPECT_EQ(456, d["foo"][2].GetInt());
+
+ Pointer("/foo/null").Set(d, Value().Move(), a);
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/null")->IsNull());
+
+ // Const Value version
+ const Value foo(d["foo"], a);
+ Pointer("/clone").Set(d, foo, a);
+ EXPECT_EQ(foo, *GetValueByPointer(d, "/clone"));
+
+ // Generic version
+ Pointer("/foo/int").Set(d, -1, a);
+ EXPECT_EQ(-1, GetValueByPointer(d, "/foo/int")->GetInt());
+
+ Pointer("/foo/uint").Set(d, 0x87654321, a);
+ EXPECT_EQ(0x87654321, GetValueByPointer(d, "/foo/uint")->GetUint());
+
+ const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
+ Pointer("/foo/int64").Set(d, i64, a);
+ EXPECT_EQ(i64, GetValueByPointer(d, "/foo/int64")->GetInt64());
+
+ const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
+ Pointer("/foo/uint64").Set(d, u64, a);
+ EXPECT_EQ(u64, GetValueByPointer(d, "/foo/uint64")->GetUint64());
+
+ Pointer("/foo/true").Set(d, true, a);
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/true")->IsTrue());
+
+ Pointer("/foo/false").Set(d, false, a);
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/false")->IsFalse());
+
+ // StringRef version
+ Pointer("/foo/hello").Set(d, "Hello", a);
+ EXPECT_STREQ("Hello", GetValueByPointer(d, "/foo/hello")->GetString());
+
+ // Copy string version
+ {
+ char buffer[256];
+ strcpy(buffer, "World");
+ Pointer("/foo/world").Set(d, buffer, a);
+ memset(buffer, 0, sizeof(buffer));
+ }
+ EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString());
+
+#if RAPIDJSON_HAS_STDSTRING
+ Pointer("/foo/c++").Set(d, std::string("C++"), a);
+ EXPECT_STREQ("C++", GetValueByPointer(d, "/foo/c++")->GetString());
+#endif
+}
+
+TEST(Pointer, Set_NoAllocator) {
+ Document d;
+ d.Parse(kJson);
+
+ // Value version
+ Pointer("/foo/0").Set(d, Value(123).Move());
+ EXPECT_EQ(123, d["foo"][0].GetInt());
+
+ Pointer("/foo/-").Set(d, Value(456).Move());
+ EXPECT_EQ(456, d["foo"][2].GetInt());
+
+ Pointer("/foo/null").Set(d, Value().Move());
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/null")->IsNull());
+
+ // Const Value version
+ const Value foo(d["foo"], d.GetAllocator());
+ Pointer("/clone").Set(d, foo);
+ EXPECT_EQ(foo, *GetValueByPointer(d, "/clone"));
+
+ // Generic version
+ Pointer("/foo/int").Set(d, -1);
+ EXPECT_EQ(-1, GetValueByPointer(d, "/foo/int")->GetInt());
+
+ Pointer("/foo/uint").Set(d, 0x87654321);
+ EXPECT_EQ(0x87654321, GetValueByPointer(d, "/foo/uint")->GetUint());
+
+ const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
+ Pointer("/foo/int64").Set(d, i64);
+ EXPECT_EQ(i64, GetValueByPointer(d, "/foo/int64")->GetInt64());
+
+ const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
+ Pointer("/foo/uint64").Set(d, u64);
+ EXPECT_EQ(u64, GetValueByPointer(d, "/foo/uint64")->GetUint64());
+
+ Pointer("/foo/true").Set(d, true);
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/true")->IsTrue());
+
+ Pointer("/foo/false").Set(d, false);
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/false")->IsFalse());
+
+ // StringRef version
+ Pointer("/foo/hello").Set(d, "Hello");
+ EXPECT_STREQ("Hello", GetValueByPointer(d, "/foo/hello")->GetString());
+
+ // Copy string version
+ {
+ char buffer[256];
+ strcpy(buffer, "World");
+ Pointer("/foo/world").Set(d, buffer);
+ memset(buffer, 0, sizeof(buffer));
+ }
+ EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString());
+
+#if RAPIDJSON_HAS_STDSTRING
+ Pointer("/foo/c++").Set(d, std::string("C++"));
+ EXPECT_STREQ("C++", GetValueByPointer(d, "/foo/c++")->GetString());
+#endif
+}
+
+TEST(Pointer, Swap) {
+ Document d;
+ d.Parse(kJson);
+ Document::AllocatorType& a = d.GetAllocator();
+ Pointer("/foo/0").Swap(d, *Pointer("/foo/1").Get(d), a);
+ EXPECT_STREQ("baz", d["foo"][0].GetString());
+ EXPECT_STREQ("bar", d["foo"][1].GetString());
+}
+
+TEST(Pointer, Swap_NoAllocator) {
+ Document d;
+ d.Parse(kJson);
+ Pointer("/foo/0").Swap(d, *Pointer("/foo/1").Get(d));
+ EXPECT_STREQ("baz", d["foo"][0].GetString());
+ EXPECT_STREQ("bar", d["foo"][1].GetString());
+}
+
+TEST(Pointer, Erase) {
+ Document d;
+ d.Parse(kJson);
+
+ EXPECT_FALSE(Pointer("").Erase(d));
+ EXPECT_FALSE(Pointer("/nonexist").Erase(d));
+ EXPECT_FALSE(Pointer("/nonexist/nonexist").Erase(d));
+ EXPECT_FALSE(Pointer("/foo/nonexist").Erase(d));
+ EXPECT_FALSE(Pointer("/foo/nonexist/nonexist").Erase(d));
+ EXPECT_FALSE(Pointer("/foo/0/nonexist").Erase(d));
+ EXPECT_FALSE(Pointer("/foo/0/nonexist/nonexist").Erase(d));
+ EXPECT_FALSE(Pointer("/foo/2/nonexist").Erase(d));
+ EXPECT_TRUE(Pointer("/foo/0").Erase(d));
+ EXPECT_EQ(1u, d["foo"].Size());
+ EXPECT_STREQ("baz", d["foo"][0].GetString());
+ EXPECT_TRUE(Pointer("/foo/0").Erase(d));
+ EXPECT_TRUE(d["foo"].Empty());
+ EXPECT_TRUE(Pointer("/foo").Erase(d));
+ EXPECT_TRUE(Pointer("/foo").Get(d) == 0);
+
+ Pointer("/a/0/b/0").Create(d);
+
+ EXPECT_TRUE(Pointer("/a/0/b/0").Get(d) != 0);
+ EXPECT_TRUE(Pointer("/a/0/b/0").Erase(d));
+ EXPECT_TRUE(Pointer("/a/0/b/0").Get(d) == 0);
+
+ EXPECT_TRUE(Pointer("/a/0/b").Get(d) != 0);
+ EXPECT_TRUE(Pointer("/a/0/b").Erase(d));
+ EXPECT_TRUE(Pointer("/a/0/b").Get(d) == 0);
+
+ EXPECT_TRUE(Pointer("/a/0").Get(d) != 0);
+ EXPECT_TRUE(Pointer("/a/0").Erase(d));
+ EXPECT_TRUE(Pointer("/a/0").Get(d) == 0);
+
+ EXPECT_TRUE(Pointer("/a").Get(d) != 0);
+ EXPECT_TRUE(Pointer("/a").Erase(d));
+ EXPECT_TRUE(Pointer("/a").Get(d) == 0);
+}
+
+TEST(Pointer, CreateValueByPointer) {
+ Document d;
+ Document::AllocatorType& a = d.GetAllocator();
+
+ {
+ Value& v = CreateValueByPointer(d, Pointer("/foo/0"), a);
+ EXPECT_EQ(&d["foo"][0], &v);
+ }
+ {
+ Value& v = CreateValueByPointer(d, "/foo/1", a);
+ EXPECT_EQ(&d["foo"][1], &v);
+ }
+}
+
+TEST(Pointer, CreateValueByPointer_NoAllocator) {
+ Document d;
+
+ {
+ Value& v = CreateValueByPointer(d, Pointer("/foo/0"));
+ EXPECT_EQ(&d["foo"][0], &v);
+ }
+ {
+ Value& v = CreateValueByPointer(d, "/foo/1");
+ EXPECT_EQ(&d["foo"][1], &v);
+ }
+}
+
+TEST(Pointer, GetValueByPointer) {
+ Document d;
+ d.Parse(kJson);
+
+ EXPECT_EQ(&d["foo"][0], GetValueByPointer(d, Pointer("/foo/0")));
+ EXPECT_EQ(&d["foo"][0], GetValueByPointer(d, "/foo/0"));
+
+ size_t unresolvedTokenIndex;
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/2", &unresolvedTokenIndex) == 0); // Out of boundary
+ EXPECT_EQ(1, unresolvedTokenIndex);
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/a", &unresolvedTokenIndex) == 0); // "/foo" is an array, cannot query by "a"
+ EXPECT_EQ(1, unresolvedTokenIndex);
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/0/0", &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query
+ EXPECT_EQ(2, unresolvedTokenIndex);
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/0/a", &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query
+ EXPECT_EQ(2, unresolvedTokenIndex);
+
+ // const version
+ const Value& v = d;
+ EXPECT_EQ(&d["foo"][0], GetValueByPointer(v, Pointer("/foo/0")));
+ EXPECT_EQ(&d["foo"][0], GetValueByPointer(v, "/foo/0"));
+
+ EXPECT_TRUE(GetValueByPointer(v, "/foo/2", &unresolvedTokenIndex) == 0); // Out of boundary
+ EXPECT_EQ(1, unresolvedTokenIndex);
+ EXPECT_TRUE(GetValueByPointer(v, "/foo/a", &unresolvedTokenIndex) == 0); // "/foo" is an array, cannot query by "a"
+ EXPECT_EQ(1, unresolvedTokenIndex);
+ EXPECT_TRUE(GetValueByPointer(v, "/foo/0/0", &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query
+ EXPECT_EQ(2, unresolvedTokenIndex);
+ EXPECT_TRUE(GetValueByPointer(v, "/foo/0/a", &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query
+ EXPECT_EQ(2, unresolvedTokenIndex);
+
+}
+
+TEST(Pointer, GetValueByPointerWithDefault_Pointer) {
+ Document d;
+ d.Parse(kJson);
+
+ Document::AllocatorType& a = d.GetAllocator();
+ const Value v("qux");
+ EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, Pointer("/foo/0"), v, a));
+ EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, Pointer("/foo/0"), v, a));
+ EXPECT_TRUE(Value("baz") == GetValueByPointerWithDefault(d, Pointer("/foo/1"), v, a));
+ EXPECT_TRUE(Value("qux") == GetValueByPointerWithDefault(d, Pointer("/foo/2"), v, a));
+ EXPECT_TRUE(Value("last") == GetValueByPointerWithDefault(d, Pointer("/foo/-"), Value("last").Move(), a));
+ EXPECT_STREQ("last", d["foo"][3].GetString());
+
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/null"), Value().Move(), a).IsNull());
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/null"), "x", a).IsNull());
+
+ // Generic version
+ EXPECT_EQ(-1, GetValueByPointerWithDefault(d, Pointer("/foo/int"), -1, a).GetInt());
+ EXPECT_EQ(-1, GetValueByPointerWithDefault(d, Pointer("/foo/int"), -2, a).GetInt());
+ EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, Pointer("/foo/uint"), 0x87654321, a).GetUint());
+ EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, Pointer("/foo/uint"), 0x12345678, a).GetUint());
+
+ const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
+ EXPECT_EQ(i64, GetValueByPointerWithDefault(d, Pointer("/foo/int64"), i64, a).GetInt64());
+ EXPECT_EQ(i64, GetValueByPointerWithDefault(d, Pointer("/foo/int64"), i64 + 1, a).GetInt64());
+
+ const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
+ EXPECT_EQ(u64, GetValueByPointerWithDefault(d, Pointer("/foo/uint64"), u64, a).GetUint64());
+ EXPECT_EQ(u64, GetValueByPointerWithDefault(d, Pointer("/foo/uint64"), u64 - 1, a).GetUint64());
+
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/true"), true, a).IsTrue());
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/true"), false, a).IsTrue());
+
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/false"), false, a).IsFalse());
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/false"), true, a).IsFalse());
+
+ // StringRef version
+ EXPECT_STREQ("Hello", GetValueByPointerWithDefault(d, Pointer("/foo/hello"), "Hello", a).GetString());
+
+ // Copy string version
+ {
+ char buffer[256];
+ strcpy(buffer, "World");
+ EXPECT_STREQ("World", GetValueByPointerWithDefault(d, Pointer("/foo/world"), buffer, a).GetString());
+ memset(buffer, 0, sizeof(buffer));
+ }
+ EXPECT_STREQ("World", GetValueByPointer(d, Pointer("/foo/world"))->GetString());
+
+#if RAPIDJSON_HAS_STDSTRING
+ EXPECT_STREQ("C++", GetValueByPointerWithDefault(d, Pointer("/foo/C++"), std::string("C++"), a).GetString());
+#endif
+}
+
+TEST(Pointer, GetValueByPointerWithDefault_String) {
+ Document d;
+ d.Parse(kJson);
+
+ Document::AllocatorType& a = d.GetAllocator();
+ const Value v("qux");
+ EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, "/foo/0", v, a));
+ EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, "/foo/0", v, a));
+ EXPECT_TRUE(Value("baz") == GetValueByPointerWithDefault(d, "/foo/1", v, a));
+ EXPECT_TRUE(Value("qux") == GetValueByPointerWithDefault(d, "/foo/2", v, a));
+ EXPECT_TRUE(Value("last") == GetValueByPointerWithDefault(d, "/foo/-", Value("last").Move(), a));
+ EXPECT_STREQ("last", d["foo"][3].GetString());
+
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/null", Value().Move(), a).IsNull());
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/null", "x", a).IsNull());
+
+ // Generic version
+ EXPECT_EQ(-1, GetValueByPointerWithDefault(d, "/foo/int", -1, a).GetInt());
+ EXPECT_EQ(-1, GetValueByPointerWithDefault(d, "/foo/int", -2, a).GetInt());
+ EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, "/foo/uint", 0x87654321, a).GetUint());
+ EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, "/foo/uint", 0x12345678, a).GetUint());
+
+ const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
+ EXPECT_EQ(i64, GetValueByPointerWithDefault(d, "/foo/int64", i64, a).GetInt64());
+ EXPECT_EQ(i64, GetValueByPointerWithDefault(d, "/foo/int64", i64 + 1, a).GetInt64());
+
+ const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
+ EXPECT_EQ(u64, GetValueByPointerWithDefault(d, "/foo/uint64", u64, a).GetUint64());
+ EXPECT_EQ(u64, GetValueByPointerWithDefault(d, "/foo/uint64", u64 - 1, a).GetUint64());
+
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/true", true, a).IsTrue());
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/true", false, a).IsTrue());
+
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/false", false, a).IsFalse());
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/false", true, a).IsFalse());
+
+ // StringRef version
+ EXPECT_STREQ("Hello", GetValueByPointerWithDefault(d, "/foo/hello", "Hello", a).GetString());
+
+ // Copy string version
+ {
+ char buffer[256];
+ strcpy(buffer, "World");
+ EXPECT_STREQ("World", GetValueByPointerWithDefault(d, "/foo/world", buffer, a).GetString());
+ memset(buffer, 0, sizeof(buffer));
+ }
+ EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString());
+
+#if RAPIDJSON_HAS_STDSTRING
+ EXPECT_STREQ("C++", GetValueByPointerWithDefault(d, "/foo/C++", std::string("C++"), a).GetString());
+#endif
+}
+
+TEST(Pointer, GetValueByPointerWithDefault_Pointer_NoAllocator) {
+ Document d;
+ d.Parse(kJson);
+
+ const Value v("qux");
+ EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, Pointer("/foo/0"), v));
+ EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, Pointer("/foo/0"), v));
+ EXPECT_TRUE(Value("baz") == GetValueByPointerWithDefault(d, Pointer("/foo/1"), v));
+ EXPECT_TRUE(Value("qux") == GetValueByPointerWithDefault(d, Pointer("/foo/2"), v));
+ EXPECT_TRUE(Value("last") == GetValueByPointerWithDefault(d, Pointer("/foo/-"), Value("last").Move()));
+ EXPECT_STREQ("last", d["foo"][3].GetString());
+
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/null"), Value().Move()).IsNull());
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/null"), "x").IsNull());
+
+ // Generic version
+ EXPECT_EQ(-1, GetValueByPointerWithDefault(d, Pointer("/foo/int"), -1).GetInt());
+ EXPECT_EQ(-1, GetValueByPointerWithDefault(d, Pointer("/foo/int"), -2).GetInt());
+ EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, Pointer("/foo/uint"), 0x87654321).GetUint());
+ EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, Pointer("/foo/uint"), 0x12345678).GetUint());
+
+ const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
+ EXPECT_EQ(i64, GetValueByPointerWithDefault(d, Pointer("/foo/int64"), i64).GetInt64());
+ EXPECT_EQ(i64, GetValueByPointerWithDefault(d, Pointer("/foo/int64"), i64 + 1).GetInt64());
+
+ const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
+ EXPECT_EQ(u64, GetValueByPointerWithDefault(d, Pointer("/foo/uint64"), u64).GetUint64());
+ EXPECT_EQ(u64, GetValueByPointerWithDefault(d, Pointer("/foo/uint64"), u64 - 1).GetUint64());
+
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/true"), true).IsTrue());
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/true"), false).IsTrue());
+
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/false"), false).IsFalse());
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, Pointer("/foo/false"), true).IsFalse());
+
+ // StringRef version
+ EXPECT_STREQ("Hello", GetValueByPointerWithDefault(d, Pointer("/foo/hello"), "Hello").GetString());
+
+ // Copy string version
+ {
+ char buffer[256];
+ strcpy(buffer, "World");
+ EXPECT_STREQ("World", GetValueByPointerWithDefault(d, Pointer("/foo/world"), buffer).GetString());
+ memset(buffer, 0, sizeof(buffer));
+ }
+ EXPECT_STREQ("World", GetValueByPointer(d, Pointer("/foo/world"))->GetString());
+
+#if RAPIDJSON_HAS_STDSTRING
+ EXPECT_STREQ("C++", GetValueByPointerWithDefault(d, Pointer("/foo/C++"), std::string("C++")).GetString());
+#endif
+}
+
+TEST(Pointer, GetValueByPointerWithDefault_String_NoAllocator) {
+ Document d;
+ d.Parse(kJson);
+
+ const Value v("qux");
+ EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, "/foo/0", v));
+ EXPECT_TRUE(Value("bar") == GetValueByPointerWithDefault(d, "/foo/0", v));
+ EXPECT_TRUE(Value("baz") == GetValueByPointerWithDefault(d, "/foo/1", v));
+ EXPECT_TRUE(Value("qux") == GetValueByPointerWithDefault(d, "/foo/2", v));
+ EXPECT_TRUE(Value("last") == GetValueByPointerWithDefault(d, "/foo/-", Value("last").Move()));
+ EXPECT_STREQ("last", d["foo"][3].GetString());
+
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/null", Value().Move()).IsNull());
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/null", "x").IsNull());
+
+ // Generic version
+ EXPECT_EQ(-1, GetValueByPointerWithDefault(d, "/foo/int", -1).GetInt());
+ EXPECT_EQ(-1, GetValueByPointerWithDefault(d, "/foo/int", -2).GetInt());
+ EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, "/foo/uint", 0x87654321).GetUint());
+ EXPECT_EQ(0x87654321, GetValueByPointerWithDefault(d, "/foo/uint", 0x12345678).GetUint());
+
+ const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
+ EXPECT_EQ(i64, GetValueByPointerWithDefault(d, "/foo/int64", i64).GetInt64());
+ EXPECT_EQ(i64, GetValueByPointerWithDefault(d, "/foo/int64", i64 + 1).GetInt64());
+
+ const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
+ EXPECT_EQ(u64, GetValueByPointerWithDefault(d, "/foo/uint64", u64).GetUint64());
+ EXPECT_EQ(u64, GetValueByPointerWithDefault(d, "/foo/uint64", u64 - 1).GetUint64());
+
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/true", true).IsTrue());
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/true", false).IsTrue());
+
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/false", false).IsFalse());
+ EXPECT_TRUE(GetValueByPointerWithDefault(d, "/foo/false", true).IsFalse());
+
+ // StringRef version
+ EXPECT_STREQ("Hello", GetValueByPointerWithDefault(d, "/foo/hello", "Hello").GetString());
+
+ // Copy string version
+ {
+ char buffer[256];
+ strcpy(buffer, "World");
+ EXPECT_STREQ("World", GetValueByPointerWithDefault(d, "/foo/world", buffer).GetString());
+ memset(buffer, 0, sizeof(buffer));
+ }
+ EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString());
+
+#if RAPIDJSON_HAS_STDSTRING
+ EXPECT_STREQ("C++", GetValueByPointerWithDefault(d, Pointer("/foo/C++"), std::string("C++")).GetString());
+#endif
+}
+
+TEST(Pointer, SetValueByPointer_Pointer) {
+ Document d;
+ d.Parse(kJson);
+ Document::AllocatorType& a = d.GetAllocator();
+
+ // Value version
+ SetValueByPointer(d, Pointer("/foo/0"), Value(123).Move(), a);
+ EXPECT_EQ(123, d["foo"][0].GetInt());
+
+ SetValueByPointer(d, Pointer("/foo/null"), Value().Move(), a);
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/null")->IsNull());
+
+ // Const Value version
+ const Value foo(d["foo"], d.GetAllocator());
+ SetValueByPointer(d, Pointer("/clone"), foo, a);
+ EXPECT_EQ(foo, *GetValueByPointer(d, "/clone"));
+
+ // Generic version
+ SetValueByPointer(d, Pointer("/foo/int"), -1, a);
+ EXPECT_EQ(-1, GetValueByPointer(d, "/foo/int")->GetInt());
+
+ SetValueByPointer(d, Pointer("/foo/uint"), 0x87654321, a);
+ EXPECT_EQ(0x87654321, GetValueByPointer(d, "/foo/uint")->GetUint());
+
+ const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
+ SetValueByPointer(d, Pointer("/foo/int64"), i64, a);
+ EXPECT_EQ(i64, GetValueByPointer(d, "/foo/int64")->GetInt64());
+
+ const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
+ SetValueByPointer(d, Pointer("/foo/uint64"), u64, a);
+ EXPECT_EQ(u64, GetValueByPointer(d, "/foo/uint64")->GetUint64());
+
+ SetValueByPointer(d, Pointer("/foo/true"), true, a);
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/true")->IsTrue());
+
+ SetValueByPointer(d, Pointer("/foo/false"), false, a);
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/false")->IsFalse());
+
+ // StringRef version
+ SetValueByPointer(d, Pointer("/foo/hello"), "Hello", a);
+ EXPECT_STREQ("Hello", GetValueByPointer(d, "/foo/hello")->GetString());
+
+ // Copy string version
+ {
+ char buffer[256];
+ strcpy(buffer, "World");
+ SetValueByPointer(d, Pointer("/foo/world"), buffer, a);
+ memset(buffer, 0, sizeof(buffer));
+ }
+ EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString());
+
+#if RAPIDJSON_HAS_STDSTRING
+ SetValueByPointer(d, Pointer("/foo/c++"), std::string("C++"), a);
+ EXPECT_STREQ("C++", GetValueByPointer(d, "/foo/c++")->GetString());
+#endif
+}
+
+TEST(Pointer, SetValueByPointer_String) {
+ Document d;
+ d.Parse(kJson);
+ Document::AllocatorType& a = d.GetAllocator();
+
+ // Value version
+ SetValueByPointer(d, "/foo/0", Value(123).Move(), a);
+ EXPECT_EQ(123, d["foo"][0].GetInt());
+
+ SetValueByPointer(d, "/foo/null", Value().Move(), a);
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/null")->IsNull());
+
+ // Const Value version
+ const Value foo(d["foo"], d.GetAllocator());
+ SetValueByPointer(d, "/clone", foo, a);
+ EXPECT_EQ(foo, *GetValueByPointer(d, "/clone"));
+
+ // Generic version
+ SetValueByPointer(d, "/foo/int", -1, a);
+ EXPECT_EQ(-1, GetValueByPointer(d, "/foo/int")->GetInt());
+
+ SetValueByPointer(d, "/foo/uint", 0x87654321, a);
+ EXPECT_EQ(0x87654321, GetValueByPointer(d, "/foo/uint")->GetUint());
+
+ const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
+ SetValueByPointer(d, "/foo/int64", i64, a);
+ EXPECT_EQ(i64, GetValueByPointer(d, "/foo/int64")->GetInt64());
+
+ const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
+ SetValueByPointer(d, "/foo/uint64", u64, a);
+ EXPECT_EQ(u64, GetValueByPointer(d, "/foo/uint64")->GetUint64());
+
+ SetValueByPointer(d, "/foo/true", true, a);
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/true")->IsTrue());
+
+ SetValueByPointer(d, "/foo/false", false, a);
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/false")->IsFalse());
+
+ // StringRef version
+ SetValueByPointer(d, "/foo/hello", "Hello", a);
+ EXPECT_STREQ("Hello", GetValueByPointer(d, "/foo/hello")->GetString());
+
+ // Copy string version
+ {
+ char buffer[256];
+ strcpy(buffer, "World");
+ SetValueByPointer(d, "/foo/world", buffer, a);
+ memset(buffer, 0, sizeof(buffer));
+ }
+ EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString());
+
+#if RAPIDJSON_HAS_STDSTRING
+ SetValueByPointer(d, "/foo/c++", std::string("C++"), a);
+ EXPECT_STREQ("C++", GetValueByPointer(d, "/foo/c++")->GetString());
+#endif
+}
+
+TEST(Pointer, SetValueByPointer_Pointer_NoAllocator) {
+ Document d;
+ d.Parse(kJson);
+
+ // Value version
+ SetValueByPointer(d, Pointer("/foo/0"), Value(123).Move());
+ EXPECT_EQ(123, d["foo"][0].GetInt());
+
+ SetValueByPointer(d, Pointer("/foo/null"), Value().Move());
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/null")->IsNull());
+
+ // Const Value version
+ const Value foo(d["foo"], d.GetAllocator());
+ SetValueByPointer(d, Pointer("/clone"), foo);
+ EXPECT_EQ(foo, *GetValueByPointer(d, "/clone"));
+
+ // Generic version
+ SetValueByPointer(d, Pointer("/foo/int"), -1);
+ EXPECT_EQ(-1, GetValueByPointer(d, "/foo/int")->GetInt());
+
+ SetValueByPointer(d, Pointer("/foo/uint"), 0x87654321);
+ EXPECT_EQ(0x87654321, GetValueByPointer(d, "/foo/uint")->GetUint());
+
+ const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
+ SetValueByPointer(d, Pointer("/foo/int64"), i64);
+ EXPECT_EQ(i64, GetValueByPointer(d, "/foo/int64")->GetInt64());
+
+ const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
+ SetValueByPointer(d, Pointer("/foo/uint64"), u64);
+ EXPECT_EQ(u64, GetValueByPointer(d, "/foo/uint64")->GetUint64());
+
+ SetValueByPointer(d, Pointer("/foo/true"), true);
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/true")->IsTrue());
+
+ SetValueByPointer(d, Pointer("/foo/false"), false);
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/false")->IsFalse());
+
+ // StringRef version
+ SetValueByPointer(d, Pointer("/foo/hello"), "Hello");
+ EXPECT_STREQ("Hello", GetValueByPointer(d, "/foo/hello")->GetString());
+
+ // Copy string version
+ {
+ char buffer[256];
+ strcpy(buffer, "World");
+ SetValueByPointer(d, Pointer("/foo/world"), buffer);
+ memset(buffer, 0, sizeof(buffer));
+ }
+ EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString());
+
+#if RAPIDJSON_HAS_STDSTRING
+ SetValueByPointer(d, Pointer("/foo/c++"), std::string("C++"));
+ EXPECT_STREQ("C++", GetValueByPointer(d, "/foo/c++")->GetString());
+#endif
+}
+
+TEST(Pointer, SetValueByPointer_String_NoAllocator) {
+ Document d;
+ d.Parse(kJson);
+
+ // Value version
+ SetValueByPointer(d, "/foo/0", Value(123).Move());
+ EXPECT_EQ(123, d["foo"][0].GetInt());
+
+ SetValueByPointer(d, "/foo/null", Value().Move());
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/null")->IsNull());
+
+ // Const Value version
+ const Value foo(d["foo"], d.GetAllocator());
+ SetValueByPointer(d, "/clone", foo);
+ EXPECT_EQ(foo, *GetValueByPointer(d, "/clone"));
+
+ // Generic version
+ SetValueByPointer(d, "/foo/int", -1);
+ EXPECT_EQ(-1, GetValueByPointer(d, "/foo/int")->GetInt());
+
+ SetValueByPointer(d, "/foo/uint", 0x87654321);
+ EXPECT_EQ(0x87654321, GetValueByPointer(d, "/foo/uint")->GetUint());
+
+ const int64_t i64 = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0));
+ SetValueByPointer(d, "/foo/int64", i64);
+ EXPECT_EQ(i64, GetValueByPointer(d, "/foo/int64")->GetInt64());
+
+ const uint64_t u64 = RAPIDJSON_UINT64_C2(0xFFFFFFFFF, 0xFFFFFFFFF);
+ SetValueByPointer(d, "/foo/uint64", u64);
+ EXPECT_EQ(u64, GetValueByPointer(d, "/foo/uint64")->GetUint64());
+
+ SetValueByPointer(d, "/foo/true", true);
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/true")->IsTrue());
+
+ SetValueByPointer(d, "/foo/false", false);
+ EXPECT_TRUE(GetValueByPointer(d, "/foo/false")->IsFalse());
+
+ // StringRef version
+ SetValueByPointer(d, "/foo/hello", "Hello");
+ EXPECT_STREQ("Hello", GetValueByPointer(d, "/foo/hello")->GetString());
+
+ // Copy string version
+ {
+ char buffer[256];
+ strcpy(buffer, "World");
+ SetValueByPointer(d, "/foo/world", buffer);
+ memset(buffer, 0, sizeof(buffer));
+ }
+ EXPECT_STREQ("World", GetValueByPointer(d, "/foo/world")->GetString());
+
+#if RAPIDJSON_HAS_STDSTRING
+ SetValueByPointer(d, "/foo/c++", std::string("C++"));
+ EXPECT_STREQ("C++", GetValueByPointer(d, "/foo/c++")->GetString());
+#endif
+}
+
+TEST(Pointer, SwapValueByPointer) {
+ Document d;
+ d.Parse(kJson);
+ Document::AllocatorType& a = d.GetAllocator();
+ SwapValueByPointer(d, Pointer("/foo/0"), *GetValueByPointer(d, "/foo/1"), a);
+ EXPECT_STREQ("baz", d["foo"][0].GetString());
+ EXPECT_STREQ("bar", d["foo"][1].GetString());
+
+ SwapValueByPointer(d, "/foo/0", *GetValueByPointer(d, "/foo/1"), a);
+ EXPECT_STREQ("bar", d["foo"][0].GetString());
+ EXPECT_STREQ("baz", d["foo"][1].GetString());
+}
+
+TEST(Pointer, SwapValueByPointer_NoAllocator) {
+ Document d;
+ d.Parse(kJson);
+ SwapValueByPointer(d, Pointer("/foo/0"), *GetValueByPointer(d, "/foo/1"));
+ EXPECT_STREQ("baz", d["foo"][0].GetString());
+ EXPECT_STREQ("bar", d["foo"][1].GetString());
+
+ SwapValueByPointer(d, "/foo/0", *GetValueByPointer(d, "/foo/1"));
+ EXPECT_STREQ("bar", d["foo"][0].GetString());
+ EXPECT_STREQ("baz", d["foo"][1].GetString());
+}
+
+TEST(Pointer, EraseValueByPointer_Pointer) {
+ Document d;
+ d.Parse(kJson);
+
+ EXPECT_FALSE(EraseValueByPointer(d, Pointer("")));
+ EXPECT_FALSE(Pointer("/foo/nonexist").Erase(d));
+ EXPECT_TRUE(EraseValueByPointer(d, Pointer("/foo/0")));
+ EXPECT_EQ(1u, d["foo"].Size());
+ EXPECT_STREQ("baz", d["foo"][0].GetString());
+ EXPECT_TRUE(EraseValueByPointer(d, Pointer("/foo/0")));
+ EXPECT_TRUE(d["foo"].Empty());
+ EXPECT_TRUE(EraseValueByPointer(d, Pointer("/foo")));
+ EXPECT_TRUE(Pointer("/foo").Get(d) == 0);
+}
+
+TEST(Pointer, EraseValueByPointer_String) {
+ Document d;
+ d.Parse(kJson);
+
+ EXPECT_FALSE(EraseValueByPointer(d, ""));
+ EXPECT_FALSE(Pointer("/foo/nonexist").Erase(d));
+ EXPECT_TRUE(EraseValueByPointer(d, "/foo/0"));
+ EXPECT_EQ(1u, d["foo"].Size());
+ EXPECT_STREQ("baz", d["foo"][0].GetString());
+ EXPECT_TRUE(EraseValueByPointer(d, "/foo/0"));
+ EXPECT_TRUE(d["foo"].Empty());
+ EXPECT_TRUE(EraseValueByPointer(d, "/foo"));
+ EXPECT_TRUE(Pointer("/foo").Get(d) == 0);
+}
+
+TEST(Pointer, Ambiguity) {
+ {
+ Document d;
+ d.Parse("{\"0\" : [123]}");
+ EXPECT_EQ(123, Pointer("/0/0").Get(d)->GetInt());
+ Pointer("/0/a").Set(d, 456); // Change array [123] to object {456}
+ EXPECT_EQ(456, Pointer("/0/a").Get(d)->GetInt());
+ }
+
+ {
+ Document d;
+ EXPECT_FALSE(d.Parse("[{\"0\": 123}]").HasParseError());
+ EXPECT_EQ(123, Pointer("/0/0").Get(d)->GetInt());
+ Pointer("/0/1").Set(d, 456); // 1 is treated as "1" to index object
+ EXPECT_EQ(123, Pointer("/0/0").Get(d)->GetInt());
+ EXPECT_EQ(456, Pointer("/0/1").Get(d)->GetInt());
+ }
+}
+
+// https://github.com/miloyip/rapidjson/issues/483
+namespace myjson {
+
+class MyAllocator
+{
+public:
+ static const bool kNeedFree = true;
+ void * Malloc(size_t _size) { return malloc(_size); }
+ void * Realloc(void *_org_p, size_t _org_size, size_t _new_size) { (void)_org_size; return realloc(_org_p, _new_size); }
+ static void Free(void *_p) { return free(_p); }
+};
+
+typedef rapidjson::GenericDocument<
+ rapidjson::UTF8<>,
+ rapidjson::MemoryPoolAllocator< MyAllocator >,
+ MyAllocator
+ > Document;
+
+typedef rapidjson::GenericPointer<
+ ::myjson::Document::ValueType,
+ MyAllocator
+ > Pointer;
+
+typedef ::myjson::Document::ValueType Value;
+
+}
+
+TEST(Pointer, Issue483) {
+ std::string mystr, path;
+ myjson::Document document;
+ myjson::Value value(rapidjson::kStringType);
+ value.SetString(mystr.c_str(), static_cast<SizeType>(mystr.length()), document.GetAllocator());
+ myjson::Pointer(path.c_str()).Set(document, value, document.GetAllocator());
+}
diff --git a/3rdparty/rapidjson/test/unittest/prettywritertest.cpp b/3rdparty/rapidjson/test/unittest/prettywritertest.cpp
new file mode 100644
index 00000000000..e05d710f8cb
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/prettywritertest.cpp
@@ -0,0 +1,180 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+#include "rapidjson/reader.h"
+#include "rapidjson/prettywriter.h"
+#include "rapidjson/stringbuffer.h"
+#include "rapidjson/filewritestream.h"
+
+using namespace rapidjson;
+
+static const char kJson[] = "{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3,-1],\"u64\":1234567890123456789,\"i64\":-1234567890123456789}";
+static const char kPrettyJson[] =
+"{\n"
+" \"hello\": \"world\",\n"
+" \"t\": true,\n"
+" \"f\": false,\n"
+" \"n\": null,\n"
+" \"i\": 123,\n"
+" \"pi\": 3.1416,\n"
+" \"a\": [\n"
+" 1,\n"
+" 2,\n"
+" 3,\n"
+" -1\n"
+" ],\n"
+" \"u64\": 1234567890123456789,\n"
+" \"i64\": -1234567890123456789\n"
+"}";
+
+TEST(PrettyWriter, Basic) {
+ StringBuffer buffer;
+ PrettyWriter<StringBuffer> writer(buffer);
+ Reader reader;
+ StringStream s(kJson);
+ reader.Parse(s, writer);
+ EXPECT_STREQ(kPrettyJson, buffer.GetString());
+}
+
+TEST(PrettyWriter, SetIndent) {
+ StringBuffer buffer;
+ PrettyWriter<StringBuffer> writer(buffer);
+ writer.SetIndent('\t', 1);
+ Reader reader;
+ StringStream s(kJson);
+ reader.Parse(s, writer);
+ EXPECT_STREQ(
+ "{\n"
+ "\t\"hello\": \"world\",\n"
+ "\t\"t\": true,\n"
+ "\t\"f\": false,\n"
+ "\t\"n\": null,\n"
+ "\t\"i\": 123,\n"
+ "\t\"pi\": 3.1416,\n"
+ "\t\"a\": [\n"
+ "\t\t1,\n"
+ "\t\t2,\n"
+ "\t\t3,\n"
+ "\t\t-1\n"
+ "\t],\n"
+ "\t\"u64\": 1234567890123456789,\n"
+ "\t\"i64\": -1234567890123456789\n"
+ "}",
+ buffer.GetString());
+}
+
+TEST(PrettyWriter, String) {
+ StringBuffer buffer;
+ PrettyWriter<StringBuffer> writer(buffer);
+ EXPECT_TRUE(writer.StartArray());
+ EXPECT_TRUE(writer.String("Hello\n"));
+ EXPECT_TRUE(writer.EndArray());
+ EXPECT_STREQ("[\n \"Hello\\n\"\n]", buffer.GetString());
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+TEST(PrettyWriter, String_STDSTRING) {
+ StringBuffer buffer;
+ PrettyWriter<StringBuffer> writer(buffer);
+ EXPECT_TRUE(writer.StartArray());
+ EXPECT_TRUE(writer.String(std::string("Hello\n")));
+ EXPECT_TRUE(writer.EndArray());
+ EXPECT_STREQ("[\n \"Hello\\n\"\n]", buffer.GetString());
+}
+#endif
+
+#include <sstream>
+
+class OStreamWrapper {
+public:
+ typedef char Ch;
+
+ OStreamWrapper(std::ostream& os) : os_(os) {}
+
+ Ch Peek() const { assert(false); return '\0'; }
+ Ch Take() { assert(false); return '\0'; }
+ size_t Tell() const { return 0; }
+
+ Ch* PutBegin() { assert(false); return 0; }
+ void Put(Ch c) { os_.put(c); }
+ void Flush() { os_.flush(); }
+ size_t PutEnd(Ch*) { assert(false); return 0; }
+
+private:
+ OStreamWrapper(const OStreamWrapper&);
+ OStreamWrapper& operator=(const OStreamWrapper&);
+
+ std::ostream& os_;
+};
+
+// For covering PutN() generic version
+TEST(PrettyWriter, OStreamWrapper) {
+ StringStream s(kJson);
+
+ std::stringstream ss;
+ OStreamWrapper os(ss);
+
+ PrettyWriter<OStreamWrapper> writer(os);
+
+ Reader reader;
+ reader.Parse(s, writer);
+
+ std::string actual = ss.str();
+ EXPECT_STREQ(kPrettyJson, actual.c_str());
+}
+
+// For covering FileWriteStream::PutN()
+TEST(PrettyWriter, FileWriteStream) {
+ char filename[L_tmpnam];
+ FILE* fp = TempFile(filename);
+ char buffer[16];
+ FileWriteStream os(fp, buffer, sizeof(buffer));
+ PrettyWriter<FileWriteStream> writer(os);
+ Reader reader;
+ StringStream s(kJson);
+ reader.Parse(s, writer);
+ fclose(fp);
+
+ fp = fopen(filename, "rb");
+ fseek(fp, 0, SEEK_END);
+ size_t size = static_cast<size_t>(ftell(fp));
+ fseek(fp, 0, SEEK_SET);
+ char* json = static_cast<char*>(malloc(size + 1));
+ size_t readLength = fread(json, 1, size, fp);
+ json[readLength] = '\0';
+ fclose(fp);
+ remove(filename);
+ EXPECT_STREQ(kPrettyJson, json);
+ free(json);
+}
+
+TEST(PrettyWriter, RawValue) {
+ StringBuffer buffer;
+ PrettyWriter<StringBuffer> writer(buffer);
+ writer.StartObject();
+ writer.Key("a");
+ writer.Int(1);
+ writer.Key("raw");
+ const char json[] = "[\"Hello\\nWorld\", 123.456]";
+ writer.RawValue(json, strlen(json), kArrayType);
+ writer.EndObject();
+ EXPECT_TRUE(writer.IsComplete());
+ EXPECT_STREQ(
+ "{\n"
+ " \"a\": 1,\n"
+ " \"raw\": [\"Hello\\nWorld\", 123.456]\n" // no indentation within raw value
+ "}",
+ buffer.GetString());
+}
diff --git a/3rdparty/rapidjson/test/unittest/readertest.cpp b/3rdparty/rapidjson/test/unittest/readertest.cpp
new file mode 100644
index 00000000000..a07e59a6c9f
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/readertest.cpp
@@ -0,0 +1,1517 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+
+#include "rapidjson/reader.h"
+#include "rapidjson/internal/dtoa.h"
+#include "rapidjson/internal/itoa.h"
+#include "rapidjson/memorystream.h"
+
+using namespace rapidjson;
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+RAPIDJSON_DIAG_OFF(float-equal)
+RAPIDJSON_DIAG_OFF(missing-noreturn)
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(variadic-macros)
+RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
+#endif
+
+template<bool expect>
+struct ParseBoolHandler : BaseReaderHandler<UTF8<>, ParseBoolHandler<expect> > {
+ ParseBoolHandler() : step_(0) {}
+ bool Default() { ADD_FAILURE(); return false; }
+ // gcc 4.8.x generates warning in EXPECT_EQ(bool, bool) on this gtest version.
+ // Workaround with EXPECT_TRUE().
+ bool Bool(bool b) { /*EXPECT_EQ(expect, b); */EXPECT_TRUE(expect == b); ++step_; return true; }
+
+ unsigned step_;
+};
+
+TEST(Reader, ParseTrue) {
+ StringStream s("true");
+ ParseBoolHandler<true> h;
+ Reader reader;
+ reader.Parse(s, h);
+ EXPECT_EQ(1u, h.step_);
+}
+
+TEST(Reader, ParseFalse) {
+ StringStream s("false");
+ ParseBoolHandler<false> h;
+ Reader reader;
+ reader.Parse(s, h);
+ EXPECT_EQ(1u, h.step_);
+}
+
+struct ParseIntHandler : BaseReaderHandler<UTF8<>, ParseIntHandler> {
+ ParseIntHandler() : step_(0), actual_() {}
+ bool Default() { ADD_FAILURE(); return false; }
+ bool Int(int i) { actual_ = i; step_++; return true; }
+
+ unsigned step_;
+ int actual_;
+};
+
+struct ParseUintHandler : BaseReaderHandler<UTF8<>, ParseUintHandler> {
+ ParseUintHandler() : step_(0), actual_() {}
+ bool Default() { ADD_FAILURE(); return false; }
+ bool Uint(unsigned i) { actual_ = i; step_++; return true; }
+
+ unsigned step_;
+ unsigned actual_;
+};
+
+struct ParseInt64Handler : BaseReaderHandler<UTF8<>, ParseInt64Handler> {
+ ParseInt64Handler() : step_(0), actual_() {}
+ bool Default() { ADD_FAILURE(); return false; }
+ bool Int64(int64_t i) { actual_ = i; step_++; return true; }
+
+ unsigned step_;
+ int64_t actual_;
+};
+
+struct ParseUint64Handler : BaseReaderHandler<UTF8<>, ParseUint64Handler> {
+ ParseUint64Handler() : step_(0), actual_() {}
+ bool Default() { ADD_FAILURE(); return false; }
+ bool Uint64(uint64_t i) { actual_ = i; step_++; return true; }
+
+ unsigned step_;
+ uint64_t actual_;
+};
+
+struct ParseDoubleHandler : BaseReaderHandler<UTF8<>, ParseDoubleHandler> {
+ ParseDoubleHandler() : step_(0), actual_() {}
+ bool Default() { ADD_FAILURE(); return false; }
+ bool Double(double d) { actual_ = d; step_++; return true; }
+
+ unsigned step_;
+ double actual_;
+};
+
+TEST(Reader, ParseNumber_Integer) {
+#define TEST_INTEGER(Handler, str, x) \
+ { \
+ StringStream s(str); \
+ Handler h; \
+ Reader reader; \
+ reader.Parse(s, h); \
+ EXPECT_EQ(1u, h.step_); \
+ EXPECT_EQ(x, h.actual_); \
+ }
+
+ TEST_INTEGER(ParseUintHandler, "0", 0u);
+ TEST_INTEGER(ParseUintHandler, "123", 123u);
+ TEST_INTEGER(ParseUintHandler, "2147483648", 2147483648u); // 2^31 - 1 (cannot be stored in int)
+ TEST_INTEGER(ParseUintHandler, "4294967295", 4294967295u);
+
+ TEST_INTEGER(ParseIntHandler, "-123", -123);
+ TEST_INTEGER(ParseIntHandler, "-2147483648", static_cast<int32_t>(0x80000000)); // -2^31 (min of int)
+
+ TEST_INTEGER(ParseUint64Handler, "4294967296", RAPIDJSON_UINT64_C2(1, 0)); // 2^32 (max of unsigned + 1, force to use uint64_t)
+ TEST_INTEGER(ParseUint64Handler, "18446744073709551615", RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF)); // 2^64 - 1 (max of uint64_t)
+
+ TEST_INTEGER(ParseInt64Handler, "-2147483649", static_cast<int64_t>(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x7FFFFFFF))); // -2^31 -1 (min of int - 1, force to use int64_t)
+ TEST_INTEGER(ParseInt64Handler, "-9223372036854775808", static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))); // -2^63 (min of int64_t)
+
+ // Random test for uint32_t/int32_t
+ {
+ union {
+ uint32_t u;
+ int32_t i;
+ }u;
+ Random r;
+
+ for (unsigned i = 0; i < 100000; i++) {
+ u.u = r();
+
+ char buffer[32];
+ *internal::u32toa(u.u, buffer) = '\0';
+ TEST_INTEGER(ParseUintHandler, buffer, u.u);
+
+ if (u.i < 0) {
+ *internal::i32toa(u.i, buffer) = '\0';
+ TEST_INTEGER(ParseIntHandler, buffer, u.i);
+ }
+ }
+ }
+
+ // Random test for uint64_t/int64_t
+ {
+ union {
+ uint64_t u;
+ int64_t i;
+ }u;
+ Random r;
+
+ for (unsigned i = 0; i < 100000; i++) {
+ u.u = uint64_t(r()) << 32;
+ u.u |= r();
+
+ char buffer[32];
+ if (u.u > uint64_t(4294967295u)) {
+ *internal::u64toa(u.u, buffer) = '\0';
+ TEST_INTEGER(ParseUint64Handler, buffer, u.u);
+ }
+
+ if (u.i < -int64_t(2147483648u)) {
+ *internal::i64toa(u.i, buffer) = '\0';
+ TEST_INTEGER(ParseInt64Handler, buffer, u.i);
+ }
+ }
+ }
+#undef TEST_INTEGER
+}
+
+template<bool fullPrecision>
+static void TestParseDouble() {
+#define TEST_DOUBLE(fullPrecision, str, x) \
+ { \
+ StringStream s(str); \
+ ParseDoubleHandler h; \
+ Reader reader; \
+ ASSERT_EQ(kParseErrorNone, reader.Parse<fullPrecision ? kParseFullPrecisionFlag : 0>(s, h).Code()); \
+ EXPECT_EQ(1u, h.step_); \
+ internal::Double e(x), a(h.actual_); \
+ if (fullPrecision) { \
+ EXPECT_EQ(e.Uint64Value(), a.Uint64Value()); \
+ if (e.Uint64Value() != a.Uint64Value()) \
+ printf(" String: %s\n Actual: %.17g\nExpected: %.17g\n", str, h.actual_, x); \
+ } \
+ else { \
+ EXPECT_EQ(e.Sign(), a.Sign()); /* for 0.0 != -0.0 */ \
+ EXPECT_DOUBLE_EQ(x, h.actual_); \
+ } \
+ }
+
+ TEST_DOUBLE(fullPrecision, "0.0", 0.0);
+ TEST_DOUBLE(fullPrecision, "-0.0", -0.0); // For checking issue #289
+ TEST_DOUBLE(fullPrecision, "1.0", 1.0);
+ TEST_DOUBLE(fullPrecision, "-1.0", -1.0);
+ TEST_DOUBLE(fullPrecision, "1.5", 1.5);
+ TEST_DOUBLE(fullPrecision, "-1.5", -1.5);
+ TEST_DOUBLE(fullPrecision, "3.1416", 3.1416);
+ TEST_DOUBLE(fullPrecision, "1E10", 1E10);
+ TEST_DOUBLE(fullPrecision, "1e10", 1e10);
+ TEST_DOUBLE(fullPrecision, "1E+10", 1E+10);
+ TEST_DOUBLE(fullPrecision, "1E-10", 1E-10);
+ TEST_DOUBLE(fullPrecision, "-1E10", -1E10);
+ TEST_DOUBLE(fullPrecision, "-1e10", -1e10);
+ TEST_DOUBLE(fullPrecision, "-1E+10", -1E+10);
+ TEST_DOUBLE(fullPrecision, "-1E-10", -1E-10);
+ TEST_DOUBLE(fullPrecision, "1.234E+10", 1.234E+10);
+ TEST_DOUBLE(fullPrecision, "1.234E-10", 1.234E-10);
+ TEST_DOUBLE(fullPrecision, "1.79769e+308", 1.79769e+308);
+ TEST_DOUBLE(fullPrecision, "2.22507e-308", 2.22507e-308);
+ TEST_DOUBLE(fullPrecision, "-1.79769e+308", -1.79769e+308);
+ TEST_DOUBLE(fullPrecision, "-2.22507e-308", -2.22507e-308);
+ TEST_DOUBLE(fullPrecision, "4.9406564584124654e-324", 4.9406564584124654e-324); // minimum denormal
+ TEST_DOUBLE(fullPrecision, "2.2250738585072009e-308", 2.2250738585072009e-308); // Max subnormal double
+ TEST_DOUBLE(fullPrecision, "2.2250738585072014e-308", 2.2250738585072014e-308); // Min normal positive double
+ TEST_DOUBLE(fullPrecision, "1.7976931348623157e+308", 1.7976931348623157e+308); // Max double
+ TEST_DOUBLE(fullPrecision, "1e-10000", 0.0); // must underflow
+ TEST_DOUBLE(fullPrecision, "18446744073709551616", 18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double)
+ TEST_DOUBLE(fullPrecision, "-9223372036854775809", -9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double)
+ TEST_DOUBLE(fullPrecision, "0.9868011474609375", 0.9868011474609375); // https://github.com/miloyip/rapidjson/issues/120
+ TEST_DOUBLE(fullPrecision, "123e34", 123e34); // Fast Path Cases In Disguise
+ TEST_DOUBLE(fullPrecision, "45913141877270640000.0", 45913141877270640000.0);
+ TEST_DOUBLE(fullPrecision, "2.2250738585072011e-308", 2.2250738585072011e-308); // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
+ TEST_DOUBLE(fullPrecision, "1e-00011111111111", 0.0); // Issue #313
+ TEST_DOUBLE(fullPrecision, "-1e-00011111111111", -0.0);
+ TEST_DOUBLE(fullPrecision, "1e-214748363", 0.0); // Maximum supported negative exponent
+ TEST_DOUBLE(fullPrecision, "1e-214748364", 0.0);
+ TEST_DOUBLE(fullPrecision, "1e-21474836311", 0.0);
+ TEST_DOUBLE(fullPrecision, "0.017976931348623157e+310", 1.7976931348623157e+308); // Max double in another form
+
+ // Since
+ // abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401123495768877590405345064751974375599... ¡Á 10^-324
+ // abs((2^-1022) - 2.2250738585072012e-308) = 1.830902327173324040642192159804623318305533274168872044... ¡Á 10 ^ -324
+ // So 2.2250738585072012e-308 should round to 2^-1022 = 2.2250738585072014e-308
+ TEST_DOUBLE(fullPrecision, "2.2250738585072012e-308", 2.2250738585072014e-308); // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
+
+ // More closer to normal/subnormal boundary
+ // boundary = 2^-1022 - 2^-1075 = 2.225073858507201136057409796709131975934819546351645648... ¡Á 10^-308
+ TEST_DOUBLE(fullPrecision, "2.22507385850720113605740979670913197593481954635164564e-308", 2.2250738585072009e-308);
+ TEST_DOUBLE(fullPrecision, "2.22507385850720113605740979670913197593481954635164565e-308", 2.2250738585072014e-308);
+
+ // 1.0 is in (1.0 - 2^-54, 1.0 + 2^-53)
+ // 1.0 - 2^-54 = 0.999999999999999944488848768742172978818416595458984375
+ TEST_DOUBLE(fullPrecision, "0.999999999999999944488848768742172978818416595458984375", 1.0); // round to even
+ TEST_DOUBLE(fullPrecision, "0.999999999999999944488848768742172978818416595458984374", 0.99999999999999989); // previous double
+ TEST_DOUBLE(fullPrecision, "0.999999999999999944488848768742172978818416595458984376", 1.0); // next double
+ // 1.0 + 2^-53 = 1.00000000000000011102230246251565404236316680908203125
+ TEST_DOUBLE(fullPrecision, "1.00000000000000011102230246251565404236316680908203125", 1.0); // round to even
+ TEST_DOUBLE(fullPrecision, "1.00000000000000011102230246251565404236316680908203124", 1.0); // previous double
+ TEST_DOUBLE(fullPrecision, "1.00000000000000011102230246251565404236316680908203126", 1.00000000000000022); // next double
+
+ // Numbers from https://github.com/floitsch/double-conversion/blob/master/test/cctest/test-strtod.cc
+
+ TEST_DOUBLE(fullPrecision, "72057594037927928.0", 72057594037927928.0);
+ TEST_DOUBLE(fullPrecision, "72057594037927936.0", 72057594037927936.0);
+ TEST_DOUBLE(fullPrecision, "72057594037927932.0", 72057594037927936.0);
+ TEST_DOUBLE(fullPrecision, "7205759403792793199999e-5", 72057594037927928.0);
+ TEST_DOUBLE(fullPrecision, "7205759403792793200001e-5", 72057594037927936.0);
+
+ TEST_DOUBLE(fullPrecision, "9223372036854774784.0", 9223372036854774784.0);
+ TEST_DOUBLE(fullPrecision, "9223372036854775808.0", 9223372036854775808.0);
+ TEST_DOUBLE(fullPrecision, "9223372036854775296.0", 9223372036854775808.0);
+ TEST_DOUBLE(fullPrecision, "922337203685477529599999e-5", 9223372036854774784.0);
+ TEST_DOUBLE(fullPrecision, "922337203685477529600001e-5", 9223372036854775808.0);
+
+ TEST_DOUBLE(fullPrecision, "10141204801825834086073718800384", 10141204801825834086073718800384.0);
+ TEST_DOUBLE(fullPrecision, "10141204801825835211973625643008", 10141204801825835211973625643008.0);
+ TEST_DOUBLE(fullPrecision, "10141204801825834649023672221696", 10141204801825835211973625643008.0);
+ TEST_DOUBLE(fullPrecision, "1014120480182583464902367222169599999e-5", 10141204801825834086073718800384.0);
+ TEST_DOUBLE(fullPrecision, "1014120480182583464902367222169600001e-5", 10141204801825835211973625643008.0);
+
+ TEST_DOUBLE(fullPrecision, "5708990770823838890407843763683279797179383808", 5708990770823838890407843763683279797179383808.0);
+ TEST_DOUBLE(fullPrecision, "5708990770823839524233143877797980545530986496", 5708990770823839524233143877797980545530986496.0);
+ TEST_DOUBLE(fullPrecision, "5708990770823839207320493820740630171355185152", 5708990770823839524233143877797980545530986496.0);
+ TEST_DOUBLE(fullPrecision, "5708990770823839207320493820740630171355185151999e-3", 5708990770823838890407843763683279797179383808.0);
+ TEST_DOUBLE(fullPrecision, "5708990770823839207320493820740630171355185152001e-3", 5708990770823839524233143877797980545530986496.0);
+
+ {
+ char n1e308[310]; // '1' followed by 308 '0'
+ n1e308[0] = '1';
+ for (int i = 1; i < 309; i++)
+ n1e308[i] = '0';
+ n1e308[309] = '\0';
+ TEST_DOUBLE(fullPrecision, n1e308, 1E308);
+ }
+
+ // Cover trimming
+ TEST_DOUBLE(fullPrecision,
+"2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508"
+"7914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012"
+"9811224514518898490572223072852551331557550159143974763979834118019993239625482890171070818506906306"
+"6665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505"
+"1080609940730262937128958950003583799967207254304360284078895771796150945516748243471030702609144621"
+"5722898802581825451803257070188608721131280795122334262883686223215037756666225039825343359745688844"
+"2390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042"
+"7567186443383770486037861622771738545623065874679014086723327636718751234567890123456789012345678901"
+"e-308",
+ 2.2250738585072014e-308);
+
+ {
+ static const unsigned count = 100; // Tested with 1000000 locally
+ Random r;
+ Reader reader; // Reusing reader to prevent heap allocation
+
+ // Exhaustively test different exponents with random significant
+ for (uint64_t exp = 0; exp < 2047; exp++) {
+ ;
+ for (unsigned i = 0; i < count; i++) {
+ // Need to call r() in two statements for cross-platform coherent sequence.
+ uint64_t u = (exp << 52) | uint64_t(r() & 0x000FFFFF) << 32;
+ u |= uint64_t(r());
+ internal::Double d = internal::Double(u);
+
+ char buffer[32];
+ *internal::dtoa(d.Value(), buffer) = '\0';
+
+ StringStream s(buffer);
+ ParseDoubleHandler h;
+ ASSERT_EQ(kParseErrorNone, reader.Parse<fullPrecision ? kParseFullPrecisionFlag : 0>(s, h).Code());
+ EXPECT_EQ(1u, h.step_);
+ internal::Double a(h.actual_);
+ if (fullPrecision) {
+ EXPECT_EQ(d.Uint64Value(), a.Uint64Value());
+ if (d.Uint64Value() != a.Uint64Value())
+ printf(" String: %s\n Actual: %.17g\nExpected: %.17g\n", buffer, h.actual_, d.Value());
+ }
+ else {
+ EXPECT_EQ(d.Sign(), a.Sign()); // for 0.0 != -0.0
+ EXPECT_DOUBLE_EQ(d.Value(), h.actual_);
+ }
+ }
+ }
+ }
+
+ // Issue #340
+ TEST_DOUBLE(fullPrecision, "7.450580596923828e-9", 7.450580596923828e-9);
+ {
+ internal::Double d(1.0);
+ for (int i = 0; i < 324; i++) {
+ char buffer[32];
+ *internal::dtoa(d.Value(), buffer) = '\0';
+
+ StringStream s(buffer);
+ ParseDoubleHandler h;
+ Reader reader;
+ ASSERT_EQ(kParseErrorNone, reader.Parse<fullPrecision ? kParseFullPrecisionFlag : 0>(s, h).Code());
+ EXPECT_EQ(1u, h.step_);
+ internal::Double a(h.actual_);
+ if (fullPrecision) {
+ EXPECT_EQ(d.Uint64Value(), a.Uint64Value());
+ if (d.Uint64Value() != a.Uint64Value())
+ printf(" String: %s\n Actual: %.17g\nExpected: %.17g\n", buffer, h.actual_, d.Value());
+ }
+ else {
+ EXPECT_EQ(d.Sign(), a.Sign()); // for 0.0 != -0.0
+ EXPECT_DOUBLE_EQ(d.Value(), h.actual_);
+ }
+
+
+ d = d.Value() * 0.5;
+ }
+ }
+#undef TEST_DOUBLE
+}
+
+TEST(Reader, ParseNumber_NormalPrecisionDouble) {
+ TestParseDouble<false>();
+}
+
+TEST(Reader, ParseNumber_FullPrecisionDouble) {
+ TestParseDouble<true>();
+}
+
+TEST(Reader, ParseNumber_NormalPrecisionError) {
+ static unsigned count = 1000000;
+ Random r;
+
+ double ulpSum = 0.0;
+ double ulpMax = 0.0;
+ for (unsigned i = 0; i < count; i++) {
+ internal::Double e, a;
+ do {
+ // Need to call r() in two statements for cross-platform coherent sequence.
+ uint64_t u = uint64_t(r()) << 32;
+ u |= uint64_t(r());
+ e = u;
+ } while (e.IsNan() || e.IsInf() || !e.IsNormal());
+
+ char buffer[32];
+ *internal::dtoa(e.Value(), buffer) = '\0';
+
+ StringStream s(buffer);
+ ParseDoubleHandler h;
+ Reader reader;
+ ASSERT_EQ(kParseErrorNone, reader.Parse(s, h).Code());
+ EXPECT_EQ(1u, h.step_);
+
+ a = h.actual_;
+ uint64_t bias1 = e.ToBias();
+ uint64_t bias2 = a.ToBias();
+ double ulp = static_cast<double>(bias1 >= bias2 ? bias1 - bias2 : bias2 - bias1);
+ ulpMax = std::max(ulpMax, ulp);
+ ulpSum += ulp;
+ }
+ printf("ULP Average = %g, Max = %g \n", ulpSum / count, ulpMax);
+}
+
+TEST(Reader, ParseNumber_Error) {
+#define TEST_NUMBER_ERROR(errorCode, str, errorOffset, streamPos) \
+ { \
+ char buffer[1001]; \
+ sprintf(buffer, "%s", str); \
+ InsituStringStream s(buffer); \
+ BaseReaderHandler<> h; \
+ Reader reader; \
+ EXPECT_FALSE(reader.Parse(s, h)); \
+ EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
+ EXPECT_EQ(errorOffset, reader.GetErrorOffset());\
+ EXPECT_EQ(streamPos, s.Tell());\
+ }
+
+ // Number too big to be stored in double.
+ {
+ char n1e309[311]; // '1' followed by 309 '0'
+ n1e309[0] = '1';
+ for (int i = 1; i < 310; i++)
+ n1e309[i] = '0';
+ n1e309[310] = '\0';
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig, n1e309, 0, 309);
+ }
+ TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "1e309", 0, 5);
+
+ // Miss fraction part in number.
+ TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1.", 2, 2);
+ TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1.a", 2, 2);
+
+ // Miss exponent in number.
+ TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e", 2, 2);
+ TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e_", 2, 2);
+
+#undef TEST_NUMBER_ERROR
+}
+
+template <typename Encoding>
+struct ParseStringHandler : BaseReaderHandler<Encoding, ParseStringHandler<Encoding> > {
+ ParseStringHandler() : str_(0), length_(0), copy_() {}
+ ~ParseStringHandler() { EXPECT_TRUE(str_ != 0); if (copy_) free(const_cast<typename Encoding::Ch*>(str_)); }
+
+ ParseStringHandler(const ParseStringHandler&);
+ ParseStringHandler& operator=(const ParseStringHandler&);
+
+ bool Default() { ADD_FAILURE(); return false; }
+ bool String(const typename Encoding::Ch* str, size_t length, bool copy) {
+ EXPECT_EQ(0, str_);
+ if (copy) {
+ str_ = static_cast<typename Encoding::Ch*>(malloc((length + 1) * sizeof(typename Encoding::Ch)));
+ memcpy(const_cast<typename Encoding::Ch*>(str_), str, (length + 1) * sizeof(typename Encoding::Ch));
+ }
+ else
+ str_ = str;
+ length_ = length;
+ copy_ = copy;
+ return true;
+ }
+
+ const typename Encoding::Ch* str_;
+ size_t length_;
+ bool copy_;
+};
+
+TEST(Reader, ParseString) {
+#define TEST_STRING(Encoding, e, x) \
+ { \
+ Encoding::Ch* buffer = StrDup(x); \
+ GenericInsituStringStream<Encoding> is(buffer); \
+ ParseStringHandler<Encoding> h; \
+ GenericReader<Encoding, Encoding> reader; \
+ reader.Parse<kParseInsituFlag | kParseValidateEncodingFlag>(is, h); \
+ EXPECT_EQ(0, StrCmp<Encoding::Ch>(e, h.str_)); \
+ EXPECT_EQ(StrLen(e), h.length_); \
+ free(buffer); \
+ GenericStringStream<Encoding> s(x); \
+ ParseStringHandler<Encoding> h2; \
+ GenericReader<Encoding, Encoding> reader2; \
+ reader2.Parse(s, h2); \
+ EXPECT_EQ(0, StrCmp<Encoding::Ch>(e, h2.str_)); \
+ EXPECT_EQ(StrLen(e), h2.length_); \
+ }
+
+ // String constant L"\xXX" can only specify character code in bytes, which is not endianness-neutral.
+ // And old compiler does not support u"" and U"" string literal. So here specify string literal by array of Ch.
+ // In addition, GCC 4.8 generates -Wnarrowing warnings when character code >= 128 are assigned to signed integer types.
+ // Therefore, utype is added for declaring unsigned array, and then cast it to Encoding::Ch.
+#define ARRAY(...) { __VA_ARGS__ }
+#define TEST_STRINGARRAY(Encoding, utype, array, x) \
+ { \
+ static const utype ue[] = array; \
+ static const Encoding::Ch* e = reinterpret_cast<const Encoding::Ch *>(&ue[0]); \
+ TEST_STRING(Encoding, e, x); \
+ }
+
+#define TEST_STRINGARRAY2(Encoding, utype, earray, xarray) \
+ { \
+ static const utype ue[] = earray; \
+ static const utype xe[] = xarray; \
+ static const Encoding::Ch* e = reinterpret_cast<const Encoding::Ch *>(&ue[0]); \
+ static const Encoding::Ch* x = reinterpret_cast<const Encoding::Ch *>(&xe[0]); \
+ TEST_STRING(Encoding, e, x); \
+ }
+
+ TEST_STRING(UTF8<>, "", "\"\"");
+ TEST_STRING(UTF8<>, "Hello", "\"Hello\"");
+ TEST_STRING(UTF8<>, "Hello\nWorld", "\"Hello\\nWorld\"");
+ TEST_STRING(UTF8<>, "\"\\/\b\f\n\r\t", "\"\\\"\\\\/\\b\\f\\n\\r\\t\"");
+ TEST_STRING(UTF8<>, "\x24", "\"\\u0024\""); // Dollar sign U+0024
+ TEST_STRING(UTF8<>, "\xC2\xA2", "\"\\u00A2\""); // Cents sign U+00A2
+ TEST_STRING(UTF8<>, "\xE2\x82\xAC", "\"\\u20AC\""); // Euro sign U+20AC
+ TEST_STRING(UTF8<>, "\xF0\x9D\x84\x9E", "\"\\uD834\\uDD1E\""); // G clef sign U+1D11E
+
+ // UTF16
+ TEST_STRING(UTF16<>, L"", L"\"\"");
+ TEST_STRING(UTF16<>, L"Hello", L"\"Hello\"");
+ TEST_STRING(UTF16<>, L"Hello\nWorld", L"\"Hello\\nWorld\"");
+ TEST_STRING(UTF16<>, L"\"\\/\b\f\n\r\t", L"\"\\\"\\\\/\\b\\f\\n\\r\\t\"");
+ TEST_STRINGARRAY(UTF16<>, wchar_t, ARRAY(0x0024, 0x0000), L"\"\\u0024\"");
+ TEST_STRINGARRAY(UTF16<>, wchar_t, ARRAY(0x00A2, 0x0000), L"\"\\u00A2\""); // Cents sign U+00A2
+ TEST_STRINGARRAY(UTF16<>, wchar_t, ARRAY(0x20AC, 0x0000), L"\"\\u20AC\""); // Euro sign U+20AC
+ TEST_STRINGARRAY(UTF16<>, wchar_t, ARRAY(0xD834, 0xDD1E, 0x0000), L"\"\\uD834\\uDD1E\""); // G clef sign U+1D11E
+
+ // UTF32
+ TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY('\0'), ARRAY('\"', '\"', '\0'));
+ TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY('H', 'e', 'l', 'l', 'o', '\0'), ARRAY('\"', 'H', 'e', 'l', 'l', 'o', '\"', '\0'));
+ TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY('H', 'e', 'l', 'l', 'o', '\n', 'W', 'o', 'r', 'l', 'd', '\0'), ARRAY('\"', 'H', 'e', 'l', 'l', 'o', '\\', 'n', 'W', 'o', 'r', 'l', 'd', '\"', '\0'));
+ TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY('\"', '\\', '/', '\b', '\f', '\n', '\r', '\t', '\0'), ARRAY('\"', '\\', '\"', '\\', '\\', '/', '\\', 'b', '\\', 'f', '\\', 'n', '\\', 'r', '\\', 't', '\"', '\0'));
+ TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY(0x00024, 0x0000), ARRAY('\"', '\\', 'u', '0', '0', '2', '4', '\"', '\0'));
+ TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY(0x000A2, 0x0000), ARRAY('\"', '\\', 'u', '0', '0', 'A', '2', '\"', '\0')); // Cents sign U+00A2
+ TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY(0x020AC, 0x0000), ARRAY('\"', '\\', 'u', '2', '0', 'A', 'C', '\"', '\0')); // Euro sign U+20AC
+ TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY(0x1D11E, 0x0000), ARRAY('\"', '\\', 'u', 'D', '8', '3', '4', '\\', 'u', 'D', 'D', '1', 'E', '\"', '\0')); // G clef sign U+1D11E
+
+#undef TEST_STRINGARRAY
+#undef ARRAY
+#undef TEST_STRING
+
+ // Support of null character in string
+ {
+ StringStream s("\"Hello\\u0000World\"");
+ const char e[] = "Hello\0World";
+ ParseStringHandler<UTF8<> > h;
+ Reader reader;
+ reader.Parse(s, h);
+ EXPECT_EQ(0, memcmp(e, h.str_, h.length_ + 1));
+ EXPECT_EQ(11u, h.length_);
+ }
+}
+
+TEST(Reader, ParseString_Transcoding) {
+ const char* x = "\"Hello\"";
+ const wchar_t* e = L"Hello";
+ GenericStringStream<UTF8<> > is(x);
+ GenericReader<UTF8<>, UTF16<> > reader;
+ ParseStringHandler<UTF16<> > h;
+ reader.Parse(is, h);
+ EXPECT_EQ(0, StrCmp<UTF16<>::Ch>(e, h.str_));
+ EXPECT_EQ(StrLen(e), h.length_);
+}
+
+TEST(Reader, ParseString_TranscodingWithValidation) {
+ const char* x = "\"Hello\"";
+ const wchar_t* e = L"Hello";
+ GenericStringStream<UTF8<> > is(x);
+ GenericReader<UTF8<>, UTF16<> > reader;
+ ParseStringHandler<UTF16<> > h;
+ reader.Parse<kParseValidateEncodingFlag>(is, h);
+ EXPECT_EQ(0, StrCmp<UTF16<>::Ch>(e, h.str_));
+ EXPECT_EQ(StrLen(e), h.length_);
+}
+
+TEST(Reader, ParseString_NonDestructive) {
+ StringStream s("\"Hello\\nWorld\"");
+ ParseStringHandler<UTF8<> > h;
+ Reader reader;
+ reader.Parse(s, h);
+ EXPECT_EQ(0, StrCmp("Hello\nWorld", h.str_));
+ EXPECT_EQ(11u, h.length_);
+}
+
+template <typename Encoding>
+ParseErrorCode TestString(const typename Encoding::Ch* str) {
+ GenericStringStream<Encoding> s(str);
+ BaseReaderHandler<Encoding> h;
+ GenericReader<Encoding, Encoding> reader;
+ reader.template Parse<kParseValidateEncodingFlag>(s, h);
+ return reader.GetParseErrorCode();
+}
+
+TEST(Reader, ParseString_Error) {
+#define TEST_STRING_ERROR(errorCode, str, errorOffset, streamPos)\
+{\
+ GenericStringStream<UTF8<> > s(str);\
+ BaseReaderHandler<UTF8<> > h;\
+ GenericReader<UTF8<> , UTF8<> > reader;\
+ reader.Parse<kParseValidateEncodingFlag>(s, h);\
+ EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
+ EXPECT_EQ(errorOffset, reader.GetErrorOffset());\
+ EXPECT_EQ(streamPos, s.Tell());\
+}
+
+#define ARRAY(...) { __VA_ARGS__ }
+#define TEST_STRINGENCODING_ERROR(Encoding, TargetEncoding, utype, array) \
+ { \
+ static const utype ue[] = array; \
+ static const Encoding::Ch* e = reinterpret_cast<const Encoding::Ch *>(&ue[0]); \
+ EXPECT_EQ(kParseErrorStringInvalidEncoding, TestString<Encoding>(e));\
+ /* decode error */\
+ GenericStringStream<Encoding> s(e);\
+ BaseReaderHandler<TargetEncoding> h;\
+ GenericReader<Encoding, TargetEncoding> reader;\
+ reader.Parse(s, h);\
+ EXPECT_EQ(kParseErrorStringInvalidEncoding, reader.GetParseErrorCode());\
+ }
+
+ // Invalid escape character in string.
+ TEST_STRING_ERROR(kParseErrorStringEscapeInvalid, "[\"\\a\"]", 2, 3);
+
+ // Incorrect hex digit after \\u escape in string.
+ TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uABCG\"]", 2, 7);
+
+ // Quotation in \\u escape in string (Issue #288)
+ TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uaaa\"]", 2, 7);
+ TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uD800\\uFFF\"]", 2, 13);
+
+ // The surrogate pair in string is invalid.
+ TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800X\"]", 2, 8);
+ TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800\\uFFFF\"]", 2, 14);
+
+ // Missing a closing quotation mark in string.
+ TEST_STRING_ERROR(kParseErrorStringMissQuotationMark, "[\"Test]", 7, 7);
+
+ // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
+
+ // 3 Malformed sequences
+
+ // 3.1 Unexpected continuation bytes
+ {
+ char e[] = { '[', '\"', 0, '\"', ']', '\0' };
+ for (unsigned char c = 0x80u; c <= 0xBFu; c++) {
+ e[2] = static_cast<char>(c);
+ ParseErrorCode error = TestString<UTF8<> >(e);
+ EXPECT_EQ(kParseErrorStringInvalidEncoding, error);
+ if (error != kParseErrorStringInvalidEncoding)
+ std::cout << static_cast<unsigned>(c) << std::endl;
+ }
+ }
+
+ // 3.2 Lonely start characters, 3.5 Impossible bytes
+ {
+ char e[] = { '[', '\"', 0, ' ', '\"', ']', '\0' };
+ for (unsigned c = 0xC0u; c <= 0xFFu; c++) {
+ e[2] = static_cast<char>(c);
+ int streamPos;
+ if (c <= 0xC1u)
+ streamPos = 3; // 0xC0 - 0xC1
+ else if (c <= 0xDFu)
+ streamPos = 4; // 0xC2 - 0xDF
+ else if (c <= 0xEFu)
+ streamPos = 5; // 0xE0 - 0xEF
+ else if (c <= 0xF4u)
+ streamPos = 6; // 0xF0 - 0xF4
+ else
+ streamPos = 3; // 0xF5 - 0xFF
+ TEST_STRING_ERROR(kParseErrorStringInvalidEncoding, e, 2, streamPos);
+ }
+ }
+
+ // 4 Overlong sequences
+
+ // 4.1 Examples of an overlong ASCII character
+ TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0xAFu, '\"', ']', '\0'));
+ TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0xAFu, '\"', ']', '\0'));
+ TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0xAFu, '\"', ']', '\0'));
+
+ // 4.2 Maximum overlong sequences
+ TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC1u, 0xBFu, '\"', ']', '\0'));
+ TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x9Fu, 0xBFu, '\"', ']', '\0'));
+ TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x8Fu, 0xBFu, 0xBFu, '\"', ']', '\0'));
+
+ // 4.3 Overlong representation of the NUL character
+ TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0x80u, '\"', ']', '\0'));
+ TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0x80u, '\"', ']', '\0'));
+ TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0x80u, '\"', ']', '\0'));
+
+ // 5 Illegal code positions
+
+ // 5.1 Single UTF-16 surrogates
+ TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xA0u, 0x80u, '\"', ']', '\0'));
+ TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xADu, 0xBFu, '\"', ']', '\0'));
+ TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xAEu, 0x80u, '\"', ']', '\0'));
+ TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xAFu, 0xBFu, '\"', ']', '\0'));
+ TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xB0u, 0x80u, '\"', ']', '\0'));
+ TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xBEu, 0x80u, '\"', ']', '\0'));
+ TEST_STRINGENCODING_ERROR(UTF8<>, UTF16<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xBFu, 0xBFu, '\"', ']', '\0'));
+
+ // Malform UTF-16 sequences
+ TEST_STRINGENCODING_ERROR(UTF16<>, UTF8<>, wchar_t, ARRAY('[', '\"', 0xDC00, 0xDC00, '\"', ']', '\0'));
+ TEST_STRINGENCODING_ERROR(UTF16<>, UTF8<>, wchar_t, ARRAY('[', '\"', 0xD800, 0xD800, '\"', ']', '\0'));
+
+ // Malform UTF-32 sequence
+ TEST_STRINGENCODING_ERROR(UTF32<>, UTF8<>, unsigned, ARRAY('[', '\"', 0x110000, '\"', ']', '\0'));
+
+ // Malform ASCII sequence
+ TEST_STRINGENCODING_ERROR(ASCII<>, UTF8<>, char, ARRAY('[', '\"', char(0x80), '\"', ']', '\0'));
+
+#undef ARRAY
+#undef TEST_STRINGARRAY_ERROR
+}
+
+template <unsigned count>
+struct ParseArrayHandler : BaseReaderHandler<UTF8<>, ParseArrayHandler<count> > {
+ ParseArrayHandler() : step_(0) {}
+
+ bool Default() { ADD_FAILURE(); return false; }
+ bool Uint(unsigned i) { EXPECT_EQ(step_, i); step_++; return true; }
+ bool StartArray() { EXPECT_EQ(0u, step_); step_++; return true; }
+ bool EndArray(SizeType) { step_++; return true; }
+
+ unsigned step_;
+};
+
+TEST(Reader, ParseEmptyArray) {
+ char *json = StrDup("[ ] ");
+ InsituStringStream s(json);
+ ParseArrayHandler<0> h;
+ Reader reader;
+ reader.Parse(s, h);
+ EXPECT_EQ(2u, h.step_);
+ free(json);
+}
+
+TEST(Reader, ParseArray) {
+ char *json = StrDup("[1, 2, 3, 4]");
+ InsituStringStream s(json);
+ ParseArrayHandler<4> h;
+ Reader reader;
+ reader.Parse(s, h);
+ EXPECT_EQ(6u, h.step_);
+ free(json);
+}
+
+TEST(Reader, ParseArray_Error) {
+#define TEST_ARRAY_ERROR(errorCode, str, errorOffset) \
+ { \
+ int streamPos = errorOffset; \
+ char buffer[1001]; \
+ strncpy(buffer, str, 1000); \
+ InsituStringStream s(buffer); \
+ BaseReaderHandler<> h; \
+ GenericReader<UTF8<>, UTF8<>, CrtAllocator> reader; \
+ EXPECT_FALSE(reader.Parse(s, h)); \
+ EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
+ EXPECT_EQ(errorOffset, reader.GetErrorOffset());\
+ EXPECT_EQ(streamPos, s.Tell());\
+ }
+
+ // Missing a comma or ']' after an array element.
+ TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1", 2);
+ TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1}", 2);
+ TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1 2]", 3);
+
+#undef TEST_ARRAY_ERROR
+}
+
+struct ParseObjectHandler : BaseReaderHandler<UTF8<>, ParseObjectHandler> {
+ ParseObjectHandler() : step_(0) {}
+
+ bool Default() { ADD_FAILURE(); return false; }
+ bool Null() { EXPECT_EQ(8u, step_); step_++; return true; }
+ bool Bool(bool b) {
+ switch(step_) {
+ case 4: EXPECT_TRUE(b); step_++; return true;
+ case 6: EXPECT_FALSE(b); step_++; return true;
+ default: ADD_FAILURE(); return false;
+ }
+ }
+ bool Int(int i) {
+ switch(step_) {
+ case 10: EXPECT_EQ(123, i); step_++; return true;
+ case 15: EXPECT_EQ(1, i); step_++; return true;
+ case 16: EXPECT_EQ(2, i); step_++; return true;
+ case 17: EXPECT_EQ(3, i); step_++; return true;
+ default: ADD_FAILURE(); return false;
+ }
+ }
+ bool Uint(unsigned i) { return Int(static_cast<int>(i)); }
+ bool Double(double d) { EXPECT_EQ(12u, step_); EXPECT_DOUBLE_EQ(3.1416, d); step_++; return true; }
+ bool String(const char* str, size_t, bool) {
+ switch(step_) {
+ case 1: EXPECT_STREQ("hello", str); step_++; return true;
+ case 2: EXPECT_STREQ("world", str); step_++; return true;
+ case 3: EXPECT_STREQ("t", str); step_++; return true;
+ case 5: EXPECT_STREQ("f", str); step_++; return true;
+ case 7: EXPECT_STREQ("n", str); step_++; return true;
+ case 9: EXPECT_STREQ("i", str); step_++; return true;
+ case 11: EXPECT_STREQ("pi", str); step_++; return true;
+ case 13: EXPECT_STREQ("a", str); step_++; return true;
+ default: ADD_FAILURE(); return false;
+ }
+ }
+ bool StartObject() { EXPECT_EQ(0u, step_); step_++; return true; }
+ bool EndObject(SizeType memberCount) { EXPECT_EQ(19u, step_); EXPECT_EQ(7u, memberCount); step_++; return true; }
+ bool StartArray() { EXPECT_EQ(14u, step_); step_++; return true; }
+ bool EndArray(SizeType elementCount) { EXPECT_EQ(18u, step_); EXPECT_EQ(3u, elementCount); step_++; return true; }
+
+ unsigned step_;
+};
+
+TEST(Reader, ParseObject) {
+ const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } ";
+
+ // Insitu
+ {
+ char* json2 = StrDup(json);
+ InsituStringStream s(json2);
+ ParseObjectHandler h;
+ Reader reader;
+ reader.Parse<kParseInsituFlag>(s, h);
+ EXPECT_EQ(20u, h.step_);
+ free(json2);
+ }
+
+ // Normal
+ {
+ StringStream s(json);
+ ParseObjectHandler h;
+ Reader reader;
+ reader.Parse(s, h);
+ EXPECT_EQ(20u, h.step_);
+ }
+}
+
+struct ParseEmptyObjectHandler : BaseReaderHandler<UTF8<>, ParseEmptyObjectHandler> {
+ ParseEmptyObjectHandler() : step_(0) {}
+
+ bool Default() { ADD_FAILURE(); return false; }
+ bool StartObject() { EXPECT_EQ(0u, step_); step_++; return true; }
+ bool EndObject(SizeType) { EXPECT_EQ(1u, step_); step_++; return true; }
+
+ unsigned step_;
+};
+
+TEST(Reader, Parse_EmptyObject) {
+ StringStream s("{ } ");
+ ParseEmptyObjectHandler h;
+ Reader reader;
+ reader.Parse(s, h);
+ EXPECT_EQ(2u, h.step_);
+}
+
+struct ParseMultipleRootHandler : BaseReaderHandler<UTF8<>, ParseMultipleRootHandler> {
+ ParseMultipleRootHandler() : step_(0) {}
+
+ bool Default() { ADD_FAILURE(); return false; }
+ bool StartObject() { EXPECT_EQ(0u, step_); step_++; return true; }
+ bool EndObject(SizeType) { EXPECT_EQ(1u, step_); step_++; return true; }
+ bool StartArray() { EXPECT_EQ(2u, step_); step_++; return true; }
+ bool EndArray(SizeType) { EXPECT_EQ(3u, step_); step_++; return true; }
+
+ unsigned step_;
+};
+
+template <unsigned parseFlags>
+void TestMultipleRoot() {
+ StringStream s("{}[] a");
+ ParseMultipleRootHandler h;
+ Reader reader;
+ EXPECT_TRUE(reader.Parse<parseFlags>(s, h));
+ EXPECT_EQ(2u, h.step_);
+ EXPECT_TRUE(reader.Parse<parseFlags>(s, h));
+ EXPECT_EQ(4u, h.step_);
+ EXPECT_EQ(' ', s.Take());
+ EXPECT_EQ('a', s.Take());
+}
+
+TEST(Reader, Parse_MultipleRoot) {
+ TestMultipleRoot<kParseStopWhenDoneFlag>();
+}
+
+TEST(Reader, ParseIterative_MultipleRoot) {
+ TestMultipleRoot<kParseIterativeFlag | kParseStopWhenDoneFlag>();
+}
+
+template <unsigned parseFlags>
+void TestInsituMultipleRoot() {
+ char* buffer = strdup("{}[] a");
+ InsituStringStream s(buffer);
+ ParseMultipleRootHandler h;
+ Reader reader;
+ EXPECT_TRUE(reader.Parse<kParseInsituFlag | parseFlags>(s, h));
+ EXPECT_EQ(2u, h.step_);
+ EXPECT_TRUE(reader.Parse<kParseInsituFlag | parseFlags>(s, h));
+ EXPECT_EQ(4u, h.step_);
+ EXPECT_EQ(' ', s.Take());
+ EXPECT_EQ('a', s.Take());
+ free(buffer);
+}
+
+TEST(Reader, ParseInsitu_MultipleRoot) {
+ TestInsituMultipleRoot<kParseStopWhenDoneFlag>();
+}
+
+TEST(Reader, ParseInsituIterative_MultipleRoot) {
+ TestInsituMultipleRoot<kParseIterativeFlag | kParseStopWhenDoneFlag>();
+}
+
+#define TEST_ERROR(errorCode, str, errorOffset) \
+ { \
+ int streamPos = errorOffset; \
+ char buffer[1001]; \
+ strncpy(buffer, str, 1000); \
+ InsituStringStream s(buffer); \
+ BaseReaderHandler<> h; \
+ Reader reader; \
+ EXPECT_FALSE(reader.Parse(s, h)); \
+ EXPECT_EQ(errorCode, reader.GetParseErrorCode());\
+ EXPECT_EQ(errorOffset, reader.GetErrorOffset());\
+ EXPECT_EQ(streamPos, s.Tell());\
+ }
+
+TEST(Reader, ParseDocument_Error) {
+ // The document is empty.
+ TEST_ERROR(kParseErrorDocumentEmpty, "", 0);
+ TEST_ERROR(kParseErrorDocumentEmpty, " ", 1);
+ TEST_ERROR(kParseErrorDocumentEmpty, " \n", 2);
+
+ // The document root must not follow by other values.
+ TEST_ERROR(kParseErrorDocumentRootNotSingular, "[] 0", 3);
+ TEST_ERROR(kParseErrorDocumentRootNotSingular, "{} 0", 3);
+ TEST_ERROR(kParseErrorDocumentRootNotSingular, "null []", 5);
+ TEST_ERROR(kParseErrorDocumentRootNotSingular, "0 {}", 2);
+}
+
+TEST(Reader, ParseValue_Error) {
+ // Invalid value.
+ TEST_ERROR(kParseErrorValueInvalid, "nulL", 3);
+ TEST_ERROR(kParseErrorValueInvalid, "truE", 3);
+ TEST_ERROR(kParseErrorValueInvalid, "falsE", 4);
+ TEST_ERROR(kParseErrorValueInvalid, "a]", 0);
+ TEST_ERROR(kParseErrorValueInvalid, ".1", 0);
+}
+
+TEST(Reader, ParseObject_Error) {
+ // Missing a name for object member.
+ TEST_ERROR(kParseErrorObjectMissName, "{1}", 1);
+ TEST_ERROR(kParseErrorObjectMissName, "{:1}", 1);
+ TEST_ERROR(kParseErrorObjectMissName, "{null:1}", 1);
+ TEST_ERROR(kParseErrorObjectMissName, "{true:1}", 1);
+ TEST_ERROR(kParseErrorObjectMissName, "{false:1}", 1);
+ TEST_ERROR(kParseErrorObjectMissName, "{1:1}", 1);
+ TEST_ERROR(kParseErrorObjectMissName, "{[]:1}", 1);
+ TEST_ERROR(kParseErrorObjectMissName, "{{}:1}", 1);
+ TEST_ERROR(kParseErrorObjectMissName, "{xyz:1}", 1);
+
+ // Missing a colon after a name of object member.
+ TEST_ERROR(kParseErrorObjectMissColon, "{\"a\" 1}", 5);
+ TEST_ERROR(kParseErrorObjectMissColon, "{\"a\",1}", 4);
+
+ // Must be a comma or '}' after an object member
+ TEST_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, "{\"a\":1]", 6);
+
+ // This tests that MemoryStream is checking the length in Peek().
+ {
+ MemoryStream ms("{\"a\"", 1);
+ BaseReaderHandler<> h;
+ Reader reader;
+ EXPECT_FALSE(reader.Parse<kParseStopWhenDoneFlag>(ms, h));
+ EXPECT_EQ(kParseErrorObjectMissName, reader.GetParseErrorCode());
+ }
+}
+
+#undef TEST_ERROR
+
+TEST(Reader, SkipWhitespace) {
+ StringStream ss(" A \t\tB\n \n\nC\r\r \rD \t\n\r E");
+ const char* expected = "ABCDE";
+ for (size_t i = 0; i < 5; i++) {
+ SkipWhitespace(ss);
+ EXPECT_EQ(expected[i], ss.Take());
+ }
+}
+
+// Test implementing a stream without copy stream optimization.
+// Clone from GenericStringStream except that copy constructor is disabled.
+template <typename Encoding>
+class CustomStringStream {
+public:
+ typedef typename Encoding::Ch Ch;
+
+ CustomStringStream(const Ch *src) : src_(src), head_(src) {}
+
+ Ch Peek() const { return *src_; }
+ Ch Take() { return *src_++; }
+ size_t Tell() const { return static_cast<size_t>(src_ - head_); }
+
+ Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+ void Put(Ch) { RAPIDJSON_ASSERT(false); }
+ void Flush() { RAPIDJSON_ASSERT(false); }
+ size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+ // Prohibit copy constructor & assignment operator.
+ CustomStringStream(const CustomStringStream&);
+ CustomStringStream& operator=(const CustomStringStream&);
+
+ const Ch* src_; //!< Current read position.
+ const Ch* head_; //!< Original head of the string.
+};
+
+// If the following code is compiled, it should generate compilation error as predicted.
+// Because CustomStringStream<> is not copyable via making copy constructor private.
+#if 0
+namespace rapidjson {
+
+template <typename Encoding>
+struct StreamTraits<CustomStringStream<Encoding> > {
+ enum { copyOptimization = 1 };
+};
+
+} // namespace rapidjson
+#endif
+
+TEST(Reader, CustomStringStream) {
+ const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } ";
+ CustomStringStream<UTF8<char> > s(json);
+ ParseObjectHandler h;
+ Reader reader;
+ reader.Parse(s, h);
+ EXPECT_EQ(20u, h.step_);
+}
+
+#include <sstream>
+
+class IStreamWrapper {
+public:
+ typedef char Ch;
+
+ IStreamWrapper(std::istream& is) : is_(is) {}
+
+ Ch Peek() const {
+ int c = is_.peek();
+ return c == std::char_traits<char>::eof() ? '\0' : static_cast<Ch>(c);
+ }
+
+ Ch Take() {
+ int c = is_.get();
+ return c == std::char_traits<char>::eof() ? '\0' : static_cast<Ch>(c);
+ }
+
+ size_t Tell() const { return static_cast<size_t>(is_.tellg()); }
+
+ Ch* PutBegin() { assert(false); return 0; }
+ void Put(Ch) { assert(false); }
+ void Flush() { assert(false); }
+ size_t PutEnd(Ch*) { assert(false); return 0; }
+
+private:
+ IStreamWrapper(const IStreamWrapper&);
+ IStreamWrapper& operator=(const IStreamWrapper&);
+
+ std::istream& is_;
+};
+
+TEST(Reader, Parse_IStreamWrapper_StringStream) {
+ const char* json = "[1,2,3,4]";
+
+ std::stringstream ss(json);
+ IStreamWrapper is(ss);
+
+ Reader reader;
+ ParseArrayHandler<4> h;
+ reader.Parse(is, h);
+ EXPECT_FALSE(reader.HasParseError());
+}
+
+// Test iterative parsing.
+
+#define TESTERRORHANDLING(text, errorCode, offset)\
+{\
+ int streamPos = offset; \
+ StringStream json(text); \
+ BaseReaderHandler<> handler; \
+ Reader reader; \
+ reader.Parse<kParseIterativeFlag>(json, handler); \
+ EXPECT_TRUE(reader.HasParseError()); \
+ EXPECT_EQ(errorCode, reader.GetParseErrorCode()); \
+ EXPECT_EQ(offset, reader.GetErrorOffset()); \
+ EXPECT_EQ(streamPos, json.Tell()); \
+}
+
+TEST(Reader, IterativeParsing_ErrorHandling) {
+ TESTERRORHANDLING("{\"a\": a}", kParseErrorValueInvalid, 6u);
+
+ TESTERRORHANDLING("", kParseErrorDocumentEmpty, 0u);
+ TESTERRORHANDLING("{}{}", kParseErrorDocumentRootNotSingular, 2u);
+
+ TESTERRORHANDLING("{1}", kParseErrorObjectMissName, 1u);
+ TESTERRORHANDLING("{\"a\", 1}", kParseErrorObjectMissColon, 4u);
+ TESTERRORHANDLING("{\"a\"}", kParseErrorObjectMissColon, 4u);
+ TESTERRORHANDLING("{\"a\": 1", kParseErrorObjectMissCommaOrCurlyBracket, 7u);
+ TESTERRORHANDLING("[1 2 3]", kParseErrorArrayMissCommaOrSquareBracket, 3u);
+ TESTERRORHANDLING("{\"a: 1", kParseErrorStringMissQuotationMark, 6u);
+
+ // Any JSON value can be a valid root element in RFC7159.
+ TESTERRORHANDLING("\"ab", kParseErrorStringMissQuotationMark, 3u);
+ TESTERRORHANDLING("truE", kParseErrorValueInvalid, 3u);
+ TESTERRORHANDLING("False", kParseErrorValueInvalid, 0u);
+ TESTERRORHANDLING("true, false", kParseErrorDocumentRootNotSingular, 4u);
+ TESTERRORHANDLING("false, false", kParseErrorDocumentRootNotSingular, 5u);
+ TESTERRORHANDLING("nulL", kParseErrorValueInvalid, 3u);
+ TESTERRORHANDLING("null , null", kParseErrorDocumentRootNotSingular, 5u);
+ TESTERRORHANDLING("1a", kParseErrorDocumentRootNotSingular, 1u);
+}
+
+template<typename Encoding = UTF8<> >
+struct IterativeParsingReaderHandler {
+ typedef typename Encoding::Ch Ch;
+
+ const static int LOG_NULL = -1;
+ const static int LOG_BOOL = -2;
+ const static int LOG_INT = -3;
+ const static int LOG_UINT = -4;
+ const static int LOG_INT64 = -5;
+ const static int LOG_UINT64 = -6;
+ const static int LOG_DOUBLE = -7;
+ const static int LOG_STRING = -8;
+ const static int LOG_STARTOBJECT = -9;
+ const static int LOG_KEY = -10;
+ const static int LOG_ENDOBJECT = -11;
+ const static int LOG_STARTARRAY = -12;
+ const static int LOG_ENDARRAY = -13;
+
+ const static size_t LogCapacity = 256;
+ int Logs[LogCapacity];
+ size_t LogCount;
+
+ IterativeParsingReaderHandler() : LogCount(0) {
+ }
+
+ bool Null() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_NULL; return true; }
+
+ bool Bool(bool) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_BOOL; return true; }
+
+ bool Int(int) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_INT; return true; }
+
+ bool Uint(unsigned) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_INT; return true; }
+
+ bool Int64(int64_t) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_INT64; return true; }
+
+ bool Uint64(uint64_t) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_UINT64; return true; }
+
+ bool Double(double) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_DOUBLE; return true; }
+
+ bool String(const Ch*, SizeType, bool) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STRING; return true; }
+
+ bool StartObject() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STARTOBJECT; return true; }
+
+ bool Key (const Ch*, SizeType, bool) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_KEY; return true; }
+
+ bool EndObject(SizeType c) {
+ RAPIDJSON_ASSERT(LogCount < LogCapacity);
+ Logs[LogCount++] = LOG_ENDOBJECT;
+ Logs[LogCount++] = static_cast<int>(c);
+ return true;
+ }
+
+ bool StartArray() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STARTARRAY; return true; }
+
+ bool EndArray(SizeType c) {
+ RAPIDJSON_ASSERT(LogCount < LogCapacity);
+ Logs[LogCount++] = LOG_ENDARRAY;
+ Logs[LogCount++] = static_cast<int>(c);
+ return true;
+ }
+};
+
+TEST(Reader, IterativeParsing_General) {
+ {
+ StringStream is("[1, {\"k\": [1, 2]}, null, false, true, \"string\", 1.2]");
+ Reader reader;
+ IterativeParsingReaderHandler<> handler;
+
+ ParseResult r = reader.Parse<kParseIterativeFlag>(is, handler);
+
+ EXPECT_FALSE(r.IsError());
+ EXPECT_FALSE(reader.HasParseError());
+
+ int e[] = {
+ handler.LOG_STARTARRAY,
+ handler.LOG_INT,
+ handler.LOG_STARTOBJECT,
+ handler.LOG_KEY,
+ handler.LOG_STARTARRAY,
+ handler.LOG_INT,
+ handler.LOG_INT,
+ handler.LOG_ENDARRAY, 2,
+ handler.LOG_ENDOBJECT, 1,
+ handler.LOG_NULL,
+ handler.LOG_BOOL,
+ handler.LOG_BOOL,
+ handler.LOG_STRING,
+ handler.LOG_DOUBLE,
+ handler.LOG_ENDARRAY, 7
+ };
+
+ EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount);
+
+ for (size_t i = 0; i < handler.LogCount; ++i) {
+ EXPECT_EQ(e[i], handler.Logs[i]) << "i = " << i;
+ }
+ }
+}
+
+TEST(Reader, IterativeParsing_Count) {
+ {
+ StringStream is("[{}, {\"k\": 1}, [1], []]");
+ Reader reader;
+ IterativeParsingReaderHandler<> handler;
+
+ ParseResult r = reader.Parse<kParseIterativeFlag>(is, handler);
+
+ EXPECT_FALSE(r.IsError());
+ EXPECT_FALSE(reader.HasParseError());
+
+ int e[] = {
+ handler.LOG_STARTARRAY,
+ handler.LOG_STARTOBJECT,
+ handler.LOG_ENDOBJECT, 0,
+ handler.LOG_STARTOBJECT,
+ handler.LOG_KEY,
+ handler.LOG_INT,
+ handler.LOG_ENDOBJECT, 1,
+ handler.LOG_STARTARRAY,
+ handler.LOG_INT,
+ handler.LOG_ENDARRAY, 1,
+ handler.LOG_STARTARRAY,
+ handler.LOG_ENDARRAY, 0,
+ handler.LOG_ENDARRAY, 4
+ };
+
+ EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount);
+
+ for (size_t i = 0; i < handler.LogCount; ++i) {
+ EXPECT_EQ(e[i], handler.Logs[i]) << "i = " << i;
+ }
+ }
+}
+
+// Test iterative parsing on kParseErrorTermination.
+struct HandlerTerminateAtStartObject : public IterativeParsingReaderHandler<> {
+ bool StartObject() { return false; }
+};
+
+struct HandlerTerminateAtStartArray : public IterativeParsingReaderHandler<> {
+ bool StartArray() { return false; }
+};
+
+struct HandlerTerminateAtEndObject : public IterativeParsingReaderHandler<> {
+ bool EndObject(SizeType) { return false; }
+};
+
+struct HandlerTerminateAtEndArray : public IterativeParsingReaderHandler<> {
+ bool EndArray(SizeType) { return false; }
+};
+
+TEST(Reader, IterativeParsing_ShortCircuit) {
+ {
+ HandlerTerminateAtStartObject handler;
+ Reader reader;
+ StringStream is("[1, {}]");
+
+ ParseResult r = reader.Parse<kParseIterativeFlag>(is, handler);
+
+ EXPECT_TRUE(reader.HasParseError());
+ EXPECT_EQ(kParseErrorTermination, r.Code());
+ EXPECT_EQ(4u, r.Offset());
+ }
+
+ {
+ HandlerTerminateAtStartArray handler;
+ Reader reader;
+ StringStream is("{\"a\": []}");
+
+ ParseResult r = reader.Parse<kParseIterativeFlag>(is, handler);
+
+ EXPECT_TRUE(reader.HasParseError());
+ EXPECT_EQ(kParseErrorTermination, r.Code());
+ EXPECT_EQ(6u, r.Offset());
+ }
+
+ {
+ HandlerTerminateAtEndObject handler;
+ Reader reader;
+ StringStream is("[1, {}]");
+
+ ParseResult r = reader.Parse<kParseIterativeFlag>(is, handler);
+
+ EXPECT_TRUE(reader.HasParseError());
+ EXPECT_EQ(kParseErrorTermination, r.Code());
+ EXPECT_EQ(5u, r.Offset());
+ }
+
+ {
+ HandlerTerminateAtEndArray handler;
+ Reader reader;
+ StringStream is("{\"a\": []}");
+
+ ParseResult r = reader.Parse<kParseIterativeFlag>(is, handler);
+
+ EXPECT_TRUE(reader.HasParseError());
+ EXPECT_EQ(kParseErrorTermination, r.Code());
+ EXPECT_EQ(7u, r.Offset());
+ }
+}
+
+// For covering BaseReaderHandler default functions
+TEST(Reader, BaseReaderHandler_Default) {
+ BaseReaderHandler<> h;
+ Reader reader;
+ StringStream is("[null, true, -1, 1, -1234567890123456789, 1234567890123456789, 3.14, \"s\", { \"a\" : 1 }]");
+ EXPECT_TRUE(reader.Parse(is, h));
+}
+
+template <int e>
+struct TerminateHandler {
+ bool Null() { return e != 0; }
+ bool Bool(bool) { return e != 1; }
+ bool Int(int) { return e != 2; }
+ bool Uint(unsigned) { return e != 3; }
+ bool Int64(int64_t) { return e != 4; }
+ bool Uint64(uint64_t) { return e != 5; }
+ bool Double(double) { return e != 6; }
+ bool String(const char*, SizeType, bool) { return e != 7; }
+ bool StartObject() { return e != 8; }
+ bool Key(const char*, SizeType, bool) { return e != 9; }
+ bool EndObject(SizeType) { return e != 10; }
+ bool StartArray() { return e != 11; }
+ bool EndArray(SizeType) { return e != 12; }
+};
+
+#define TEST_TERMINATION(e, json)\
+{\
+ Reader reader;\
+ TerminateHandler<e> h;\
+ StringStream is(json);\
+ EXPECT_FALSE(reader.Parse(is, h));\
+ EXPECT_EQ(kParseErrorTermination, reader.GetParseErrorCode());\
+}
+
+TEST(Reader, ParseTerminationByHandler) {
+ TEST_TERMINATION(0, "[null");
+ TEST_TERMINATION(1, "[true");
+ TEST_TERMINATION(1, "[false");
+ TEST_TERMINATION(2, "[-1");
+ TEST_TERMINATION(3, "[1");
+ TEST_TERMINATION(4, "[-1234567890123456789");
+ TEST_TERMINATION(5, "[1234567890123456789");
+ TEST_TERMINATION(6, "[0.5]");
+ TEST_TERMINATION(7, "[\"a\"");
+ TEST_TERMINATION(8, "[{");
+ TEST_TERMINATION(9, "[{\"a\"");
+ TEST_TERMINATION(10, "[{}");
+ TEST_TERMINATION(10, "[{\"a\":1}"); // non-empty object
+ TEST_TERMINATION(11, "{\"a\":[");
+ TEST_TERMINATION(12, "{\"a\":[]");
+ TEST_TERMINATION(12, "{\"a\":[1]"); // non-empty array
+}
+
+TEST(Reader, ParseComments) {
+ const char* json =
+ "// Here is a one-line comment.\n"
+ "{// And here's another one\n"
+ " /*And here's an in-line one.*/\"hello\" : \"world\","
+ " \"t\" :/* And one with '*' symbol*/true ,"
+ "/* A multiline comment\n"
+ " goes here*/"
+ " \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3]"
+ "}/*And the last one to be sure */";
+
+ StringStream s(json);
+ ParseObjectHandler h;
+ Reader reader;
+ EXPECT_TRUE(reader.Parse<kParseCommentsFlag>(s, h));
+ EXPECT_EQ(20u, h.step_);
+}
+
+TEST(Reader, ParseEmptyInlineComment) {
+ const char* json = "{/**/\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
+
+ StringStream s(json);
+ ParseObjectHandler h;
+ Reader reader;
+ EXPECT_TRUE(reader.Parse<kParseCommentsFlag>(s, h));
+ EXPECT_EQ(20u, h.step_);
+}
+
+TEST(Reader, ParseEmptyOnelineComment) {
+ const char* json = "{//\n\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
+
+ StringStream s(json);
+ ParseObjectHandler h;
+ Reader reader;
+ EXPECT_TRUE(reader.Parse<kParseCommentsFlag>(s, h));
+ EXPECT_EQ(20u, h.step_);
+}
+
+TEST(Reader, ParseMultipleCommentsInARow) {
+ const char* json =
+ "{/* first comment *//* second */\n"
+ "/* third */ /*fourth*/// last one\n"
+ "\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
+
+ StringStream s(json);
+ ParseObjectHandler h;
+ Reader reader;
+ EXPECT_TRUE(reader.Parse<kParseCommentsFlag>(s, h));
+ EXPECT_EQ(20u, h.step_);
+}
+
+TEST(Reader, InlineCommentsAreDisabledByDefault) {
+ {
+ const char* json = "{/* Inline comment. */\"hello\" : \"world\", \"t\" : true, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
+
+ StringStream s(json);
+ ParseObjectHandler h;
+ Reader reader;
+ EXPECT_FALSE(reader.Parse<kParseDefaultFlags>(s, h));
+ }
+
+ {
+ const char* json =
+ "{\"hello\" : /* Multiline comment starts here\n"
+ " continues here\n"
+ " and ends here */\"world\", \"t\" :true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
+
+ StringStream s(json);
+ ParseObjectHandler h;
+ Reader reader;
+ EXPECT_FALSE(reader.Parse<kParseDefaultFlags>(s, h));
+ }
+}
+
+TEST(Reader, OnelineCommentsAreDisabledByDefault) {
+ const char* json = "{// One-line comment\n\"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] }";
+
+ StringStream s(json);
+ ParseObjectHandler h;
+ Reader reader;
+ EXPECT_FALSE(reader.Parse<kParseDefaultFlags>(s, h));
+}
+
+TEST(Reader, EofAfterOneLineComment) {
+ const char* json = "{\"hello\" : \"world\" // EOF is here -->\0 \n}";
+
+ StringStream s(json);
+ ParseObjectHandler h;
+ Reader reader;
+ EXPECT_FALSE(reader.Parse<kParseCommentsFlag>(s, h));
+ EXPECT_EQ(kParseErrorObjectMissCommaOrCurlyBracket, reader.GetParseErrorCode());
+}
+
+TEST(Reader, IncompleteMultilineComment) {
+ const char* json = "{\"hello\" : \"world\" /* EOF is here -->\0 */}";
+
+ StringStream s(json);
+ ParseObjectHandler h;
+ Reader reader;
+ EXPECT_FALSE(reader.Parse<kParseCommentsFlag>(s, h));
+ EXPECT_EQ(kParseErrorUnspecificSyntaxError, reader.GetParseErrorCode());
+}
+
+TEST(Reader, IncompleteMultilineComment2) {
+ const char* json = "{\"hello\" : \"world\" /* *\0 */}";
+
+ StringStream s(json);
+ ParseObjectHandler h;
+ Reader reader;
+ EXPECT_FALSE(reader.Parse<kParseCommentsFlag>(s, h));
+ EXPECT_EQ(kParseErrorUnspecificSyntaxError, reader.GetParseErrorCode());
+}
+
+TEST(Reader, UnrecognizedComment) {
+ const char* json = "{\"hello\" : \"world\" /! }";
+
+ StringStream s(json);
+ ParseObjectHandler h;
+ Reader reader;
+ EXPECT_FALSE(reader.Parse<kParseCommentsFlag>(s, h));
+ EXPECT_EQ(kParseErrorUnspecificSyntaxError, reader.GetParseErrorCode());
+}
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
diff --git a/3rdparty/rapidjson/test/unittest/regextest.cpp b/3rdparty/rapidjson/test/unittest/regextest.cpp
new file mode 100644
index 00000000000..e3371d168ca
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/regextest.cpp
@@ -0,0 +1,576 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+#include "rapidjson/internal/regex.h"
+
+using namespace rapidjson::internal;
+
+TEST(Regex, Concatenation) {
+ Regex re("abc");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("abc"));
+ EXPECT_FALSE(re.Match(""));
+ EXPECT_FALSE(re.Match("a"));
+ EXPECT_FALSE(re.Match("b"));
+ EXPECT_FALSE(re.Match("ab"));
+ EXPECT_FALSE(re.Match("abcd"));
+}
+
+TEST(Regex, Alternation1) {
+ Regex re("abab|abbb");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("abab"));
+ EXPECT_TRUE(re.Match("abbb"));
+ EXPECT_FALSE(re.Match(""));
+ EXPECT_FALSE(re.Match("ab"));
+ EXPECT_FALSE(re.Match("ababa"));
+ EXPECT_FALSE(re.Match("abb"));
+ EXPECT_FALSE(re.Match("abbbb"));
+}
+
+TEST(Regex, Alternation2) {
+ Regex re("a|b|c");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("a"));
+ EXPECT_TRUE(re.Match("b"));
+ EXPECT_TRUE(re.Match("c"));
+ EXPECT_FALSE(re.Match(""));
+ EXPECT_FALSE(re.Match("aa"));
+ EXPECT_FALSE(re.Match("ab"));
+}
+
+TEST(Regex, Parenthesis1) {
+ Regex re("(ab)c");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("abc"));
+ EXPECT_FALSE(re.Match(""));
+ EXPECT_FALSE(re.Match("a"));
+ EXPECT_FALSE(re.Match("b"));
+ EXPECT_FALSE(re.Match("ab"));
+ EXPECT_FALSE(re.Match("abcd"));
+}
+
+TEST(Regex, Parenthesis2) {
+ Regex re("a(bc)");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("abc"));
+ EXPECT_FALSE(re.Match(""));
+ EXPECT_FALSE(re.Match("a"));
+ EXPECT_FALSE(re.Match("b"));
+ EXPECT_FALSE(re.Match("ab"));
+ EXPECT_FALSE(re.Match("abcd"));
+}
+
+TEST(Regex, Parenthesis3) {
+ Regex re("(a|b)(c|d)");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("ac"));
+ EXPECT_TRUE(re.Match("ad"));
+ EXPECT_TRUE(re.Match("bc"));
+ EXPECT_TRUE(re.Match("bd"));
+ EXPECT_FALSE(re.Match(""));
+ EXPECT_FALSE(re.Match("ab"));
+ EXPECT_FALSE(re.Match("cd"));
+}
+
+TEST(Regex, ZeroOrOne1) {
+ Regex re("a?");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match(""));
+ EXPECT_TRUE(re.Match("a"));
+ EXPECT_FALSE(re.Match("aa"));
+}
+
+TEST(Regex, ZeroOrOne2) {
+ Regex re("a?b");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("b"));
+ EXPECT_TRUE(re.Match("ab"));
+ EXPECT_FALSE(re.Match("a"));
+ EXPECT_FALSE(re.Match("aa"));
+ EXPECT_FALSE(re.Match("bb"));
+ EXPECT_FALSE(re.Match("ba"));
+}
+
+TEST(Regex, ZeroOrOne3) {
+ Regex re("ab?");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("a"));
+ EXPECT_TRUE(re.Match("ab"));
+ EXPECT_FALSE(re.Match("b"));
+ EXPECT_FALSE(re.Match("aa"));
+ EXPECT_FALSE(re.Match("bb"));
+ EXPECT_FALSE(re.Match("ba"));
+}
+
+TEST(Regex, ZeroOrOne4) {
+ Regex re("a?b?");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match(""));
+ EXPECT_TRUE(re.Match("a"));
+ EXPECT_TRUE(re.Match("b"));
+ EXPECT_TRUE(re.Match("ab"));
+ EXPECT_FALSE(re.Match("aa"));
+ EXPECT_FALSE(re.Match("bb"));
+ EXPECT_FALSE(re.Match("ba"));
+ EXPECT_FALSE(re.Match("abc"));
+}
+
+TEST(Regex, ZeroOrOne5) {
+ Regex re("a(ab)?b");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("ab"));
+ EXPECT_TRUE(re.Match("aabb"));
+ EXPECT_FALSE(re.Match("aab"));
+ EXPECT_FALSE(re.Match("abb"));
+}
+
+TEST(Regex, ZeroOrMore1) {
+ Regex re("a*");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match(""));
+ EXPECT_TRUE(re.Match("a"));
+ EXPECT_TRUE(re.Match("aa"));
+ EXPECT_FALSE(re.Match("b"));
+ EXPECT_FALSE(re.Match("ab"));
+}
+
+TEST(Regex, ZeroOrMore2) {
+ Regex re("a*b");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("b"));
+ EXPECT_TRUE(re.Match("ab"));
+ EXPECT_TRUE(re.Match("aab"));
+ EXPECT_FALSE(re.Match(""));
+ EXPECT_FALSE(re.Match("bb"));
+}
+
+TEST(Regex, ZeroOrMore3) {
+ Regex re("a*b*");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match(""));
+ EXPECT_TRUE(re.Match("a"));
+ EXPECT_TRUE(re.Match("aa"));
+ EXPECT_TRUE(re.Match("b"));
+ EXPECT_TRUE(re.Match("bb"));
+ EXPECT_TRUE(re.Match("ab"));
+ EXPECT_TRUE(re.Match("aabb"));
+ EXPECT_FALSE(re.Match("ba"));
+}
+
+TEST(Regex, ZeroOrMore4) {
+ Regex re("a(ab)*b");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("ab"));
+ EXPECT_TRUE(re.Match("aabb"));
+ EXPECT_TRUE(re.Match("aababb"));
+ EXPECT_FALSE(re.Match(""));
+ EXPECT_FALSE(re.Match("aa"));
+}
+
+TEST(Regex, OneOrMore1) {
+ Regex re("a+");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("a"));
+ EXPECT_TRUE(re.Match("aa"));
+ EXPECT_FALSE(re.Match(""));
+ EXPECT_FALSE(re.Match("b"));
+ EXPECT_FALSE(re.Match("ab"));
+}
+
+TEST(Regex, OneOrMore2) {
+ Regex re("a+b");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("ab"));
+ EXPECT_TRUE(re.Match("aab"));
+ EXPECT_FALSE(re.Match(""));
+ EXPECT_FALSE(re.Match("b"));
+}
+
+TEST(Regex, OneOrMore3) {
+ Regex re("a+b+");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("ab"));
+ EXPECT_TRUE(re.Match("aab"));
+ EXPECT_TRUE(re.Match("abb"));
+ EXPECT_TRUE(re.Match("aabb"));
+ EXPECT_FALSE(re.Match(""));
+ EXPECT_FALSE(re.Match("b"));
+ EXPECT_FALSE(re.Match("ba"));
+}
+
+TEST(Regex, OneOrMore4) {
+ Regex re("a(ab)+b");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("aabb"));
+ EXPECT_TRUE(re.Match("aababb"));
+ EXPECT_FALSE(re.Match(""));
+ EXPECT_FALSE(re.Match("ab"));
+}
+
+TEST(Regex, QuantifierExact1) {
+ Regex re("ab{3}c");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("abbbc"));
+ EXPECT_FALSE(re.Match("ac"));
+ EXPECT_FALSE(re.Match("abc"));
+ EXPECT_FALSE(re.Match("abbc"));
+ EXPECT_FALSE(re.Match("abbbbc"));
+}
+
+TEST(Regex, QuantifierExact2) {
+ Regex re("a(bc){3}d");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("abcbcbcd"));
+ EXPECT_FALSE(re.Match("ad"));
+ EXPECT_FALSE(re.Match("abcd"));
+ EXPECT_FALSE(re.Match("abcbcd"));
+ EXPECT_FALSE(re.Match("abcbcbcbcd"));
+}
+
+TEST(Regex, QuantifierExact3) {
+ Regex re("a(b|c){3}d");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("abbbd"));
+ EXPECT_TRUE(re.Match("acccd"));
+ EXPECT_TRUE(re.Match("abcbd"));
+ EXPECT_FALSE(re.Match("ad"));
+ EXPECT_FALSE(re.Match("abbd"));
+ EXPECT_FALSE(re.Match("accccd"));
+ EXPECT_FALSE(re.Match("abbbbd"));
+}
+
+TEST(Regex, QuantifierMin1) {
+ Regex re("ab{3,}c");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("abbbc"));
+ EXPECT_TRUE(re.Match("abbbbc"));
+ EXPECT_TRUE(re.Match("abbbbbc"));
+ EXPECT_FALSE(re.Match("ac"));
+ EXPECT_FALSE(re.Match("abc"));
+ EXPECT_FALSE(re.Match("abbc"));
+}
+
+TEST(Regex, QuantifierMin2) {
+ Regex re("a(bc){3,}d");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("abcbcbcd"));
+ EXPECT_TRUE(re.Match("abcbcbcbcd"));
+ EXPECT_FALSE(re.Match("ad"));
+ EXPECT_FALSE(re.Match("abcd"));
+ EXPECT_FALSE(re.Match("abcbcd"));
+}
+
+TEST(Regex, QuantifierMin3) {
+ Regex re("a(b|c){3,}d");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("abbbd"));
+ EXPECT_TRUE(re.Match("acccd"));
+ EXPECT_TRUE(re.Match("abcbd"));
+ EXPECT_TRUE(re.Match("accccd"));
+ EXPECT_TRUE(re.Match("abbbbd"));
+ EXPECT_FALSE(re.Match("ad"));
+ EXPECT_FALSE(re.Match("abbd"));
+}
+
+TEST(Regex, QuantifierMinMax1) {
+ Regex re("ab{3,5}c");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("abbbc"));
+ EXPECT_TRUE(re.Match("abbbbc"));
+ EXPECT_TRUE(re.Match("abbbbbc"));
+ EXPECT_FALSE(re.Match("ac"));
+ EXPECT_FALSE(re.Match("abc"));
+ EXPECT_FALSE(re.Match("abbc"));
+ EXPECT_FALSE(re.Match("abbbbbbc"));
+}
+
+TEST(Regex, QuantifierMinMax2) {
+ Regex re("a(bc){3,5}d");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("abcbcbcd"));
+ EXPECT_TRUE(re.Match("abcbcbcbcd"));
+ EXPECT_TRUE(re.Match("abcbcbcbcbcd"));
+ EXPECT_FALSE(re.Match("ad"));
+ EXPECT_FALSE(re.Match("abcd"));
+ EXPECT_FALSE(re.Match("abcbcd"));
+ EXPECT_FALSE(re.Match("abcbcbcbcbcbcd"));
+}
+
+TEST(Regex, QuantifierMinMax3) {
+ Regex re("a(b|c){3,5}d");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("abbbd"));
+ EXPECT_TRUE(re.Match("acccd"));
+ EXPECT_TRUE(re.Match("abcbd"));
+ EXPECT_TRUE(re.Match("accccd"));
+ EXPECT_TRUE(re.Match("abbbbd"));
+ EXPECT_TRUE(re.Match("acccccd"));
+ EXPECT_TRUE(re.Match("abbbbbd"));
+ EXPECT_FALSE(re.Match("ad"));
+ EXPECT_FALSE(re.Match("abbd"));
+ EXPECT_FALSE(re.Match("accccccd"));
+ EXPECT_FALSE(re.Match("abbbbbbd"));
+}
+
+// Issue538
+TEST(Regex, QuantifierMinMax4) {
+ Regex re("a(b|c){0,3}d");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("ad"));
+ EXPECT_TRUE(re.Match("abd"));
+ EXPECT_TRUE(re.Match("acd"));
+ EXPECT_TRUE(re.Match("abbd"));
+ EXPECT_TRUE(re.Match("accd"));
+ EXPECT_TRUE(re.Match("abcd"));
+ EXPECT_TRUE(re.Match("abbbd"));
+ EXPECT_TRUE(re.Match("acccd"));
+ EXPECT_FALSE(re.Match("abbbbd"));
+ EXPECT_FALSE(re.Match("add"));
+ EXPECT_FALSE(re.Match("accccd"));
+ EXPECT_FALSE(re.Match("abcbcd"));
+}
+
+// Issue538
+TEST(Regex, QuantifierMinMax5) {
+ Regex re("a(b|c){0,}d");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("ad"));
+ EXPECT_TRUE(re.Match("abd"));
+ EXPECT_TRUE(re.Match("acd"));
+ EXPECT_TRUE(re.Match("abbd"));
+ EXPECT_TRUE(re.Match("accd"));
+ EXPECT_TRUE(re.Match("abcd"));
+ EXPECT_TRUE(re.Match("abbbd"));
+ EXPECT_TRUE(re.Match("acccd"));
+ EXPECT_TRUE(re.Match("abbbbd"));
+ EXPECT_TRUE(re.Match("accccd"));
+ EXPECT_TRUE(re.Match("abcbcd"));
+ EXPECT_FALSE(re.Match("add"));
+ EXPECT_FALSE(re.Match("aad"));
+}
+
+#define EURO "\xE2\x82\xAC" // "\xE2\x82\xAC" is UTF-8 sequence of Euro sign U+20AC
+
+TEST(Regex, Unicode) {
+ Regex re("a" EURO "+b");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("a" EURO "b"));
+ EXPECT_TRUE(re.Match("a" EURO EURO "b"));
+ EXPECT_FALSE(re.Match("a?b"));
+ EXPECT_FALSE(re.Match("a" EURO "\xAC" "b")); // unaware of UTF-8 will match
+}
+
+TEST(Regex, AnyCharacter) {
+ Regex re(".");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("a"));
+ EXPECT_TRUE(re.Match("b"));
+ EXPECT_TRUE(re.Match(EURO));
+ EXPECT_FALSE(re.Match(""));
+ EXPECT_FALSE(re.Match("aa"));
+}
+
+TEST(Regex, CharacterRange1) {
+ Regex re("[abc]");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("a"));
+ EXPECT_TRUE(re.Match("b"));
+ EXPECT_TRUE(re.Match("c"));
+ EXPECT_FALSE(re.Match(""));
+ EXPECT_FALSE(re.Match("`"));
+ EXPECT_FALSE(re.Match("d"));
+ EXPECT_FALSE(re.Match("aa"));
+}
+
+TEST(Regex, CharacterRange2) {
+ Regex re("[^abc]");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("`"));
+ EXPECT_TRUE(re.Match("d"));
+ EXPECT_FALSE(re.Match("a"));
+ EXPECT_FALSE(re.Match("b"));
+ EXPECT_FALSE(re.Match("c"));
+ EXPECT_FALSE(re.Match(""));
+ EXPECT_FALSE(re.Match("aa"));
+}
+
+TEST(Regex, CharacterRange3) {
+ Regex re("[a-c]");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("a"));
+ EXPECT_TRUE(re.Match("b"));
+ EXPECT_TRUE(re.Match("c"));
+ EXPECT_FALSE(re.Match(""));
+ EXPECT_FALSE(re.Match("`"));
+ EXPECT_FALSE(re.Match("d"));
+ EXPECT_FALSE(re.Match("aa"));
+}
+
+TEST(Regex, CharacterRange4) {
+ Regex re("[^a-c]");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("`"));
+ EXPECT_TRUE(re.Match("d"));
+ EXPECT_FALSE(re.Match("a"));
+ EXPECT_FALSE(re.Match("b"));
+ EXPECT_FALSE(re.Match("c"));
+ EXPECT_FALSE(re.Match(""));
+ EXPECT_FALSE(re.Match("aa"));
+}
+
+TEST(Regex, CharacterRange5) {
+ Regex re("[-]");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("-"));
+ EXPECT_FALSE(re.Match(""));
+ EXPECT_FALSE(re.Match("a"));
+}
+
+TEST(Regex, CharacterRange6) {
+ Regex re("[a-]");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("a"));
+ EXPECT_TRUE(re.Match("-"));
+ EXPECT_FALSE(re.Match(""));
+ EXPECT_FALSE(re.Match("`"));
+ EXPECT_FALSE(re.Match("b"));
+}
+
+TEST(Regex, CharacterRange7) {
+ Regex re("[-a]");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("a"));
+ EXPECT_TRUE(re.Match("-"));
+ EXPECT_FALSE(re.Match(""));
+ EXPECT_FALSE(re.Match("`"));
+ EXPECT_FALSE(re.Match("b"));
+}
+
+TEST(Regex, CharacterRange8) {
+ Regex re("[a-zA-Z0-9]*");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("Milo"));
+ EXPECT_TRUE(re.Match("MT19937"));
+ EXPECT_TRUE(re.Match("43"));
+ EXPECT_FALSE(re.Match("a_b"));
+ EXPECT_FALSE(re.Match("!"));
+}
+
+TEST(Regex, Search) {
+ Regex re("abc");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Search("abc"));
+ EXPECT_TRUE(re.Search("_abc"));
+ EXPECT_TRUE(re.Search("abc_"));
+ EXPECT_TRUE(re.Search("_abc_"));
+ EXPECT_TRUE(re.Search("__abc__"));
+ EXPECT_TRUE(re.Search("abcabc"));
+ EXPECT_FALSE(re.Search("a"));
+ EXPECT_FALSE(re.Search("ab"));
+ EXPECT_FALSE(re.Search("bc"));
+ EXPECT_FALSE(re.Search("cba"));
+}
+
+TEST(Regex, Search_BeginAnchor) {
+ Regex re("^abc");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Search("abc"));
+ EXPECT_TRUE(re.Search("abc_"));
+ EXPECT_TRUE(re.Search("abcabc"));
+ EXPECT_FALSE(re.Search("_abc"));
+ EXPECT_FALSE(re.Search("_abc_"));
+ EXPECT_FALSE(re.Search("a"));
+ EXPECT_FALSE(re.Search("ab"));
+ EXPECT_FALSE(re.Search("bc"));
+ EXPECT_FALSE(re.Search("cba"));
+}
+
+TEST(Regex, Search_EndAnchor) {
+ Regex re("abc$");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Search("abc"));
+ EXPECT_TRUE(re.Search("_abc"));
+ EXPECT_TRUE(re.Search("abcabc"));
+ EXPECT_FALSE(re.Search("abc_"));
+ EXPECT_FALSE(re.Search("_abc_"));
+ EXPECT_FALSE(re.Search("a"));
+ EXPECT_FALSE(re.Search("ab"));
+ EXPECT_FALSE(re.Search("bc"));
+ EXPECT_FALSE(re.Search("cba"));
+}
+
+TEST(Regex, Search_BothAnchor) {
+ Regex re("^abc$");
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Search("abc"));
+ EXPECT_FALSE(re.Search(""));
+ EXPECT_FALSE(re.Search("a"));
+ EXPECT_FALSE(re.Search("b"));
+ EXPECT_FALSE(re.Search("ab"));
+ EXPECT_FALSE(re.Search("abcd"));
+}
+
+TEST(Regex, Escape) {
+ const char* s = "\\^\\$\\|\\(\\)\\?\\*\\+\\.\\[\\]\\{\\}\\\\\\f\\n\\r\\t\\v[\\b][\\[][\\]]";
+ Regex re(s);
+ ASSERT_TRUE(re.IsValid());
+ EXPECT_TRUE(re.Match("^$|()?*+.[]{}\\\x0C\n\r\t\x0B\b[]"));
+ EXPECT_FALSE(re.Match(s)); // Not escaping
+}
+
+TEST(Regex, Invalid) {
+#define TEST_INVALID(s) \
+ {\
+ Regex re(s);\
+ EXPECT_FALSE(re.IsValid());\
+ }
+
+ TEST_INVALID("");
+ TEST_INVALID("a|");
+ TEST_INVALID("()");
+ TEST_INVALID(")");
+ TEST_INVALID("(a))");
+ TEST_INVALID("(a|)");
+ TEST_INVALID("(a||b)");
+ TEST_INVALID("(|b)");
+ TEST_INVALID("?");
+ TEST_INVALID("*");
+ TEST_INVALID("+");
+ TEST_INVALID("{");
+ TEST_INVALID("{}");
+ TEST_INVALID("a{a}");
+ TEST_INVALID("a{0}");
+ TEST_INVALID("a{-1}");
+ TEST_INVALID("a{}");
+ // TEST_INVALID("a{0,}"); // Support now
+ TEST_INVALID("a{,0}");
+ TEST_INVALID("a{1,0}");
+ TEST_INVALID("a{-1,0}");
+ TEST_INVALID("a{-1,1}");
+ TEST_INVALID("[]");
+ TEST_INVALID("[^]");
+ TEST_INVALID("[\\a]");
+ TEST_INVALID("\\a");
+
+#undef TEST_INVALID
+}
+
+TEST(Regex, Issue538) {
+ Regex re("^[0-9]+(\\\\.[0-9]+){0,2}");
+ EXPECT_TRUE(re.IsValid());
+}
+
+#undef EURO
diff --git a/3rdparty/rapidjson/test/unittest/schematest.cpp b/3rdparty/rapidjson/test/unittest/schematest.cpp
new file mode 100644
index 00000000000..623c65ac61e
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/schematest.cpp
@@ -0,0 +1,1157 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+#include "rapidjson/schema.h"
+#include "rapidjson/stringbuffer.h"
+#include "rapidjson/writer.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(variadic-macros)
+#endif
+
+using namespace rapidjson;
+
+#define TEST_HASHER(json1, json2, expected) \
+{\
+ Document d1, d2;\
+ d1.Parse(json1);\
+ ASSERT_FALSE(d1.HasParseError());\
+ d2.Parse(json2);\
+ ASSERT_FALSE(d2.HasParseError());\
+ internal::Hasher<Value, CrtAllocator> h1, h2;\
+ d1.Accept(h1);\
+ d2.Accept(h2);\
+ ASSERT_TRUE(h1.IsValid());\
+ ASSERT_TRUE(h2.IsValid());\
+ /*printf("%s: 0x%016llx\n%s: 0x%016llx\n\n", json1, h1.GetHashCode(), json2, h2.GetHashCode());*/\
+ EXPECT_TRUE(expected == (h1.GetHashCode() == h2.GetHashCode()));\
+}
+
+TEST(SchemaValidator, Hasher) {
+ TEST_HASHER("null", "null", true);
+
+ TEST_HASHER("true", "true", true);
+ TEST_HASHER("false", "false", true);
+ TEST_HASHER("true", "false", false);
+ TEST_HASHER("false", "true", false);
+ TEST_HASHER("true", "null", false);
+ TEST_HASHER("false", "null", false);
+
+ TEST_HASHER("1", "1", true);
+ TEST_HASHER("1.5", "1.5", true);
+ TEST_HASHER("1", "1.0", true);
+ TEST_HASHER("1", "-1", false);
+ TEST_HASHER("0.0", "-0.0", false);
+ TEST_HASHER("1", "true", false);
+ TEST_HASHER("0", "false", false);
+ TEST_HASHER("0", "null", false);
+
+ TEST_HASHER("\"\"", "\"\"", true);
+ TEST_HASHER("\"\"", "\"\\u0000\"", false);
+ TEST_HASHER("\"Hello\"", "\"Hello\"", true);
+ TEST_HASHER("\"Hello\"", "\"World\"", false);
+ TEST_HASHER("\"Hello\"", "null", false);
+ TEST_HASHER("\"Hello\\u0000\"", "\"Hello\"", false);
+ TEST_HASHER("\"\"", "null", false);
+ TEST_HASHER("\"\"", "true", false);
+ TEST_HASHER("\"\"", "false", false);
+
+ TEST_HASHER("[]", "[ ]", true);
+ TEST_HASHER("[1, true, false]", "[1, true, false]", true);
+ TEST_HASHER("[1, true, false]", "[1, true]", false);
+ TEST_HASHER("[1, 2]", "[2, 1]", false);
+ TEST_HASHER("[[1], 2]", "[[1, 2]]", false);
+ TEST_HASHER("[1, 2]", "[1, [2]]", false);
+ TEST_HASHER("[]", "null", false);
+ TEST_HASHER("[]", "true", false);
+ TEST_HASHER("[]", "false", false);
+ TEST_HASHER("[]", "0", false);
+ TEST_HASHER("[]", "0.0", false);
+ TEST_HASHER("[]", "\"\"", false);
+
+ TEST_HASHER("{}", "{ }", true);
+ TEST_HASHER("{\"a\":1}", "{\"a\":1}", true);
+ TEST_HASHER("{\"a\":1}", "{\"b\":1}", false);
+ TEST_HASHER("{\"a\":1}", "{\"a\":2}", false);
+ TEST_HASHER("{\"a\":1, \"b\":2}", "{\"b\":2, \"a\":1}", true); // Member order insensitive
+ TEST_HASHER("{}", "null", false);
+ TEST_HASHER("{}", "false", false);
+ TEST_HASHER("{}", "true", false);
+ TEST_HASHER("{}", "0", false);
+ TEST_HASHER("{}", "0.0", false);
+ TEST_HASHER("{}", "\"\"", false);
+}
+
+// Test cases following http://spacetelescope.github.io/understanding-json-schema
+
+#define VALIDATE(schema, json, expected) \
+{\
+ SchemaValidator validator(schema);\
+ Document d;\
+ /*printf("\n%s\n", json);*/\
+ d.Parse(json);\
+ EXPECT_FALSE(d.HasParseError());\
+ EXPECT_TRUE(expected == d.Accept(validator));\
+ EXPECT_TRUE(expected == validator.IsValid());\
+ if (expected && !validator.IsValid()) {\
+ StringBuffer sb;\
+ validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);\
+ printf("Invalid schema: %s\n", sb.GetString());\
+ printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());\
+ sb.Clear();\
+ validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);\
+ printf("Invalid document: %s\n", sb.GetString());\
+ }\
+}
+
+#define INVALIDATE(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer) \
+{\
+ SchemaValidator validator(schema);\
+ Document d;\
+ /*printf("\n%s\n", json);*/\
+ d.Parse(json);\
+ EXPECT_FALSE(d.HasParseError());\
+ EXPECT_FALSE(d.Accept(validator));\
+ EXPECT_FALSE(validator.IsValid());\
+ if (validator.GetInvalidSchemaPointer() != Pointer(invalidSchemaPointer)) {\
+ StringBuffer sb;\
+ validator.GetInvalidSchemaPointer().Stringify(sb);\
+ printf("GetInvalidSchemaPointer() Expected: %s Actual: %s\n", invalidSchemaPointer, sb.GetString());\
+ ADD_FAILURE();\
+ }\
+ ASSERT_TRUE(validator.GetInvalidSchemaKeyword() != 0);\
+ if (strcmp(validator.GetInvalidSchemaKeyword(), invalidSchemaKeyword) != 0) {\
+ printf("GetInvalidSchemaKeyword() Expected: %s Actual %s\n", invalidSchemaKeyword, validator.GetInvalidSchemaKeyword());\
+ ADD_FAILURE();\
+ }\
+ if (validator.GetInvalidDocumentPointer() != Pointer(invalidDocumentPointer)) {\
+ StringBuffer sb;\
+ validator.GetInvalidDocumentPointer().Stringify(sb);\
+ printf("GetInvalidDocumentPointer() Expected: %s Actual: %s\n", invalidDocumentPointer, sb.GetString());\
+ ADD_FAILURE();\
+ }\
+}
+
+TEST(SchemaValidator, Typeless) {
+ Document sd;
+ sd.Parse("{}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "42", true);
+ VALIDATE(s, "\"I'm a string\"", true);
+ VALIDATE(s, "{ \"an\": [ \"arbitrarily\", \"nested\" ], \"data\": \"structure\" }", true);
+}
+
+TEST(SchemaValidator, MultiType) {
+ Document sd;
+ sd.Parse("{ \"type\": [\"number\", \"string\"] }");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "42", true);
+ VALIDATE(s, "\"Life, the universe, and everything\"", true);
+ INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "");
+}
+
+TEST(SchemaValidator, Enum_Typed) {
+ Document sd;
+ sd.Parse("{ \"type\": \"string\", \"enum\" : [\"red\", \"amber\", \"green\"] }");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "\"red\"", true);
+ INVALIDATE(s, "\"blue\"", "", "enum", "");
+}
+
+TEST(SchemaValidator, Enum_Typless) {
+ Document sd;
+ sd.Parse("{ \"enum\": [\"red\", \"amber\", \"green\", null, 42] }");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "\"red\"", true);
+ VALIDATE(s, "null", true);
+ VALIDATE(s, "42", true);
+ INVALIDATE(s, "0", "", "enum", "");
+}
+
+TEST(SchemaValidator, Enum_InvalidType) {
+ Document sd;
+ sd.Parse("{ \"type\": \"string\", \"enum\": [\"red\", \"amber\", \"green\", null] }");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "\"red\"", true);
+ INVALIDATE(s, "null", "", "type", "");
+}
+
+TEST(SchemaValidator, AllOf) {
+ {
+ Document sd;
+ sd.Parse("{\"allOf\": [{ \"type\": \"string\" }, { \"type\": \"string\", \"maxLength\": 5 }]}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "\"ok\"", true);
+ INVALIDATE(s, "\"too long\"", "", "allOf", "");
+ }
+ {
+ Document sd;
+ sd.Parse("{\"allOf\": [{ \"type\": \"string\" }, { \"type\": \"number\" } ] }");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "\"No way\"", false);
+ INVALIDATE(s, "-1", "", "allOf", "");
+ }
+}
+
+TEST(SchemaValidator, AnyOf) {
+ Document sd;
+ sd.Parse("{\"anyOf\": [{ \"type\": \"string\" }, { \"type\": \"number\" } ] }");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "\"Yes\"", true);
+ VALIDATE(s, "42", true);
+ INVALIDATE(s, "{ \"Not a\": \"string or number\" }", "", "anyOf", "");
+}
+
+TEST(SchemaValidator, OneOf) {
+ Document sd;
+ sd.Parse("{\"oneOf\": [{ \"type\": \"number\", \"multipleOf\": 5 }, { \"type\": \"number\", \"multipleOf\": 3 } ] }");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "10", true);
+ VALIDATE(s, "9", true);
+ INVALIDATE(s, "2", "", "oneOf", "");
+ INVALIDATE(s, "15", "", "oneOf", "");
+}
+
+TEST(SchemaValidator, Not) {
+ Document sd;
+ sd.Parse("{\"not\":{ \"type\": \"string\"}}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "42", true);
+ VALIDATE(s, "{ \"key\": \"value\" }", true);
+ INVALIDATE(s, "\"I am a string\"", "", "not", "");
+}
+
+TEST(SchemaValidator, Ref) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"$schema\": \"http://json-schema.org/draft-04/schema#\","
+ ""
+ " \"definitions\": {"
+ " \"address\": {"
+ " \"type\": \"object\","
+ " \"properties\": {"
+ " \"street_address\": { \"type\": \"string\" },"
+ " \"city\": { \"type\": \"string\" },"
+ " \"state\": { \"type\": \"string\" }"
+ " },"
+ " \"required\": [\"street_address\", \"city\", \"state\"]"
+ " }"
+ " },"
+ " \"type\": \"object\","
+ " \"properties\": {"
+ " \"billing_address\": { \"$ref\": \"#/definitions/address\" },"
+ " \"shipping_address\": { \"$ref\": \"#/definitions/address\" }"
+ " }"
+ "}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\"}, \"billing_address\": {\"street_address\": \"1st Street SE\", \"city\": \"Washington\", \"state\": \"DC\"} }", true);
+}
+
+TEST(SchemaValidator, Ref_AllOf) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"$schema\": \"http://json-schema.org/draft-04/schema#\","
+ ""
+ " \"definitions\": {"
+ " \"address\": {"
+ " \"type\": \"object\","
+ " \"properties\": {"
+ " \"street_address\": { \"type\": \"string\" },"
+ " \"city\": { \"type\": \"string\" },"
+ " \"state\": { \"type\": \"string\" }"
+ " },"
+ " \"required\": [\"street_address\", \"city\", \"state\"]"
+ " }"
+ " },"
+ " \"type\": \"object\","
+ " \"properties\": {"
+ " \"billing_address\": { \"$ref\": \"#/definitions/address\" },"
+ " \"shipping_address\": {"
+ " \"allOf\": ["
+ " { \"$ref\": \"#/definitions/address\" },"
+ " { \"properties\":"
+ " { \"type\": { \"enum\": [ \"residential\", \"business\" ] } },"
+ " \"required\": [\"type\"]"
+ " }"
+ " ]"
+ " }"
+ " }"
+ "}");
+ SchemaDocument s(sd);
+
+ INVALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\"} }", "/properties/shipping_address", "allOf", "/shipping_address");
+ VALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\", \"type\": \"business\"} }", true);
+}
+
+TEST(SchemaValidator, String) {
+ Document sd;
+ sd.Parse("{\"type\":\"string\"}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "\"I'm a string\"", true);
+ INVALIDATE(s, "42", "", "type", "");
+}
+
+TEST(SchemaValidator, String_LengthRange) {
+ Document sd;
+ sd.Parse("{\"type\":\"string\",\"minLength\":2,\"maxLength\":3}");
+ SchemaDocument s(sd);
+
+ INVALIDATE(s, "\"A\"", "", "minLength", "");
+ VALIDATE(s, "\"AB\"", true);
+ VALIDATE(s, "\"ABC\"", true);
+ INVALIDATE(s, "\"ABCD\"", "", "maxLength", "");
+}
+
+#if RAPIDJSON_SCHEMA_HAS_REGEX
+TEST(SchemaValidator, String_Pattern) {
+ Document sd;
+ sd.Parse("{\"type\":\"string\",\"pattern\":\"^(\\\\([0-9]{3}\\\\))?[0-9]{3}-[0-9]{4}$\"}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "\"555-1212\"", true);
+ VALIDATE(s, "\"(888)555-1212\"", true);
+ INVALIDATE(s, "\"(888)555-1212 ext. 532\"", "", "pattern", "");
+ INVALIDATE(s, "\"(800)FLOWERS\"", "", "pattern", "");
+}
+#endif
+
+TEST(SchemaValidator, Integer) {
+ Document sd;
+ sd.Parse("{\"type\":\"integer\"}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "42", true);
+ VALIDATE(s, "-1", true);
+ INVALIDATE(s, "3.1415926", "", "type", "");
+ INVALIDATE(s, "\"42\"", "", "type", "");
+}
+
+TEST(SchemaValidator, Integer_Range) {
+ Document sd;
+ sd.Parse("{\"type\":\"integer\",\"minimum\":0,\"maximum\":100,\"exclusiveMaximum\":true}");
+ SchemaDocument s(sd);
+
+ INVALIDATE(s, "-1", "", "minimum", "");
+ VALIDATE(s, "0", true);
+ VALIDATE(s, "10", true);
+ VALIDATE(s, "99", true);
+ INVALIDATE(s, "100", "", "maximum", "");
+ INVALIDATE(s, "101", "", "maximum", "");
+}
+
+TEST(SchemaValidator, Integer_Range64Boundary) {
+ Document sd;
+ sd.Parse("{\"type\":\"integer\",\"minimum\":-9223372036854775807,\"maximum\":18446744073709551614}");
+ SchemaDocument s(sd);
+
+ INVALIDATE(s, "-9223372036854775808", "", "minimum", "");
+ VALIDATE(s, "-9223372036854775807", true);
+ VALIDATE(s, "18446744073709551614", true);
+ INVALIDATE(s, "18446744073709551615", "", "maximum", "");
+}
+
+TEST(SchemaValidator, Integer_Range64BoundaryExclusive) {
+ Document sd;
+ sd.Parse("{\"type\":\"integer\",\"minimum\":-9223372036854775808,\"maximum\":18446744073709551615,\"exclusiveMinimum\":true,\"exclusiveMaximum\":true}");
+ SchemaDocument s(sd);
+
+ INVALIDATE(s, "-9223372036854775808", "", "minimum", "");
+ VALIDATE(s, "-9223372036854775807", true);
+ VALIDATE(s, "18446744073709551614", true);
+ INVALIDATE(s, "18446744073709551615", "", "maximum", "");
+}
+
+TEST(SchemaValidator, Integer_MultipleOf) {
+ Document sd;
+ sd.Parse("{\"type\":\"integer\",\"multipleOf\":10}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "0", true);
+ VALIDATE(s, "10", true);
+ VALIDATE(s, "-10", true);
+ VALIDATE(s, "20", true);
+ INVALIDATE(s, "23", "", "multipleOf", "");
+ INVALIDATE(s, "-23", "", "multipleOf", "");
+}
+
+TEST(SchemaValidator, Integer_MultipleOf64Boundary) {
+ Document sd;
+ sd.Parse("{\"type\":\"integer\",\"multipleOf\":18446744073709551615}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "0", true);
+ VALIDATE(s, "18446744073709551615", true);
+ INVALIDATE(s, "18446744073709551614", "", "multipleOf", "");
+}
+
+TEST(SchemaValidator, Number_Range) {
+ Document sd;
+ sd.Parse("{\"type\":\"number\",\"minimum\":0,\"maximum\":100,\"exclusiveMaximum\":true}");
+ SchemaDocument s(sd);
+
+ INVALIDATE(s, "-1", "", "minimum", "");
+ VALIDATE(s, "0", true);
+ VALIDATE(s, "10", true);
+ VALIDATE(s, "99", true);
+ INVALIDATE(s, "100", "", "maximum", "");
+ INVALIDATE(s, "101", "", "maximum", "");
+}
+
+TEST(SchemaValidator, Number_MultipleOf) {
+ Document sd;
+ sd.Parse("{\"type\":\"number\",\"multipleOf\":10.0}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "0", true);
+ VALIDATE(s, "10", true);
+ VALIDATE(s, "-10", true);
+ VALIDATE(s, "20", true);
+ INVALIDATE(s, "23", "", "multipleOf", "");
+}
+
+TEST(SchemaValidator, Number_MultipleOfOne) {
+ Document sd;
+ sd.Parse("{\"type\":\"number\",\"multipleOf\":1}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "42", true);
+ VALIDATE(s, "42.0", true);
+ INVALIDATE(s, "3.1415926", "", "multipleOf", "");
+}
+
+TEST(SchemaValidator, Object) {
+ Document sd;
+ sd.Parse("{\"type\":\"object\"}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "{\"key\":\"value\",\"another_key\":\"another_value\"}", true);
+ VALIDATE(s, "{\"Sun\":1.9891e30,\"Jupiter\":1.8986e27,\"Saturn\":5.6846e26,\"Neptune\":10.243e25,\"Uranus\":8.6810e25,\"Earth\":5.9736e24,\"Venus\":4.8685e24,\"Mars\":6.4185e23,\"Mercury\":3.3022e23,\"Moon\":7.349e22,\"Pluto\":1.25e22}", true);
+ INVALIDATE(s, "[\"An\", \"array\", \"not\", \"an\", \"object\"]", "", "type", "");
+ INVALIDATE(s, "\"Not an object\"", "", "type", "");
+}
+
+TEST(SchemaValidator, Object_Properties) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\": \"object\","
+ " \"properties\" : {"
+ " \"number\": { \"type\": \"number\" },"
+ " \"street_name\" : { \"type\": \"string\" },"
+ " \"street_type\" : { \"type\": \"string\", \"enum\" : [\"Street\", \"Avenue\", \"Boulevard\"] }"
+ " }"
+ "}");
+
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
+ INVALIDATE(s, "{ \"number\": \"1600\", \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", "/properties/number", "type", "/number");
+ VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\" }", true);
+ VALIDATE(s, "{}", true);
+ VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", true);
+}
+
+TEST(SchemaValidator, Object_AdditionalPropertiesBoolean) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\": \"object\","
+ " \"properties\" : {"
+ " \"number\": { \"type\": \"number\" },"
+ " \"street_name\" : { \"type\": \"string\" },"
+ " \"street_type\" : { \"type\": \"string\","
+ " \"enum\" : [\"Street\", \"Avenue\", \"Boulevard\"]"
+ " }"
+ " },"
+ " \"additionalProperties\": false"
+ "}");
+
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
+ INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", "", "additionalProperties", "/direction");
+}
+
+TEST(SchemaValidator, Object_AdditionalPropertiesObject) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\": \"object\","
+ " \"properties\" : {"
+ " \"number\": { \"type\": \"number\" },"
+ " \"street_name\" : { \"type\": \"string\" },"
+ " \"street_type\" : { \"type\": \"string\","
+ " \"enum\" : [\"Street\", \"Avenue\", \"Boulevard\"]"
+ " }"
+ " },"
+ " \"additionalProperties\": { \"type\": \"string\" }"
+ "}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true);
+ VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", true);
+ INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"office_number\": 201 }", "/additionalProperties", "type", "/office_number");
+}
+
+TEST(SchemaValidator, Object_Required) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\": \"object\","
+ " \"properties\" : {"
+ " \"name\": { \"type\": \"string\" },"
+ " \"email\" : { \"type\": \"string\" },"
+ " \"address\" : { \"type\": \"string\" },"
+ " \"telephone\" : { \"type\": \"string\" }"
+ " },"
+ " \"required\":[\"name\", \"email\"]"
+ "}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "{ \"name\": \"William Shakespeare\", \"email\" : \"bill@stratford-upon-avon.co.uk\" }", true);
+ VALIDATE(s, "{ \"name\": \"William Shakespeare\", \"email\" : \"bill@stratford-upon-avon.co.uk\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\", \"authorship\" : \"in question\"}", true);
+ INVALIDATE(s, "{ \"name\": \"William Shakespeare\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\" }", "", "required", "");
+}
+
+
+TEST(SchemaValidator, Object_PropertiesRange) {
+ Document sd;
+ sd.Parse("{\"type\":\"object\", \"minProperties\":2, \"maxProperties\":3}");
+ SchemaDocument s(sd);
+
+ INVALIDATE(s, "{}", "", "minProperties", "");
+ INVALIDATE(s, "{\"a\":0}", "", "minProperties", "");
+ VALIDATE(s, "{\"a\":0,\"b\":1}", true);
+ VALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2}", true);
+ INVALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2,\"d\":3}", "", "maxProperties", "");
+}
+
+TEST(SchemaValidator, Object_PropertyDependencies) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\": \"object\","
+ " \"properties\": {"
+ " \"name\": { \"type\": \"string\" },"
+ " \"credit_card\": { \"type\": \"number\" },"
+ " \"billing_address\": { \"type\": \"string\" }"
+ " },"
+ " \"required\": [\"name\"],"
+ " \"dependencies\": {"
+ " \"credit_card\": [\"billing_address\"]"
+ " }"
+ "}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555, \"billing_address\": \"555 Debtor's Lane\" }", true);
+ INVALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555 }", "", "dependencies", "");
+ VALIDATE(s, "{ \"name\": \"John Doe\"}", true);
+ VALIDATE(s, "{ \"name\": \"John Doe\", \"billing_address\": \"555 Debtor's Lane\" }", true);
+}
+
+TEST(SchemaValidator, Object_SchemaDependencies) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\": \"object\","
+ " \"properties\" : {"
+ " \"name\": { \"type\": \"string\" },"
+ " \"credit_card\" : { \"type\": \"number\" }"
+ " },"
+ " \"required\" : [\"name\"],"
+ " \"dependencies\" : {"
+ " \"credit_card\": {"
+ " \"properties\": {"
+ " \"billing_address\": { \"type\": \"string\" }"
+ " },"
+ " \"required\" : [\"billing_address\"]"
+ " }"
+ " }"
+ "}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555,\"billing_address\" : \"555 Debtor's Lane\"}", true);
+ INVALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555 }", "", "dependencies", "");
+ VALIDATE(s, "{\"name\": \"John Doe\", \"billing_address\" : \"555 Debtor's Lane\"}", true);
+}
+
+#if RAPIDJSON_SCHEMA_HAS_REGEX
+TEST(SchemaValidator, Object_PatternProperties) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\": \"object\","
+ " \"patternProperties\": {"
+ " \"^S_\": { \"type\": \"string\" },"
+ " \"^I_\": { \"type\": \"integer\" }"
+ " }"
+ "}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "{ \"S_25\": \"This is a string\" }", true);
+ VALIDATE(s, "{ \"I_0\": 42 }", true);
+ INVALIDATE(s, "{ \"S_0\": 42 }", "", "patternProperties", "/S_0");
+ INVALIDATE(s, "{ \"I_42\": \"This is a string\" }", "", "patternProperties", "/I_42");
+ VALIDATE(s, "{ \"keyword\": \"value\" }", true);
+}
+
+TEST(SchemaValidator, Object_PatternProperties_AdditionalProperties) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\": \"object\","
+ " \"properties\": {"
+ " \"builtin\": { \"type\": \"number\" }"
+ " },"
+ " \"patternProperties\": {"
+ " \"^S_\": { \"type\": \"string\" },"
+ " \"^I_\": { \"type\": \"integer\" }"
+ " },"
+ " \"additionalProperties\": { \"type\": \"string\" }"
+ "}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "{ \"builtin\": 42 }", true);
+ VALIDATE(s, "{ \"keyword\": \"value\" }", true);
+ INVALIDATE(s, "{ \"keyword\": 42 }", "/additionalProperties", "type", "/keyword");
+}
+#endif
+
+TEST(SchemaValidator, Array) {
+ Document sd;
+ sd.Parse("{\"type\":\"array\"}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "[1, 2, 3, 4, 5]", true);
+ VALIDATE(s, "[3, \"different\", { \"types\" : \"of values\" }]", true);
+ INVALIDATE(s, "{\"Not\": \"an array\"}", "", "type", "");
+}
+
+TEST(SchemaValidator, Array_ItemsList) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\": \"array\","
+ " \"items\" : {"
+ " \"type\": \"number\""
+ " }"
+ "}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "[1, 2, 3, 4, 5]", true);
+ INVALIDATE(s, "[1, 2, \"3\", 4, 5]", "/items", "type", "/2");
+ VALIDATE(s, "[]", true);
+}
+
+TEST(SchemaValidator, Array_ItemsTuple) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\": \"array\","
+ " \"items\": ["
+ " {"
+ " \"type\": \"number\""
+ " },"
+ " {"
+ " \"type\": \"string\""
+ " },"
+ " {"
+ " \"type\": \"string\","
+ " \"enum\": [\"Street\", \"Avenue\", \"Boulevard\"]"
+ " },"
+ " {"
+ " \"type\": \"string\","
+ " \"enum\": [\"NW\", \"NE\", \"SW\", \"SE\"]"
+ " }"
+ " ]"
+ "}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\"]", true);
+ INVALIDATE(s, "[24, \"Sussex\", \"Drive\"]", "/items/2", "enum", "/2");
+ INVALIDATE(s, "[\"Palais de l'Elysee\"]", "/items/0", "type", "/0");
+ VALIDATE(s, "[10, \"Downing\", \"Street\"]", true);
+ VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", true);
+}
+
+TEST(SchemaValidator, Array_AdditionalItmes) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\": \"array\","
+ " \"items\": ["
+ " {"
+ " \"type\": \"number\""
+ " },"
+ " {"
+ " \"type\": \"string\""
+ " },"
+ " {"
+ " \"type\": \"string\","
+ " \"enum\": [\"Street\", \"Avenue\", \"Boulevard\"]"
+ " },"
+ " {"
+ " \"type\": \"string\","
+ " \"enum\": [\"NW\", \"NE\", \"SW\", \"SE\"]"
+ " }"
+ " ],"
+ " \"additionalItems\": false"
+ "}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\"]", true);
+ VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\"]", true);
+ INVALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", "", "items", "/4");
+}
+
+TEST(SchemaValidator, Array_ItemsRange) {
+ Document sd;
+ sd.Parse("{\"type\": \"array\",\"minItems\": 2,\"maxItems\" : 3}");
+ SchemaDocument s(sd);
+
+ INVALIDATE(s, "[]", "", "minItems", "");
+ INVALIDATE(s, "[1]", "", "minItems", "");
+ VALIDATE(s, "[1, 2]", true);
+ VALIDATE(s, "[1, 2, 3]", true);
+ INVALIDATE(s, "[1, 2, 3, 4]", "", "maxItems", "");
+}
+
+TEST(SchemaValidator, Array_UniqueItems) {
+ Document sd;
+ sd.Parse("{\"type\": \"array\", \"uniqueItems\": true}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "[1, 2, 3, 4, 5]", true);
+ INVALIDATE(s, "[1, 2, 3, 3, 4]", "", "uniqueItems", "/3");
+ VALIDATE(s, "[]", true);
+}
+
+TEST(SchemaValidator, Boolean) {
+ Document sd;
+ sd.Parse("{\"type\":\"boolean\"}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "true", true);
+ VALIDATE(s, "false", true);
+ INVALIDATE(s, "\"true\"", "", "type", "");
+ INVALIDATE(s, "0", "", "type", "");
+}
+
+TEST(SchemaValidator, Null) {
+ Document sd;
+ sd.Parse("{\"type\":\"null\"}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "null", true);
+ INVALIDATE(s, "false", "", "type", "");
+ INVALIDATE(s, "0", "", "type", "");
+ INVALIDATE(s, "\"\"", "", "type", "");
+}
+
+// Additional tests
+
+TEST(SchemaValidator, ObjectInArray) {
+ Document sd;
+ sd.Parse("{\"type\":\"array\", \"items\": { \"type\":\"string\" }}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "[\"a\"]", true);
+ INVALIDATE(s, "[1]", "/items", "type", "/0");
+ INVALIDATE(s, "[{}]", "/items", "type", "/0");
+}
+
+TEST(SchemaValidator, MultiTypeInObject) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\":\"object\","
+ " \"properties\": {"
+ " \"tel\" : {"
+ " \"type\":[\"integer\", \"string\"]"
+ " }"
+ " }"
+ "}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "{ \"tel\": 999 }", true);
+ VALIDATE(s, "{ \"tel\": \"123-456\" }", true);
+ INVALIDATE(s, "{ \"tel\": true }", "/properties/tel", "type", "/tel");
+}
+
+TEST(SchemaValidator, MultiTypeWithObject) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"type\": [\"object\",\"string\"],"
+ " \"properties\": {"
+ " \"tel\" : {"
+ " \"type\": \"integer\""
+ " }"
+ " }"
+ "}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "\"Hello\"", true);
+ VALIDATE(s, "{ \"tel\": 999 }", true);
+ INVALIDATE(s, "{ \"tel\": \"fail\" }", "/properties/tel", "type", "/tel");
+}
+
+TEST(SchemaValidator, AllOf_Nested) {
+ Document sd;
+ sd.Parse(
+ "{"
+ " \"allOf\": ["
+ " { \"type\": \"string\", \"minLength\": 2 },"
+ " { \"type\": \"string\", \"maxLength\": 5 },"
+ " { \"allOf\": [ { \"enum\" : [\"ok\", \"okay\", \"OK\", \"o\"] }, { \"enum\" : [\"ok\", \"OK\", \"o\"]} ] }"
+ " ]"
+ "}");
+ SchemaDocument s(sd);
+
+ VALIDATE(s, "\"ok\"", true);
+ VALIDATE(s, "\"OK\"", true);
+ INVALIDATE(s, "\"okay\"", "", "allOf", "");
+ INVALIDATE(s, "\"o\"", "", "allOf", "");
+ INVALIDATE(s, "\"n\"", "", "allOf", "");
+ INVALIDATE(s, "\"too long\"", "", "allOf", "");
+ INVALIDATE(s, "123", "", "allOf", "");
+}
+
+template <typename Allocator>
+static char* ReadFile(const char* filename, Allocator& allocator) {
+ const char *paths[] = {
+ "",
+ "bin/",
+ "../bin/",
+ "../../bin/",
+ "../../../bin/"
+ };
+ char buffer[1024];
+ FILE *fp = 0;
+ for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
+ sprintf(buffer, "%s%s", paths[i], filename);
+ fp = fopen(buffer, "rb");
+ if (fp)
+ break;
+ }
+
+ if (!fp)
+ return 0;
+
+ fseek(fp, 0, SEEK_END);
+ size_t length = static_cast<size_t>(ftell(fp));
+ fseek(fp, 0, SEEK_SET);
+ char* json = reinterpret_cast<char*>(allocator.Malloc(length + 1));
+ size_t readLength = fread(json, 1, length, fp);
+ json[readLength] = '\0';
+ fclose(fp);
+ return json;
+}
+
+TEST(SchemaValidator, ValidateMetaSchema) {
+ CrtAllocator allocator;
+ char* json = ReadFile("draft-04/schema", allocator);
+ Document d;
+ d.Parse(json);
+ ASSERT_FALSE(d.HasParseError());
+ SchemaDocument sd(d);
+ SchemaValidator validator(sd);
+ if (!d.Accept(validator)) {
+ StringBuffer sb;
+ validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
+ printf("Invalid schema: %s\n", sb.GetString());
+ printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
+ sb.Clear();
+ validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
+ printf("Invalid document: %s\n", sb.GetString());
+ ADD_FAILURE();
+ }
+ CrtAllocator::Free(json);
+}
+
+TEST(SchemaValidator, ValidateMetaSchema_UTF16) {
+ typedef GenericDocument<UTF16<> > D;
+ typedef GenericSchemaDocument<D::ValueType> SD;
+ typedef GenericSchemaValidator<SD> SV;
+
+ CrtAllocator allocator;
+ char* json = ReadFile("draft-04/schema", allocator);
+
+ D d;
+ StringStream ss(json);
+ d.ParseStream<0, UTF8<> >(ss);
+ ASSERT_FALSE(d.HasParseError());
+ SD sd(d);
+ SV validator(sd);
+ if (!d.Accept(validator)) {
+ GenericStringBuffer<UTF16<> > sb;
+ validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
+ wprintf(L"Invalid schema: %ls\n", sb.GetString());
+ wprintf(L"Invalid keyword: %ls\n", validator.GetInvalidSchemaKeyword());
+ sb.Clear();
+ validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
+ wprintf(L"Invalid document: %ls\n", sb.GetString());
+ ADD_FAILURE();
+ }
+ CrtAllocator::Free(json);
+}
+
+template <typename SchemaDocumentType = SchemaDocument>
+class RemoteSchemaDocumentProvider : public IGenericRemoteSchemaDocumentProvider<SchemaDocumentType> {
+public:
+ RemoteSchemaDocumentProvider() :
+ documentAllocator_(documentBuffer_, sizeof(documentBuffer_)),
+ schemaAllocator_(schemaBuffer_, sizeof(schemaBuffer_))
+ {
+ const char* filenames[kCount] = {
+ "jsonschema/remotes/integer.json",
+ "jsonschema/remotes/subSchemas.json",
+ "jsonschema/remotes/folder/folderInteger.json",
+ "draft-04/schema"
+ };
+
+ for (size_t i = 0; i < kCount; i++) {
+ sd_[i] = 0;
+
+ char jsonBuffer[8192];
+ MemoryPoolAllocator<> jsonAllocator(jsonBuffer, sizeof(jsonBuffer));
+ char* json = ReadFile(filenames[i], jsonAllocator);
+ if (!json) {
+ printf("json remote file %s not found", filenames[i]);
+ ADD_FAILURE();
+ }
+ else {
+ char stackBuffer[4096];
+ MemoryPoolAllocator<> stackAllocator(stackBuffer, sizeof(stackBuffer));
+ DocumentType d(&documentAllocator_, 1024, &stackAllocator);
+ d.Parse(json);
+ sd_[i] = new SchemaDocumentType(d, 0, &schemaAllocator_);
+ MemoryPoolAllocator<>::Free(json);
+ }
+ };
+ }
+
+ ~RemoteSchemaDocumentProvider() {
+ for (size_t i = 0; i < kCount; i++)
+ delete sd_[i];
+ }
+
+ virtual const SchemaDocumentType* GetRemoteDocument(const char* uri, SizeType length) {
+ const char* uris[kCount] = {
+ "http://localhost:1234/integer.json",
+ "http://localhost:1234/subSchemas.json",
+ "http://localhost:1234/folder/folderInteger.json",
+ "http://json-schema.org/draft-04/schema"
+ };
+
+ for (size_t i = 0; i < kCount; i++)
+ if (strncmp(uri, uris[i], length) == 0)
+ return sd_[i];
+ return 0;
+ }
+
+private:
+ typedef GenericDocument<typename SchemaDocumentType::EncodingType, MemoryPoolAllocator<>, MemoryPoolAllocator<> > DocumentType;
+
+ RemoteSchemaDocumentProvider(const RemoteSchemaDocumentProvider&);
+ RemoteSchemaDocumentProvider& operator=(const RemoteSchemaDocumentProvider&);
+
+ static const size_t kCount = 4;
+ SchemaDocumentType* sd_[kCount];
+ typename DocumentType::AllocatorType documentAllocator_;
+ typename SchemaDocumentType::AllocatorType schemaAllocator_;
+ char documentBuffer_[16384];
+ char schemaBuffer_[128 * 1024];
+};
+
+TEST(SchemaValidator, TestSuite) {
+ const char* filenames[] = {
+ "additionalItems.json",
+ "additionalProperties.json",
+ "allOf.json",
+ "anyOf.json",
+ "default.json",
+ "definitions.json",
+ "dependencies.json",
+ "enum.json",
+ "items.json",
+ "maximum.json",
+ "maxItems.json",
+ "maxLength.json",
+ "maxProperties.json",
+ "minimum.json",
+ "minItems.json",
+ "minLength.json",
+ "minProperties.json",
+ "multipleOf.json",
+ "not.json",
+ "oneOf.json",
+ "pattern.json",
+ "patternProperties.json",
+ "properties.json",
+ "ref.json",
+ "refRemote.json",
+ "required.json",
+ "type.json",
+ "uniqueItems.json"
+ };
+
+ const char* onlyRunDescription = 0;
+ //const char* onlyRunDescription = "a string is a string";
+
+ unsigned testCount = 0;
+ unsigned passCount = 0;
+
+ typedef GenericSchemaDocument<Value, MemoryPoolAllocator<> > SchemaDocumentType;
+ RemoteSchemaDocumentProvider<SchemaDocumentType> provider;
+
+ char jsonBuffer[65536];
+ char documentBuffer[65536];
+ char documentStackBuffer[65536];
+ char schemaBuffer[65536];
+ char validatorBuffer[65536];
+ MemoryPoolAllocator<> jsonAllocator(jsonBuffer, sizeof(jsonBuffer));
+ MemoryPoolAllocator<> documentAllocator(documentBuffer, sizeof(documentBuffer));
+ MemoryPoolAllocator<> documentStackAllocator(documentStackBuffer, sizeof(documentStackBuffer));
+ MemoryPoolAllocator<> schemaAllocator(schemaBuffer, sizeof(schemaBuffer));
+ MemoryPoolAllocator<> validatorAllocator(validatorBuffer, sizeof(validatorBuffer));
+
+ for (size_t i = 0; i < sizeof(filenames) / sizeof(filenames[0]); i++) {
+ char filename[FILENAME_MAX];
+ sprintf(filename, "jsonschema/tests/draft4/%s", filenames[i]);
+ char* json = ReadFile(filename, jsonAllocator);
+ if (!json) {
+ printf("json test suite file %s not found", filename);
+ ADD_FAILURE();
+ }
+ else {
+ GenericDocument<UTF8<>, MemoryPoolAllocator<>, MemoryPoolAllocator<> > d(&documentAllocator, 1024, &documentStackAllocator);
+ d.Parse(json);
+ if (d.HasParseError()) {
+ printf("json test suite file %s has parse error", filename);
+ ADD_FAILURE();
+ }
+ else {
+ for (Value::ConstValueIterator schemaItr = d.Begin(); schemaItr != d.End(); ++schemaItr) {
+ {
+ SchemaDocumentType schema((*schemaItr)["schema"], &provider, &schemaAllocator);
+ GenericSchemaValidator<SchemaDocumentType, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > validator(schema, &validatorAllocator);
+ const char* description1 = (*schemaItr)["description"].GetString();
+ const Value& tests = (*schemaItr)["tests"];
+ for (Value::ConstValueIterator testItr = tests.Begin(); testItr != tests.End(); ++testItr) {
+ const char* description2 = (*testItr)["description"].GetString();
+ if (!onlyRunDescription || strcmp(description2, onlyRunDescription) == 0) {
+ const Value& data = (*testItr)["data"];
+ bool expected = (*testItr)["valid"].GetBool();
+ testCount++;
+ validator.Reset();
+ bool actual = data.Accept(validator);
+ if (expected != actual)
+ printf("Fail: %30s \"%s\" \"%s\"\n", filename, description1, description2);
+ else
+ passCount++;
+ }
+ }
+ //printf("%zu %zu %zu\n", documentAllocator.Size(), schemaAllocator.Size(), validatorAllocator.Size());
+ }
+ schemaAllocator.Clear();
+ validatorAllocator.Clear();
+ }
+ }
+ }
+ documentAllocator.Clear();
+ MemoryPoolAllocator<>::Free(json);
+ jsonAllocator.Clear();
+ }
+ printf("%d / %d passed (%2d%%)\n", passCount, testCount, passCount * 100 / testCount);
+ // if (passCount != testCount)
+ // ADD_FAILURE();
+}
+
+TEST(SchemaValidatingReader, Simple) {
+ Document sd;
+ sd.Parse("{ \"type\": \"string\", \"enum\" : [\"red\", \"amber\", \"green\"] }");
+ SchemaDocument s(sd);
+
+ Document d;
+ StringStream ss("\"red\"");
+ SchemaValidatingReader<kParseDefaultFlags, StringStream, UTF8<> > reader(ss, s);
+ d.Populate(reader);
+ EXPECT_TRUE(reader.GetParseResult());
+ EXPECT_TRUE(reader.IsValid());
+ EXPECT_TRUE(d.IsString());
+ EXPECT_STREQ("red", d.GetString());
+}
+
+TEST(SchemaValidatingReader, Invalid) {
+ Document sd;
+ sd.Parse("{\"type\":\"string\",\"minLength\":2,\"maxLength\":3}");
+ SchemaDocument s(sd);
+
+ Document d;
+ StringStream ss("\"ABCD\"");
+ SchemaValidatingReader<kParseDefaultFlags, StringStream, UTF8<> > reader(ss, s);
+ d.Populate(reader);
+ EXPECT_FALSE(reader.GetParseResult());
+ EXPECT_FALSE(reader.IsValid());
+ EXPECT_EQ(kParseErrorTermination, reader.GetParseResult().Code());
+ EXPECT_STREQ("maxLength", reader.GetInvalidSchemaKeyword());
+ EXPECT_TRUE(reader.GetInvalidSchemaPointer() == SchemaDocument::PointerType(""));
+ EXPECT_TRUE(reader.GetInvalidDocumentPointer() == SchemaDocument::PointerType(""));
+ EXPECT_TRUE(d.IsNull());
+}
+
+TEST(SchemaValidatingWriter, Simple) {
+ Document sd;
+ sd.Parse("{\"type\":\"string\",\"minLength\":2,\"maxLength\":3}");
+ SchemaDocument s(sd);
+
+ Document d;
+ StringBuffer sb;
+ Writer<StringBuffer> writer(sb);
+ GenericSchemaValidator<SchemaDocument, Writer<StringBuffer> > validator(s, writer);
+
+ d.Parse("\"red\"");
+ EXPECT_TRUE(d.Accept(validator));
+ EXPECT_TRUE(validator.IsValid());
+ EXPECT_STREQ("\"red\"", sb.GetString());
+
+ sb.Clear();
+ validator.Reset();
+ d.Parse("\"ABCD\"");
+ EXPECT_FALSE(d.Accept(validator));
+ EXPECT_FALSE(validator.IsValid());
+ EXPECT_TRUE(validator.GetInvalidSchemaPointer() == SchemaDocument::PointerType(""));
+ EXPECT_TRUE(validator.GetInvalidDocumentPointer() == SchemaDocument::PointerType(""));
+}
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
diff --git a/3rdparty/rapidjson/test/unittest/simdtest.cpp b/3rdparty/rapidjson/test/unittest/simdtest.cpp
new file mode 100644
index 00000000000..6ded7402fbf
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/simdtest.cpp
@@ -0,0 +1,159 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+// Since Travis CI installs old Valgrind 3.7.0, which fails with some SSE4.2
+// The unit tests prefix with SIMD should be skipped by Valgrind test
+
+// __SSE2__ and __SSE4_2__ are recognized by gcc, clang, and the Intel compiler.
+// We use -march=native with gmake to enable -msse2 and -msse4.2, if supported.
+#if defined(__SSE4_2__)
+# define RAPIDJSON_SSE42
+#elif defined(__SSE2__)
+# define RAPIDJSON_SSE2
+#endif
+
+#define RAPIDJSON_NAMESPACE rapidjson_simd
+
+#include "unittest.h"
+
+#include "rapidjson/reader.h"
+#include "rapidjson/writer.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+using namespace rapidjson_simd;
+
+#ifdef RAPIDJSON_SSE2
+#define SIMD_SUFFIX(name) name##_SSE2
+#elif defined(RAPIDJSON_SSE42)
+#define SIMD_SUFFIX(name) name##_SSE42
+#else
+#define SIMD_SUFFIX(name) name
+#endif
+
+template <typename StreamType>
+void TestSkipWhitespace() {
+ for (size_t step = 1; step < 32; step++) {
+ char buffer[1025];
+ for (size_t i = 0; i < 1024; i++)
+ buffer[i] = " \t\r\n"[i % 4];
+ for (size_t i = 0; i < 1024; i += step)
+ buffer[i] = 'X';
+ buffer[1024] = '\0';
+
+ StreamType s(buffer);
+ size_t i = 0;
+ for (;;) {
+ SkipWhitespace(s);
+ if (s.Peek() == '\0')
+ break;
+ EXPECT_EQ(i, s.Tell());
+ EXPECT_EQ('X', s.Take());
+ i += step;
+ }
+ }
+}
+
+TEST(SIMD, SIMD_SUFFIX(SkipWhitespace)) {
+ TestSkipWhitespace<StringStream>();
+ TestSkipWhitespace<InsituStringStream>();
+}
+
+struct ScanCopyUnescapedStringHandler : BaseReaderHandler<UTF8<>, ScanCopyUnescapedStringHandler> {
+ bool String(const char* str, size_t length, bool) {
+ memcpy(buffer, str, length + 1);
+ return true;
+ }
+ char buffer[1024 + 5];
+};
+
+template <unsigned parseFlags, typename StreamType>
+void TestScanCopyUnescapedString() {
+ for (size_t step = 0; step < 1024; step++) {
+ char json[1024 + 5];
+ char *p = json;
+ *p ++= '\"';
+ for (size_t i = 0; i < step; i++)
+ *p++= "ABCD"[i % 4];
+ *p++ = '\\';
+ *p++ = '\\';
+ *p++ = '\"';
+ *p++ = '\0';
+
+ StreamType s(json);
+ Reader reader;
+ ScanCopyUnescapedStringHandler h;
+ reader.Parse<parseFlags>(s, h);
+ EXPECT_TRUE(memcmp(h.buffer, json + 1, step) == 0);
+ EXPECT_EQ('\\', h.buffer[step]); // escaped
+ EXPECT_EQ('\0', h.buffer[step + 1]);
+ }
+}
+
+TEST(SIMD, SIMD_SUFFIX(ScanCopyUnescapedString)) {
+ TestScanCopyUnescapedString<kParseDefaultFlags, StringStream>();
+ TestScanCopyUnescapedString<kParseInsituFlag, InsituStringStream>();
+}
+
+TEST(SIMD, SIMD_SUFFIX(ScanWriteUnescapedString)) {
+ for (size_t step = 0; step < 1024; step++) {
+ char s[2048 + 1];
+ char *p = s;
+ for (size_t i = 0; i < step; i++)
+ *p++= "ABCD"[i % 4];
+ char escape = "\0\n\\\""[step % 4];
+ *p++ = escape;
+ for (size_t i = 0; i < step; i++)
+ *p++= "ABCD"[i % 4];
+
+ StringBuffer sb;
+ Writer<StringBuffer> writer(sb);
+ writer.String(s, SizeType(step * 2 + 1));
+ const char* q = sb.GetString();
+ EXPECT_EQ('\"', *q++);
+ for (size_t i = 0; i < step; i++)
+ EXPECT_EQ("ABCD"[i % 4], *q++);
+ if (escape == '\0') {
+ EXPECT_EQ('\\', *q++);
+ EXPECT_EQ('u', *q++);
+ EXPECT_EQ('0', *q++);
+ EXPECT_EQ('0', *q++);
+ EXPECT_EQ('0', *q++);
+ EXPECT_EQ('0', *q++);
+ }
+ else if (escape == '\n') {
+ EXPECT_EQ('\\', *q++);
+ EXPECT_EQ('n', *q++);
+ }
+ else if (escape == '\\') {
+ EXPECT_EQ('\\', *q++);
+ EXPECT_EQ('\\', *q++);
+ }
+ else if (escape == '\"') {
+ EXPECT_EQ('\\', *q++);
+ EXPECT_EQ('\"', *q++);
+ }
+ for (size_t i = 0; i < step; i++)
+ EXPECT_EQ("ABCD"[i % 4], *q++);
+ EXPECT_EQ('\"', *q++);
+ EXPECT_EQ('\0', *q++);
+ }
+}
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
diff --git a/3rdparty/rapidjson/test/unittest/strfunctest.cpp b/3rdparty/rapidjson/test/unittest/strfunctest.cpp
new file mode 100644
index 00000000000..cc1bb22f0e9
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/strfunctest.cpp
@@ -0,0 +1,30 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+#include "rapidjson/internal/strfunc.h"
+
+using namespace rapidjson;
+using namespace rapidjson::internal;
+
+TEST(StrFunc, CountStringCodePoint) {
+ SizeType count;
+ EXPECT_TRUE(CountStringCodePoint<UTF8<> >("", 0, &count));
+ EXPECT_EQ(0u, count);
+ EXPECT_TRUE(CountStringCodePoint<UTF8<> >("Hello", 5, &count));
+ EXPECT_EQ(5u, count);
+ EXPECT_TRUE(CountStringCodePoint<UTF8<> >("\xC2\xA2\xE2\x82\xAC\xF0\x9D\x84\x9E", 9, &count)); // cents euro G-clef
+ EXPECT_EQ(3u, count);
+ EXPECT_FALSE(CountStringCodePoint<UTF8<> >("\xC2\xA2\xE2\x82\xAC\xF0\x9D\x84\x9E\x80", 10, &count));
+}
diff --git a/3rdparty/rapidjson/test/unittest/stringbuffertest.cpp b/3rdparty/rapidjson/test/unittest/stringbuffertest.cpp
new file mode 100644
index 00000000000..9be98fce268
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/stringbuffertest.cpp
@@ -0,0 +1,163 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+#include "rapidjson/stringbuffer.h"
+#include "rapidjson/writer.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
+using namespace rapidjson;
+
+TEST(StringBuffer, InitialSize) {
+ StringBuffer buffer;
+ EXPECT_EQ(0u, buffer.GetSize());
+ EXPECT_STREQ("", buffer.GetString());
+}
+
+TEST(StringBuffer, Put) {
+ StringBuffer buffer;
+ buffer.Put('A');
+
+ EXPECT_EQ(1u, buffer.GetSize());
+ EXPECT_STREQ("A", buffer.GetString());
+}
+
+TEST(StringBuffer, Clear) {
+ StringBuffer buffer;
+ buffer.Put('A');
+ buffer.Put('B');
+ buffer.Put('C');
+ buffer.Clear();
+
+ EXPECT_EQ(0u, buffer.GetSize());
+ EXPECT_STREQ("", buffer.GetString());
+}
+
+TEST(StringBuffer, Push) {
+ StringBuffer buffer;
+ buffer.Push(5);
+
+ EXPECT_EQ(5u, buffer.GetSize());
+
+ // Causes sudden expansion to make the stack's capacity equal to size
+ buffer.Push(65536u);
+ EXPECT_EQ(5u + 65536u, buffer.GetSize());
+}
+
+TEST(StringBuffer, Pop) {
+ StringBuffer buffer;
+ buffer.Put('A');
+ buffer.Put('B');
+ buffer.Put('C');
+ buffer.Put('D');
+ buffer.Put('E');
+ buffer.Pop(3);
+
+ EXPECT_EQ(2u, buffer.GetSize());
+ EXPECT_STREQ("AB", buffer.GetString());
+}
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+#if 0 // Many old compiler does not support these. Turn it off temporaily.
+
+#include <type_traits>
+
+TEST(StringBuffer, Traits) {
+ static_assert( std::is_constructible<StringBuffer>::value, "");
+ static_assert( std::is_default_constructible<StringBuffer>::value, "");
+#ifndef _MSC_VER
+ static_assert(!std::is_copy_constructible<StringBuffer>::value, "");
+#endif
+ static_assert( std::is_move_constructible<StringBuffer>::value, "");
+
+ static_assert(!std::is_nothrow_constructible<StringBuffer>::value, "");
+ static_assert(!std::is_nothrow_default_constructible<StringBuffer>::value, "");
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1800
+ static_assert(!std::is_nothrow_copy_constructible<StringBuffer>::value, "");
+ static_assert(!std::is_nothrow_move_constructible<StringBuffer>::value, "");
+#endif
+
+ static_assert( std::is_assignable<StringBuffer,StringBuffer>::value, "");
+#ifndef _MSC_VER
+ static_assert(!std::is_copy_assignable<StringBuffer>::value, "");
+#endif
+ static_assert( std::is_move_assignable<StringBuffer>::value, "");
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1800
+ static_assert(!std::is_nothrow_assignable<StringBuffer, StringBuffer>::value, "");
+#endif
+
+ static_assert(!std::is_nothrow_copy_assignable<StringBuffer>::value, "");
+ static_assert(!std::is_nothrow_move_assignable<StringBuffer>::value, "");
+
+ static_assert( std::is_destructible<StringBuffer>::value, "");
+#ifndef _MSC_VER
+ static_assert(std::is_nothrow_destructible<StringBuffer>::value, "");
+#endif
+}
+
+#endif
+
+TEST(StringBuffer, MoveConstructor) {
+ StringBuffer x;
+ x.Put('A');
+ x.Put('B');
+ x.Put('C');
+ x.Put('D');
+
+ EXPECT_EQ(4u, x.GetSize());
+ EXPECT_STREQ("ABCD", x.GetString());
+
+ // StringBuffer y(x); // does not compile (!is_copy_constructible)
+ StringBuffer y(std::move(x));
+ EXPECT_EQ(0u, x.GetSize());
+ EXPECT_EQ(4u, y.GetSize());
+ EXPECT_STREQ("ABCD", y.GetString());
+
+ // StringBuffer z = y; // does not compile (!is_copy_assignable)
+ StringBuffer z = std::move(y);
+ EXPECT_EQ(0u, y.GetSize());
+ EXPECT_EQ(4u, z.GetSize());
+ EXPECT_STREQ("ABCD", z.GetString());
+}
+
+TEST(StringBuffer, MoveAssignment) {
+ StringBuffer x;
+ x.Put('A');
+ x.Put('B');
+ x.Put('C');
+ x.Put('D');
+
+ EXPECT_EQ(4u, x.GetSize());
+ EXPECT_STREQ("ABCD", x.GetString());
+
+ StringBuffer y;
+ // y = x; // does not compile (!is_copy_assignable)
+ y = std::move(x);
+ EXPECT_EQ(0u, x.GetSize());
+ EXPECT_EQ(4u, y.GetSize());
+ EXPECT_STREQ("ABCD", y.GetString());
+}
+
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
diff --git a/3rdparty/rapidjson/test/unittest/strtodtest.cpp b/3rdparty/rapidjson/test/unittest/strtodtest.cpp
new file mode 100644
index 00000000000..a42d96e4a67
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/strtodtest.cpp
@@ -0,0 +1,132 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+
+#include "rapidjson/internal/strtod.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(unreachable-code)
+#endif
+
+#define BIGINTEGER_LITERAL(s) BigInteger(s, sizeof(s) - 1)
+
+using namespace rapidjson::internal;
+
+TEST(Strtod, CheckApproximationCase) {
+ static const int kSignificandSize = 52;
+ static const int kExponentBias = 0x3FF;
+ static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
+ static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
+ static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
+
+ // http://www.exploringbinary.com/using-integers-to-check-a-floating-point-approximation/
+ // Let b = 0x1.465a72e467d88p-149
+ // = 5741268244528520 x 2^-201
+ union {
+ double d;
+ uint64_t u;
+ }u;
+ u.u = 0x465a72e467d88 | ((static_cast<uint64_t>(-149 + kExponentBias)) << kSignificandSize);
+ const double b = u.d;
+ const uint64_t bInt = (u.u & kSignificandMask) | kHiddenBit;
+ const int bExp = ((u.u & kExponentMask) >> kSignificandSize) - kExponentBias - kSignificandSize;
+ EXPECT_DOUBLE_EQ(1.7864e-45, b);
+ EXPECT_EQ(RAPIDJSON_UINT64_C2(0x001465a7, 0x2e467d88), bInt);
+ EXPECT_EQ(-201, bExp);
+
+ // Let d = 17864 x 10-49
+ const char dInt[] = "17864";
+ const int dExp = -49;
+
+ // Let h = 2^(bExp-1)
+ const int hExp = bExp - 1;
+ EXPECT_EQ(-202, hExp);
+
+ int dS_Exp2 = 0;
+ int dS_Exp5 = 0;
+ int bS_Exp2 = 0;
+ int bS_Exp5 = 0;
+ int hS_Exp2 = 0;
+ int hS_Exp5 = 0;
+
+ // Adjust for decimal exponent
+ if (dExp >= 0) {
+ dS_Exp2 += dExp;
+ dS_Exp5 += dExp;
+ }
+ else {
+ bS_Exp2 -= dExp;
+ bS_Exp5 -= dExp;
+ hS_Exp2 -= dExp;
+ hS_Exp5 -= dExp;
+ }
+
+ // Adjust for binary exponent
+ if (bExp >= 0)
+ bS_Exp2 += bExp;
+ else {
+ dS_Exp2 -= bExp;
+ hS_Exp2 -= bExp;
+ }
+
+ // Adjust for half ulp exponent
+ if (hExp >= 0)
+ hS_Exp2 += hExp;
+ else {
+ dS_Exp2 -= hExp;
+ bS_Exp2 -= hExp;
+ }
+
+ // Remove common power of two factor from all three scaled values
+ int common_Exp2 = std::min(dS_Exp2, std::min(bS_Exp2, hS_Exp2));
+ dS_Exp2 -= common_Exp2;
+ bS_Exp2 -= common_Exp2;
+ hS_Exp2 -= common_Exp2;
+
+ EXPECT_EQ(153, dS_Exp2);
+ EXPECT_EQ(0, dS_Exp5);
+ EXPECT_EQ(1, bS_Exp2);
+ EXPECT_EQ(49, bS_Exp5);
+ EXPECT_EQ(0, hS_Exp2);
+ EXPECT_EQ(49, hS_Exp5);
+
+ BigInteger dS = BIGINTEGER_LITERAL(dInt);
+ dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<size_t>(dS_Exp2);
+
+ BigInteger bS(bInt);
+ bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<size_t>(bS_Exp2);
+
+ BigInteger hS(1);
+ hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<size_t>(hS_Exp2);
+
+ EXPECT_TRUE(BIGINTEGER_LITERAL("203970822259994138521801764465966248930731085529088") == dS);
+ EXPECT_TRUE(BIGINTEGER_LITERAL("203970822259994122305215569213032722473144531250000") == bS);
+ EXPECT_TRUE(BIGINTEGER_LITERAL("17763568394002504646778106689453125") == hS);
+
+ EXPECT_EQ(1, dS.Compare(bS));
+
+ BigInteger delta(0);
+ EXPECT_FALSE(dS.Difference(bS, &delta));
+ EXPECT_TRUE(BIGINTEGER_LITERAL("16216586195252933526457586554279088") == delta);
+ EXPECT_TRUE(bS.Difference(dS, &delta));
+ EXPECT_TRUE(BIGINTEGER_LITERAL("16216586195252933526457586554279088") == delta);
+
+ EXPECT_EQ(-1, delta.Compare(hS));
+}
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
diff --git a/3rdparty/rapidjson/test/unittest/unittest.cpp b/3rdparty/rapidjson/test/unittest/unittest.cpp
new file mode 100644
index 00000000000..e0e8576ee21
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/unittest.cpp
@@ -0,0 +1,50 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+#include "rapidjson/rapidjson.h"
+
+#ifdef __clang__
+#pragma GCC diagnostic push
+#if __has_warning("-Wdeprecated")
+#pragma GCC diagnostic ignored "-Wdeprecated"
+#endif
+#endif
+
+AssertException::~AssertException() throw() {}
+
+#ifdef __clang__
+#pragma GCC diagnostic pop
+#endif
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ std::cout << "RapidJSON v" << RAPIDJSON_VERSION_STRING << std::endl;
+
+#ifdef _MSC_VER
+ _CrtMemState memoryState = { 0 };
+ _CrtMemCheckpoint(&memoryState);
+ //_CrtSetBreakAlloc(X);
+ //void *testWhetherMemoryLeakDetectionWorks = malloc(1);
+#endif
+
+ int ret = RUN_ALL_TESTS();
+
+#ifdef _MSC_VER
+ // Current gtest constantly leak 2 blocks at exit
+ _CrtMemDumpAllObjectsSince(&memoryState);
+#endif
+ return ret;
+}
diff --git a/3rdparty/rapidjson/test/unittest/unittest.h b/3rdparty/rapidjson/test/unittest/unittest.h
new file mode 100644
index 00000000000..e125bf88dc3
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/unittest.h
@@ -0,0 +1,135 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef UNITTEST_H_
+#define UNITTEST_H_
+
+// gtest indirectly included inttypes.h, without __STDC_CONSTANT_MACROS.
+#ifndef __STDC_CONSTANT_MACROS
+#ifdef __clang__
+#pragma GCC diagnostic push
+#if __has_warning("-Wreserved-id-macro")
+#pragma GCC diagnostic ignored "-Wreserved-id-macro"
+#endif
+#endif
+
+# define __STDC_CONSTANT_MACROS 1 // required by C++ standard
+
+#ifdef __clang__
+#pragma GCC diagnostic pop
+#endif
+#endif
+
+#ifdef _MSC_VER
+#define _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#pragma warning(disable : 4996) // 'function': was declared deprecated
+#endif
+
+#if defined(__clang__) || defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
+#if defined(__clang__) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+#pragma GCC diagnostic push
+#endif
+#pragma GCC diagnostic ignored "-Weffc++"
+#endif
+
+#include "gtest/gtest.h"
+#include <stdexcept>
+
+#if defined(__clang__) || defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+#pragma GCC diagnostic pop
+#endif
+
+#ifdef __clang__
+// All TEST() macro generated this warning, disable globally
+#pragma GCC diagnostic ignored "-Wglobal-constructors"
+#endif
+
+template <typename Ch>
+inline unsigned StrLen(const Ch* s) {
+ const Ch* p = s;
+ while (*p) p++;
+ return unsigned(p - s);
+}
+
+template<typename Ch>
+inline int StrCmp(const Ch* s1, const Ch* s2) {
+ while(*s1 && (*s1 == *s2)) { s1++; s2++; }
+ return static_cast<unsigned>(*s1) < static_cast<unsigned>(*s2) ? -1 : static_cast<unsigned>(*s1) > static_cast<unsigned>(*s2);
+}
+
+template <typename Ch>
+inline Ch* StrDup(const Ch* str) {
+ size_t bufferSize = sizeof(Ch) * (StrLen(str) + 1);
+ Ch* buffer = static_cast<Ch*>(malloc(bufferSize));
+ memcpy(buffer, str, bufferSize);
+ return buffer;
+}
+
+inline FILE* TempFile(char *filename) {
+#ifdef _MSC_VER
+ filename = tmpnam(filename);
+
+ // For Visual Studio, tmpnam() adds a backslash in front. Remove it.
+ if (filename[0] == '\\')
+ for (int i = 0; filename[i] != '\0'; i++)
+ filename[i] = filename[i + 1];
+
+ return fopen(filename, "wb");
+#else
+ strcpy(filename, "/tmp/fileXXXXXX");
+ int fd = mkstemp(filename);
+ return fdopen(fd, "w");
+#endif
+}
+
+// Use exception for catching assert
+#ifdef _MSC_VER
+#pragma warning(disable : 4127)
+#endif
+
+#ifdef __clang__
+#pragma GCC diagnostic push
+#if __has_warning("-Wdeprecated")
+#pragma GCC diagnostic ignored "-Wdeprecated"
+#endif
+#endif
+
+class AssertException : public std::logic_error {
+public:
+ AssertException(const char* w) : std::logic_error(w) {}
+ AssertException(const AssertException& rhs) : std::logic_error(rhs) {}
+ virtual ~AssertException() throw();
+};
+
+#ifdef __clang__
+#pragma GCC diagnostic pop
+#endif
+
+#define RAPIDJSON_ASSERT(x) if (!(x)) throw AssertException(RAPIDJSON_STRINGIFY(x))
+
+class Random {
+public:
+ Random(unsigned seed = 0) : mSeed(seed) {}
+
+ unsigned operator()() {
+ mSeed = 214013 * mSeed + 2531011;
+ return mSeed;
+ }
+
+private:
+ unsigned mSeed;
+};
+
+#endif // UNITTEST_H_
diff --git a/3rdparty/rapidjson/test/unittest/valuetest.cpp b/3rdparty/rapidjson/test/unittest/valuetest.cpp
new file mode 100644
index 00000000000..5e88a77e3a3
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/valuetest.cpp
@@ -0,0 +1,1498 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+#include "rapidjson/document.h"
+#include <algorithm>
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
+using namespace rapidjson;
+
+TEST(Value, DefaultConstructor) {
+ Value x;
+ EXPECT_EQ(kNullType, x.GetType());
+ EXPECT_TRUE(x.IsNull());
+
+ //std::cout << "sizeof(Value): " << sizeof(x) << std::endl;
+}
+
+// Should not pass compilation
+//TEST(Value, copy_constructor) {
+// Value x(1234);
+// Value y = x;
+//}
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+#if 0 // Many old compiler does not support these. Turn it off temporaily.
+
+#include <type_traits>
+
+TEST(Value, Traits) {
+ typedef GenericValue<UTF8<>, CrtAllocator> Value;
+ static_assert(std::is_constructible<Value>::value, "");
+ static_assert(std::is_default_constructible<Value>::value, "");
+#ifndef _MSC_VER
+ static_assert(!std::is_copy_constructible<Value>::value, "");
+#endif
+ static_assert(std::is_move_constructible<Value>::value, "");
+
+#ifndef _MSC_VER
+ static_assert(std::is_nothrow_constructible<Value>::value, "");
+ static_assert(std::is_nothrow_default_constructible<Value>::value, "");
+ static_assert(!std::is_nothrow_copy_constructible<Value>::value, "");
+ static_assert(std::is_nothrow_move_constructible<Value>::value, "");
+#endif
+
+ static_assert(std::is_assignable<Value,Value>::value, "");
+#ifndef _MSC_VER
+ static_assert(!std::is_copy_assignable<Value>::value, "");
+#endif
+ static_assert(std::is_move_assignable<Value>::value, "");
+
+#ifndef _MSC_VER
+ static_assert(std::is_nothrow_assignable<Value, Value>::value, "");
+#endif
+ static_assert(!std::is_nothrow_copy_assignable<Value>::value, "");
+#ifndef _MSC_VER
+ static_assert(std::is_nothrow_move_assignable<Value>::value, "");
+#endif
+
+ static_assert(std::is_destructible<Value>::value, "");
+#ifndef _MSC_VER
+ static_assert(std::is_nothrow_destructible<Value>::value, "");
+#endif
+}
+
+#endif
+
+TEST(Value, MoveConstructor) {
+ typedef GenericValue<UTF8<>, CrtAllocator> Value;
+ Value::AllocatorType allocator;
+
+ Value x((Value(kArrayType)));
+ x.Reserve(4u, allocator);
+ x.PushBack(1, allocator).PushBack(2, allocator).PushBack(3, allocator).PushBack(4, allocator);
+ EXPECT_TRUE(x.IsArray());
+ EXPECT_EQ(4u, x.Size());
+
+ // Value y(x); // does not compile (!is_copy_constructible)
+ Value y(std::move(x));
+ EXPECT_TRUE(x.IsNull());
+ EXPECT_TRUE(y.IsArray());
+ EXPECT_EQ(4u, y.Size());
+
+ // Value z = y; // does not compile (!is_copy_assignable)
+ Value z = std::move(y);
+ EXPECT_TRUE(y.IsNull());
+ EXPECT_TRUE(z.IsArray());
+ EXPECT_EQ(4u, z.Size());
+}
+
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+TEST(Value, AssignmentOperator) {
+ Value x(1234);
+ Value y;
+ y = x;
+ EXPECT_TRUE(x.IsNull()); // move semantic
+ EXPECT_EQ(1234, y.GetInt());
+
+ y = 5678;
+ EXPECT_TRUE(y.IsInt());
+ EXPECT_EQ(5678, y.GetInt());
+
+ x = "Hello";
+ EXPECT_TRUE(x.IsString());
+ EXPECT_STREQ(x.GetString(),"Hello");
+
+ y = StringRef(x.GetString(),x.GetStringLength());
+ EXPECT_TRUE(y.IsString());
+ EXPECT_EQ(y.GetString(),x.GetString());
+ EXPECT_EQ(y.GetStringLength(),x.GetStringLength());
+
+ static char mstr[] = "mutable";
+ // y = mstr; // should not compile
+ y = StringRef(mstr);
+ EXPECT_TRUE(y.IsString());
+ EXPECT_EQ(y.GetString(),mstr);
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ // C++11 move assignment
+ x = Value("World");
+ EXPECT_TRUE(x.IsString());
+ EXPECT_STREQ("World", x.GetString());
+
+ x = std::move(y);
+ EXPECT_TRUE(y.IsNull());
+ EXPECT_TRUE(x.IsString());
+ EXPECT_EQ(x.GetString(), mstr);
+
+ y = std::move(Value().SetInt(1234));
+ EXPECT_TRUE(y.IsInt());
+ EXPECT_EQ(1234, y);
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+}
+
+template <typename A, typename B>
+void TestEqual(const A& a, const B& b) {
+ EXPECT_TRUE (a == b);
+ EXPECT_FALSE(a != b);
+ EXPECT_TRUE (b == a);
+ EXPECT_FALSE(b != a);
+}
+
+template <typename A, typename B>
+void TestUnequal(const A& a, const B& b) {
+ EXPECT_FALSE(a == b);
+ EXPECT_TRUE (a != b);
+ EXPECT_FALSE(b == a);
+ EXPECT_TRUE (b != a);
+}
+
+TEST(Value, EqualtoOperator) {
+ Value::AllocatorType allocator;
+ Value x(kObjectType);
+ x.AddMember("hello", "world", allocator)
+ .AddMember("t", Value(true).Move(), allocator)
+ .AddMember("f", Value(false).Move(), allocator)
+ .AddMember("n", Value(kNullType).Move(), allocator)
+ .AddMember("i", 123, allocator)
+ .AddMember("pi", 3.14, allocator)
+ .AddMember("a", Value(kArrayType).Move().PushBack(1, allocator).PushBack(2, allocator).PushBack(3, allocator), allocator);
+
+ // Test templated operator==() and operator!=()
+ TestEqual(x["hello"], "world");
+ const char* cc = "world";
+ TestEqual(x["hello"], cc);
+ char* c = strdup("world");
+ TestEqual(x["hello"], c);
+ free(c);
+
+ TestEqual(x["t"], true);
+ TestEqual(x["f"], false);
+ TestEqual(x["i"], 123);
+ TestEqual(x["pi"], 3.14);
+
+ // Test operator==() (including different allocators)
+ CrtAllocator crtAllocator;
+ GenericValue<UTF8<>, CrtAllocator> y;
+ GenericDocument<UTF8<>, CrtAllocator> z(&crtAllocator);
+ y.CopyFrom(x, crtAllocator);
+ z.CopyFrom(y, z.GetAllocator());
+ TestEqual(x, y);
+ TestEqual(y, z);
+ TestEqual(z, x);
+
+ // Swapping member order should be fine.
+ EXPECT_TRUE(y.RemoveMember("t"));
+ TestUnequal(x, y);
+ TestUnequal(z, y);
+ EXPECT_TRUE(z.RemoveMember("t"));
+ TestUnequal(x, z);
+ TestEqual(y, z);
+ y.AddMember("t", false, crtAllocator);
+ z.AddMember("t", false, z.GetAllocator());
+ TestUnequal(x, y);
+ TestUnequal(z, x);
+ y["t"] = true;
+ z["t"] = true;
+ TestEqual(x, y);
+ TestEqual(y, z);
+ TestEqual(z, x);
+
+ // Swapping element order is not OK
+ x["a"][0].Swap(x["a"][1]);
+ TestUnequal(x, y);
+ x["a"][0].Swap(x["a"][1]);
+ TestEqual(x, y);
+
+ // Array of different size
+ x["a"].PushBack(4, allocator);
+ TestUnequal(x, y);
+ x["a"].PopBack();
+ TestEqual(x, y);
+
+ // Issue #129: compare Uint64
+ x.SetUint64(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFF0));
+ y.SetUint64(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF));
+ TestUnequal(x, y);
+}
+
+template <typename Value>
+void TestCopyFrom() {
+ typename Value::AllocatorType a;
+ Value v1(1234);
+ Value v2(v1, a); // deep copy constructor
+ EXPECT_TRUE(v1.GetType() == v2.GetType());
+ EXPECT_EQ(v1.GetInt(), v2.GetInt());
+
+ v1.SetString("foo");
+ v2.CopyFrom(v1, a);
+ EXPECT_TRUE(v1.GetType() == v2.GetType());
+ EXPECT_STREQ(v1.GetString(), v2.GetString());
+ EXPECT_EQ(v1.GetString(), v2.GetString()); // string NOT copied
+
+ v1.SetString("bar", a); // copy string
+ v2.CopyFrom(v1, a);
+ EXPECT_TRUE(v1.GetType() == v2.GetType());
+ EXPECT_STREQ(v1.GetString(), v2.GetString());
+ EXPECT_NE(v1.GetString(), v2.GetString()); // string copied
+
+
+ v1.SetArray().PushBack(1234, a);
+ v2.CopyFrom(v1, a);
+ EXPECT_TRUE(v2.IsArray());
+ EXPECT_EQ(v1.Size(), v2.Size());
+
+ v1.PushBack(Value().SetString("foo", a), a); // push string copy
+ EXPECT_TRUE(v1.Size() != v2.Size());
+ v2.CopyFrom(v1, a);
+ EXPECT_TRUE(v1.Size() == v2.Size());
+ EXPECT_STREQ(v1[1].GetString(), v2[1].GetString());
+ EXPECT_NE(v1[1].GetString(), v2[1].GetString()); // string got copied
+}
+
+TEST(Value, CopyFrom) {
+ TestCopyFrom<Value>();
+ TestCopyFrom<GenericValue<UTF8<>, CrtAllocator> >();
+}
+
+TEST(Value, Swap) {
+ Value v1(1234);
+ Value v2(kObjectType);
+
+ EXPECT_EQ(&v1, &v1.Swap(v2));
+ EXPECT_TRUE(v1.IsObject());
+ EXPECT_TRUE(v2.IsInt());
+ EXPECT_EQ(1234, v2.GetInt());
+
+ // testing std::swap compatibility
+ using std::swap;
+ swap(v1, v2);
+ EXPECT_TRUE(v1.IsInt());
+ EXPECT_TRUE(v2.IsObject());
+}
+
+TEST(Value, Null) {
+ // Default constructor
+ Value x;
+ EXPECT_EQ(kNullType, x.GetType());
+ EXPECT_TRUE(x.IsNull());
+
+ EXPECT_FALSE(x.IsTrue());
+ EXPECT_FALSE(x.IsFalse());
+ EXPECT_FALSE(x.IsNumber());
+ EXPECT_FALSE(x.IsString());
+ EXPECT_FALSE(x.IsObject());
+ EXPECT_FALSE(x.IsArray());
+
+ // Constructor with type
+ Value y(kNullType);
+ EXPECT_TRUE(y.IsNull());
+
+ // SetNull();
+ Value z(true);
+ z.SetNull();
+ EXPECT_TRUE(z.IsNull());
+}
+
+TEST(Value, True) {
+ // Constructor with bool
+ Value x(true);
+ EXPECT_EQ(kTrueType, x.GetType());
+ EXPECT_TRUE(x.GetBool());
+ EXPECT_TRUE(x.IsBool());
+ EXPECT_TRUE(x.IsTrue());
+
+ EXPECT_FALSE(x.IsNull());
+ EXPECT_FALSE(x.IsFalse());
+ EXPECT_FALSE(x.IsNumber());
+ EXPECT_FALSE(x.IsString());
+ EXPECT_FALSE(x.IsObject());
+ EXPECT_FALSE(x.IsArray());
+
+ // Constructor with type
+ Value y(kTrueType);
+ EXPECT_TRUE(y.IsTrue());
+
+ // SetBool()
+ Value z;
+ z.SetBool(true);
+ EXPECT_TRUE(z.IsTrue());
+}
+
+TEST(Value, False) {
+ // Constructor with bool
+ Value x(false);
+ EXPECT_EQ(kFalseType, x.GetType());
+ EXPECT_TRUE(x.IsBool());
+ EXPECT_TRUE(x.IsFalse());
+
+ EXPECT_FALSE(x.IsNull());
+ EXPECT_FALSE(x.IsTrue());
+ EXPECT_FALSE(x.GetBool());
+ //EXPECT_FALSE((bool)x);
+ EXPECT_FALSE(x.IsNumber());
+ EXPECT_FALSE(x.IsString());
+ EXPECT_FALSE(x.IsObject());
+ EXPECT_FALSE(x.IsArray());
+
+ // Constructor with type
+ Value y(kFalseType);
+ EXPECT_TRUE(y.IsFalse());
+
+ // SetBool()
+ Value z;
+ z.SetBool(false);
+ EXPECT_TRUE(z.IsFalse());
+}
+
+TEST(Value, Int) {
+ // Constructor with int
+ Value x(1234);
+ EXPECT_EQ(kNumberType, x.GetType());
+ EXPECT_EQ(1234, x.GetInt());
+ EXPECT_EQ(1234u, x.GetUint());
+ EXPECT_EQ(1234, x.GetInt64());
+ EXPECT_EQ(1234u, x.GetUint64());
+ EXPECT_NEAR(1234.0, x.GetDouble(), 0.0);
+ //EXPECT_EQ(1234, (int)x);
+ //EXPECT_EQ(1234, (unsigned)x);
+ //EXPECT_EQ(1234, (int64_t)x);
+ //EXPECT_EQ(1234, (uint64_t)x);
+ //EXPECT_EQ(1234, (double)x);
+ EXPECT_TRUE(x.IsNumber());
+ EXPECT_TRUE(x.IsInt());
+ EXPECT_TRUE(x.IsUint());
+ EXPECT_TRUE(x.IsInt64());
+ EXPECT_TRUE(x.IsUint64());
+
+ EXPECT_FALSE(x.IsDouble());
+ EXPECT_FALSE(x.IsNull());
+ EXPECT_FALSE(x.IsBool());
+ EXPECT_FALSE(x.IsFalse());
+ EXPECT_FALSE(x.IsTrue());
+ EXPECT_FALSE(x.IsString());
+ EXPECT_FALSE(x.IsObject());
+ EXPECT_FALSE(x.IsArray());
+
+ Value nx(-1234);
+ EXPECT_EQ(-1234, nx.GetInt());
+ EXPECT_EQ(-1234, nx.GetInt64());
+ EXPECT_TRUE(nx.IsInt());
+ EXPECT_TRUE(nx.IsInt64());
+ EXPECT_FALSE(nx.IsUint());
+ EXPECT_FALSE(nx.IsUint64());
+
+ // Constructor with type
+ Value y(kNumberType);
+ EXPECT_TRUE(y.IsNumber());
+ EXPECT_TRUE(y.IsInt());
+ EXPECT_EQ(0, y.GetInt());
+
+ // SetInt()
+ Value z;
+ z.SetInt(1234);
+ EXPECT_EQ(1234, z.GetInt());
+
+ // operator=(int)
+ z = 5678;
+ EXPECT_EQ(5678, z.GetInt());
+}
+
+TEST(Value, Uint) {
+ // Constructor with int
+ Value x(1234u);
+ EXPECT_EQ(kNumberType, x.GetType());
+ EXPECT_EQ(1234, x.GetInt());
+ EXPECT_EQ(1234u, x.GetUint());
+ EXPECT_EQ(1234, x.GetInt64());
+ EXPECT_EQ(1234u, x.GetUint64());
+ EXPECT_TRUE(x.IsNumber());
+ EXPECT_TRUE(x.IsInt());
+ EXPECT_TRUE(x.IsUint());
+ EXPECT_TRUE(x.IsInt64());
+ EXPECT_TRUE(x.IsUint64());
+ EXPECT_NEAR(1234.0, x.GetDouble(), 0.0); // Number can always be cast as double but !IsDouble().
+
+ EXPECT_FALSE(x.IsDouble());
+ EXPECT_FALSE(x.IsNull());
+ EXPECT_FALSE(x.IsBool());
+ EXPECT_FALSE(x.IsFalse());
+ EXPECT_FALSE(x.IsTrue());
+ EXPECT_FALSE(x.IsString());
+ EXPECT_FALSE(x.IsObject());
+ EXPECT_FALSE(x.IsArray());
+
+ // SetUint()
+ Value z;
+ z.SetUint(1234);
+ EXPECT_EQ(1234u, z.GetUint());
+
+ // operator=(unsigned)
+ z = 5678u;
+ EXPECT_EQ(5678u, z.GetUint());
+
+ z = 2147483648u; // 2^31, cannot cast as int
+ EXPECT_EQ(2147483648u, z.GetUint());
+ EXPECT_FALSE(z.IsInt());
+ EXPECT_TRUE(z.IsInt64()); // Issue 41: Incorrect parsing of unsigned int number types
+}
+
+TEST(Value, Int64) {
+ // Constructor with int
+ Value x(int64_t(1234));
+ EXPECT_EQ(kNumberType, x.GetType());
+ EXPECT_EQ(1234, x.GetInt());
+ EXPECT_EQ(1234u, x.GetUint());
+ EXPECT_EQ(1234, x.GetInt64());
+ EXPECT_EQ(1234u, x.GetUint64());
+ EXPECT_TRUE(x.IsNumber());
+ EXPECT_TRUE(x.IsInt());
+ EXPECT_TRUE(x.IsUint());
+ EXPECT_TRUE(x.IsInt64());
+ EXPECT_TRUE(x.IsUint64());
+
+ EXPECT_FALSE(x.IsDouble());
+ EXPECT_FALSE(x.IsNull());
+ EXPECT_FALSE(x.IsBool());
+ EXPECT_FALSE(x.IsFalse());
+ EXPECT_FALSE(x.IsTrue());
+ EXPECT_FALSE(x.IsString());
+ EXPECT_FALSE(x.IsObject());
+ EXPECT_FALSE(x.IsArray());
+
+ Value nx(int64_t(-1234));
+ EXPECT_EQ(-1234, nx.GetInt());
+ EXPECT_EQ(-1234, nx.GetInt64());
+ EXPECT_TRUE(nx.IsInt());
+ EXPECT_TRUE(nx.IsInt64());
+ EXPECT_FALSE(nx.IsUint());
+ EXPECT_FALSE(nx.IsUint64());
+
+ // SetInt64()
+ Value z;
+ z.SetInt64(1234);
+ EXPECT_EQ(1234, z.GetInt64());
+
+ z.SetInt64(2147483648u); // 2^31, cannot cast as int
+ EXPECT_FALSE(z.IsInt());
+ EXPECT_TRUE(z.IsUint());
+ EXPECT_NEAR(2147483648.0, z.GetDouble(), 0.0);
+
+ z.SetInt64(int64_t(4294967295u) + 1); // 2^32, cannot cast as uint
+ EXPECT_FALSE(z.IsInt());
+ EXPECT_FALSE(z.IsUint());
+ EXPECT_NEAR(4294967296.0, z.GetDouble(), 0.0);
+
+ z.SetInt64(-int64_t(2147483648u) - 1); // -2^31-1, cannot cast as int
+ EXPECT_FALSE(z.IsInt());
+ EXPECT_NEAR(-2147483649.0, z.GetDouble(), 0.0);
+
+ z.SetInt64(static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 00000000)));
+ EXPECT_DOUBLE_EQ(-9223372036854775808.0, z.GetDouble());
+}
+
+TEST(Value, Uint64) {
+ // Constructor with int
+ Value x(uint64_t(1234));
+ EXPECT_EQ(kNumberType, x.GetType());
+ EXPECT_EQ(1234, x.GetInt());
+ EXPECT_EQ(1234u, x.GetUint());
+ EXPECT_EQ(1234, x.GetInt64());
+ EXPECT_EQ(1234u, x.GetUint64());
+ EXPECT_TRUE(x.IsNumber());
+ EXPECT_TRUE(x.IsInt());
+ EXPECT_TRUE(x.IsUint());
+ EXPECT_TRUE(x.IsInt64());
+ EXPECT_TRUE(x.IsUint64());
+
+ EXPECT_FALSE(x.IsDouble());
+ EXPECT_FALSE(x.IsNull());
+ EXPECT_FALSE(x.IsBool());
+ EXPECT_FALSE(x.IsFalse());
+ EXPECT_FALSE(x.IsTrue());
+ EXPECT_FALSE(x.IsString());
+ EXPECT_FALSE(x.IsObject());
+ EXPECT_FALSE(x.IsArray());
+
+ // SetUint64()
+ Value z;
+ z.SetUint64(1234);
+ EXPECT_EQ(1234u, z.GetUint64());
+
+ z.SetUint64(uint64_t(2147483648u)); // 2^31, cannot cast as int
+ EXPECT_FALSE(z.IsInt());
+ EXPECT_TRUE(z.IsUint());
+ EXPECT_TRUE(z.IsInt64());
+
+ z.SetUint64(uint64_t(4294967295u) + 1); // 2^32, cannot cast as uint
+ EXPECT_FALSE(z.IsInt());
+ EXPECT_FALSE(z.IsUint());
+ EXPECT_TRUE(z.IsInt64());
+
+ z.SetUint64(RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)); // 2^63 cannot cast as int64
+ EXPECT_FALSE(z.IsInt64());
+ EXPECT_EQ(RAPIDJSON_UINT64_C2(0x80000000, 0x00000000), z.GetUint64()); // Issue 48
+ EXPECT_DOUBLE_EQ(9223372036854775808.0, z.GetDouble());
+}
+
+TEST(Value, Double) {
+ // Constructor with double
+ Value x(12.34);
+ EXPECT_EQ(kNumberType, x.GetType());
+ EXPECT_NEAR(12.34, x.GetDouble(), 0.0);
+ EXPECT_TRUE(x.IsNumber());
+ EXPECT_TRUE(x.IsDouble());
+
+ EXPECT_FALSE(x.IsInt());
+ EXPECT_FALSE(x.IsNull());
+ EXPECT_FALSE(x.IsBool());
+ EXPECT_FALSE(x.IsFalse());
+ EXPECT_FALSE(x.IsTrue());
+ EXPECT_FALSE(x.IsString());
+ EXPECT_FALSE(x.IsObject());
+ EXPECT_FALSE(x.IsArray());
+
+ // SetDouble()
+ Value z;
+ z.SetDouble(12.34);
+ EXPECT_NEAR(12.34, z.GetDouble(), 0.0);
+
+ z = 56.78;
+ EXPECT_NEAR(56.78, z.GetDouble(), 0.0);
+}
+
+TEST(Value, Float) {
+ // Constructor with double
+ Value x(12.34f);
+ EXPECT_EQ(kNumberType, x.GetType());
+ EXPECT_NEAR(12.34f, x.GetFloat(), 0.0);
+ EXPECT_TRUE(x.IsNumber());
+ EXPECT_TRUE(x.IsDouble());
+ EXPECT_TRUE(x.IsFloat());
+
+ EXPECT_FALSE(x.IsInt());
+ EXPECT_FALSE(x.IsNull());
+ EXPECT_FALSE(x.IsBool());
+ EXPECT_FALSE(x.IsFalse());
+ EXPECT_FALSE(x.IsTrue());
+ EXPECT_FALSE(x.IsString());
+ EXPECT_FALSE(x.IsObject());
+ EXPECT_FALSE(x.IsArray());
+
+ // SetFloat()
+ Value z;
+ z.SetFloat(12.34f);
+ EXPECT_NEAR(12.34f, z.GetFloat(), 0.0f);
+
+ z = 56.78f;
+ EXPECT_NEAR(56.78f, z.GetFloat(), 0.0f);
+}
+
+TEST(Value, IsLosslessDouble) {
+ EXPECT_TRUE(Value(12.34).IsLosslessDouble());
+ EXPECT_TRUE(Value(-123).IsLosslessDouble());
+ EXPECT_TRUE(Value(2147483648u).IsLosslessDouble());
+ EXPECT_TRUE(Value(static_cast<int64_t>(-RAPIDJSON_UINT64_C2(0x40000000, 0x00000000))).IsLosslessDouble());
+ EXPECT_TRUE(Value(RAPIDJSON_UINT64_C2(0xA0000000, 0x00000000)).IsLosslessDouble());
+
+ EXPECT_FALSE(Value(static_cast<int64_t>(-RAPIDJSON_UINT64_C2(0x7FFFFFFF, 0xFFFFFFFF))).IsLosslessDouble());
+ EXPECT_FALSE(Value(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF)).IsLosslessDouble());
+}
+
+TEST(Value, IsLosslessFloat) {
+ EXPECT_TRUE(Value(12.25).IsLosslessFloat());
+ EXPECT_TRUE(Value(-123).IsLosslessFloat());
+ EXPECT_TRUE(Value(2147483648u).IsLosslessFloat());
+ EXPECT_TRUE(Value(3.4028234e38f).IsLosslessFloat());
+ EXPECT_TRUE(Value(-3.4028234e38f).IsLosslessFloat());
+ EXPECT_FALSE(Value(3.4028235e38).IsLosslessFloat());
+ EXPECT_FALSE(Value(0.3).IsLosslessFloat());
+}
+
+TEST(Value, String) {
+ // Construction with const string
+ Value x("Hello", 5); // literal
+ EXPECT_EQ(kStringType, x.GetType());
+ EXPECT_TRUE(x.IsString());
+ EXPECT_STREQ("Hello", x.GetString());
+ EXPECT_EQ(5u, x.GetStringLength());
+
+ EXPECT_FALSE(x.IsNumber());
+ EXPECT_FALSE(x.IsNull());
+ EXPECT_FALSE(x.IsBool());
+ EXPECT_FALSE(x.IsFalse());
+ EXPECT_FALSE(x.IsTrue());
+ EXPECT_FALSE(x.IsObject());
+ EXPECT_FALSE(x.IsArray());
+
+ static const char cstr[] = "World"; // const array
+ Value(cstr).Swap(x);
+ EXPECT_TRUE(x.IsString());
+ EXPECT_EQ(x.GetString(), cstr);
+ EXPECT_EQ(x.GetStringLength(), sizeof(cstr)-1);
+
+ static char mstr[] = "Howdy"; // non-const array
+ // Value(mstr).Swap(x); // should not compile
+ Value(StringRef(mstr)).Swap(x);
+ EXPECT_TRUE(x.IsString());
+ EXPECT_EQ(x.GetString(), mstr);
+ EXPECT_EQ(x.GetStringLength(), sizeof(mstr)-1);
+ strncpy(mstr,"Hello", sizeof(mstr));
+ EXPECT_STREQ(x.GetString(), "Hello");
+
+ const char* pstr = cstr;
+ //Value(pstr).Swap(x); // should not compile
+ Value(StringRef(pstr)).Swap(x);
+ EXPECT_TRUE(x.IsString());
+ EXPECT_EQ(x.GetString(), cstr);
+ EXPECT_EQ(x.GetStringLength(), sizeof(cstr)-1);
+
+ char* mpstr = mstr;
+ Value(StringRef(mpstr,sizeof(mstr)-1)).Swap(x);
+ EXPECT_TRUE(x.IsString());
+ EXPECT_EQ(x.GetString(), mstr);
+ EXPECT_EQ(x.GetStringLength(), 5u);
+ EXPECT_STREQ(x.GetString(), "Hello");
+
+ // Constructor with copy string
+ MemoryPoolAllocator<> allocator;
+ Value c(x.GetString(), x.GetStringLength(), allocator);
+ EXPECT_NE(x.GetString(), c.GetString());
+ EXPECT_EQ(x.GetStringLength(), c.GetStringLength());
+ EXPECT_STREQ(x.GetString(), c.GetString());
+ //x.SetString("World");
+ x.SetString("World", 5);
+ EXPECT_STREQ("Hello", c.GetString());
+ EXPECT_EQ(5u, c.GetStringLength());
+
+ // Constructor with type
+ Value y(kStringType);
+ EXPECT_TRUE(y.IsString());
+ EXPECT_STREQ("", y.GetString()); // Empty string should be "" instead of 0 (issue 226)
+ EXPECT_EQ(0u, y.GetStringLength());
+
+ // SetConsttring()
+ Value z;
+ z.SetString("Hello");
+ EXPECT_TRUE(x.IsString());
+ z.SetString("Hello", 5);
+ EXPECT_STREQ("Hello", z.GetString());
+ EXPECT_STREQ("Hello", z.GetString());
+ EXPECT_EQ(5u, z.GetStringLength());
+
+ z.SetString("Hello");
+ EXPECT_TRUE(z.IsString());
+ EXPECT_STREQ("Hello", z.GetString());
+
+ //z.SetString(mstr); // should not compile
+ //z.SetString(pstr); // should not compile
+ z.SetString(StringRef(mstr));
+ EXPECT_TRUE(z.IsString());
+ EXPECT_STREQ(z.GetString(), mstr);
+
+ z.SetString(cstr);
+ EXPECT_TRUE(z.IsString());
+ EXPECT_EQ(cstr, z.GetString());
+
+ z = cstr;
+ EXPECT_TRUE(z.IsString());
+ EXPECT_EQ(cstr, z.GetString());
+
+ // SetString()
+ char s[] = "World";
+ Value w;
+ w.SetString(s, static_cast<SizeType>(strlen(s)), allocator);
+ s[0] = '\0';
+ EXPECT_STREQ("World", w.GetString());
+ EXPECT_EQ(5u, w.GetStringLength());
+
+#if RAPIDJSON_HAS_STDSTRING
+ {
+ std::string str = "Hello World";
+ str[5] = '\0';
+ EXPECT_STREQ(str.data(),"Hello"); // embedded '\0'
+ EXPECT_EQ(str.size(), 11u);
+
+ // no copy
+ Value vs0(StringRef(str));
+ EXPECT_TRUE(vs0.IsString());
+ EXPECT_EQ(vs0.GetString(), str.data());
+ EXPECT_EQ(vs0.GetStringLength(), str.size());
+ TestEqual(vs0, str);
+
+ // do copy
+ Value vs1(str, allocator);
+ EXPECT_TRUE(vs1.IsString());
+ EXPECT_NE(vs1.GetString(), str.data());
+ EXPECT_NE(vs1.GetString(), str); // not equal due to embedded '\0'
+ EXPECT_EQ(vs1.GetStringLength(), str.size());
+ TestEqual(vs1, str);
+
+ // SetString
+ str = "World";
+ vs0.SetNull().SetString(str, allocator);
+ EXPECT_TRUE(vs0.IsString());
+ EXPECT_STREQ(vs0.GetString(), str.c_str());
+ EXPECT_EQ(vs0.GetStringLength(), str.size());
+ TestEqual(str, vs0);
+ TestUnequal(str, vs1);
+
+ // vs1 = str; // should not compile
+ vs1 = StringRef(str);
+ TestEqual(str, vs1);
+ TestEqual(vs0, vs1);
+ }
+#endif // RAPIDJSON_HAS_STDSTRING
+}
+
+// Issue 226: Value of string type should not point to NULL
+TEST(Value, SetStringNullException) {
+ Value v;
+ EXPECT_THROW(v.SetString(0, 0), AssertException);
+}
+
+TEST(Value, Array) {
+ Value x(kArrayType);
+ const Value& y = x;
+ Value::AllocatorType allocator;
+
+ EXPECT_EQ(kArrayType, x.GetType());
+ EXPECT_TRUE(x.IsArray());
+ EXPECT_TRUE(x.Empty());
+ EXPECT_EQ(0u, x.Size());
+ EXPECT_TRUE(y.IsArray());
+ EXPECT_TRUE(y.Empty());
+ EXPECT_EQ(0u, y.Size());
+
+ EXPECT_FALSE(x.IsNull());
+ EXPECT_FALSE(x.IsBool());
+ EXPECT_FALSE(x.IsFalse());
+ EXPECT_FALSE(x.IsTrue());
+ EXPECT_FALSE(x.IsString());
+ EXPECT_FALSE(x.IsObject());
+
+ // PushBack()
+ Value v;
+ x.PushBack(v, allocator);
+ v.SetBool(true);
+ x.PushBack(v, allocator);
+ v.SetBool(false);
+ x.PushBack(v, allocator);
+ v.SetInt(123);
+ x.PushBack(v, allocator);
+ //x.PushBack((const char*)"foo", allocator); // should not compile
+ x.PushBack("foo", allocator);
+
+ EXPECT_FALSE(x.Empty());
+ EXPECT_EQ(5u, x.Size());
+ EXPECT_FALSE(y.Empty());
+ EXPECT_EQ(5u, y.Size());
+ EXPECT_TRUE(x[SizeType(0)].IsNull());
+ EXPECT_TRUE(x[1].IsTrue());
+ EXPECT_TRUE(x[2].IsFalse());
+ EXPECT_TRUE(x[3].IsInt());
+ EXPECT_EQ(123, x[3].GetInt());
+ EXPECT_TRUE(y[SizeType(0)].IsNull());
+ EXPECT_TRUE(y[1].IsTrue());
+ EXPECT_TRUE(y[2].IsFalse());
+ EXPECT_TRUE(y[3].IsInt());
+ EXPECT_EQ(123, y[3].GetInt());
+ EXPECT_TRUE(y[4].IsString());
+ EXPECT_STREQ("foo", y[4].GetString());
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ // PushBack(GenericValue&&, Allocator&);
+ {
+ Value y2(kArrayType);
+ y2.PushBack(Value(true), allocator);
+ y2.PushBack(std::move(Value(kArrayType).PushBack(Value(1), allocator).PushBack("foo", allocator)), allocator);
+ EXPECT_EQ(2u, y2.Size());
+ EXPECT_TRUE(y2[0].IsTrue());
+ EXPECT_TRUE(y2[1].IsArray());
+ EXPECT_EQ(2u, y2[1].Size());
+ EXPECT_TRUE(y2[1][0].IsInt());
+ EXPECT_TRUE(y2[1][1].IsString());
+ }
+#endif
+
+ // iterator
+ Value::ValueIterator itr = x.Begin();
+ EXPECT_TRUE(itr != x.End());
+ EXPECT_TRUE(itr->IsNull());
+ ++itr;
+ EXPECT_TRUE(itr != x.End());
+ EXPECT_TRUE(itr->IsTrue());
+ ++itr;
+ EXPECT_TRUE(itr != x.End());
+ EXPECT_TRUE(itr->IsFalse());
+ ++itr;
+ EXPECT_TRUE(itr != x.End());
+ EXPECT_TRUE(itr->IsInt());
+ EXPECT_EQ(123, itr->GetInt());
+ ++itr;
+ EXPECT_TRUE(itr != x.End());
+ EXPECT_TRUE(itr->IsString());
+ EXPECT_STREQ("foo", itr->GetString());
+
+ // const iterator
+ Value::ConstValueIterator citr = y.Begin();
+ EXPECT_TRUE(citr != y.End());
+ EXPECT_TRUE(citr->IsNull());
+ ++citr;
+ EXPECT_TRUE(citr != y.End());
+ EXPECT_TRUE(citr->IsTrue());
+ ++citr;
+ EXPECT_TRUE(citr != y.End());
+ EXPECT_TRUE(citr->IsFalse());
+ ++citr;
+ EXPECT_TRUE(citr != y.End());
+ EXPECT_TRUE(citr->IsInt());
+ EXPECT_EQ(123, citr->GetInt());
+ ++citr;
+ EXPECT_TRUE(citr != y.End());
+ EXPECT_TRUE(citr->IsString());
+ EXPECT_STREQ("foo", citr->GetString());
+
+ // PopBack()
+ x.PopBack();
+ EXPECT_EQ(4u, x.Size());
+ EXPECT_TRUE(y[SizeType(0)].IsNull());
+ EXPECT_TRUE(y[1].IsTrue());
+ EXPECT_TRUE(y[2].IsFalse());
+ EXPECT_TRUE(y[3].IsInt());
+
+ // Clear()
+ x.Clear();
+ EXPECT_TRUE(x.Empty());
+ EXPECT_EQ(0u, x.Size());
+ EXPECT_TRUE(y.Empty());
+ EXPECT_EQ(0u, y.Size());
+
+ // Erase(ValueIterator)
+
+ // Use array of array to ensure removed elements' destructor is called.
+ // [[0],[1],[2],...]
+ for (int i = 0; i < 10; i++)
+ x.PushBack(Value(kArrayType).PushBack(i, allocator).Move(), allocator);
+
+ // Erase the first
+ itr = x.Erase(x.Begin());
+ EXPECT_EQ(x.Begin(), itr);
+ EXPECT_EQ(9u, x.Size());
+ for (int i = 0; i < 9; i++)
+ EXPECT_EQ(i + 1, x[static_cast<SizeType>(i)][0].GetInt());
+
+ // Ease the last
+ itr = x.Erase(x.End() - 1);
+ EXPECT_EQ(x.End(), itr);
+ EXPECT_EQ(8u, x.Size());
+ for (int i = 0; i < 8; i++)
+ EXPECT_EQ(i + 1, x[static_cast<SizeType>(i)][0].GetInt());
+
+ // Erase the middle
+ itr = x.Erase(x.Begin() + 4);
+ EXPECT_EQ(x.Begin() + 4, itr);
+ EXPECT_EQ(7u, x.Size());
+ for (int i = 0; i < 4; i++)
+ EXPECT_EQ(i + 1, x[static_cast<SizeType>(i)][0].GetInt());
+ for (int i = 4; i < 7; i++)
+ EXPECT_EQ(i + 2, x[static_cast<SizeType>(i)][0].GetInt());
+
+ // Erase(ValueIterator, ValueIterator)
+ // Exhaustive test with all 0 <= first < n, first <= last <= n cases
+ const unsigned n = 10;
+ for (unsigned first = 0; first < n; first++) {
+ for (unsigned last = first; last <= n; last++) {
+ x.Clear();
+ for (unsigned i = 0; i < n; i++)
+ x.PushBack(Value(kArrayType).PushBack(i, allocator).Move(), allocator);
+
+ itr = x.Erase(x.Begin() + first, x.Begin() + last);
+ if (last == n)
+ EXPECT_EQ(x.End(), itr);
+ else
+ EXPECT_EQ(x.Begin() + first, itr);
+
+ size_t removeCount = last - first;
+ EXPECT_EQ(n - removeCount, x.Size());
+ for (unsigned i = 0; i < first; i++)
+ EXPECT_EQ(i, x[i][0].GetUint());
+ for (unsigned i = first; i < n - removeCount; i++)
+ EXPECT_EQ(i + removeCount, x[static_cast<SizeType>(i)][0].GetUint());
+ }
+ }
+
+ // Working in gcc without C++11, but VS2013 cannot compile. To be diagnosed.
+ // http://en.wikipedia.org/wiki/Erase-remove_idiom
+ x.Clear();
+ for (int i = 0; i < 10; i++)
+ if (i % 2 == 0)
+ x.PushBack(i, allocator);
+ else
+ x.PushBack(Value(kNullType).Move(), allocator);
+
+ const Value null(kNullType);
+ x.Erase(std::remove(x.Begin(), x.End(), null), x.End());
+ EXPECT_EQ(5u, x.Size());
+ for (int i = 0; i < 5; i++)
+ EXPECT_EQ(i * 2, x[static_cast<SizeType>(i)]);
+
+ // SetArray()
+ Value z;
+ z.SetArray();
+ EXPECT_TRUE(z.IsArray());
+ EXPECT_TRUE(z.Empty());
+}
+
+TEST(Value, Object) {
+ Value x(kObjectType);
+ const Value& y = x; // const version
+ Value::AllocatorType allocator;
+
+ EXPECT_EQ(kObjectType, x.GetType());
+ EXPECT_TRUE(x.IsObject());
+ EXPECT_TRUE(x.ObjectEmpty());
+ EXPECT_EQ(0u, x.MemberCount());
+ EXPECT_EQ(kObjectType, y.GetType());
+ EXPECT_TRUE(y.IsObject());
+ EXPECT_TRUE(y.ObjectEmpty());
+ EXPECT_EQ(0u, y.MemberCount());
+
+ // AddMember()
+ x.AddMember("A", "Apple", allocator);
+ EXPECT_FALSE(x.ObjectEmpty());
+ EXPECT_EQ(1u, x.MemberCount());
+
+ Value value("Banana", 6);
+ x.AddMember("B", "Banana", allocator);
+ EXPECT_EQ(2u, x.MemberCount());
+
+ // AddMember<T>(StringRefType, T, Allocator)
+ {
+ Value o(kObjectType);
+ o.AddMember("true", true, allocator);
+ o.AddMember("false", false, allocator);
+ o.AddMember("int", -1, allocator);
+ o.AddMember("uint", 1u, allocator);
+ o.AddMember("int64", int64_t(-4294967296), allocator);
+ o.AddMember("uint64", uint64_t(4294967296), allocator);
+ o.AddMember("double", 3.14, allocator);
+ o.AddMember("string", "Jelly", allocator);
+
+ EXPECT_TRUE(o["true"].GetBool());
+ EXPECT_FALSE(o["false"].GetBool());
+ EXPECT_EQ(-1, o["int"].GetInt());
+ EXPECT_EQ(1u, o["uint"].GetUint());
+ EXPECT_EQ(int64_t(-4294967296), o["int64"].GetInt64());
+ EXPECT_EQ(uint64_t(4294967296), o["uint64"].GetUint64());
+ EXPECT_STREQ("Jelly",o["string"].GetString());
+ EXPECT_EQ(8u, o.MemberCount());
+ }
+
+ // AddMember<T>(Value&, T, Allocator)
+ {
+ Value o(kObjectType);
+
+ Value n("s");
+ o.AddMember(n, "string", allocator);
+ EXPECT_EQ(1u, o.MemberCount());
+
+ Value count("#");
+ o.AddMember(count, o.MemberCount(), allocator);
+ EXPECT_EQ(2u, o.MemberCount());
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ {
+ // AddMember(StringRefType, const std::string&, Allocator)
+ Value o(kObjectType);
+ o.AddMember("b", std::string("Banana"), allocator);
+ EXPECT_STREQ("Banana", o["b"].GetString());
+
+ // RemoveMember(const std::string&)
+ o.RemoveMember(std::string("b"));
+ EXPECT_TRUE(o.ObjectEmpty());
+ }
+#endif
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ // AddMember(GenericValue&&, ...) variants
+ {
+ Value o(kObjectType);
+ o.AddMember(Value("true"), Value(true), allocator);
+ o.AddMember(Value("false"), Value(false).Move(), allocator); // value is lvalue ref
+ o.AddMember(Value("int").Move(), Value(-1), allocator); // name is lvalue ref
+ o.AddMember("uint", std::move(Value().SetUint(1u)), allocator); // name is literal, value is rvalue
+ EXPECT_TRUE(o["true"].GetBool());
+ EXPECT_FALSE(o["false"].GetBool());
+ EXPECT_EQ(-1, o["int"].GetInt());
+ EXPECT_EQ(1u, o["uint"].GetUint());
+ EXPECT_EQ(4u, o.MemberCount());
+ }
+#endif
+
+ // Tests a member with null character
+ Value name;
+ const Value C0D("C\0D", 3);
+ name.SetString(C0D.GetString(), 3);
+ value.SetString("CherryD", 7);
+ x.AddMember(name, value, allocator);
+
+ // HasMember()
+ EXPECT_TRUE(x.HasMember("A"));
+ EXPECT_TRUE(x.HasMember("B"));
+ EXPECT_TRUE(y.HasMember("A"));
+ EXPECT_TRUE(y.HasMember("B"));
+
+#if RAPIDJSON_HAS_STDSTRING
+ EXPECT_TRUE(x.HasMember(std::string("A")));
+#endif
+
+ name.SetString("C\0D");
+ EXPECT_TRUE(x.HasMember(name));
+ EXPECT_TRUE(y.HasMember(name));
+
+ GenericValue<UTF8<>, CrtAllocator> othername("A");
+ EXPECT_TRUE(x.HasMember(othername));
+ EXPECT_TRUE(y.HasMember(othername));
+ othername.SetString("C\0D");
+ EXPECT_TRUE(x.HasMember(othername));
+ EXPECT_TRUE(y.HasMember(othername));
+
+ // operator[]
+ EXPECT_STREQ("Apple", x["A"].GetString());
+ EXPECT_STREQ("Banana", x["B"].GetString());
+ EXPECT_STREQ("CherryD", x[C0D].GetString());
+ EXPECT_STREQ("CherryD", x[othername].GetString());
+ EXPECT_THROW(x["nonexist"], AssertException);
+
+ // const operator[]
+ EXPECT_STREQ("Apple", y["A"].GetString());
+ EXPECT_STREQ("Banana", y["B"].GetString());
+ EXPECT_STREQ("CherryD", y[C0D].GetString());
+
+#if RAPIDJSON_HAS_STDSTRING
+ EXPECT_STREQ("Apple", x["A"].GetString());
+ EXPECT_STREQ("Apple", y[std::string("A")].GetString());
+#endif
+
+ // member iterator
+ Value::MemberIterator itr = x.MemberBegin();
+ EXPECT_TRUE(itr != x.MemberEnd());
+ EXPECT_STREQ("A", itr->name.GetString());
+ EXPECT_STREQ("Apple", itr->value.GetString());
+ ++itr;
+ EXPECT_TRUE(itr != x.MemberEnd());
+ EXPECT_STREQ("B", itr->name.GetString());
+ EXPECT_STREQ("Banana", itr->value.GetString());
+ ++itr;
+ EXPECT_TRUE(itr != x.MemberEnd());
+ EXPECT_TRUE(memcmp(itr->name.GetString(), "C\0D", 4) == 0);
+ EXPECT_STREQ("CherryD", itr->value.GetString());
+ ++itr;
+ EXPECT_FALSE(itr != x.MemberEnd());
+
+ // const member iterator
+ Value::ConstMemberIterator citr = y.MemberBegin();
+ EXPECT_TRUE(citr != y.MemberEnd());
+ EXPECT_STREQ("A", citr->name.GetString());
+ EXPECT_STREQ("Apple", citr->value.GetString());
+ ++citr;
+ EXPECT_TRUE(citr != y.MemberEnd());
+ EXPECT_STREQ("B", citr->name.GetString());
+ EXPECT_STREQ("Banana", citr->value.GetString());
+ ++citr;
+ EXPECT_TRUE(citr != y.MemberEnd());
+ EXPECT_TRUE(memcmp(citr->name.GetString(), "C\0D", 4) == 0);
+ EXPECT_STREQ("CherryD", citr->value.GetString());
+ ++citr;
+ EXPECT_FALSE(citr != y.MemberEnd());
+
+ // member iterator conversions/relations
+ itr = x.MemberBegin();
+ citr = x.MemberBegin(); // const conversion
+ TestEqual(itr, citr);
+ EXPECT_TRUE(itr < x.MemberEnd());
+ EXPECT_FALSE(itr > y.MemberEnd());
+ EXPECT_TRUE(citr < x.MemberEnd());
+ EXPECT_FALSE(citr > y.MemberEnd());
+ ++citr;
+ TestUnequal(itr, citr);
+ EXPECT_FALSE(itr < itr);
+ EXPECT_TRUE(itr < citr);
+ EXPECT_FALSE(itr > itr);
+ EXPECT_TRUE(citr > itr);
+ EXPECT_EQ(1, citr - x.MemberBegin());
+ EXPECT_EQ(0, itr - y.MemberBegin());
+ itr += citr - x.MemberBegin();
+ EXPECT_EQ(1, itr - y.MemberBegin());
+ TestEqual(citr, itr);
+ EXPECT_TRUE(itr <= citr);
+ EXPECT_TRUE(citr <= itr);
+ itr++;
+ EXPECT_TRUE(itr >= citr);
+ EXPECT_FALSE(citr >= itr);
+
+ // RemoveMember()
+ EXPECT_TRUE(x.RemoveMember("A"));
+ EXPECT_FALSE(x.HasMember("A"));
+
+ EXPECT_TRUE(x.RemoveMember("B"));
+ EXPECT_FALSE(x.HasMember("B"));
+
+ EXPECT_FALSE(x.RemoveMember("nonexist"));
+
+ EXPECT_TRUE(x.RemoveMember(othername));
+ EXPECT_FALSE(x.HasMember(name));
+
+ EXPECT_TRUE(x.MemberBegin() == x.MemberEnd());
+
+ // EraseMember(ConstMemberIterator)
+
+ // Use array members to ensure removed elements' destructor is called.
+ // { "a": [0], "b": [1],[2],...]
+ const char keys[][2] = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j" };
+ for (int i = 0; i < 10; i++)
+ x.AddMember(keys[i], Value(kArrayType).PushBack(i, allocator), allocator);
+
+ // MemberCount, iterator difference
+ EXPECT_EQ(x.MemberCount(), SizeType(x.MemberEnd() - x.MemberBegin()));
+
+ // Erase the first
+ itr = x.EraseMember(x.MemberBegin());
+ EXPECT_FALSE(x.HasMember(keys[0]));
+ EXPECT_EQ(x.MemberBegin(), itr);
+ EXPECT_EQ(9u, x.MemberCount());
+ for (; itr != x.MemberEnd(); ++itr) {
+ size_t i = static_cast<size_t>((itr - x.MemberBegin())) + 1;
+ EXPECT_STREQ(itr->name.GetString(), keys[i]);
+ EXPECT_EQ(i, itr->value[0].GetInt());
+ }
+
+ // Erase the last
+ itr = x.EraseMember(x.MemberEnd() - 1);
+ EXPECT_FALSE(x.HasMember(keys[9]));
+ EXPECT_EQ(x.MemberEnd(), itr);
+ EXPECT_EQ(8u, x.MemberCount());
+ for (; itr != x.MemberEnd(); ++itr) {
+ size_t i = static_cast<size_t>(itr - x.MemberBegin()) + 1;
+ EXPECT_STREQ(itr->name.GetString(), keys[i]);
+ EXPECT_EQ(i, itr->value[0].GetInt());
+ }
+
+ // Erase the middle
+ itr = x.EraseMember(x.MemberBegin() + 4);
+ EXPECT_FALSE(x.HasMember(keys[5]));
+ EXPECT_EQ(x.MemberBegin() + 4, itr);
+ EXPECT_EQ(7u, x.MemberCount());
+ for (; itr != x.MemberEnd(); ++itr) {
+ size_t i = static_cast<size_t>(itr - x.MemberBegin());
+ i += (i < 4) ? 1 : 2;
+ EXPECT_STREQ(itr->name.GetString(), keys[i]);
+ EXPECT_EQ(i, itr->value[0].GetInt());
+ }
+
+ // EraseMember(ConstMemberIterator, ConstMemberIterator)
+ // Exhaustive test with all 0 <= first < n, first <= last <= n cases
+ const unsigned n = 10;
+ for (unsigned first = 0; first < n; first++) {
+ for (unsigned last = first; last <= n; last++) {
+ Value(kObjectType).Swap(x);
+ for (unsigned i = 0; i < n; i++)
+ x.AddMember(keys[i], Value(kArrayType).PushBack(i, allocator), allocator);
+
+ itr = x.EraseMember(x.MemberBegin() + static_cast<int>(first), x.MemberBegin() + static_cast<int>(last));
+ if (last == n)
+ EXPECT_EQ(x.MemberEnd(), itr);
+ else
+ EXPECT_EQ(x.MemberBegin() + static_cast<int>(first), itr);
+
+ size_t removeCount = last - first;
+ EXPECT_EQ(n - removeCount, x.MemberCount());
+ for (unsigned i = 0; i < first; i++)
+ EXPECT_EQ(i, x[keys[i]][0].GetUint());
+ for (unsigned i = first; i < n - removeCount; i++)
+ EXPECT_EQ(i + removeCount, x[keys[i+removeCount]][0].GetUint());
+ }
+ }
+
+ // RemoveAllMembers()
+ x.RemoveAllMembers();
+ EXPECT_TRUE(x.ObjectEmpty());
+ EXPECT_EQ(0u, x.MemberCount());
+
+ // SetObject()
+ Value z;
+ z.SetObject();
+ EXPECT_TRUE(z.IsObject());
+}
+
+TEST(Value, EraseMember_String) {
+ Value::AllocatorType allocator;
+ Value x(kObjectType);
+ x.AddMember("A", "Apple", allocator);
+ x.AddMember("B", "Banana", allocator);
+
+ EXPECT_TRUE(x.EraseMember("B"));
+ EXPECT_FALSE(x.HasMember("B"));
+
+ EXPECT_FALSE(x.EraseMember("nonexist"));
+
+ GenericValue<UTF8<>, CrtAllocator> othername("A");
+ EXPECT_TRUE(x.EraseMember(othername));
+ EXPECT_FALSE(x.HasMember("A"));
+
+ EXPECT_TRUE(x.MemberBegin() == x.MemberEnd());
+}
+
+TEST(Value, BigNestedArray) {
+ MemoryPoolAllocator<> allocator;
+ Value x(kArrayType);
+ static const SizeType n = 200;
+
+ for (SizeType i = 0; i < n; i++) {
+ Value y(kArrayType);
+ for (SizeType j = 0; j < n; j++) {
+ Value number(static_cast<int>(i * n + j));
+ y.PushBack(number, allocator);
+ }
+ x.PushBack(y, allocator);
+ }
+
+ for (SizeType i = 0; i < n; i++)
+ for (SizeType j = 0; j < n; j++) {
+ EXPECT_TRUE(x[i][j].IsInt());
+ EXPECT_EQ(static_cast<int>(i * n + j), x[i][j].GetInt());
+ }
+}
+
+TEST(Value, BigNestedObject) {
+ MemoryPoolAllocator<> allocator;
+ Value x(kObjectType);
+ static const SizeType n = 200;
+
+ for (SizeType i = 0; i < n; i++) {
+ char name1[10];
+ sprintf(name1, "%d", i);
+
+ // Value name(name1); // should not compile
+ Value name(name1, static_cast<SizeType>(strlen(name1)), allocator);
+ Value object(kObjectType);
+
+ for (SizeType j = 0; j < n; j++) {
+ char name2[10];
+ sprintf(name2, "%d", j);
+
+ Value name3(name2, static_cast<SizeType>(strlen(name2)), allocator);
+ Value number(static_cast<int>(i * n + j));
+ object.AddMember(name3, number, allocator);
+ }
+
+ // x.AddMember(name1, object, allocator); // should not compile
+ x.AddMember(name, object, allocator);
+ }
+
+ for (SizeType i = 0; i < n; i++) {
+ char name1[10];
+ sprintf(name1, "%d", i);
+
+ for (SizeType j = 0; j < n; j++) {
+ char name2[10];
+ sprintf(name2, "%d", j);
+ x[name1];
+ EXPECT_EQ(static_cast<int>(i * n + j), x[name1][name2].GetInt());
+ }
+ }
+}
+
+// Issue 18: Error removing last element of object
+// http://code.google.com/p/rapidjson/issues/detail?id=18
+TEST(Value, RemoveLastElement) {
+ rapidjson::Document doc;
+ rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
+ rapidjson::Value objVal(rapidjson::kObjectType);
+ objVal.AddMember("var1", 123, allocator);
+ objVal.AddMember("var2", "444", allocator);
+ objVal.AddMember("var3", 555, allocator);
+ EXPECT_TRUE(objVal.HasMember("var3"));
+ objVal.RemoveMember("var3"); // Assertion here in r61
+ EXPECT_FALSE(objVal.HasMember("var3"));
+}
+
+// Issue 38: Segmentation fault with CrtAllocator
+TEST(Document, CrtAllocator) {
+ typedef GenericValue<UTF8<>, CrtAllocator> V;
+
+ V::AllocatorType allocator;
+ V o(kObjectType);
+ o.AddMember("x", 1, allocator); // Should not call destructor on uninitialized name/value of newly allocated members.
+
+ V a(kArrayType);
+ a.PushBack(1, allocator); // Should not call destructor on uninitialized Value of newly allocated elements.
+}
+
+static void TestShortStringOptimization(const char* str) {
+ const rapidjson::SizeType len = static_cast<rapidjson::SizeType>(strlen(str));
+
+ rapidjson::Document doc;
+ rapidjson::Value val;
+ val.SetString(str, len, doc.GetAllocator());
+
+ EXPECT_EQ(val.GetStringLength(), len);
+ EXPECT_STREQ(val.GetString(), str);
+}
+
+TEST(Value, AllocateShortString) {
+ TestShortStringOptimization(""); // edge case: empty string
+ TestShortStringOptimization("12345678"); // regular case for short strings: 8 chars
+ TestShortStringOptimization("12345678901"); // edge case: 11 chars in 32-bit mode (=> short string)
+ TestShortStringOptimization("123456789012"); // edge case: 12 chars in 32-bit mode (=> regular string)
+ TestShortStringOptimization("123456789012345"); // edge case: 15 chars in 64-bit mode (=> short string)
+ TestShortStringOptimization("1234567890123456"); // edge case: 16 chars in 64-bit mode (=> regular string)
+}
+
+template <int e>
+struct TerminateHandler {
+ bool Null() { return e != 0; }
+ bool Bool(bool) { return e != 1; }
+ bool Int(int) { return e != 2; }
+ bool Uint(unsigned) { return e != 3; }
+ bool Int64(int64_t) { return e != 4; }
+ bool Uint64(uint64_t) { return e != 5; }
+ bool Double(double) { return e != 6; }
+ bool String(const char*, SizeType, bool) { return e != 7; }
+ bool StartObject() { return e != 8; }
+ bool Key(const char*, SizeType, bool) { return e != 9; }
+ bool EndObject(SizeType) { return e != 10; }
+ bool StartArray() { return e != 11; }
+ bool EndArray(SizeType) { return e != 12; }
+};
+
+#define TEST_TERMINATION(e, json)\
+{\
+ Document d; \
+ EXPECT_FALSE(d.Parse(json).HasParseError()); \
+ Reader reader; \
+ TerminateHandler<e> h;\
+ EXPECT_FALSE(d.Accept(h));\
+}
+
+TEST(Value, AcceptTerminationByHandler) {
+ TEST_TERMINATION(0, "[null]");
+ TEST_TERMINATION(1, "[true]");
+ TEST_TERMINATION(1, "[false]");
+ TEST_TERMINATION(2, "[-1]");
+ TEST_TERMINATION(3, "[2147483648]");
+ TEST_TERMINATION(4, "[-1234567890123456789]");
+ TEST_TERMINATION(5, "[9223372036854775808]");
+ TEST_TERMINATION(6, "[0.5]");
+ TEST_TERMINATION(7, "[\"a\"]");
+ TEST_TERMINATION(8, "[{}]");
+ TEST_TERMINATION(9, "[{\"a\":1}]");
+ TEST_TERMINATION(10, "[{}]");
+ TEST_TERMINATION(11, "{\"a\":[]}");
+ TEST_TERMINATION(12, "{\"a\":[]}");
+}
+
+struct ValueIntComparer {
+ bool operator()(const Value& lhs, const Value& rhs) const {
+ return lhs.GetInt() < rhs.GetInt();
+ }
+};
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+TEST(Value, Sorting) {
+ Value::AllocatorType allocator;
+ Value a(kArrayType);
+ a.PushBack(5, allocator);
+ a.PushBack(1, allocator);
+ a.PushBack(3, allocator);
+ std::sort(a.Begin(), a.End(), ValueIntComparer());
+ EXPECT_EQ(1, a[0].GetInt());
+ EXPECT_EQ(3, a[1].GetInt());
+ EXPECT_EQ(5, a[2].GetInt());
+}
+#endif
+
+// http://stackoverflow.com/questions/35222230/
+
+static void MergeDuplicateKey(Value& v, Value::AllocatorType& a) {
+ if (v.IsObject()) {
+ // Convert all key:value into key:[value]
+ for (Value::MemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
+ itr->value = Value(kArrayType).Move().PushBack(itr->value, a);
+
+ // Merge arrays if key is duplicated
+ for (Value::MemberIterator itr = v.MemberBegin(); itr != v.MemberEnd();) {
+ Value::MemberIterator itr2 = v.FindMember(itr->name);
+ if (itr != itr2) {
+ itr2->value.PushBack(itr->value[0], a);
+ itr = v.EraseMember(itr);
+ }
+ else
+ ++itr;
+ }
+
+ // Convert key:[values] back to key:value if there is only one value
+ for (Value::MemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) {
+ if (itr->value.Size() == 1)
+ itr->value = itr->value[0];
+ MergeDuplicateKey(itr->value, a); // Recursion on the value
+ }
+ }
+ else if (v.IsArray())
+ for (Value::ValueIterator itr = v.Begin(); itr != v.End(); ++itr)
+ MergeDuplicateKey(*itr, a);
+}
+
+TEST(Value, MergeDuplicateKey) {
+ Document d;
+ d.Parse(
+ "{"
+ " \"key1\": {"
+ " \"a\": \"asdf\","
+ " \"b\": \"foo\","
+ " \"b\": \"bar\","
+ " \"c\": \"fdas\""
+ " }"
+ "}");
+
+ Document d2;
+ d2.Parse(
+ "{"
+ " \"key1\": {"
+ " \"a\": \"asdf\","
+ " \"b\": ["
+ " \"foo\","
+ " \"bar\""
+ " ],"
+ " \"c\": \"fdas\""
+ " }"
+ "}");
+
+ EXPECT_NE(d2, d);
+ MergeDuplicateKey(d, d.GetAllocator());
+ EXPECT_EQ(d2, d);
+}
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
diff --git a/3rdparty/rapidjson/test/unittest/writertest.cpp b/3rdparty/rapidjson/test/unittest/writertest.cpp
new file mode 100644
index 00000000000..238aa79e72e
--- /dev/null
+++ b/3rdparty/rapidjson/test/unittest/writertest.cpp
@@ -0,0 +1,441 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include "unittest.h"
+
+#include "rapidjson/document.h"
+#include "rapidjson/reader.h"
+#include "rapidjson/writer.h"
+#include "rapidjson/stringbuffer.h"
+
+using namespace rapidjson;
+
+TEST(Writer, Compact) {
+ StringStream s("{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } ");
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ buffer.ShrinkToFit();
+ Reader reader;
+ reader.Parse<0>(s, writer);
+ EXPECT_STREQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3]}", buffer.GetString());
+ EXPECT_EQ(77u, buffer.GetSize());
+ EXPECT_TRUE(writer.IsComplete());
+}
+
+// json -> parse -> writer -> json
+#define TEST_ROUNDTRIP(json) \
+ { \
+ StringStream s(json); \
+ StringBuffer buffer; \
+ Writer<StringBuffer> writer(buffer); \
+ Reader reader; \
+ reader.Parse<kParseFullPrecisionFlag>(s, writer); \
+ EXPECT_STREQ(json, buffer.GetString()); \
+ EXPECT_TRUE(writer.IsComplete()); \
+ }
+
+TEST(Writer, Root) {
+ TEST_ROUNDTRIP("null");
+ TEST_ROUNDTRIP("true");
+ TEST_ROUNDTRIP("false");
+ TEST_ROUNDTRIP("0");
+ TEST_ROUNDTRIP("\"foo\"");
+ TEST_ROUNDTRIP("[]");
+ TEST_ROUNDTRIP("{}");
+}
+
+TEST(Writer, Int) {
+ TEST_ROUNDTRIP("[-1]");
+ TEST_ROUNDTRIP("[-123]");
+ TEST_ROUNDTRIP("[-2147483648]");
+}
+
+TEST(Writer, UInt) {
+ TEST_ROUNDTRIP("[0]");
+ TEST_ROUNDTRIP("[1]");
+ TEST_ROUNDTRIP("[123]");
+ TEST_ROUNDTRIP("[2147483647]");
+ TEST_ROUNDTRIP("[4294967295]");
+}
+
+TEST(Writer, Int64) {
+ TEST_ROUNDTRIP("[-1234567890123456789]");
+ TEST_ROUNDTRIP("[-9223372036854775808]");
+}
+
+TEST(Writer, Uint64) {
+ TEST_ROUNDTRIP("[1234567890123456789]");
+ TEST_ROUNDTRIP("[9223372036854775807]");
+}
+
+TEST(Writer, String) {
+ TEST_ROUNDTRIP("[\"Hello\"]");
+ TEST_ROUNDTRIP("[\"Hello\\u0000World\"]");
+ TEST_ROUNDTRIP("[\"\\\"\\\\/\\b\\f\\n\\r\\t\"]");
+
+#if RAPIDJSON_HAS_STDSTRING
+ {
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ writer.String(std::string("Hello\n"));
+ EXPECT_STREQ("\"Hello\\n\"", buffer.GetString());
+ }
+#endif
+}
+
+TEST(Writer, Double) {
+ TEST_ROUNDTRIP("[1.2345,1.2345678,0.123456789012,1234567.8]");
+ TEST_ROUNDTRIP("0.0");
+ TEST_ROUNDTRIP("-0.0"); // Issue #289
+ TEST_ROUNDTRIP("1e30");
+ TEST_ROUNDTRIP("1.0");
+ TEST_ROUNDTRIP("5e-324"); // Min subnormal positive double
+ TEST_ROUNDTRIP("2.225073858507201e-308"); // Max subnormal positive double
+ TEST_ROUNDTRIP("2.2250738585072014e-308"); // Min normal positive double
+ TEST_ROUNDTRIP("1.7976931348623157e308"); // Max double
+
+}
+
+TEST(Writer, Transcode) {
+ const char json[] = "{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3],\"dollar\":\"\x24\",\"cents\":\"\xC2\xA2\",\"euro\":\"\xE2\x82\xAC\",\"gclef\":\"\xF0\x9D\x84\x9E\"}";
+
+ // UTF8 -> UTF16 -> UTF8
+ {
+ StringStream s(json);
+ StringBuffer buffer;
+ Writer<StringBuffer, UTF16<>, UTF8<> > writer(buffer);
+ GenericReader<UTF8<>, UTF16<> > reader;
+ reader.Parse(s, writer);
+ EXPECT_STREQ(json, buffer.GetString());
+ }
+
+ // UTF8 -> UTF8 -> ASCII -> UTF8 -> UTF8
+ {
+ StringStream s(json);
+ StringBuffer buffer;
+ Writer<StringBuffer, UTF8<>, ASCII<> > writer(buffer);
+ Reader reader;
+ reader.Parse(s, writer);
+
+ StringBuffer buffer2;
+ Writer<StringBuffer> writer2(buffer2);
+ GenericReader<ASCII<>, UTF8<> > reader2;
+ StringStream s2(buffer.GetString());
+ reader2.Parse(s2, writer2);
+
+ EXPECT_STREQ(json, buffer2.GetString());
+ }
+}
+
+#include <sstream>
+
+class OStreamWrapper {
+public:
+ typedef char Ch;
+
+ OStreamWrapper(std::ostream& os) : os_(os) {}
+
+ Ch Peek() const { assert(false); return '\0'; }
+ Ch Take() { assert(false); return '\0'; }
+ size_t Tell() const { return 0; }
+
+ Ch* PutBegin() { assert(false); return 0; }
+ void Put(Ch c) { os_.put(c); }
+ void Flush() { os_.flush(); }
+ size_t PutEnd(Ch*) { assert(false); return 0; }
+
+private:
+ OStreamWrapper(const OStreamWrapper&);
+ OStreamWrapper& operator=(const OStreamWrapper&);
+
+ std::ostream& os_;
+};
+
+TEST(Writer, OStreamWrapper) {
+ StringStream s("{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3], \"u64\": 1234567890123456789, \"i64\":-1234567890123456789 } ");
+
+ std::stringstream ss;
+ OStreamWrapper os(ss);
+
+ Writer<OStreamWrapper> writer(os);
+
+ Reader reader;
+ reader.Parse<0>(s, writer);
+
+ std::string actual = ss.str();
+ EXPECT_STREQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3],\"u64\":1234567890123456789,\"i64\":-1234567890123456789}", actual.c_str());
+}
+
+TEST(Writer, AssertRootMayBeAnyValue) {
+#define T(x)\
+ {\
+ StringBuffer buffer;\
+ Writer<StringBuffer> writer(buffer);\
+ EXPECT_TRUE(x);\
+ }
+ T(writer.Bool(false));
+ T(writer.Bool(true));
+ T(writer.Null());
+ T(writer.Int(0));
+ T(writer.Uint(0));
+ T(writer.Int64(0));
+ T(writer.Uint64(0));
+ T(writer.Double(0));
+ T(writer.String("foo"));
+#undef T
+}
+
+TEST(Writer, AssertIncorrectObjectLevel) {
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ writer.StartObject();
+ writer.EndObject();
+ ASSERT_THROW(writer.EndObject(), AssertException);
+}
+
+TEST(Writer, AssertIncorrectArrayLevel) {
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ writer.StartArray();
+ writer.EndArray();
+ ASSERT_THROW(writer.EndArray(), AssertException);
+}
+
+TEST(Writer, AssertIncorrectEndObject) {
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ writer.StartObject();
+ ASSERT_THROW(writer.EndArray(), AssertException);
+}
+
+TEST(Writer, AssertIncorrectEndArray) {
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ writer.StartObject();
+ ASSERT_THROW(writer.EndArray(), AssertException);
+}
+
+TEST(Writer, AssertObjectKeyNotString) {
+#define T(x)\
+ {\
+ StringBuffer buffer;\
+ Writer<StringBuffer> writer(buffer);\
+ writer.StartObject();\
+ ASSERT_THROW(x, AssertException); \
+ }
+ T(writer.Bool(false));
+ T(writer.Bool(true));
+ T(writer.Null());
+ T(writer.Int(0));
+ T(writer.Uint(0));
+ T(writer.Int64(0));
+ T(writer.Uint64(0));
+ T(writer.Double(0));
+ T(writer.StartObject());
+ T(writer.StartArray());
+#undef T
+}
+
+TEST(Writer, AssertMultipleRoot) {
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+
+ writer.StartObject();
+ writer.EndObject();
+ ASSERT_THROW(writer.StartObject(), AssertException);
+
+ writer.Reset(buffer);
+ writer.Null();
+ ASSERT_THROW(writer.Int(0), AssertException);
+
+ writer.Reset(buffer);
+ writer.String("foo");
+ ASSERT_THROW(writer.StartArray(), AssertException);
+
+ writer.Reset(buffer);
+ writer.StartArray();
+ writer.EndArray();
+ //ASSERT_THROW(writer.Double(3.14), AssertException);
+}
+
+TEST(Writer, RootObjectIsComplete) {
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ EXPECT_FALSE(writer.IsComplete());
+ writer.StartObject();
+ EXPECT_FALSE(writer.IsComplete());
+ writer.String("foo");
+ EXPECT_FALSE(writer.IsComplete());
+ writer.Int(1);
+ EXPECT_FALSE(writer.IsComplete());
+ writer.EndObject();
+ EXPECT_TRUE(writer.IsComplete());
+}
+
+TEST(Writer, RootArrayIsComplete) {
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ EXPECT_FALSE(writer.IsComplete());
+ writer.StartArray();
+ EXPECT_FALSE(writer.IsComplete());
+ writer.String("foo");
+ EXPECT_FALSE(writer.IsComplete());
+ writer.Int(1);
+ EXPECT_FALSE(writer.IsComplete());
+ writer.EndArray();
+ EXPECT_TRUE(writer.IsComplete());
+}
+
+TEST(Writer, RootValueIsComplete) {
+#define T(x)\
+ {\
+ StringBuffer buffer;\
+ Writer<StringBuffer> writer(buffer);\
+ EXPECT_FALSE(writer.IsComplete()); \
+ x; \
+ EXPECT_TRUE(writer.IsComplete()); \
+ }
+ T(writer.Null());
+ T(writer.Bool(true));
+ T(writer.Bool(false));
+ T(writer.Int(0));
+ T(writer.Uint(0));
+ T(writer.Int64(0));
+ T(writer.Uint64(0));
+ T(writer.Double(0));
+ T(writer.String(""));
+#undef T
+}
+
+TEST(Writer, InvalidEncoding) {
+ // Fail in decoding invalid UTF-8 sequence http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
+ {
+ GenericStringBuffer<UTF16<> > buffer;
+ Writer<GenericStringBuffer<UTF16<> >, UTF8<>, UTF16<> > writer(buffer);
+ writer.StartArray();
+ EXPECT_FALSE(writer.String("\xfe"));
+ EXPECT_FALSE(writer.String("\xff"));
+ EXPECT_FALSE(writer.String("\xfe\xfe\xff\xff"));
+ writer.EndArray();
+ }
+
+ // Fail in encoding
+ {
+ StringBuffer buffer;
+ Writer<StringBuffer, UTF32<> > writer(buffer);
+ static const UTF32<>::Ch s[] = { 0x110000, 0 }; // Out of U+0000 to U+10FFFF
+ EXPECT_FALSE(writer.String(s));
+ }
+
+ // Fail in unicode escaping in ASCII output
+ {
+ StringBuffer buffer;
+ Writer<StringBuffer, UTF32<>, ASCII<> > writer(buffer);
+ static const UTF32<>::Ch s[] = { 0x110000, 0 }; // Out of U+0000 to U+10FFFF
+ EXPECT_FALSE(writer.String(s));
+ }
+}
+
+TEST(Writer, ValidateEncoding) {
+ {
+ StringBuffer buffer;
+ Writer<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteValidateEncodingFlag> writer(buffer);
+ writer.StartArray();
+ EXPECT_TRUE(writer.String("\x24")); // Dollar sign U+0024
+ EXPECT_TRUE(writer.String("\xC2\xA2")); // Cents sign U+00A2
+ EXPECT_TRUE(writer.String("\xE2\x82\xAC")); // Euro sign U+20AC
+ EXPECT_TRUE(writer.String("\xF0\x9D\x84\x9E")); // G clef sign U+1D11E
+ writer.EndArray();
+ EXPECT_STREQ("[\"\x24\",\"\xC2\xA2\",\"\xE2\x82\xAC\",\"\xF0\x9D\x84\x9E\"]", buffer.GetString());
+ }
+
+ // Fail in decoding invalid UTF-8 sequence http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
+ {
+ StringBuffer buffer;
+ Writer<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteValidateEncodingFlag> writer(buffer);
+ writer.StartArray();
+ EXPECT_FALSE(writer.String("\xfe"));
+ EXPECT_FALSE(writer.String("\xff"));
+ EXPECT_FALSE(writer.String("\xfe\xfe\xff\xff"));
+ writer.EndArray();
+ }
+}
+
+TEST(Writer, InvalidEventSequence) {
+ // {]
+ {
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ writer.StartObject();
+ EXPECT_THROW(writer.EndArray(), AssertException);
+ EXPECT_FALSE(writer.IsComplete());
+ }
+
+ // [}
+ {
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ writer.StartArray();
+ EXPECT_THROW(writer.EndObject(), AssertException);
+ EXPECT_FALSE(writer.IsComplete());
+ }
+
+ // { 1:
+ {
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ writer.StartObject();
+ EXPECT_THROW(writer.Int(1), AssertException);
+ EXPECT_FALSE(writer.IsComplete());
+ }
+}
+
+extern double zero; // clang -Wmissing-variable-declarations
+double zero = 0.0; // Use global variable to prevent compiler warning
+
+TEST(Writer, NaN) {
+ double nan = zero / zero;
+ EXPECT_TRUE(internal::Double(nan).IsNan());
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ EXPECT_FALSE(writer.Double(nan));
+}
+
+TEST(Writer, Inf) {
+ double inf = 1.0 / zero;
+ EXPECT_TRUE(internal::Double(inf).IsInf());
+ StringBuffer buffer;
+ {
+ Writer<StringBuffer> writer(buffer);
+ EXPECT_FALSE(writer.Double(inf));
+ }
+ {
+ Writer<StringBuffer> writer(buffer);
+ EXPECT_FALSE(writer.Double(-inf));
+ }
+}
+
+TEST(Writer, RawValue) {
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ writer.StartObject();
+ writer.Key("a");
+ writer.Int(1);
+ writer.Key("raw");
+ const char json[] = "[\"Hello\\nWorld\", 123.456]";
+ writer.RawValue(json, strlen(json), kArrayType);
+ writer.EndObject();
+ EXPECT_TRUE(writer.IsComplete());
+ EXPECT_STREQ("{\"a\":1,\"raw\":[\"Hello\\nWorld\", 123.456]}", buffer.GetString());
+}
diff --git a/3rdparty/rapidjson/travis-doxygen.sh b/3rdparty/rapidjson/travis-doxygen.sh
new file mode 100644
index 00000000000..e9eb6b9c2b9
--- /dev/null
+++ b/3rdparty/rapidjson/travis-doxygen.sh
@@ -0,0 +1,122 @@
+#!/bin/bash
+# Update Doxygen documentation after push to 'master'.
+# Author: @pah
+
+set -e
+
+DOXYGEN_VER=doxygen-1.8.7
+DOXYGEN_TAR=${DOXYGEN_VER}.linux.bin.tar.gz
+DOXYGEN_URL="http://ftp.stack.nl/pub/users/dimitri/${DOXYGEN_TAR}"
+DOXYGEN_BIN="/usr/local/bin/doxygen"
+
+: ${GITHUB_REPO:="miloyip/rapidjson"}
+GITHUB_HOST="github.com"
+GITHUB_CLONE="git://${GITHUB_HOST}/${GITHUB_REPO}"
+GITHUB_URL="https://${GITHUB_HOST}/${GITHUB_PUSH-${GITHUB_REPO}}"
+
+# if not set, ignore password
+#GIT_ASKPASS="${TRAVIS_BUILD_DIR}/gh_ignore_askpass.sh"
+
+skip() {
+ echo "$@" 1>&2
+ echo "Exiting..." 1>&2
+ exit 0
+}
+
+abort() {
+ echo "Error: $@" 1>&2
+ echo "Exiting..." 1>&2
+ exit 1
+}
+
+# TRAVIS_BUILD_DIR not set, exiting
+[ -d "${TRAVIS_BUILD_DIR-/nonexistent}" ] || \
+ abort '${TRAVIS_BUILD_DIR} not set or nonexistent.'
+
+# check for pull-requests
+[ "${TRAVIS_PULL_REQUEST}" = "false" ] || \
+ skip "Not running Doxygen for pull-requests."
+
+# check for branch name
+[ "${TRAVIS_BRANCH}" = "master" ] || \
+ skip "Running Doxygen only for updates on 'master' branch (current: ${TRAVIS_BRANCH})."
+
+# check for job number
+[ "${TRAVIS_JOB_NUMBER}" = "${TRAVIS_BUILD_NUMBER}.1" ] || \
+ skip "Running Doxygen only on first job of build ${TRAVIS_BUILD_NUMBER} (current: ${TRAVIS_JOB_NUMBER})."
+
+# install doxygen binary distribution
+doxygen_install()
+{
+ wget -O - "${DOXYGEN_URL}" | \
+ tar xz -C ${TMPDIR-/tmp} ${DOXYGEN_VER}/bin/doxygen
+ export PATH="${TMPDIR-/tmp}/${DOXYGEN_VER}/bin:$PATH"
+}
+
+doxygen_run()
+{
+ cd "${TRAVIS_BUILD_DIR}";
+ doxygen ${TRAVIS_BUILD_DIR}/build/doc/Doxyfile;
+ doxygen ${TRAVIS_BUILD_DIR}/build/doc/Doxyfile.zh-cn;
+}
+
+gh_pages_prepare()
+{
+ cd "${TRAVIS_BUILD_DIR}/build/doc";
+ [ ! -d "html" ] || \
+ abort "Doxygen target directory already exists."
+ git --version
+ git clone -b gh-pages "${GITHUB_CLONE}" html
+ cd html
+ # setup git config (with defaults)
+ git config user.name "${GIT_NAME-travis}"
+ git config user.email "${GIT_EMAIL-"travis@localhost"}"
+ # clean working dir
+ rm -f .git/index
+ git clean -df
+}
+
+gh_pages_commit() {
+ cd "${TRAVIS_BUILD_DIR}/build/doc/html";
+ echo "rapidjson.org" > CNAME
+ git add --all;
+ git diff-index --quiet HEAD || git commit -m "Automatic doxygen build";
+}
+
+gh_setup_askpass() {
+ cat > ${GIT_ASKPASS} <<EOF
+#!/bin/bash
+echo
+exit 0
+EOF
+ chmod a+x "$GIT_ASKPASS"
+}
+
+gh_pages_push() {
+ # check for secure variables
+ [ "${TRAVIS_SECURE_ENV_VARS}" = "true" ] || \
+ skip "Secure variables not available, not updating GitHub pages."
+ # check for GitHub access token
+ [ "${GH_TOKEN+set}" = set ] || \
+ skip "GitHub access token not available, not updating GitHub pages."
+ [ "${#GH_TOKEN}" -eq 40 ] || \
+ abort "GitHub token invalid: found ${#GH_TOKEN} characters, expected 40."
+
+ cd "${TRAVIS_BUILD_DIR}/build/doc/html";
+ # setup credentials (hide in "set -x" mode)
+ git remote set-url --push origin "${GITHUB_URL}"
+ git config credential.helper 'store'
+ # ( set +x ; git config credential.username "${GH_TOKEN}" )
+ ( set +x ; [ -f ${HOME}/.git-credentials ] || \
+ ( echo "https://${GH_TOKEN}:@${GITHUB_HOST}" > ${HOME}/.git-credentials ; \
+ chmod go-rw ${HOME}/.git-credentials ) )
+ # push to GitHub
+ git push origin gh-pages
+}
+
+doxygen_install
+gh_pages_prepare
+doxygen_run
+gh_pages_commit
+gh_pages_push
+