//-------------------------------------------------------------------------------------- // File: hdrdump.cpp // // HDR (RGBE) file content examination utility // // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. //-------------------------------------------------------------------------------------- #include #include #include #include namespace { //--------------------------------------------------------------------------------- struct handle_closer { void operator()(HANDLE h) noexcept { if (h) CloseHandle(h); } }; using ScopedHandle = std::unique_ptr; inline HANDLE safe_handle(HANDLE h) noexcept { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; } inline size_t FindEOL(const char* str) { size_t pos = 0; for (;;) { if (str[pos] == '\n') return pos; else if (str[pos] == '\0') return size_t(-1); ++pos; } } //-------------------------------------------------------------------------------------- HRESULT LoadTextureDataFromFile(_In_z_ const wchar_t* fileName, std::unique_ptr& hdrData ) { // open the file #if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) ScopedHandle hFile(safe_handle(CreateFile2(fileName, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, nullptr))); #else ScopedHandle hFile(safe_handle(CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr))); #endif if (!hFile) return HRESULT_FROM_WIN32(GetLastError()); // Get the file size FILE_STANDARD_INFO fileInfo; if (!GetFileInformationByHandleEx(hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo))) { return HRESULT_FROM_WIN32(GetLastError()); } // File is too big for 32-bit allocation, so reject read if (fileInfo.EndOfFile.HighPart > 0) { return E_FAIL; } // Need at least enough data to fill the basic header if (fileInfo.EndOfFile.LowPart <= 10) { return E_FAIL; } // create enough space for the file data size_t dataLen = std::min(fileInfo.EndOfFile.LowPart, 16384); hdrData.reset(new uint8_t[dataLen + 1]); if (!hdrData) { return E_OUTOFMEMORY; } // read the data in DWORD BytesRead = 0; if (!ReadFile(hFile.get(), hdrData.get(), static_cast(dataLen), &BytesRead, nullptr)) { return HRESULT_FROM_WIN32(GetLastError()); } if (BytesRead < dataLen) { return E_FAIL; } // Ensure buffer has an eof marker hdrData[dataLen] = 0; // Valid HDR requires "#?RADIANCE" or "#?RGBE" if (memcmp(hdrData.get(), "#?RADIANCE", 10) != 0 && memcmp(hdrData.get(), "#?RGBE", 6) != 0) { return E_FAIL; } return S_OK; } inline void OutputHeader(const uint8_t* hdrData, const wchar_t* fname) { wprintf(L"HDR %ls\n\n", fname); auto info = reinterpret_cast(hdrData); char buff[256] = {}; for (;;) { if (*info == '\n') { ++info; break; } size_t len = FindEOL(info); if (len == size_t(-1)) { wprintf(L"ERROR: Failed parsing header\n"); return; } strncpy_s(buff, info, std::min(255, len)); printf("%s\n", buff); info += len + 1; } size_t len = FindEOL(info); if (len == size_t(-1)) { wprintf(L"ERROR: Failed parsing header\n"); return; } strncpy_s(buff, info, std::min(255, len)); printf("%s\n", buff); } } int __cdecl wmain(int argc, wchar_t* argv[]) { if (argc < 2 || argc > 2) { printf("Usage: hdrdump \n"); return 0; } std::unique_ptr hdrData; HRESULT hr = LoadTextureDataFromFile(argv[1], hdrData); if (FAILED(hr)) { wprintf(L"ERROR: failed to load %ls\n", argv[1]); return -1; } OutputHeader(hdrData.get(), argv[1]); return 0; }