-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[path_provider] Remove
win32
(#7073)
Per https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#dependencies, we generally do not want third-party dependencies. `path_provider` in particular is a key part of the ecosystem (well over 1,000 packages depend directly on it, and transitively it's probably several times that at least), and thus the maintenance and security considerations are particularly acute. This eliminates the dependency on `win32`, a large third-party dependency, in favor of direct FFI code written from scratch using the official Win32 reference documentation from Microsoft as the source. The only behavioral change that should result here is that the exceptions thrown in failure cases have changed, but they were never documented, and were entirely platform-specific, so it's relatively unlikely that people will be broken by that. (As noted in a TODO, the longer term solution is to provide real exceptions for this package, and use those across platforms.) Fixes flutter/flutter#130940
- Loading branch information
1 parent
9627de9
commit 47a92db
Showing
8 changed files
with
314 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
115 changes: 61 additions & 54 deletions
115
packages/path_provider/path_provider_windows/lib/src/folders.dart
Large diffs are not rendered by default.
Oops, something went wrong.
51 changes: 51 additions & 0 deletions
51
packages/path_provider/path_provider_windows/lib/src/guid.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
import 'dart:ffi'; | ||
import 'dart:typed_data'; | ||
|
||
/// Representation of the Win32 GUID struct. | ||
// For the layout of this struct, see | ||
// https://learn.microsoft.com/windows/win32/api/guiddef/ns-guiddef-guid | ||
@Packed(4) | ||
base class GUID extends Struct { | ||
/// Native Data1 field. | ||
@Uint32() | ||
external int data1; | ||
|
||
/// Native Data2 field. | ||
@Uint16() | ||
external int data2; | ||
|
||
/// Native Data3 field. | ||
@Uint16() | ||
external int data3; | ||
|
||
/// Native Data4 field. | ||
// This should be an eight-element byte array, but there's no such annotation. | ||
@Uint64() | ||
external int data4; | ||
|
||
/// Parses a GUID string, with optional enclosing "{}"s and optional "-"s, | ||
/// into data. | ||
void parse(String guid) { | ||
final String hexOnly = guid.replaceAll(RegExp(r'[{}-]'), ''); | ||
if (hexOnly.length != 32) { | ||
throw ArgumentError.value(guid, 'guid', 'Invalid GUID string'); | ||
} | ||
final ByteData bytes = ByteData(16); | ||
for (int i = 0; i < 16; ++i) { | ||
bytes.setUint8( | ||
i, int.parse(hexOnly.substring(i * 2, i * 2 + 2), radix: 16)); | ||
} | ||
data1 = bytes.getInt32(0); | ||
data2 = bytes.getInt16(4); | ||
data3 = bytes.getInt16(6); | ||
// [bytes] is big endian, but the host is little endian, so a default | ||
// big-endian read would reverse the bytes. Since data4 is supposed to be | ||
// a byte array, the order should be preserved, so do a little-endian read. | ||
// https://en.wikipedia.org/wiki/Universally_unique_identifier#Encoding | ||
data4 = bytes.getInt64(8, Endian.little); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
112 changes: 112 additions & 0 deletions
112
packages/path_provider/path_provider_windows/lib/src/win32_wrappers.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
// The types and functions here correspond directly to corresponding Windows | ||
// types and functions, so the Windows docs are the definitive source of | ||
// documentation. | ||
// ignore_for_file: public_member_api_docs | ||
|
||
import 'dart:ffi'; | ||
|
||
import 'package:ffi/ffi.dart'; | ||
|
||
import 'guid.dart'; | ||
|
||
typedef BOOL = Int32; | ||
typedef BYTE = Uint8; | ||
typedef DWORD = Uint32; | ||
typedef UINT = Uint32; | ||
typedef HANDLE = IntPtr; | ||
typedef HMODULE = HANDLE; | ||
typedef HRESULT = Int32; | ||
typedef LPCVOID = Pointer<NativeType>; | ||
typedef LPCWSTR = Pointer<Utf16>; | ||
typedef LPDWORD = Pointer<DWORD>; | ||
typedef LPWSTR = Pointer<Utf16>; | ||
typedef LPVOID = Pointer<NativeType>; | ||
typedef PUINT = Pointer<UINT>; | ||
typedef PWSTR = Pointer<Pointer<Utf16>>; | ||
typedef WCHAR = Uint16; | ||
|
||
const int NULL = 0; | ||
|
||
// https://learn.microsoft.com/windows/win32/fileio/maximum-file-path-limitation?tabs=registry | ||
const int MAX_PATH = 260; | ||
|
||
// https://learn.microsoft.com/windows/win32/seccrypto/common-hresult-values | ||
// ignore: non_constant_identifier_names | ||
final int E_FAIL = 0x80004005.toSigned(32); | ||
// ignore: non_constant_identifier_names | ||
final int E_INVALIDARG = 0x80070057.toSigned(32); | ||
|
||
// https://learn.microsoft.com/windows/win32/api/winerror/nf-winerror-failed#remarks | ||
// ignore: non_constant_identifier_names | ||
bool FAILED(int hr) => hr < 0; | ||
|
||
// https://learn.microsoft.com/windows/win32/api/shlobj_core/ne-shlobj_core-known_folder_flag | ||
const int KF_FLAG_DEFAULT = 0x00000000; | ||
|
||
final DynamicLibrary _dllKernel32 = DynamicLibrary.open('kernel32.dll'); | ||
final DynamicLibrary _dllVersion = DynamicLibrary.open('version.dll'); | ||
final DynamicLibrary _dllShell32 = DynamicLibrary.open('shell32.dll'); | ||
|
||
// https://learn.microsoft.com/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath | ||
typedef _FFITypeSHGetKnownFolderPath = HRESULT Function( | ||
Pointer<GUID>, DWORD, HANDLE, PWSTR); | ||
typedef FFITypeSHGetKnownFolderPathDart = int Function( | ||
Pointer<GUID>, int, int, Pointer<Pointer<Utf16>>); | ||
// ignore: non_constant_identifier_names | ||
final FFITypeSHGetKnownFolderPathDart SHGetKnownFolderPath = | ||
_dllShell32.lookupFunction<_FFITypeSHGetKnownFolderPath, | ||
FFITypeSHGetKnownFolderPathDart>('SHGetKnownFolderPath'); | ||
|
||
// https://learn.microsoft.com/windows/win32/api/winver/nf-winver-getfileversioninfow | ||
typedef _FFITypeGetFileVersionInfoW = BOOL Function( | ||
LPCWSTR, DWORD, DWORD, LPVOID); | ||
typedef FFITypeGetFileVersionInfoW = int Function( | ||
Pointer<Utf16>, int, int, Pointer<NativeType>); | ||
// ignore: non_constant_identifier_names | ||
final FFITypeGetFileVersionInfoW GetFileVersionInfo = _dllVersion | ||
.lookupFunction<_FFITypeGetFileVersionInfoW, FFITypeGetFileVersionInfoW>( | ||
'GetFileVersionInfoW'); | ||
|
||
// https://learn.microsoft.com/windows/win32/api/winver/nf-winver-getfileversioninfosizew | ||
typedef _FFITypeGetFileVersionInfoSizeW = DWORD Function(LPCWSTR, LPDWORD); | ||
typedef FFITypeGetFileVersionInfoSizeW = int Function( | ||
Pointer<Utf16>, Pointer<Uint32>); | ||
// ignore: non_constant_identifier_names | ||
final FFITypeGetFileVersionInfoSizeW GetFileVersionInfoSize = | ||
_dllVersion.lookupFunction<_FFITypeGetFileVersionInfoSizeW, | ||
FFITypeGetFileVersionInfoSizeW>('GetFileVersionInfoSizeW'); | ||
|
||
// https://learn.microsoft.com/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror | ||
typedef _FFITypeGetLastError = DWORD Function(); | ||
typedef FFITypeGetLastError = int Function(); | ||
// ignore: non_constant_identifier_names | ||
final FFITypeGetLastError GetLastError = _dllKernel32 | ||
.lookupFunction<_FFITypeGetLastError, FFITypeGetLastError>('GetLastError'); | ||
|
||
// https://learn.microsoft.com/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamew | ||
typedef _FFITypeGetModuleFileNameW = DWORD Function(HMODULE, LPWSTR, DWORD); | ||
typedef FFITypeGetModuleFileNameW = int Function(int, Pointer<Utf16>, int); | ||
// ignore: non_constant_identifier_names | ||
final FFITypeGetModuleFileNameW GetModuleFileName = _dllKernel32.lookupFunction< | ||
_FFITypeGetModuleFileNameW, | ||
FFITypeGetModuleFileNameW>('GetModuleFileNameW'); | ||
|
||
// https://learn.microsoft.com/windows/win32/api/winver/nf-winver-verqueryvaluew | ||
typedef _FFITypeVerQueryValueW = BOOL Function(LPCVOID, LPCWSTR, LPVOID, PUINT); | ||
typedef FFITypeVerQueryValueW = int Function( | ||
Pointer<NativeType>, Pointer<Utf16>, Pointer<NativeType>, Pointer<Uint32>); | ||
// ignore: non_constant_identifier_names | ||
final FFITypeVerQueryValueW VerQueryValue = | ||
_dllVersion.lookupFunction<_FFITypeVerQueryValueW, FFITypeVerQueryValueW>( | ||
'VerQueryValueW'); | ||
|
||
// https://learn.microsoft.com/windows/win32/api/fileapi/nf-fileapi-gettemppathw | ||
typedef _FFITypeGetTempPathW = DWORD Function(DWORD, LPWSTR); | ||
typedef FFITypeGetTempPathW = int Function(int, Pointer<Utf16>); | ||
// ignore: non_constant_identifier_names | ||
final FFITypeGetTempPathW GetTempPath = _dllKernel32 | ||
.lookupFunction<_FFITypeGetTempPathW, FFITypeGetTempPathW>('GetTempPathW'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
63 changes: 63 additions & 0 deletions
63
packages/path_provider/path_provider_windows/test/guid_test.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
import 'dart:ffi'; | ||
import 'dart:typed_data'; | ||
|
||
import 'package:ffi/ffi.dart'; | ||
import 'package:flutter_test/flutter_test.dart'; | ||
import 'package:path_provider_windows/src/guid.dart'; | ||
|
||
void main() { | ||
test('has correct byte representation', () async { | ||
final Pointer<GUID> guid = calloc<GUID>() | ||
..ref.parse('{00112233-4455-6677-8899-aabbccddeeff}'); | ||
final ByteData data = ByteData(16) | ||
..setInt32(0, guid.ref.data1, Endian.little) | ||
..setInt16(4, guid.ref.data2, Endian.little) | ||
..setInt16(6, guid.ref.data3, Endian.little) | ||
..setInt64(8, guid.ref.data4, Endian.little); | ||
expect(data.getUint8(0), 0x33); | ||
expect(data.getUint8(1), 0x22); | ||
expect(data.getUint8(2), 0x11); | ||
expect(data.getUint8(3), 0x00); | ||
expect(data.getUint8(4), 0x55); | ||
expect(data.getUint8(5), 0x44); | ||
expect(data.getUint8(6), 0x77); | ||
expect(data.getUint8(7), 0x66); | ||
expect(data.getUint8(8), 0x88); | ||
expect(data.getUint8(9), 0x99); | ||
expect(data.getUint8(10), 0xAA); | ||
expect(data.getUint8(11), 0xBB); | ||
expect(data.getUint8(12), 0xCC); | ||
expect(data.getUint8(13), 0xDD); | ||
expect(data.getUint8(14), 0xEE); | ||
expect(data.getUint8(15), 0xFF); | ||
|
||
calloc.free(guid); | ||
}); | ||
|
||
test('handles alternate forms', () async { | ||
final Pointer<GUID> guid1 = calloc<GUID>() | ||
..ref.parse('{00112233-4455-6677-8899-aabbccddeeff}'); | ||
final Pointer<GUID> guid2 = calloc<GUID>() | ||
..ref.parse('00112233445566778899AABBCCDDEEFF'); | ||
|
||
expect(guid1.ref.data1, guid2.ref.data1); | ||
expect(guid1.ref.data2, guid2.ref.data2); | ||
expect(guid1.ref.data3, guid2.ref.data3); | ||
expect(guid1.ref.data4, guid2.ref.data4); | ||
|
||
calloc.free(guid1); | ||
calloc.free(guid2); | ||
}); | ||
|
||
test('throws for bad data', () async { | ||
final Pointer<GUID> guid = calloc<GUID>(); | ||
|
||
expect(() => guid.ref.parse('{00112233-4455-6677-88'), throwsArgumentError); | ||
|
||
calloc.free(guid); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,7 +13,6 @@ | |
# cautious about adding to this list. | ||
- build_verify | ||
- google_maps | ||
- win32 | ||
|
||
## Allowed by default | ||
|
||
|