diff --git a/libraries.api.php b/libraries.api.php
index 1182f7b..910ec6c 100644
--- a/libraries.api.php
+++ b/libraries.api.php
@@ -114,9 +114,11 @@
  *       library with a certain part of the libraries array passed as $library
  *       each time.
  *     - $version: If the $library array belongs to a certain version (see
- *       above), a string containing the version. NULL, otherwise.
+ *       above), a string containing the version. This argument may be empty, so
+ *       NULL should be specified as default value.
  *     - $variant: If the $library array belongs to a certain variant (see
- *       above), a string containing the variant name. NULL, otherwise.
+ *       above), a string containing the variant name. This argument may be
+ *       empty, so NULL should be specified as default value.
  *     Valid callback groups are:
  *     - info: Callbacks registered in this group are applied after the library
  *       information has been retrieved via hook_libraries_info() or info files.
diff --git a/libraries.module b/libraries.module
index 2255b4a..f39e790 100644
--- a/libraries.module
+++ b/libraries.module
@@ -180,12 +180,12 @@ function libraries_invoke($group, &$library) {
  */
 function libraries_traverse_library(&$library, $callback) {
   // Always apply the callback to the top-level library.
-  $callback($library, NULL, NULL);
+  $callback($library);
 
   // Apply the callback to versions.
   if (isset($library['versions'])) {
     foreach ($library['versions'] as $version_string => &$version) {
-      $callback($version, $version_string, NULL);
+      $callback($version, $version_string);
       // Versions can include variants as well.
       if (isset($version['variants'])) {
         foreach ($version['variants'] as $version_variant_name => &$version_variant) {
@@ -204,6 +204,89 @@ function libraries_traverse_library(&$library, $callback) {
 }
 
 /**
+* Helper callback to make 'files' property of libraries consistent.
+*
+* This turns libraries' file information declared as e.g.
+* @code
+* $library['files']['js'] = array('example_1.js', 'example_2.js');
+* @endcode
+* into
+* @code
+* $library['files']['js'] = array(
+*   'example_1.js' => array(),
+*   'example_2.js' => array(),
+* );
+* @endcode
+* It does the same for the 'integration files' property.
+*
+* @param $library
+*   An associative array of library information or a part of it, passed by
+*   reference.
+* @param $version
+*   If the library information belongs to a specific version, the version
+*   string. NULL otherwise.
+* @param $variant
+*   If the library information belongs to a specific variant, the variant name.
+*   NULL otherwise.
+*
+* @see libraries_info()
+* @see libraries_invoke()
+*/
+function libraries_prepare_files(&$library, $version = NULL, $variant = NULL) {
+  // Both the 'files' property and the 'integration files' property contain file
+  // declarations, and we want to make both consistent.
+  $file_types = array();
+  if (isset($library['files'])) {
+    $file_types[] = &$library['files'];
+  }
+  if (isset($library['integration files'])) {
+    // Integration files are additionally keyed by module.
+    foreach ($library['integration files'] as &$integration_files) {
+      $file_types[] = &$integration_files;
+    }
+  }
+  foreach ($file_types as &$files) {
+    // Go through all supported types of files.
+    foreach (array('js', 'css', 'php') as $type) {
+      if (isset($files[$type])) {
+        foreach ($files[$type] as $key => $value) {
+          // Entries with explicit (i.e., non-integer) keys, are assumed tto be
+          // fine the way they are.
+          if (is_int($key)) {
+            // JavaScript settings.
+            if ($type == 'js' && is_array($value)) {
+              $files[$type][$key] = array(
+                'type' => 'setting',
+                'data' => $value,
+              );
+            }
+            else {
+              // External files.
+              if (url_is_external($value)) {
+                $files[$type][$value] = array('type' => 'external');
+              }
+              // Local files.
+              elseif(!preg_match('$[^a-zA-Z0-9-_.\/]$', $value)) {
+                $files[$type][$value] = array('type' => 'file');
+              }
+              // Inline JavaScript and CSS.
+              elseif ($type == 'js' || $type == 'css') {
+                $files[$type][$value] = array('type' => 'inline');
+              }
+              unset($files[$type][$key]);
+            }
+            // Apply the default group if the group isn't explicitly given.
+            if (($type == 'js' || $type == 'css') && !isset($options['group'])) {
+              $options['group'] = ($type == 'js') ? JS_DEFAULT : CSS_DEFAULT;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+/**
  * Returns information about registered libraries.
  *
  * The returned information is unprocessed, i.e. as registered by modules.
@@ -292,6 +375,10 @@ function libraries_info_defaults(&$library, $name) {
     'post-detect' => array(),
     'load' => array(),
   );
+
+  // Add our own callbacks before any others.
+  $library['callbacks']['info'] = array_merge(array('libraries_prepare_files'), $library['callbacks']['info']);
+
   return $library;
 }
 
@@ -522,23 +609,12 @@ function libraries_load_files($library) {
   foreach (array('js', 'css') as $type) {
     if (!empty($library['files'][$type])) {
       foreach ($library['files'][$type] as $data => $options) {
-        // If the value is not an array, it's a filename and passed as first
-        // (and only) argument.
-        if (!is_array($options)) {
-          // Prepend the library path to the file name.
-          $data = "$path/$options";
-          $options = NULL;
+        if ($options['type'] == 'file') {
+          $data = "$path/$data";
         }
-        // In some cases, the first parameter ($data) is an array. Arrays can't
-        // be passed as keys in PHP, so we have to get $data from the value
-        // array.
-        if (is_numeric($data)) {
+        if ($options['type'] == 'setting') {
           $data = $options['data'];
-          unset($options['data']);
-        }
-        // Apply the default group if the group isn't explicitly given.
-        if (!isset($options['group'])) {
-          $options['group'] = ($type == 'js') ? JS_DEFAULT : CSS_DEFAULT;
+          $options = 'setting';
         }
         call_user_func('drupal_add_' . $type, $data, $options);
         $count++;
@@ -548,7 +624,7 @@ function libraries_load_files($library) {
 
   // Load PHP files.
   if (!empty($library['files']['php'])) {
-    foreach ($library['files']['php'] as $file) {
+    foreach ($library['files']['php'] as $file => $array) {
       $file_path = DRUPAL_ROOT . '/' . $path . '/' . $file;
       if (file_exists($file_path)) {
         require_once $file_path;
diff --git a/tests/libraries.test b/tests/libraries.test
index d70a10e..2a2e2cf 100644
--- a/tests/libraries.test
+++ b/tests/libraries.test
@@ -32,15 +32,33 @@ class LibrariesTestCase extends DrupalWebTestCase {
     // Test libraries_get_path().
     $this->assertEqual(libraries_get_path('example'), FALSE, 'libraries_get_path() returns FALSE for a missing library.');
 
+    // Test libraries_prepare_files().
+    $expected = array(
+      'files' => array(
+        'js' => array('example.js' => array()),
+        'css' => array('example.css' => array()),
+        'php' => array('example.php' => array()),
+      ),
+    );
+    $library = array(
+      'files' => array(
+        'js' => array('example.js'),
+        'css' => array('example.css'),
+        'php' => array('example.php'),
+      ),
+    );
+    libraries_prepare_files($library, NULL, NULL);
+    $this->assertEqual($expected, $library, 'libraries_prepare_files() works correctly.');
+
     // Test that library information is found correctly.
     $expected = array(
       'name' => 'Example files',
       'library path' => drupal_get_path('module', 'libraries') . '/tests/example',
       'version' => '1',
       'files' => array(
-        'js' => array('example_1.js'),
-        'css' => array('example_1.css'),
-        'php' => array('example_1.php'),
+        'js' => array('example_1.js' => array()),
+        'css' => array('example_1.css' => array()),
+        'php' => array('example_1.php' => array()),
       ),
       'module' => 'libraries_test',
     );
@@ -107,9 +125,9 @@ class LibrariesTestCase extends DrupalWebTestCase {
     // Test a top-level files property.
     $library = libraries_detect('example_files');
     $files = array(
-      'js' => array('example_1.js'),
-      'css' => array('example_1.css'),
-      'php' => array('example_1.php'),
+      'js' => array('example_1.js' => array()),
+      'css' => array('example_1.css' => array()),
+      'php' => array('example_1.php' => array()),
     );
     $this->verbose('<pre>' . var_export($library, TRUE) . '</pre>');
     $this->assertEqual($library['files'], $files, 'Top-level files property works.');
@@ -117,9 +135,9 @@ class LibrariesTestCase extends DrupalWebTestCase {
     // Test version-specific library files.
     $library = libraries_detect('example_versions');
     $files = array(
-      'js' => array('example_2.js'),
-      'css' => array('example_2.css'),
-      'php' => array('example_2.php'),
+      'js' => array('example_2.js' => array()),
+      'css' => array('example_2.css' => array()),
+      'php' => array('example_2.php' => array()),
     );
     $this->verbose('<pre>' . var_export($library, TRUE) . '</pre>');
     $this->assertEqual($library['files'], $files, 'Version-specific library files found.');
diff --git a/tests/libraries_test.module b/tests/libraries_test.module
index 4893b11..a7bb1c7 100644
--- a/tests/libraries_test.module
+++ b/tests/libraries_test.module
@@ -73,6 +73,44 @@ function libraries_test_libraries_info() {
     ),
   );
 
+  // Test all types of JavaScript and CSS supported by drupal_add_js() and
+  // drupal_add_css().
+  $libraries['example_js_css'] = array(
+    'name' => 'Example JavaScript and CSS',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/example',
+    'version' => 1,
+    'variants' => array(
+      'file' => array(
+        'files' => array(
+          'js' => array('example_1.js'),
+          'css' => array('example_1.css'),
+        ),
+      ),
+      'external' => array(
+        'files' => array(
+          'js' => array(url(NULL, array('absolute' => TRUE)) . '/' . drupal_get_path('module', 'libraries') . '/tests/example/example_1.js'),
+          'css' => array(url(NULL, array('absolute' => TRUE)) . '/' . drupal_get_path('module', 'libraries') . '/tests/example/example_1.css'),
+        ),
+      ),
+      'inline' => array(
+        'files' => array(
+          'js' => array('jQuery(document).ready(function(){jQuery(".libraries-test-javascript").text("If this text shows up, inline JavaScript code was loaded successfully.");});'),
+          // This is the content of example_1.css.
+          'css' => array('.libraries-test-css{color:red;}'),
+        ),
+      ),
+      // There is no CSS equivalent of JavaScript settings.
+      'setting' => array(
+        'files' => array(
+          'js' => array(
+            array('librariesTest' => array('testSetting' => TRUE)),
+            'jQuery(document).ready(function(){if(Drupal.settings.librariesTest.testSetting){jQuery(".libraries-test-javascript").text("If this text shows up, JavaScript settings were loaded successfully.");}});',
+          ),
+        ),
+      )
+    ),
+  );
+
   // Test loading of integration files.
   // Normally added by the corresponding module via hook_libraries_info_alter(),
   // these files should be automatically loaded when the library is loaded.
@@ -333,7 +371,7 @@ function _libraries_test_return_installed($library, $name, $installed) {
  *
  * @see _libraries_test_callback()
  */
-function _libraries_test_info_callback(&$library, $version, $variant) {
+function _libraries_test_info_callback(&$library, $version = NULL, $variant = NULL) {
   _libraries_test_callback($library, $version, $variant, 'info');
 }
 
@@ -344,7 +382,7 @@ function _libraries_test_info_callback(&$library, $version, $variant) {
  *
  * @see _libraries_test_callback()
  */
-function _libraries_test_pre_detect_callback(&$library, $version, $variant) {
+function _libraries_test_pre_detect_callback(&$library, $version = NULL, $variant = NULL) {
   _libraries_test_callback($library, $version, $variant, 'pre-detect');
 }
 
@@ -355,7 +393,7 @@ function _libraries_test_pre_detect_callback(&$library, $version, $variant) {
  *
  * @see _libraries_test_callback()
  */
-function _libraries_test_post_detect_callback(&$library, $version, $variant) {
+function _libraries_test_post_detect_callback(&$library, $versio = NULL, $variant = NULL) {
   _libraries_test_callback($library, $version, $variant, 'post-detect');
 }
 
@@ -366,7 +404,7 @@ function _libraries_test_post_detect_callback(&$library, $version, $variant) {
  *
  * @see _libraries_test_callback()
  */
-function _libraries_test_load_callback(&$library, $version, $variant) {
+function _libraries_test_load_callback(&$library, $version = NULL, $variant = NULL) {
   _libraries_test_callback($library, $version, $variant, 'load');
 }
 
@@ -442,6 +480,30 @@ function libraries_test_menu() {
     'page arguments' => array('example_versions_and_variants', 'example_variant_2'),
     'access callback' => TRUE,
   );
+  $items['libraries_test/js_css/file'] = array(
+    'title' => 'Test JavaScript and CSS: Local files',
+    'page callback' => '_libraries_test_load',
+    'page arguments' => array('example_js_css', 'file'),
+    'access callback' => TRUE,
+  );
+  $items['libraries_test/js_css/external'] = array(
+    'title' => 'Test JavaScript and CSS: External files',
+    'page callback' => '_libraries_test_load',
+    'page arguments' => array('example_js_css', 'external'),
+    'access callback' => TRUE,
+  );
+  $items['libraries_test/js_css/inline'] = array(
+    'title' => 'Test JavaScript and CSS: Inline code',
+    'page callback' => '_libraries_test_load',
+    'page arguments' => array('example_js_css', 'inline'),
+    'access callback' => TRUE,
+  );
+  $items['libraries_test/js_css/setting'] = array(
+    'title' => 'Test JavaScript and CSS: JavaScript settings',
+    'page callback' => '_libraries_test_load',
+    'page arguments' => array('example_js_css', 'setting'),
+    'access callback' => TRUE,
+  );
   return $items;
 }
 
