Chromium Code Reviews| 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,238 @@ |
| +// 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); |
| +} |
| + |
| +char* WideToUtf8(const wchar_t* str) { |
|
amit
2011/03/15 20:54:35
nit: we probably need mini_installer_utils.h/cc fo
tommi (sloooow) - chröme
2011/03/16 02:43:30
Yes, eventually. However right now, we don't need
amit
2011/03/16 15:50:26
That's reasonable.
|
| + char* ret = NULL; |
| + int size = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); |
| + if (size) { |
| + ret = reinterpret_cast<char*>(Alloc(size * sizeof(ret[0]))); |
| + if (ret) |
| + WideCharToMultiByte(CP_UTF8, 0, str, -1, ret, size, NULL, NULL); |
| + } |
| + 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; |
| + |
| + switch (fdint) { |
| + case fdintCOPY_FILE: { |
| + // 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); |
| + 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; |
| + FILE_BASIC_INFO fbi; |
| + |
| + // Converts MS-DOS date and time values to a file time |
| + if (DosDateTimeToFileTime(pfdin->date, pfdin->time, &file_time) && |
| + LocalFileTimeToFileTime(&file_time, &local)) { |
| + fbi.CreationTime.LowPart = local.dwLowDateTime; |
| + fbi.CreationTime.HighPart = local.dwHighDateTime; |
| + fbi.LastWriteTime.QuadPart = -1; |
| + fbi.ChangeTime.QuadPart = -1; |
| + fbi.LastAccessTime.QuadPart = -1; |
| + fbi.FileAttributes = pfdin->attribs; |
| + fbi.FileAttributes &= FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | |
| + FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE; |
| + SetFileInformationByHandle(reinterpret_cast<HANDLE>(pfdin->hf), |
| + FileBasicInfo, &fbi, sizeof(fbi)); |
| + } |
| + |
| + result = !Close(pfdin->hf); |
| + 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) { |
| + // This DLL should be available on all supported versions of Windows. |
| + g_fdi = ::LoadLibraryW(L"cabinet.dll"); |
|
amit
2011/03/15 20:54:35
shouldn't this be loaded from a known path, to pre
tommi (sloooow) - chröme
2011/03/16 02:43:30
We don't have a lib for cabinet.dll but this is ef
amit
2011/03/16 15:50:26
sounds good
tommi (sloooow) - chröme
2011/03/16 20:22:20
Done.
|
| + 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(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. |
| + 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)); |
| + // The directory part is assumed to have a trailing backslash. |
| + wchar_t save = source_name[0]; |
| + *source_name = L'\0'; |
| + scoped_ptr<char> source_path_utf8(WideToUtf8(source)); |
| + *source_name = save; |
| + |
| + scoped_ptr<char> dest_utf8(WideToUtf8(destination)); |
| + 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 |