Fixed wrapper not found error when running pub run ffigen (#42)

Possibly fixes #41 (Needs to be tested after publishing).

- Using `dart:cli` to resolve package uri and get wrapper.c for running `pub run ffigen:setup`.
- If `dart:cli` is unavailable, fallback tries to work up the current directory to find `.dart_tool/package_config.json` and get rootUri of `package:ffigen` and find wrapper.c from there.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2d65c34..83afb0b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,6 @@
+# 0.1.2
+- Fixed wrapper not found error when running `pub run ffigen`.
+
 # 0.1.1
 - Address pub score: follow dart File conventions, provide documentation, and pass static analysis.
 
diff --git a/bin/setup.dart b/bin/setup.dart
index e933691..ef618fc 100644
--- a/bin/setup.dart
+++ b/bin/setup.dart
@@ -27,7 +27,7 @@
 import 'dart:io';
 import 'package:args/args.dart';
 import 'package:meta/meta.dart';
-import 'package:ffigen/src/find_dot_dart_tool.dart';
+import 'package:ffigen/src/find_resource.dart';
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:path/path.dart' as path;
 
@@ -140,14 +140,7 @@
 ///
 /// Throws error if not found.
 String _getWrapperPath(String wrapperName) {
-  final file = File(path.join(
-    Platform.script
-        .resolve(path.posix.join('..', 'lib', 'src', 'clang_library'))
-        // This needs to be in posix style or illegal character exception is
-        // thrown on windows.
-        .toFilePath(),
-    wrapperName,
-  ));
+  final file = File.fromUri(findWrapper(wrapperName));
   if (file.existsSync()) {
     return file.absolute.path;
   } else {
diff --git a/lib/src/code_generator.dart b/lib/src/code_generator.dart
index 9eb01b6..efbb1a2 100644
--- a/lib/src/code_generator.dart
+++ b/lib/src/code_generator.dart
@@ -14,4 +14,3 @@
 export 'code_generator/struc.dart';
 export 'code_generator/type.dart';
 export 'code_generator/typedef.dart';
-
diff --git a/lib/src/find_dot_dart_tool.dart b/lib/src/find_dot_dart_tool.dart
deleted file mode 100644
index 07c4a98..0000000
--- a/lib/src/find_dot_dart_tool.dart
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library finddotdarttool;
-
-export 'find_dot_dart_tool/finddotdarttool_fallback.dart'
-    if (dart.library.cli) 'find_dot_dart_tool/finddotdarttool_cli.dart';
diff --git a/lib/src/find_dot_dart_tool/finddotdarttool_fallback.dart b/lib/src/find_dot_dart_tool/finddotdarttool_fallback.dart
deleted file mode 100644
index 50e2c4c..0000000
--- a/lib/src/find_dot_dart_tool/finddotdarttool_fallback.dart
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
-// for details. 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:io' show Platform, File;
-
-/// Find the `.dart_tool/` folder, returns `null` if unable to find it.
-Uri findDotDartTool() {
-  // HACK: Because 'dart:isolate' is unavailable in Flutter we have no means
-  //       by which we can find the location of the package_config.json file.
-  //       Which we need, because the binary library created by:
-  //         flutter pub run ffigen:setup
-  //       is located relative to this path. As a workaround we use
-  //       `Platform.script` and traverse level-up until we find a
-  //       `.dart_tool/package_config.json` file.
-  // Find script directory
-  var root = Platform.script.resolve('./');
-  // Traverse up until we see a `.dart_tool/package_config.json` file.
-  do {
-    if (File.fromUri(root.resolve('.dart_tool/package_config.json'))
-        .existsSync()) {
-      return root.resolve('.dart_tool/');
-    }
-  } while (root != (root = root.resolve('..')));
-  return null;
-}
diff --git a/lib/src/find_resource.dart b/lib/src/find_resource.dart
new file mode 100644
index 0000000..e9a9dae
--- /dev/null
+++ b/lib/src/find_resource.dart
@@ -0,0 +1,8 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library find_resource;
+
+export 'find_resource/find_resource_fallback.dart'
+    if (dart.library.cli) 'find_resource/find_resource_cli.dart';
diff --git a/lib/src/find_dot_dart_tool/finddotdarttool_cli.dart b/lib/src/find_resource/find_resource_cli.dart
similarity index 73%
rename from lib/src/find_dot_dart_tool/finddotdarttool_cli.dart
rename to lib/src/find_resource/find_resource_cli.dart
index 0773410..d3885b5 100644
--- a/lib/src/find_dot_dart_tool/finddotdarttool_cli.dart
+++ b/lib/src/find_resource/find_resource_cli.dart
@@ -5,7 +5,7 @@
 import 'dart:cli' as cli;
 import 'dart:io' show File;
 import 'dart:isolate' show Isolate;
-import 'finddotdarttool_fallback.dart' as fallback;
+import 'find_resource_fallback.dart' as fallback;
 
 /// Find the `.dart_tool/` folder, returns `null` if unable to find it.
 Uri findDotDartTool() {
@@ -27,3 +27,11 @@
   // current script location and traverse up from there.
   return fallback.findDotDartTool();
 }
+
+Uri findWrapper(String wrapperName) {
+  final wrapperUri = cli.waitFor(Isolate.resolvePackageUri(
+      Uri.parse('package:ffigen/src/clang_library/$wrapperName')));
+  // If [Isolate.packageConfig] isn't helpful we fallback to looking at the
+  // current script location and traverse up from there.
+  return wrapperUri ?? fallback.findWrapper(wrapperName);
+}
diff --git a/lib/src/find_resource/find_resource_fallback.dart b/lib/src/find_resource/find_resource_fallback.dart
new file mode 100644
index 0000000..0db61ee
--- /dev/null
+++ b/lib/src/find_resource/find_resource_fallback.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. 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:convert' show jsonDecode;
+import 'dart:io' show File, Directory;
+
+/// Find the `.dart_tool/` folder, returns `null` if unable to find it.
+Uri findDotDartTool() {
+  // HACK: Because 'dart:isolate' is unavailable in Flutter we have no means
+  //       by which we can find the location of the package_config.json file.
+  //       Which we need, because the binary library created by:
+  //         flutter pub run ffigen:setup
+  //       is located relative to this path. As a workaround we use
+  //       `Platform.script` and traverse level-up until we find a
+  //       `.dart_tool/package_config.json` file.
+  // Find script directory
+  var root = Directory.current.uri;
+  // Traverse up until we see a `.dart_tool/package_config.json` file.
+  do {
+    if (File.fromUri(root.resolve('.dart_tool/package_config.json'))
+        .existsSync()) {
+      return root.resolve('.dart_tool/');
+    }
+  } while (root != (root = root.resolve('..')));
+  return null;
+}
+
+Uri findWrapper(String wrapperName) {
+  var root = Directory.current.uri;
+  // Traverse up until we see a `.dart_tool/package_config.json` file.
+  do {
+    final file = File.fromUri(root.resolve('.dart_tool/package_config.json'));
+    if (file.existsSync()) {
+      /// Read the package_config.json file to extract path of wrapper.
+      try {
+        final packageMap =
+            jsonDecode(file.readAsStringSync()) as Map<String, dynamic>;
+        if (packageMap['configVersion'] == 2) {
+          var ffigenRootUriString = ((packageMap['packages'] as List<dynamic>)
+                  .cast<Map<String, dynamic>>()
+                  .firstWhere(
+                      (element) => element['name'] == 'ffigen')['rootUri']
+              as String);
+          ffigenRootUriString = ffigenRootUriString.endsWith('/')
+              ? ffigenRootUriString
+              : ffigenRootUriString + '/';
+
+          /// [ffigenRootUri] can be relative to .dart_tool if its from
+          /// filesystem so we need to resolve it from .dart_tool first.
+          return file.parent.uri
+              .resolve(ffigenRootUriString)
+              .resolve('lib/src/clang_library/$wrapperName');
+        }
+      } catch (e, s) {
+        print(s);
+        throw Exception('Cannot resolve package:ffigen\'s rootUri.');
+      }
+    }
+  } while (root != (root = root.resolve('..')));
+  return null;
+}
diff --git a/lib/src/header_parser/parser.dart b/lib/src/header_parser/parser.dart
index a2b1593..832127a 100644
--- a/lib/src/header_parser/parser.dart
+++ b/lib/src/header_parser/parser.dart
@@ -7,7 +7,7 @@
 import 'package:ffi/ffi.dart';
 import 'package:ffigen/src/code_generator.dart';
 import 'package:ffigen/src/config_provider.dart';
-import 'package:ffigen/src/find_dot_dart_tool.dart';
+import 'package:ffigen/src/find_resource.dart';
 import 'package:ffigen/src/header_parser/translation_unit_parser.dart';
 import 'package:ffigen/src/strings.dart' as strings;
 import 'package:logging/logging.dart';
diff --git a/pubspec.yaml b/pubspec.yaml
index 201cf67..8da3a6a 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,7 +3,7 @@
 # BSD-style license that can be found in the LICENSE file.
 
 name: ffigen
-version: 0.1.1
+version: 0.1.2
 homepage: https://github.com/dart-lang/ffigen
 description: Experimental generator for FFI bindings, using LibClang to parse C/C++ header files.