updater: Add windows updater module

This commit is contained in:
jp9000
2017-02-20 04:50:17 -08:00
parent 1355243697
commit 86862b672e
9 changed files with 2582 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
if(NOT ENABLE_WIN_UPDATER)
return()
endif()
if(NOT DEFINED STATIC_ZLIB_PATH OR "${STATIC_ZLIB_PATH}" STREQUAL "")
message(STATUS "STATIC_ZLIB_PATH not set, windows updater disabled")
return()
endif()
project(updater)
include_directories(${OBS_JANSSON_INCLUDE_DIRS})
include_directories(${LIBLZMA_INCLUDE_DIRS})
include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/libobs")
include_directories(${BLAKE2_INCLUDE_DIR})
find_package(ZLIB REQUIRED)
set(updater_HEADERS
../win-update-helpers.hpp
resource.h
updater.hpp
)
set(updater_SOURCES
../win-update-helpers.cpp
updater.cpp
patch.cpp
http.cpp
hash.cpp
updater.rc
)
add_definitions(-DNOMINMAX -DUNICODE -D_UNICODE)
if(MSVC)
add_compile_options("$<$<CONFIG:RelWithDebInfo>:/MT>")
endif()
add_executable(updater WIN32
${updater_HEADERS}
${updater_SOURCES}
)
target_link_libraries(updater
${OBS_JANSSON_IMPORT}
${STATIC_ZLIB_PATH}
lzma
blake2
comctl32
shell32
winhttp
)

View File

@@ -0,0 +1,61 @@
#include "updater.hpp"
#include <util/windows/WinHandle.hpp>
#include <vector>
using namespace std;
void HashToString(const uint8_t *in, wchar_t *out)
{
const wchar_t alphabet[] = L"0123456789abcdef";
for (int i = 0; i != BLAKE2_HASH_LENGTH; ++i) {
out[2 * i] = alphabet[in[i] / 16];
out[2 * i + 1] = alphabet[in[i] % 16];
}
out[BLAKE2_HASH_LENGTH * 2] = 0;
}
void StringToHash(const wchar_t *in, BYTE *out)
{
int temp;
for (int i = 0; i < BLAKE2_HASH_LENGTH; i++) {
swscanf_s(in + i * 2, L"%02x", &temp);
out[i] = (BYTE)temp;
}
}
bool CalculateFileHash(const wchar_t *path, BYTE *hash)
{
blake2b_state blake2;
if (blake2b_init(&blake2, BLAKE2_HASH_LENGTH) != 0)
return false;
WinHandle handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
nullptr, OPEN_EXISTING, 0, nullptr);
if (handle == INVALID_HANDLE_VALUE)
return false;
vector<BYTE> buf;
buf.resize(65536);
for (;;) {
DWORD read = 0;
if (!ReadFile(handle, buf.data(), (DWORD)buf.size(), &read,
nullptr))
return false;
if (!read)
break;
if (blake2b_update(&blake2, buf.data(), read) != 0)
return false;
}
if (blake2b_final(&blake2, hash, BLAKE2_HASH_LENGTH) != 0)
return false;
return true;
}

View File

@@ -0,0 +1,537 @@
#include "Updater.hpp"
#include <algorithm>
using namespace std;
#define MAX_BUF_SIZE 262144
#define READ_BUF_SIZE 32768
/* ------------------------------------------------------------------------ */
class ZipStream {
z_stream strm = {};
bool initialized = false;
public:
inline ~ZipStream()
{
if (initialized)
inflateEnd(&strm);
}
inline operator z_stream*() {return &strm;}
inline z_stream *operator->() {return &strm;}
inline bool inflate()
{
int ret = inflateInit2(&strm, 16 + MAX_WBITS);
initialized = (ret == Z_OK);
return initialized;
}
};
/* ------------------------------------------------------------------------ */
static bool ReadZippedHTTPData(string &responseBuf, z_stream *strm,
string &zipBuf, const uint8_t *buffer, DWORD outSize)
{
do {
strm->avail_in = outSize;
strm->next_in = buffer;
strm->avail_out = (uInt)zipBuf.size();
strm->next_out = (Bytef *)zipBuf.data();
int zret = inflate(strm, Z_NO_FLUSH);
if (zret != Z_STREAM_END && zret != Z_OK)
return false;
try {
responseBuf.append(zipBuf.data(),
zipBuf.size() - strm->avail_out);
} catch (...) {
return false;
}
} while (strm->avail_out == 0);
return true;
}
static bool ReadHTTPData(string &responseBuf, const uint8_t *buffer,
DWORD outSize)
{
try {
responseBuf.append((const char *)buffer, outSize);
} catch (...) {
return false;
}
return true;
}
bool HTTPPostData(const wchar_t *url,
const BYTE * data,
int dataLen,
const wchar_t *extraHeaders,
int * responseCode,
string & responseBuf)
{
HttpHandle hSession;
HttpHandle hConnect;
HttpHandle hRequest;
string zipBuf;
URL_COMPONENTS urlComponents = {};
bool secure = false;
wchar_t hostName[256];
wchar_t path[1024];
const wchar_t *acceptTypes[] = {L"*/*", nullptr};
responseBuf.clear();
/* -------------------------------------- *
* get URL components */
urlComponents.dwStructSize = sizeof(urlComponents);
urlComponents.lpszHostName = hostName;
urlComponents.dwHostNameLength = _countof(hostName);
urlComponents.lpszUrlPath = path;
urlComponents.dwUrlPathLength = _countof(path);
WinHttpCrackUrl(url, 0, 0, &urlComponents);
if (urlComponents.nPort == 443)
secure = true;
/* -------------------------------------- *
* connect to server */
hSession = WinHttpOpen(L"OBS Updater/2.1",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS,
0);
if (!hSession) {
*responseCode = -1;
return false;
}
hConnect = WinHttpConnect(hSession, hostName,
secure
? INTERNET_DEFAULT_HTTPS_PORT
: INTERNET_DEFAULT_HTTP_PORT, 0);
if (!hConnect) {
*responseCode = -2;
return false;
}
/* -------------------------------------- *
* request data */
hRequest = WinHttpOpenRequest(hConnect,
L"POST",
path,
nullptr,
WINHTTP_NO_REFERER,
acceptTypes,
secure
? WINHTTP_FLAG_SECURE |
WINHTTP_FLAG_REFRESH
: WINHTTP_FLAG_REFRESH);
if (!hRequest) {
*responseCode = -3;
return false;
}
bool bResults = !!WinHttpSendRequest(hRequest, extraHeaders,
extraHeaders ? -1 : 0,
(void *)data, dataLen, dataLen, 0);
/* -------------------------------------- *
* end request */
if (bResults) {
bResults = !!WinHttpReceiveResponse(hRequest, nullptr);
} else {
*responseCode = GetLastError();
return false;
}
/* -------------------------------------- *
* get headers */
wchar_t encoding[64];
DWORD encodingLen;
wchar_t statusCode[8];
DWORD statusCodeLen;
statusCodeLen = sizeof(statusCode);
if (!WinHttpQueryHeaders(hRequest,
WINHTTP_QUERY_STATUS_CODE,
WINHTTP_HEADER_NAME_BY_INDEX,
&statusCode,
&statusCodeLen,
WINHTTP_NO_HEADER_INDEX)) {
*responseCode = -4;
return false;
} else {
statusCode[_countof(statusCode) - 1] = 0;
}
encodingLen = sizeof(encoding);
if (!WinHttpQueryHeaders(hRequest,
WINHTTP_QUERY_CONTENT_ENCODING,
WINHTTP_HEADER_NAME_BY_INDEX,
encoding,
&encodingLen,
WINHTTP_NO_HEADER_INDEX)) {
encoding[0] = 0;
if (GetLastError() != ERROR_WINHTTP_HEADER_NOT_FOUND) {
*responseCode = -5;
return false;
}
} else {
encoding[_countof(encoding) - 1] = 0;
}
/* -------------------------------------- *
* allocate response data */
DWORD responseBufSize = MAX_BUF_SIZE;
try {
responseBuf.reserve(responseBufSize);
} catch (...) {
*responseCode = -6;
return false;
}
/* -------------------------------------- *
* if zipped, initialize zip data */
ZipStream strm;
bool gzip = wcscmp(encoding, L"gzip") == 0;
if (gzip) {
strm->zalloc = Z_NULL;
strm->zfree = Z_NULL;
strm->opaque = Z_NULL;
strm->avail_in = 0;
strm->next_in = Z_NULL;
if (!strm.inflate())
return false;
try {
zipBuf.resize(MAX_BUF_SIZE);
} catch (...) {
*responseCode = -6;
return false;
}
}
/* -------------------------------------- *
* read data */
*responseCode = wcstoul(statusCode, nullptr, 10);
/* are we supposed to return true here? */
if (!bResults || *responseCode != 200)
return true;
BYTE buffer[READ_BUF_SIZE];
DWORD dwSize, outSize;
do {
/* Check for available data. */
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) {
*responseCode = -8;
return false;
}
dwSize = std::min(dwSize, (DWORD)sizeof(buffer));
if (!WinHttpReadData(hRequest, (void *)buffer, dwSize,
&outSize)) {
*responseCode = -9;
return false;
}
if (!outSize)
break;
if (gzip) {
if (!ReadZippedHTTPData(responseBuf, strm, zipBuf,
buffer, outSize)) {
*responseCode = -6;
return false;
}
} else {
if (!ReadHTTPData(responseBuf, buffer, outSize)) {
*responseCode = -6;
return false;
}
}
if (WaitForSingleObject(cancelRequested, 0) == WAIT_OBJECT_0) {
*responseCode = -14;
return false;
}
} while (dwSize > 0);
return true;
}
/* ------------------------------------------------------------------------ */
static bool ReadHTTPZippedFile(z_stream *strm, HANDLE updateFile,
string &zipBuf, const uint8_t *buffer, DWORD outSize,
int *responseCode)
{
do {
strm->avail_in = outSize;
strm->next_in = buffer;
strm->avail_out = (uInt)zipBuf.size();
strm->next_out = (Bytef *)zipBuf.data();
int zret = inflate(strm, Z_NO_FLUSH);
if (zret != Z_STREAM_END && zret != Z_OK)
return false;
DWORD written;
if (!WriteFile(updateFile,
zipBuf.data(),
MAX_BUF_SIZE - strm->avail_out,
&written,
nullptr)) {
*responseCode = -10;
return false;
}
if (written != MAX_BUF_SIZE - strm->avail_out) {
*responseCode = -11;
return false;
}
completedFileSize += written;
} while (strm->avail_out == 0);
return true;
}
static bool ReadHTTPFile(HANDLE updateFile, const uint8_t *buffer,
DWORD outSize, int *responseCode)
{
DWORD written;
if (!WriteFile(updateFile, buffer, outSize, &written, nullptr)) {
*responseCode = -12;
return false;
}
if (written != outSize) {
*responseCode = -13;
return false;
}
completedFileSize += outSize;
return true;
}
bool HTTPGetFile(HINTERNET hConnect,
const wchar_t *url,
const wchar_t *outputPath,
const wchar_t *extraHeaders,
int * responseCode)
{
HttpHandle hRequest;
const wchar_t *acceptTypes[] = {L"*/*", nullptr};
URL_COMPONENTS urlComponents = {};
bool secure = false;
string zipBuf;
wchar_t hostName[256];
wchar_t path[1024];
/* -------------------------------------- *
* get URL components */
urlComponents.dwStructSize = sizeof(urlComponents);
urlComponents.lpszHostName = hostName;
urlComponents.dwHostNameLength = _countof(hostName);
urlComponents.lpszUrlPath = path;
urlComponents.dwUrlPathLength = _countof(path);
WinHttpCrackUrl(url, 0, 0, &urlComponents);
if (urlComponents.nPort == 443)
secure = true;
/* -------------------------------------- *
* request data */
hRequest = WinHttpOpenRequest(hConnect,
L"GET",
path,
nullptr,
WINHTTP_NO_REFERER,
acceptTypes,
secure
? WINHTTP_FLAG_SECURE |
WINHTTP_FLAG_REFRESH
: WINHTTP_FLAG_REFRESH);
if (!hRequest) {
*responseCode = -3;
return false;
}
bool bResults = !!WinHttpSendRequest(hRequest, extraHeaders,
extraHeaders ? -1 : 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
/* -------------------------------------- *
* end request */
if (bResults) {
bResults = !!WinHttpReceiveResponse(hRequest, nullptr);
} else {
*responseCode = GetLastError();
return false;
}
/* -------------------------------------- *
* get headers */
wchar_t encoding[64];
DWORD encodingLen;
wchar_t statusCode[8];
DWORD statusCodeLen;
statusCodeLen = sizeof(statusCode);
if (!WinHttpQueryHeaders(hRequest,
WINHTTP_QUERY_STATUS_CODE,
WINHTTP_HEADER_NAME_BY_INDEX,
&statusCode,
&statusCodeLen,
WINHTTP_NO_HEADER_INDEX)) {
*responseCode = -4;
return false;
} else {
statusCode[_countof(statusCode) - 1] = 0;
}
encodingLen = sizeof(encoding);
if (!WinHttpQueryHeaders(hRequest,
WINHTTP_QUERY_CONTENT_ENCODING,
WINHTTP_HEADER_NAME_BY_INDEX,
encoding,
&encodingLen,
WINHTTP_NO_HEADER_INDEX)) {
encoding[0] = 0;
if (GetLastError() != ERROR_WINHTTP_HEADER_NOT_FOUND) {
*responseCode = -5;
return false;
}
} else {
encoding[_countof(encoding) - 1] = 0;
}
/* -------------------------------------- *
* allocate response data */
ZipStream strm;
bool gzip = wcscmp(encoding, L"gzip") == 0;
if (gzip) {
strm->zalloc = Z_NULL;
strm->zfree = Z_NULL;
strm->opaque = Z_NULL;
strm->avail_in = 0;
strm->next_in = Z_NULL;
if (!strm.inflate())
return false;
try {
zipBuf.resize(MAX_BUF_SIZE);
} catch (...) {
*responseCode = -6;
return false;
}
}
/* -------------------------------------- *
* read data */
*responseCode = wcstoul(statusCode, nullptr, 10);
/* are we supposed to return true here? */
if (!bResults || *responseCode != 200)
return true;
BYTE buffer[READ_BUF_SIZE];
DWORD dwSize, outSize;
int lastPosition = 0;
WinHandle updateFile = CreateFile(outputPath, GENERIC_WRITE, 0,
nullptr, CREATE_ALWAYS, 0, nullptr);
if (!updateFile.Valid()) {
*responseCode = -7;
return false;
}
do {
/* Check for available data. */
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) {
*responseCode = -8;
return false;
}
dwSize = std::min(dwSize, (DWORD)sizeof(buffer));
if (!WinHttpReadData(hRequest, (void *)buffer, dwSize,
&outSize)) {
*responseCode = -9;
return false;
} else {
if (!outSize)
break;
if (gzip) {
if (!ReadHTTPZippedFile(strm, updateFile,
zipBuf, buffer,
outSize, responseCode))
return false;
} else {
if (!ReadHTTPFile(updateFile, buffer,
outSize, responseCode))
return false;
}
int position = (int)(((float)completedFileSize /
(float)totalFileSize) * 100.0f);
if (position > lastPosition) {
lastPosition = position;
SendDlgItemMessage(hwndMain, IDC_PROGRESS,
PBM_SETPOS, position, 0);
}
}
if (WaitForSingleObject(cancelRequested, 0) == WAIT_OBJECT_0) {
*responseCode = -14;
return false;
}
} while (dwSize > 0);
return true;
}

View File

@@ -0,0 +1,301 @@
#include "updater.hpp"
#include <stdint.h>
#include <vector>
#include <lzma.h>
using namespace std;
#define MAX_BUF_SIZE 262144
#define READ_BUF_SIZE 32768
/* ------------------------------------------------------------------------ */
class LZMAStream {
lzma_stream strm = {};
bool initialized = false;
public:
inline ~LZMAStream()
{
if (initialized) {
lzma_end(&strm);
}
}
inline bool init_decoder()
{
lzma_ret ret = lzma_stream_decoder(
&strm,
200 * 1024 * 1024,
0);
initialized = (ret == LZMA_OK);
return initialized;
}
inline operator lzma_stream *() { return &strm; }
inline bool operator!() const { return !initialized; }
inline lzma_stream *get() { return &strm; }
};
class File {
FILE *f = nullptr;
public:
inline ~File()
{
if (f)
fclose(f);
}
inline FILE **operator&() { return &f; }
inline operator FILE *() const { return f; }
inline bool operator!() const { return !f; }
};
/* ------------------------------------------------------------------------ */
struct bspatch_stream {
void *opaque;
int (*read)(const struct bspatch_stream *stream, void *buffer,
int length);
};
/* ------------------------------------------------------------------------ */
static int64_t offtin(const uint8_t *buf)
{
int64_t y;
y = buf[7] & 0x7F;
y = y * 256;
y += buf[6];
y = y * 256;
y += buf[5];
y = y * 256;
y += buf[4];
y = y * 256;
y += buf[3];
y = y * 256;
y += buf[2];
y = y * 256;
y += buf[1];
y = y * 256;
y += buf[0];
if (buf[7] & 0x80)
y = -y;
return y;
}
/* ------------------------------------------------------------------------ */
static int bspatch(const uint8_t *old, int64_t oldsize, uint8_t *newp,
int64_t newsize, struct bspatch_stream *stream)
{
uint8_t buf[8];
int64_t oldpos, newpos;
int64_t ctrl[3];
int64_t i;
oldpos = 0;
newpos = 0;
while (newpos < newsize) {
/* Read control data */
for (i = 0; i <= 2; i++) {
if (stream->read(stream, buf, 8))
return -1;
ctrl[i] = offtin(buf);
};
/* Sanity-check */
if (newpos + ctrl[0] > newsize)
return -1;
/* Read diff string */
if (stream->read(stream, newp + newpos, (int)ctrl[0]))
return -1;
/* Add old data to diff string */
for (i = 0; i < ctrl[0]; i++)
if ((oldpos + i >= 0) && (oldpos + i < oldsize))
newp[newpos + i] += old[oldpos + i];
/* Adjust pointers */
newpos += ctrl[0];
oldpos += ctrl[0];
/* Sanity-check */
if (newpos + ctrl[1] > newsize)
return -1;
/* Read extra string */
if (stream->read(stream, newp + newpos, (int)ctrl[1]))
return -1;
/* Adjust pointers */
newpos += ctrl[1];
oldpos += ctrl[2];
};
return 0;
}
/* ------------------------------------------------------------------------ */
struct patch_data {
HANDLE h;
lzma_stream *strm;
uint8_t buf[READ_BUF_SIZE];
};
static int read_lzma(const struct bspatch_stream *stream, void *buffer, int len)
{
if (!len)
return 0;
patch_data *data = (patch_data*)stream->opaque;
HANDLE h = data->h;
lzma_stream *strm = data->strm;
strm->avail_out = (size_t)len;
strm->next_out = (uint8_t *)buffer;
for (;;) {
if (strm->avail_in == 0) {
DWORD read_size;
if (!ReadFile(h, data->buf, READ_BUF_SIZE, &read_size,
nullptr))
return -1;
if (read_size == 0)
return -1;
strm->avail_in = (size_t)read_size;
strm->next_in = data->buf;
}
lzma_ret ret = lzma_code(strm, LZMA_RUN);
if (ret == LZMA_STREAM_END)
return 0;
if (ret != LZMA_OK)
return -1;
if (strm->avail_out == 0)
break;
}
return 0;
}
int ApplyPatch(const wchar_t *patchFile, const wchar_t *targetFile)
try {
uint8_t header[24];
int64_t newsize;
struct bspatch_stream stream;
bool success;
WinHandle hPatch;
WinHandle hTarget;
LZMAStream strm;
/* --------------------------------- *
* open patch and file to patch */
hPatch = CreateFile(patchFile, GENERIC_READ, 0, nullptr,
OPEN_EXISTING, 0, nullptr);
if (!hPatch.Valid())
throw int(GetLastError());
hTarget = CreateFile(targetFile, GENERIC_READ, 0, nullptr,
OPEN_EXISTING, 0, nullptr);
if (!hTarget.Valid())
throw int(GetLastError());
/* --------------------------------- *
* read patch header */
DWORD read;
success = !!ReadFile(hPatch, header, sizeof(header), &read, nullptr);
if (success && read == sizeof(header)) {
if (memcmp(header, "JIMSLEY/BSDIFF43", 16))
throw int(-4);
} else {
throw int(GetLastError());
}
/* --------------------------------- *
* allocate new file size data */
newsize = offtin(header + 16);
if (newsize < 0 || newsize >= 0x7ffffffff)
throw int(-5);
vector<uint8_t> newData;
try {
newData.resize(newsize);
} catch (...) {
throw int(-1);
}
/* --------------------------------- *
* read old file */
DWORD targetFileSize;
targetFileSize = GetFileSize(hTarget, nullptr);
if (targetFileSize == INVALID_FILE_SIZE)
throw int(GetLastError());
vector<uint8_t> oldData;
try {
oldData.resize(targetFileSize);
} catch (...) {
throw int(-1);
}
if (!ReadFile(hTarget, &oldData[0], targetFileSize, &read, nullptr))
throw int(GetLastError());
if (read != targetFileSize)
throw int(-1);
/* --------------------------------- *
* patch to new file data */
if (!strm.init_decoder())
throw int(-10);
patch_data data;
data.h = hPatch;
data.strm = strm.get();
stream.read = read_lzma;
stream.opaque = &data;
int ret = bspatch(oldData.data(), oldData.size(), newData.data(),
newData.size(), &stream);
if (ret != 0)
throw int(-9);
/* --------------------------------- *
* write new file */
hTarget = nullptr;
hTarget = CreateFile(targetFile, GENERIC_WRITE, 0, nullptr,
CREATE_ALWAYS, 0, nullptr);
if (!hTarget.Valid())
throw int(GetLastError());
DWORD written;
success = !!WriteFile(hTarget, newData.data(), (DWORD)newsize,
&written, nullptr);
if (!success || written != newsize)
throw int(GetLastError());
return 0;
} catch (int code) {
return code;
}

View File

@@ -0,0 +1,21 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by updater.rc
//
#define IDD_UPDATEDIALOG 101
#define IDI_ICON1 103
#define IDC_PROGRESS 1001
#define IDC_STATUS 1002
#define IDCBUTTON 1004
#define IDC_BUTTON 1004
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 104
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1005
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,103 @@
#pragma once
#define WINVER 0x0600
#define _WIN32_WINDOWS 0x0600
#define _WIN32_WINNT 0x0600
#define WIN32_LEAN_AND_MEAN
#define ZLIB_CONST
#include <windows.h>
#include <winhttp.h>
#include <commctrl.h>
#include <Wincrypt.h>
#include <shlobj.h>
#include <shellapi.h>
#include <malloc.h>
#include <stdlib.h>
#include <tchar.h>
#include <strsafe.h>
#include <zlib.h>
#include <ctype.h>
#include <blake2.h>
#include <string>
#include "../win-update-helpers.hpp"
#define BLAKE2_HASH_LENGTH 20
#define BLAKE2_HASH_STR_LENGTH ((BLAKE2_HASH_LENGTH * 2) + 1)
#if defined _M_IX86
#pragma comment(linker, \
"/manifestdependency:\"type='win32' " \
"name='Microsoft.Windows.Common-Controls' " \
"version='6.0.0.0' " \
"processorArchitecture='x86' " \
"publicKeyToken='6595b64144ccf1df' " \
"language='*'\"")
#elif defined _M_IA64
#pragma comment(linker, \
"/manifestdependency:\"type='win32' " \
"name='Microsoft.Windows.Common-Controls' " \
"version='6.0.0.0' " \
"processorArchitecture='ia64' " \
"publicKeyToken='6595b64144ccf1df' " \
"language='*'\"")
#elif defined _M_X64
#pragma comment(linker, \
"/manifestdependency:\"type='win32' " \
"name='Microsoft.Windows.Common-Controls' " \
"version='6.0.0.0' " \
"processorArchitecture='amd64' " \
"publicKeyToken='6595b64144ccf1df' " \
"language='*'\"")
#else
#pragma comment(linker, \
"/manifestdependency:\"type='win32' " \
"name='Microsoft.Windows.Common-Controls' " \
"version='6.0.0.0' processorArchitecture='*' " \
"publicKeyToken='6595b64144ccf1df' " \
"language='*'\"")
#endif
#include <util/windows/WinHandle.hpp>
#include <jansson.h>
#include "resource.h"
bool HTTPGetFile(HINTERNET hConnect,
const wchar_t *url,
const wchar_t *outputPath,
const wchar_t *extraHeaders,
int * responseCode);
bool HTTPPostData(const wchar_t *url,
const BYTE * data,
int dataLen,
const wchar_t *extraHeaders,
int * responseCode,
std::string & response);
void HashToString(const BYTE *in, wchar_t *out);
void StringToHash(const wchar_t *in, BYTE *out);
bool CalculateFileHash(const wchar_t *path, BYTE *hash);
int ApplyPatch(LPCTSTR patchFile, LPCTSTR targetFile);
extern HWND hwndMain;
extern HCRYPTPROV hProvider;
extern int totalFileSize;
extern int completedFileSize;
extern HANDLE cancelRequested;
#pragma pack(push, r1, 1)
typedef struct {
BLOBHEADER blobheader;
RSAPUBKEY rsapubkey;
} PUBLICKEYHEADER;
#pragma pack(pop, r1)
void FreeWinHttpHandle(HINTERNET handle);
using HttpHandle = CustomHandle<HINTERNET, FreeWinHttpHandle>;

View File

@@ -0,0 +1,145 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_UPDATEDIALOG DIALOGEX 0, 0, 316, 56
STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW
CAPTION "OBS Studio Update"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
PUSHBUTTON "Cancel",IDC_BUTTON,259,34,50,14
CONTROL "",IDC_PROGRESS,"msctls_progress32",PBS_SMOOTH,7,17,302,14
LTEXT "Waiting for OBS to exit...",IDC_STATUS,7,7,302,8,SS_WORDELLIPSIS
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_UPDATEDIALOG, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 309
TOPMARGIN, 7
BOTTOMMARGIN, 48
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "obsproject.com"
VALUE "FileDescription", "OBS Updater"
VALUE "FileVersion", "1.0.0.1"
VALUE "InternalName", "updater.exe"
VALUE "LegalCopyright", "Copyright (C) 2013 Richard Stanway"
VALUE "OriginalFilename", "updater.exe"
VALUE "ProductName", "OBS Updater"
VALUE "ProductVersion", "1.0.0.1"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1 ICON "../../../cmake/winrc/obs-studio.ico"
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED