| Index: chrome/installer/mini_installer/decompress.cc
|
| ===================================================================
|
| --- chrome/installer/mini_installer/decompress.cc (revision 0)
|
| +++ chrome/installer/mini_installer/decompress.cc (revision 0)
|
| @@ -0,0 +1,240 @@
|
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include <windows.h> // NOLINT
|
| +#include <fcntl.h> // for _O_* constants
|
| +#include <fdi.h>
|
| +
|
| +#include "chrome/installer/mini_installer/decompress.h"
|
| +
|
| +namespace {
|
| +
|
| +FNALLOC(Alloc) {
|
| + return ::HeapAlloc(::GetProcessHeap(), 0, cb);
|
| +}
|
| +
|
| +FNFREE(Free) {
|
| + ::HeapFree(::GetProcessHeap(), 0, pv);
|
| +}
|
| +
|
| +// Converts a wide string to utf8. Set |len| to -1 if |str| is zero terminated
|
| +// and you want to convert the entire string.
|
| +// The returned string will have been allocated with Alloc(), so free it
|
| +// with a call to Free().
|
| +char* WideToUtf8(const wchar_t* str, int len) {
|
| + char* ret = NULL;
|
| + int size = WideCharToMultiByte(CP_UTF8, 0, str, len, NULL, 0, NULL, NULL);
|
| + if (size) {
|
| + if (len != -1)
|
| + ++size; // include space for the terminator.
|
| + ret = reinterpret_cast<char*>(Alloc(size * sizeof(ret[0])));
|
| + if (ret) {
|
| + WideCharToMultiByte(CP_UTF8, 0, str, len, ret, size, NULL, NULL);
|
| + if (len != -1)
|
| + ret[size - 1] = '\0'; // terminate the string
|
| + }
|
| + }
|
| + return ret;
|
| +}
|
| +
|
| +wchar_t* Utf8ToWide(const char* str) {
|
| + wchar_t* ret = NULL;
|
| + int size = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
|
| + if (size) {
|
| + ret = reinterpret_cast<wchar_t*>(Alloc(size * sizeof(ret[0])));
|
| + if (ret)
|
| + MultiByteToWideChar(CP_UTF8, 0, str, -1, ret, size);
|
| + }
|
| + return ret;
|
| +}
|
| +
|
| +template <typename T>
|
| +class scoped_ptr {
|
| + public:
|
| + explicit scoped_ptr(T* a) : a_(a) {
|
| + }
|
| + ~scoped_ptr() {
|
| + if (a_)
|
| + Free(a_);
|
| + }
|
| + operator T*() {
|
| + return a_;
|
| + }
|
| + private:
|
| + T* a_;
|
| +};
|
| +
|
| +FNOPEN(Open) {
|
| + DWORD access = 0;
|
| + DWORD disposition = 0;
|
| +
|
| + if (oflag & _O_RDWR) {
|
| + access = GENERIC_READ | GENERIC_WRITE;
|
| + } else if (oflag & _O_WRONLY) {
|
| + access = GENERIC_WRITE;
|
| + } else {
|
| + access = GENERIC_READ;
|
| + }
|
| +
|
| + if (oflag & _O_CREAT) {
|
| + disposition = CREATE_ALWAYS;
|
| + } else {
|
| + disposition = OPEN_EXISTING;
|
| + }
|
| +
|
| + scoped_ptr<wchar_t> path(Utf8ToWide(pszFile));
|
| + HANDLE file = CreateFileW(path, access, FILE_SHARE_READ, NULL, disposition,
|
| + FILE_ATTRIBUTE_NORMAL, NULL);
|
| + return reinterpret_cast<INT_PTR>(file);
|
| +}
|
| +
|
| +FNREAD(Read) {
|
| + DWORD read = 0;
|
| + if (!::ReadFile(reinterpret_cast<HANDLE>(hf), pv, cb, &read, NULL))
|
| + read = static_cast<DWORD>(-1L);
|
| + return read;
|
| +}
|
| +
|
| +FNWRITE(Write) {
|
| + DWORD written = 0;
|
| + if (!::WriteFile(reinterpret_cast<HANDLE>(hf), pv, cb, &written, NULL))
|
| + written = static_cast<DWORD>(-1L);
|
| + return written;
|
| +}
|
| +
|
| +FNCLOSE(Close) {
|
| + return ::CloseHandle(reinterpret_cast<HANDLE>(hf)) ? 0 : -1;
|
| +}
|
| +
|
| +FNSEEK(Seek) {
|
| + return ::SetFilePointer(reinterpret_cast<HANDLE>(hf), dist, NULL, seektype);
|
| +}
|
| +
|
| +FNFDINOTIFY(Notify) {
|
| + INT_PTR result = 0;
|
| +
|
| + // Since we will only ever be decompressing a single file at a time
|
| + // we take a shortcut and provide a pointer to the wide destination file
|
| + // of the file we want to write. This way we don't have to bother with
|
| + // utf8/wide conversion and concatenation of directory and file name.
|
| + const wchar_t* destination = reinterpret_cast<const wchar_t*>(pfdin->pv);
|
| +
|
| + switch (fdint) {
|
| + case fdintCOPY_FILE: {
|
| + result = reinterpret_cast<INT_PTR>(::CreateFileW(destination,
|
| + GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS,
|
| + FILE_ATTRIBUTE_NORMAL, NULL));
|
| + break;
|
| + }
|
| +
|
| + case fdintCLOSE_FILE_INFO: {
|
| + FILETIME file_time;
|
| + FILETIME local;
|
| + // Converts MS-DOS date and time values to a file time
|
| + if (DosDateTimeToFileTime(pfdin->date, pfdin->time, &file_time) &&
|
| + LocalFileTimeToFileTime(&file_time, &local)) {
|
| + SetFileTime(reinterpret_cast<HANDLE>(pfdin->hf), &local, NULL, NULL);
|
| + }
|
| +
|
| + result = !Close(pfdin->hf);
|
| + pfdin->attribs &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
|
| + FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE;
|
| + ::SetFileAttributes(destination, pfdin->attribs);
|
| + break;
|
| + }
|
| +
|
| + case fdintCABINET_INFO:
|
| + case fdintENUMERATE:
|
| + // OK. continue as normal.
|
| + result = 0;
|
| + break;
|
| +
|
| + case fdintPARTIAL_FILE:
|
| + case fdintNEXT_CABINET:
|
| + default:
|
| + // Error case.
|
| + result = -1;
|
| + break;
|
| + }
|
| +
|
| + return result;
|
| +}
|
| +
|
| +// Module handle of cabinet.dll
|
| +HMODULE g_fdi = NULL;
|
| +
|
| +// API prototypes.
|
| +typedef HFDI (DIAMONDAPI* FDICreateFn)(PFNALLOC alloc, PFNFREE free,
|
| + PFNOPEN open, PFNREAD read,
|
| + PFNWRITE write, PFNCLOSE close,
|
| + PFNSEEK seek, int cpu_type, PERF perf);
|
| +typedef BOOL (DIAMONDAPI* FDIDestroyFn)(HFDI fdi);
|
| +typedef BOOL (DIAMONDAPI* FDICopyFn)(HFDI fdi, char* cab, char* cab_path,
|
| + int flags, PFNFDINOTIFY notify,
|
| + PFNFDIDECRYPT decrypt, void* context);
|
| +FDICreateFn g_FDICreate = NULL;
|
| +FDIDestroyFn g_FDIDestroy = NULL;
|
| +FDICopyFn g_FDICopy = NULL;
|
| +
|
| +bool InitializeFdi() {
|
| + if (!g_fdi) {
|
| + wchar_t path[MAX_PATH] = {0};
|
| + ::ExpandEnvironmentStringsW(L"%WINDIR%\\system32\\cabinet.dll", path,
|
| + MAX_PATH);
|
| + // This DLL should be available on all supported versions of Windows.
|
| + g_fdi = ::LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
|
| + g_FDICreate =
|
| + reinterpret_cast<FDICreateFn>(::GetProcAddress(g_fdi, "FDICreate"));
|
| + g_FDIDestroy =
|
| + reinterpret_cast<FDIDestroyFn>(::GetProcAddress(g_fdi, "FDIDestroy"));
|
| + g_FDICopy =
|
| + reinterpret_cast<FDICopyFn>(::GetProcAddress(g_fdi, "FDICopy"));
|
| + }
|
| +
|
| + return g_FDICreate && g_FDIDestroy && g_FDICopy;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +namespace mini_installer {
|
| +
|
| +bool Expand(const wchar_t* source, const wchar_t* destination) {
|
| + if (!InitializeFdi())
|
| + return false;
|
| +
|
| + // Start by splitting up the source path and convert to utf8 since the
|
| + // cabinet API doesn't support wide strings.
|
| + const wchar_t* source_name = source + lstrlenW(source);
|
| + while (source_name > source && *source_name != L'\\')
|
| + --source_name;
|
| + if (source_name == source)
|
| + return false;
|
| +
|
| + // Convert the name to utf8.
|
| + source_name++;
|
| + scoped_ptr<char> source_name_utf8(WideToUtf8(source_name, -1));
|
| + // The directory part is assumed to have a trailing backslash.
|
| + scoped_ptr<char> source_path_utf8(WideToUtf8(source, source_name - source));
|
| +
|
| + scoped_ptr<char> dest_utf8(WideToUtf8(destination, -1));
|
| + if (!dest_utf8 || !source_name_utf8 || !source_path_utf8)
|
| + return false;
|
| +
|
| + bool success = false;
|
| +
|
| + ERF erf = {0};
|
| + HFDI fdi = g_FDICreate(&Alloc, &Free, &Open, &Read, &Write, &Close, &Seek,
|
| + cpuUNKNOWN, &erf);
|
| + if (fdi) {
|
| + if (g_FDICopy(fdi, source_name_utf8, source_path_utf8, 0,
|
| + &Notify, NULL, const_cast<wchar_t*>(destination))) {
|
| + success = true;
|
| + }
|
| + g_FDIDestroy(fdi);
|
| + }
|
| +
|
| + return success;
|
| +}
|
| +
|
| +} // namespace mini_installer
|
|
|
| Property changes on: chrome\installer\mini_installer\decompress.cc
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|