| 817 | } |
| 818 | |
| 819 | bool CsvParser::Open(std::wstring const& path, uint32_t processId) { |
| 820 | for (uint32_t i = 0; i < _countof(headerColumnIndex_); ++i) { |
| 821 | headerColumnIndex_[i] = SIZE_MAX; |
| 822 | } |
| 823 | cols_.clear(); |
| 824 | |
| 825 | if (_wfopen_s(&fp_, path.c_str(), L"r")) { |
| 826 | return false; |
| 827 | } |
| 828 | |
| 829 | // Remove UTF-8 marker if there is one. |
| 830 | if (fread(row_, 3, 1, fp_) != 1 || |
| 831 | row_[0] != -17 || // 0xef |
| 832 | row_[1] != -69 || // 0xbb |
| 833 | row_[2] != -65) { // 0xbf |
| 834 | fseek(fp_, 0, SEEK_SET); |
| 835 | } |
| 836 | |
| 837 | // Read the header and ensure required columns are present |
| 838 | ReadRow(); |
| 839 | |
| 840 | for (size_t i = 0, n = cols_.size(); i < n; ++i) { |
| 841 | auto h = FindHeader(cols_[i]); |
| 842 | switch (h) { |
| 843 | case KnownHeaderCount: |
| 844 | case UnknownHeader: |
| 845 | // This is fine for when processing ETLs for testing the middleware |
| 846 | // as there are columns in the CSV that do not have corresponding |
| 847 | // metrics so we can just ignore them. |
| 848 | break; |
| 849 | default: |
| 850 | if ((size_t)h < KnownHeaderCount) { |
| 851 | if (headerColumnIndex_[(size_t)h] != SIZE_MAX) { |
| 852 | std::wstring errorMessage = L"Duplicate column: "; |
| 853 | errorMessage += pmon::util::str::ToWide(cols_[i]); |
| 854 | Assert::Fail(errorMessage.c_str()); |
| 855 | } |
| 856 | else { |
| 857 | headerColumnIndex_[(size_t)h] = i; |
| 858 | } |
| 859 | break; |
| 860 | } |
| 861 | else { |
| 862 | std::wstring errorMessage = L"Index outside of known headers."; |
| 863 | Assert::Fail(errorMessage.c_str()); |
| 864 | } |
| 865 | } |
| 866 | } |
| 867 | |
| 868 | bool columnsOK = true; |
| 869 | CheckAll(headerColumnIndex_, &columnsOK, { Header_Application, |
| 870 | Header_ProcessID, |
| 871 | Header_SwapChainAddress, |
| 872 | Header_PresentRuntime, |
| 873 | Header_SyncInterval, |
| 874 | Header_PresentFlags, |
| 875 | Header_AllowsTearing, |
| 876 | Header_PresentMode, |