Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2325)

Unified Diff: chrome/installer/mini_installer/decompress.cc

Issue 6693015: Switch out the setup api for using the cabinet API directly.... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698