+ for (;;) {
+ /*
+ * Try to fetch the system directory.
+ *
+ * GetSystemDirectoryW() expects a buffer size in units
+ * of WCHARs, not bytes, and returns a directory path
+ * length in units of WCHARs, not bytes.
+ *
+ * For extra fun, if GetSystemDirectoryW() succeeds,
+ * the return value is the length of the directory
+ * path in units of WCHARs, *not* including the
+ * terminating '\0', but if it fails because the
+ * path string wouldn't fit, the return value is
+ * the length of the directory path in units of WCHARs,
+ * *including* the terminating '\0'.
+ */
+ system_directory_len = GetSystemDirectoryW(dll_directory,
+ system_directory_buf_len);
+ if (system_directory_len == 0)
+ error("GetSystemDirectoryW() failed");
+
+ /*
+ * Did the directory path fit in the buffer?
+ *
+ * As per the above, this means that the return value
+ * *plus 1*, so that the terminating '\0' is counted,
+ * is <= the buffer size.
+ *
+ * (If the directory path, complete with the terminating
+ * '\0', fits *exactly*, the return value would be the
+ * size of the buffer minus 1, as it doesn't count the
+ * terminating '\0', so the test below would succeed.
+ *
+ * If everything *but* the terminating '\0' fits,
+ * the return value would be the size of the buffer + 1,
+ * i.e., the size that the string in question would
+ * have required.
+ *
+ * The astute reader will note that returning the
+ * size of the buffer is not one of the two cases
+ * above, and should never happen.)
+ */
+ if ((system_directory_len + 1) <= system_directory_buf_len) {
+ /*
+ * No. We have a buffer that's large enough
+ * for our purposes.
+ */
+ break;
+ }
+
+ /*
+ * Yes. Grow the buffer.
+ *
+ * The space we'll need in the buffer for the system
+ * directory, in units of WCHARs, is system_directory_len,
+ * as that's the length of the system directory path
+ * including the terminating '\0'.
+ */
+ system_directory_buf_len = system_directory_len;
+
+ /*
+ * The size of the DLL directory buffer, in *bytes*, must
+ * be the number of WCHARs taken by the system directory,
+ * *minus* the terminating '\0' (as we'll overwrite that
+ * with the "\" of the "\Npcap" string), multiplied by
+ * sizeof(WCHAR) to convert it to the number of bytes,
+ * plus the size of the "\Npcap" string, in bytes (which
+ * will include the terminating '\0', as that will become
+ * the DLL path's terminating '\0').
+ */
+ dll_directory_buf_len =
+ ((system_directory_len - 1)*sizeof(WCHAR)) + sizeof npcap;
+ dll_directory = realloc(dll_directory, dll_directory_buf_len);
+ if (dll_directory == NULL)
+ error("Can't allocate string for Npcap directory");
+ }
+
+ /*
+ * OK, that worked.
+ *
+ * Now append \Npcap. We add the length of the system directory path,
+ * in WCHARs, *not* including the terminating '\0' (which, since
+ * GetSystemDirectoryW() succeeded, is the return value of
+ * GetSystemDirectoryW(), as per the above), to the pointer to the
+ * beginning of the path, to go past the end of the system directory
+ * to point to the terminating '\0'.
+ */
+ memcpy(dll_directory + system_directory_len, npcap, sizeof npcap);
+
+ /*
+ * Now add that as a system DLL directory.
+ */
+ if (!SetDllDirectoryW(dll_directory))
+ error("SetDllDirectory failed");
+
+ free(dll_directory);
+#endif // _WIN32
+
+ /*
+ * Initialize the netdissect code.
+ */
+ if (nd_init(ebuf, sizeof(ebuf)) == -1)
+ error("%s", ebuf);
+
+ memset(ndo, 0, sizeof(*ndo));
+ ndo_set_function_pointers(ndo);
+
+ cnt = -1;
+ device = NULL;
+ infile = NULL;
+ RFileName = NULL;
+ VFileName = NULL;
+ VFile = NULL;
+ WFileName = NULL;
+ dlt = -1;
+ if ((cp = strrchr(argv[0], PATH_SEPARATOR)) != NULL)
+ ndo->program_name = program_name = cp + 1;
+ else
+ ndo->program_name = program_name = argv[0];
+
+#if defined(HAVE_PCAP_WSOCKINIT)
+ if (pcap_wsockinit() != 0)
+ error("Attempting to initialize Winsock failed");
+#elif defined(HAVE_WSOCKINIT)
+ if (wsockinit() != 0)
+ error("Attempting to initialize Winsock failed");
+#endif
+
+ /*
+ * An explicit tzset() call is usually not needed as it happens
+ * implicitly the first time we call localtime() or mktime(),
+ * but in some cases (sandboxing, chroot) this may be too late.
+ */
+ tzset();
+
+ while (
+ (op = getopt_long(argc, argv, SHORTOPTS, longopts, NULL)) != -1)
+ switch (op) {