You are here

swftools.module in SWF Tools 6.3

Same filename and directory in other branches
  1. 5 swftools.module
  2. 6 swftools.module
  3. 6.2 swftools.module

The primary component of SWF Tools that enables comprehensive media handling.

File

swftools.module
View source
<?php

/**
 * @file
 * The primary component of SWF Tools that enables comprehensive media handling.
 */

// Include the generic player module for basic mp3 and flv support
module_load_include('inc', 'swftools', 'includes/swftools.genericplayers');

// Load core module
module_load_include('inc', 'swftools', 'includes/swftools.core');

/**
 * @addtogroup swftools
 * @{
 */

/**
 * Other modules can query whether SWF Tools is present by checking for this constant.
 */
define('SWFTOOLS_INSTALLED', TRUE);

/**
 * Used in various places to indicate that the requested item is undefined.
 */
define('SWFTOOLS_UNDEFINED', '__undefined');

/**
 * The calling function is requesting player settings and only needs settings that are non-default.
 */
define('SWFTOOLS_MINIMUM_SETTINGS', 0x1);

/**
 * The calling function is requesting player settings and wants the full set, including blanks and defaults.
 */
define('SWFTOOLS_FULL_SETTINGS', 0x2);

/**
 * SWF Tools should return mark up to place on the page.
 */
define('SWFTOOLS_RETURN_MARKUP', 0x0);

/**
 * SWF Tools should return the cid for the content which was stored in the cache.
 */
define('SWFTOOLS_RETURN_CID', 0x1);

/**
 * This playlist does not return xml but updates the data array directly.
 */
define('SWFTOOLS_NON_XML_PLAYLIST', '');

/**
 * Settings are being stored in to the variables table.
 */
define('SWFTOOLS_ADMIN_STORE', 0x1);

/**
 * Settings are being retrieved from the variables table.
 */
define('SWFTOOLS_ADMIN_RETRIEVE', 0x0);

/**
 * Don't write any error messages.
 */
define('SWFTOOLS_ERROR_NONE', 0x0);

/**
 * Write error messages to the watchdog.
 */
define('SWFTOOLS_ERROR_WATCHDOG', 0x1);

/**
 * Write error messages to the screen.
 */
define('SWFTOOLS_ERROR_SCREEN', 0x2);

/**
 * Write error messages to both screen and watchdog.
 */
define('SWFTOOLS_ERROR_WATCHDOG_AND_SCREEN', 0x3);

/**
 * Accessible controls should be disabled.
 */
define('SWFTOOLS_ACCESSIBLE_DISABLED', 0x0);

/**
 * Accessible controls should be enabled but hidden.
 */
define('SWFTOOLS_ACCESSIBLE_HIDDEN', 0x1);

/**
 * Accessible controls should be enabled and visible on the page.
 */
define('SWFTOOLS_ACCESSIBLE_VISIBLE', 0x3);

/**
 * SWF Tools does not allow access to private files by default.
 */
define('SWFTOOLS_PRIVATE_ACCESS_DENIED', 0x0);

/**
 * When private access via SWF Tools is enabled grant access to these extensions.
 */
define('SWFTOOLS_PRIVATE_ACCESS_ALLOWED_EXTENSIONS', 'swf flv xml mp3 jpg jpeg png');

/**
 * The swf content was not available in the cache.
 */
define('SWFTOOLS_NOT_CACHED', FALSE);

/**
 * @} End of "addtogroup swftools"
 */

/**
 * Implementation of hook_init().
 */
function swftools_init() {

  // Add JavaScript that allows other scripts to access movies from the DOM
  drupal_add_js(drupal_get_path('module', 'swftools') . '/swftools.js');

  // Add CSS to enable hiding of accessible controls
  drupal_add_css(drupal_get_path('module', 'swftools') . '/swftools.css');
}

/**
 * Implementation of hook_menu().
 */
function swftools_menu() {

  // Reset methods cache
  $methods = swftools_get_methods('', TRUE);

  // Should this be administer swf tools?
  $swf_admin = array(
    'administer flash',
  );
  $items['admin/settings/swftools'] = array(
    'title' => 'SWF Tools',
    'description' => 'Settings to control how SWF Tools integrates with Adobe Flash related methods and tools like video players, MP3 players and image viewers.',
    'access arguments' => $swf_admin,
    'page callback' => 'system_admin_menu_block_page',
    'file' => 'system.admin.inc',
    'file path' => drupal_get_path('module', 'system'),
  );
  $items['admin/settings/swftools/handling'] = array(
    'title' => 'File handling',
    'description' => 'Configure how SWF Tools should handle different types of file.',
    'access arguments' => $swf_admin,
    'weight' => -2,
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'swftools_admin_handling_form',
    ),
    'file' => 'includes/swftools.admin.inc',
  );
  $items['swftools/playlist/%'] = array(
    'title' => 'SWF Tools playlist',
    'page callback' => 'swftools_get_xml',
    'page arguments' => array(
      2,
    ),
    'access arguments' => array(
      'access content',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['swftools/page/%'] = array(
    'title' => 'SWF Tools',
    'page callback' => 'swftools_get_html',
    'page arguments' => array(
      2,
    ),
    'access arguments' => array(
      'access content',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['admin/settings/swftools/embed'] = array(
    'title' => 'Embedding settings',
    'description' => 'Set the embedding method that SWF Tools should use, and configure embedding defaults.',
    'access arguments' => $swf_admin,
    'weight' => -2,
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'swftools_admin_embed_form',
    ),
    'file' => 'includes/swftools.admin.inc',
  );

  // If CCK is active then add a link to the CCK formatters
  if (module_exists('content')) {
    $items['admin/settings/swftools/cck'] = array(
      'title' => 'CCK formatters',
      'description' => 'Additional settings to control how SWF Tools should interact with CCK.',
      'access arguments' => $swf_admin,
      'page callback' => 'drupal_get_form',
      'page arguments' => array(
        'swftools_admin_cck_form',
      ),
      'file' => 'includes/swftools.admin.inc',
    );
  }

  // Add SWF Tools status report
  $items['admin/reports/swftools'] = array(
    'title' => 'SWF Tools status',
    'description' => 'Get an overview of the status of the SWF Tools module and its supporting files.',
    'page callback' => 'swftools_status',
    'access arguments' => $swf_admin,
    'file' => 'includes/swftools.admin.status.inc',
    'weight' => 9,
  );

  // Integrate items from the generic players module
  $items = array_merge($items, swftools_genericplayers_menu());

  // Return array of menu items
  return $items;
}

/**
 * Implementation of hook_perm().
 */
function swftools_perm() {
  return array(
    'administer flash',
  );
}

/**
 * Processes a file, or an array of files, and returns the relevant mark-up to
 * render a Flash based player.
 *
 * @param mixed $content
 *   The content to be played. If it is a SWF file it will usually be embedded directly.
 *   Use a full URL, a path relative to webroot, or a path relative to the configured files directory.
 *   If an array is passed then the array will be converted to a playlist automatically.
 *   If it is a string and it is a complete url then SWF Tools will pass it along unaltered.
 *   If the string is a partial path then it will either be resolved to the local file system,
 *   or to a remote host, depending whether the swftools_media_url variable is set.
 * @param array $options
 *   An associative array of optional paramters and settings containing:
 *   - params: An associative array of <param> variables to set.eg. array('bgcolor'=>'FF00FF'),
 *     or to set the height and width: array('width'=>'200', 'height'=>'120').
 *     If you pass nothing, and the file to play is a .swf, swftools will try and
 *     establish a natural width and height from the actual .swf file that you've
 *     passed into $file.
 *   - flashvars: An associative array of flashvar variables to set. eg.
 *     array('playlist'=>'files/my_playlist.xml')
 *   - othervars: An associative array of variables that might be required by the $player
 *     or $embed technique. These values are not output as params or flashvars.
 *   - methods: An array of data to explicitly declare an action, player or embed method and
 *     over-ride the default value that SWF Tools will otherwise use. Contains the following
 *     optional keys:
 *     - action: (string) A specific action to be taken, e.g. image_list
 *     - player: (string) A specific player to be used, e.g. flowplayer3
 *     - embed: (string) A specific embedding method, e.g. swftools_direct
 *
 * @return string
 *   A markup string.
 *
 * @ingroup swftools
 */
function swf($content, $options = array()) {

  //  $time_start = microtime(true);
  // TODO: We should put SWF Tools own settings somewhere safe in the othervars array
  // If someone passes a variable from the input filter it could collide.
  // Maybe put them under #swftools (since the data are properties of swftools?)
  // A finished item has player, profile, cid, id, file_url, src_path, src
  // Initialise any $options array elements that weren't passed by the caller
  swftools_initialise_options($options);

  // Initialise othervars with some defaults
  $options['othervars'] += array(
    'profile' => '',
    'return' => SWFTOOLS_RETURN_MARKUP,
    'playlist_data' => '',
    'image' => '',
    'stream' => FALSE,
    'xml' => '',
  );

  // Initialise methods with some defaults
  $options['methods'] += array(
    'action' => '',
    'player' => '',
    'embed' => '',
  );

  // Initialise params with some defaults
  $options['params'] += array(
    'base' => swftools_get_base(),
  );

  // See if we can get this item from the SWF Tools cache
  if (($ret = swftools_get_from_cache($content, $options)) && variable_get('swftools_cache', CACHE_NORMAL)) {

    //      $time_end = microtime(true);
    //      $time = $time_end - $time_start;
    //      dsm('Used cache in ' . $time);
    if ($ret->headers && ($script_location = variable_get('swftools_javascript_location', SWFTOOLS_JAVASCRIPT_INLINE))) {
      drupal_add_js($ret->headers, 'inline', $script_location == SWFTOOLS_JAVASCRIPT_HEADER ? 'header' : 'footer');
    }
    return $options['othervars']['return'] == SWFTOOLS_RETURN_CID ? $options['othervars']['cid'] : $ret->data['html'];
  }

  // Ensure id is unique, or assign an id if one isn't set
  $options['othervars']['id'] = swftools_get_id($options['othervars']['id']);

  // If swf() was called with an array of files, make a playlist
  if (is_array($content)) {

    // Turn the array in to a playlist and attach it to othervars
    swftools_prepare_playlist($content, $options);
  }

  // ACTION
  // Work out what SWF Tools should do with this file (e.g. video, audio)
  // If an explicit action wasn't set then try to determine an appropriate one using the filename
  $options['methods']['action'] = $options['methods']['action'] ? swftools_fix_old_action_names($options['methods']['action']) : swftools_get_action($content);

  // RESOLVE PLAYER AND EMBEDDING
  // 'resolved' refers to the fact that these are the methods we now intend to use, not /all/ methods available.
  // PLAYER
  // Work out what player SWF Tools will need to use for this action
  // If an explicit player wasn't set then find out what player is configured for the current action
  $options['methods']['player'] = $options['methods']['player'] ? swftools_fix_old_player_names($options['methods']['player']) : swftools_get_player($options['methods']['action'], $options['othervars']['profile']);

  // If there is no player assigned we don't what to do with this action
  if (!$options['methods']['player']) {

    // Get the descriptions that go with the actions
    $actions = swftools_get_actions();

    // If we have a matching description for the specified action, create a meaningful message
    if (isset($actions[$options['methods']['action']]['#description'])) {

      // If we also have a meaningful profile name use that too
      if ($options['othervars']['profile']) {
        if (function_exists('swftools_profiles_get_profile') && ($profile = swftools_profiles_get_profile($options['othervars']['profile']))) {
          $profile = $profile['name'];
        }
        else {
          $profile = $options['othervars']['profile'];
        }
        $profile = t('@profile profile', array(
          '@profile' => $profile,
        ));
      }
      else {
        $profile = 'SWF Tools';
      }

      // And output a message
      swftools_set_error('swftools', 'No player is configured for %action. Check the %profile file handling settings.', array(
        '%action' => $actions[$options['methods']['action']]['#description'],
        '%profile' => $profile,
      ), WATCHDOG_WARNING);
    }
    else {
      swftools_set_error('swftools', 'No modules have registered the action %action. Check any required supporting modules are enabled.', array(
        '%action' => $options['methods']['action'],
      ), WATCHDOG_WARNING);
    }

    // We couldn't find a player for this content, so fallback to the alternate markup and return
    return theme('swftools_html_alt', $options);
  }

  // Get all the actions, tools and embedding options available to us
  $all_methods = swftools_get_methods();

  // Check that the action / player combination is valid (it should appear in the array of all methods)
  if (isset($all_methods[$options['methods']['action']][$options['methods']['player']])) {

    // The combination was found, place player information in to resolved_methods
    $options['resolved_methods']['player'] = $all_methods[$options['methods']['action']][$options['methods']['player']];
  }
  else {

    // Get the descriptions that go with the actions
    $actions = swftools_get_actions();

    // Set an error
    swftools_set_error('swftools', 'The combination of %player with %action is not valid. Check that the player is available and that it supports the requested action.', array(
      '%player' => $options['methods']['player'],
      '%action' => $options['methods']['action'],
    ), WATCHDOG_WARNING);

    // Return alternate markup
    return theme('swftools_html_alt', $options);
  }

  // EMBED
  // Work out what embedding method SWF Tools should use for this content
  // If an explicit embed method was not set then assign one now
  $options['methods']['embed'] = $options['methods']['embed'] ? $options['methods']['embed'] : variable_get('swftools_embed_method', 'swftools_direct');

  // Place the embedding method information in to resolved_methods
  $options['resolved_methods']['embed'] = $all_methods['swftools_embed_method'][$options['methods']['embed']];

  // PARAMS
  // If $options['params'] is not an array then assume it is width x height as a string
  // TODO: This is an ugly legacy - can we retire it?
  if (!is_array($options['params'])) {

    // Explode string
    $dimensions = explode('x', $options['params']);

    // If we got two pieces assume success
    if (count($dimensions) == 2) {
      $options['params'] = array(
        'width' => $dimensions[0],
        'height' => $dimensions[1],
      );
    }
  }

  // FLASHVARS
  // If the flashvars were passed as a string then turn it in to an array
  // Does the filter pass the flashvars as a string? Could we explode the string in
  // their, and then we know we only get an array?
  if (!is_array($options['flashvars'])) {
    parse_str($options['flashvars'], $options['flashvars']);
  }

  // XML PLAYLIST
  // Determine if we are trying to generate a playlist that needs xml output, and create it if required
  // If $options['othervars']['playlist_data'] is set then we are processing a playlist
  if ($options['othervars']['playlist_data']) {

    // Try to generate an xml playlist and get the path to the xml file. $content will be an empty string if we don't need xml.
    $content = swftools_generate_playlist($options);
  }

  // FILE
  // Make sure that the file path in $content is valid, and as necessary try to
  // expand it to a relative url on the local file system, or point to the remote media directory
  // First we assume that we can just set $file_url to the value in $content
  $file_url = $content;

  // If we are not streaming this file, and $content isn't empty, then we might need to process it to get a proper path
  if (!$options['othervars']['stream'] && $content) {

    // Process to get a url (in src) and expand the path (in src_path) if necessary
    $source = swftools_get_url_and_path($content);

    // If FALSE was returned then the file doesn't exist so return $html_alt
    if (!$source) {
      return theme('swftools_html_alt', $options);
    }

    // $file might need to be changed to reflect a path on the local file system
    // This happens when the user just supplied a filename and files are being sourced locally
    // Put $content = $source['filepath'] in case that happened
    $content = $source['filepath'];

    // In all cases $file_url is now an absolute, or relative, url to the file that we can use
    $file_url = $source['fileurl'];
  }

  // Attach file_url to othervars so player modules have access if required
  $options['othervars']['file_url'] = $file_url;

  // Depending if we are outputting a swf or using a player we need to attach $file in different places
  switch ($options['methods']['player']) {

    // Embedding an swf directly - no player
    case 'swf':
      $options['othervars']['filepath'] = $content;
      $options['othervars']['fileurl'] = $file_url;
      break;

    // Embedding with a player
    default:
      if ($options['resolved_methods']['player']['library']) {
        $options['othervars']['filepath'] = $options['resolved_methods']['player']['library'];
        $options['othervars']['fileurl'] = base_path() . $options['othervars']['filepath'];
      }
  }

  // Merge default and user defined parameters, with user defined ones taking precedence
  $options['params'] = array_merge(_swftools_params(), $options['params']);

  // If player requires a higher version of flash than the current default then over-ride the default
  if (version_compare($options['resolved_methods']['player']['version'], $options['params']['version'], '>')) {
    $options['params']['version'] = $options['resolved_methods']['player']['version'];
  }

  /**
   * We used to call hook_flashvars, using the module name, but we are starting to do a lot
   * more than just flashvars. So we will borrow from the theme system and implement
   * hook_swftools_preprocess_[playername]. Normally you would just expect the module that
   * defines the player to handle its own players, but in theory anyone can hook in at this
   * point and manipulate the entire data array just before we output it.
   */
  $preprocess = 'swftools_preprocess_' . $options['resolved_methods']['player']['name'];
  foreach (module_implements($preprocess) as $module) {
    $function = $module . '_' . $preprocess;
    $function($options);
  }

  // TODO: Can we deprecate this - we are accommodating the ability to specify width x height in a string on params.
  // We used to set height and width on $vars->params, but they're not actually params and they were
  // being unset in individual embedding functions. So we'll move them to $vars->othervars.
  // We will continue to let users pass the data on $vars->params so as not to break existing code.
  if (!isset($options['othervars']['height']) && !empty($options['params']['height'])) {
    $options['othervars']['height'] = $options['params']['height'];
    unset($options['params']['height']);
  }
  if (!isset($options['othervars']['width']) && !empty($options['params']['width'])) {
    $options['othervars']['width'] = $options['params']['width'];
    unset($options['params']['width']);
  }

  // Try and make sure we have a size set on this content
  swftools_set_size($options);

  // Change html_alt to include the first image when handling an image list
  // TODO: Should this be an option that can be disabled?
  if ($options['methods']['action'] == 'image_list') {
    swftools_image_html_alt($options);
  }

  // See if anyone wants to alter anything just before it is output
  drupal_alter('swftools', $options);

  // Call theme function
  $output = theme('swftools_embed', $options);

  // See if the embed placed a script for us to cache
  $script = ($data = drupal_get_js($options['othervars']['id'])) ? str_replace(array(
    "<script type=\"text/javascript\">\n<!--//--><![CDATA[//><!--\n",
    "\n//--><!]]>\n</script>\n",
  ), '', $data) : '';

  // Cache the result using an array to store the markup and any associated xml
  cache_set($options['othervars']['cid'], array(
    'html' => $output,
    'xml' => $options['othervars']['xml'],
  ), 'cache_swftools', CACHE_TEMPORARY, $script);

  // If we want just the cid then return that
  if ($options['othervars']['return'] == SWFTOOLS_RETURN_CID) {
    return $options['othervars']['cid'];
  }

  // Return the markup
  return $output;
}

/**
 * Converts an array of paramters to JSON and returns them as a string ready for use as a flashvar.
 *
 * @param array $params
 *   An array of parameters.
 * @param string $attribute
 *   The attribute that the JSON string will be attached to.
 *
 * @return string
 *   A string in the form [attr]={JSON}
 */
function swftools_json_params(&$params, $attribute = 'swftools') {
  return $attribute . "='" . drupal_to_js($params) . "'";
}

/**
 * Returns 'true' or 'false' for JavaScript based the supplied value $bool.
 *
 * @param bool $bool
 *   The value that should be cast to true or false.
 *
 * @return string
 *   The string value 'true' or 'false' depending on the supplied value.
 */
function _swftools_tf($bool) {

  // String 'false' is treated as TRUE in PHP logic, so force to FALSE
  if (strtolower($bool) == 'false') {
    $bool = FALSE;
  }

  // Return 'true' or 'false' now we are sure of result
  return $bool ? 'true' : 'false';
}

/**
 * Returns the currently configured player for the specified action and profile.
 *
 * We use a static array so that if we are generating a complex page we can
 * quickly locate the relevant action/profile player after we've done it the
 * first time. This saves us from repeat calls to swftools_variable_get().
 *
 * @param string $action
 *   The SWF Tools action to be performed.
 * @param string $profile
 *   (optional) The profile being used for this item.
 *
 * @return string
 *   The name of the currently configured player for this action.
 */
function swftools_get_player($action, $profile = '') {

  // Initialise a static array for this page call
  static $players = array();

  // We need to give the empty profile a name to place it in the array
  $_profile = $profile ? $profile : SWFTOOLS_UNDEFINED;

  // Do we already know the players for this profile?
  if (!isset($players[$_profile])) {

    // Register the players for this profile in the array
    $players[$_profile] = swftools_get_players($profile);
  }

  // Return the result
  return isset($players[$_profile][$action]) ? $players[$_profile][$action] : FALSE;
}

/**
 * Returns an array of default values to use as the swf parameters.
 * Parameters are described in the Adobe knowledge base TechNote 12701
 * http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_12701
 */
function _swftools_params() {

  // Cache this
  static $params = array();

  // If not set then get defaults
  if (!$params) {

    // Define default parameters for case when settings have been stored
    $defaults = array(
      'swliveconnect' => 'false',
      'play' => 'true',
      'loop' => 'true',
      'menu' => 'false',
      'allowfullscreen' => 'true',
      'quality' => 'autohigh',
      'scale' => 'showall',
      'align' => 'l',
      'salign' => 'tl',
      'wmode' => 'opaque',
      'bgcolor' => '',
      'version' => '7',
      'allowscriptaccess' => 'sameDomain',
    );

    // Retrieve settings from the database if available
    $params = variable_get('swftools_params', $defaults);
  }

  // Return the default parameters
  return $params;
}

/**
 * Returns information about the specified file.
 *
 * We use this function to try and get the height and width for content that
 * we don't have a specific size for.
 *
 * The returned value is an array that may include width, height, extension,
 * file_size, mime_type. We return FALSE if we didn't get a valid file, or if
 * image_get_info() couldn't tell us anything.
 *
 * @parameter string $file
 *   Path to a local file that we want to interrogate.
 *
 * @return mixed
 *   An array of data, or FALSE if we didn't get anything.
 */
function swftools_get_info($file) {

  // Assume we won't have data
  $info = FALSE;

  // Try to get image info (first assume it is in the file directory (most likely case))
  if ($try = file_create_path($file)) {
    $info = image_get_info($try);
  }

  // If it wasn't in the file system just try the file path - that might be valid
  if (!$info) {
    $info = image_get_info($file);
  }

  // Return either the info array, or it will be FALSE if we got nothing
  return $info;
}

/**
 * Generates an playlist and places it in {cache_swftools} ready for use.
 *
 * This relies on player modules implementing hook_swftools_playlist_[player].
 * A module implementing this hook may either return an xml string that will be
 * used by the player, or it may update the data array directly.
 *
 * We don't check for the existence of this content in the cache already. If we
 * are here then the swf wasn't in the cache, so the xml isn't either.
 *
 * We used to create an actual file. Now we place the content in {cache_swftools}
 * and access it via swftools/playlist/nnn, where nnn is the cid.
 *
 * The xml result from this function is attached to $options['othervars']['xml']
 * and the the calling swf() function will cache this for us.
 *
 * @param &$options
 *   The SWF Tools data array for this element.
 *
 * @return
 *   The path to the virtual xml file (will be in the form swftools/playlist/nnn),
 *   or an empty string (SWFTOOLS_NON_XML_PLAYLIST) if there is no xml.
 */
function swftools_generate_playlist(&$options) {

  // Determine the name of the hook that would be used to generate an xml playlist
  $hook = '_swftools_playlist_' . $options['resolved_methods']['player']['name'];

  // Build the name of the function we would call
  $function = $options['resolved_methods']['player']['module'] . $hook;

  // See if the function exists - if it doesn't the module doesn't implement this hook
  if (function_exists($function)) {

    // Call the function and pass variables by reference
    $playlist = $function($options);

    // If playlist is not empty this is an xml playlist
    if ($playlist) {

      // Store the result on to $optinos['othervars']['xml']
      $options['othervars']['xml'] = $playlist;

      // Return the path to the xml
      //      return url('swftools/playlist/' . $options['othervars']['cid'] . '.xml');
      return url('swftools/playlist/' . $options['othervars']['cid']);
    }
  }

  // We don't have hook_swftools_playlist_[player] for this player, return an empty string
  return SWFTOOLS_NON_XML_PLAYLIST;
}

/**
 * Prepares an array of filenames, or file objects, for use in a playlist.
 *
 * This function processes the supplied array and returns an array of playlist data which has
 * two elements, header and playlist. The header array contains the playlist title, which may
 * be an empty string if nothing was set. The playlist array contains an array of playlist
 * elements. As a minimum each element will contain:
 * - filepath : the filepath for the file, if it is a local file, or FALSE if a full url
 * - title : the title for the element, set to the filename if nothing given
 * - filename : the filename for the file
 * - fileurl : the full url to the file
 *
 * drupal_alter is called just prior to returning the playlist, so a module can implement
 * hook_swftools_playlist_alter(&$playlist_data) to modify the playlist prior to return. This
 * means other modules can modify, or add, elements. For example, the swftools_getid3 module
 * implements this hook to attach ID3 data to each playlist element.
 *
 * @param array $files
 *   An array of files that will be added to the playlist.
 * @param array $options
 *   Array of data passed in from the calling swf() function.
 *
 * @return nothing
 *   Attaches the resulting playlist data to $options['othervars']['playlist_data']
 */
function swftools_prepare_playlist($files, &$options) {

  // Make sure stream and action are present on options
  $options['methods'] += array(
    'player' => '',
  );

  // Initialise two flags for establishing the action to be taken on this playlist
  $action = '';
  $mixed_media = FALSE;

  // Initialise playlist data array
  $playlist_data = array(
    'header' => array(),
    'playlist' => array(),
  );

  // Iterate over the array of files to set filepath, fileurl and title keys
  foreach ($files as $key => $data) {

    // If $data is an object convert it to an array
    if (is_object($data)) {
      $data = (array) $data;
    }
    elseif (!is_array($data)) {

      // Create an array with key filepath set to the $data string
      $data = array(
        'filepath' => $data,
      );
    }

    // Attach the incoming element to the playlist
    $playlist_data['playlist'][$key] = $data;

    /**
     * Ensure the title key is present to simplify later code as we know it will be present.
     * Note we no longer set a default title. We leave it empty since all output should
     * now be handled by a theme function, so if the user wants to make a default we can
     * let them since they will know a specific value wasn't given. We don't do it for them.
     *
     * We also initialise some other empty strings to make checks in other modules easier.
     */
    $playlist_data['playlist'][$key] += array(
      'title' => '',
      'image' => '',
      'description' => '',
      'author' => '',
      'date' => '',
      'link' => '',
      'duration' => '',
      'stream' => FALSE,
    );

    // Find out if this item is a stream by checking for rtmp and exploding it
    if (strpos($playlist_data['playlist'][$key]['filepath'], 'rtmp:') === 0) {
      $stream = explode(' ', $playlist_data['playlist'][$key]['filepath']);

      // If the filepath exploded then assume we have a valid stream
      if (count($stream) == 2) {
        list($playlist_data['playlist'][$key]['stream'], $playlist_data['playlist'][$key]['filepath']) = $stream;
        $options['othervars']['stream'] = TRUE;

        // TODO: Action checking fails as streams don't have an extension - assume mixed media
        $options['methods']['action'] = 'media_list';
      }
    }

    // If this whole playlist isn't a stream, and this item isn't a stream
    if (!is_string($options['othervars']['stream']) && !$playlist_data['playlist'][$key]['stream']) {

      // Expand $file as necessary if local or remote
      $source = swftools_get_url_and_path($playlist_data['playlist'][$key]['filepath']);

      // Store results
      $playlist_data['playlist'][$key]['filepath'] = $source['filepath'];
      $playlist_data['playlist'][$key]['fileurl'] = $source['fileurl'];
    }
    else {
      $playlist_data['playlist'][$key]['fileurl'] = $playlist_data['playlist'][$key]['filepath'];
    }

    // See if we have an image we need to expand
    if ($playlist_data['playlist'][$key]['image']) {
      $source = swftools_get_url_and_path($playlist_data['playlist'][$key]['image']);
      $playlist_data['playlist'][$key]['image'] = $source['fileurl'];
    }

    // Allow other modules to modify this playlist element (e.g. getID3)
    drupal_alter('swftools_playlist_element', $playlist_data['playlist'][$key]);

    // If the caller wants us to work out the action for them then it happens in here
    if (!$options['methods']['action']) {

      // Get the extension for this item
      $extension = strtolower(pathinfo($playlist_data['playlist'][$key]['fileurl'], PATHINFO_EXTENSION));

      // Only try to determine actions if there's an extension to work with, and we didn't already work out it's mixed
      if ($extension && !$mixed_media) {

        // Work out what we'd do with this file
        $action_for_this_file = swftools_get_action('dummy.' . $extension);

        // If this is the first file we've processed we log it
        if (!$action) {
          $action = $action_for_this_file;
        }

        // Is this action the same as the first file we saw? If not we have mixed media
        if ($action != $action_for_this_file) {
          $mixed_media = TRUE;
          $action = 'media_list';
        }
      }
    }
  }

  // If we didn't get an action (happens with streams as they have no extension) then specify an action now
  $action = $action ? $action : 'media_list';

  // Pluralize the action for multiple files if not already pluralized
  $action = substr($action, -5, 5) == '_list' ? $action : $action . '_list';

  // If the called didn't specify an action then assign it now
  $options['methods']['action'] = $options['methods']['action'] ? $options['methods']['action'] : $action;

  // Attach the resulting playlist to the array (we are working by reference)
  $options['othervars']['playlist_data'] = $playlist_data;

  // Call drupal_alter to let other modules modify the entire playlist if they want
  drupal_alter('swftools_playlist', $playlist_data);
}

/**
 * Implementation of hook_filter_tips().
 */
function swftools_filter_tips($delta, $format, $long = FALSE) {
  if ($long) {
    return t('
    <h3 id="swftools_filter">SWF Tools Filter</h3>
    <p>The basic syntax for embedding a flash file (.swf), flash movie (.flv) or audio file (.mp3) is:</p>
    <blockquote><code>[swf file="filename.swf"]</code></blockquote>

    <p>If you would like to override SWF Tools and flash player default settings,
       you can specify additional parameters. For example:</p>
    <blockquote><code>[swf file="song.mp3" flashvars="backcolor=#AABBCC&&forecolor=#11AA11"]</code></blockquote>
    <p>If you would like to output a list of files then the format is:</p>
    <blockquote><code>[swf files="image1.jpg&&image2.jpg&&..."]</code></blockquote>
    SWF Tools Filter will accept following:
    <ul>
      <li><b>params</b> : You can specify values for parameters to be passed to Flash
                           to control the appearance of the output. Typical values are
                           bgcolor and wmode. Example: <code>params="wmode=true&&bgcolor="#00FF00"</code>
                           Alternatively you can supply each parameter individually without using
                           <code>params</code>. Example <code>wmode="true" bgcolor="#00FF00"</code></li>
      <li><b>flashvars</b> : You can specify values for output as flashvars, which
                           become available to the Flash movie that is playing. This is often done
                           to control a media player. Refer to the documentation of the flash player
                           you are using to know what flashvar options are available.
                           Example: <code>flashvars="autostart=true&&volume=80"</code></li>
      <li><b>methods</b> : Optional information about how to display the file. The most
                           common usage is to specify a particular media player and
                           thus override the default specified on the settings page.
                           Example: <code>methods="player=onepixelout_mp3"</code></li>
       </ul>
      <p><strong>WARNING</strong>: with params, flashvars and othervars, pass multiple values
                      separated by <strong>&amp;&amp;</strong>.</p>');
  }
  else {
    return t('You may use [swf file="song.mp3"] to display Flash files and media.');
  }
}

/**
 * Implementation of hook_filter().
 */
function swftools_filter($op, $delta = 0, $format = -1, $text = '') {
  switch ($op) {
    case 'list':
      return array(
        0 => t('SWF Tools filter'),
      );
    case 'no cache':
      return FALSE;
    case 'description':
      return t('Substitutes [swf file="filename.flv"] or [swf files="file1.jpg&&file2.jpg"] with embedding code.');
    case 'prepare':

      // replace <swf > with [swf ] to prevent other filters stripping
      return preg_replace('/\\<(swflist|swf)\\s*(.*)>/sU', '[\\1 \\2]', $text);
    case 'process':
      return _swftools_filter_process_text($text);
  }
}

/**
 * Processes text obtained from the input filter.
 *
 * This function processes the filter text that the user has added to the text area.
 * If the filter is wrapped in <p></p> then these are stripped as part of the processing
 * This eliminates a validation error in the resulting mark up if SWF Tools filter is
 * being used in conjunction with other HTML filters that correct line breaks.
 * It won't work in EVERY case, but it will work in MOST cases.
 * Filters that are embedded in-line with text will continue to fail validation.
 */
function _swftools_filter_process_text($text) {
  $endl = chr(13);
  if (preg_match_all('@(?:<p>)?\\[(swflist|swf)\\s*(.*?)\\](?:</p>)?@s', $text, $match)) {

    // $match[0][#] .... fully matched string <swf|swflist parm_0="value_0" parm_1="value_1" parm_2="value_2">
    // $match[1][#] .... matched tag type ( swf | swflist )
    // $match[2][#] .... full params string until the closing '>'
    $swftools_parameters = array(
      'file',
      'params',
      'flashvars',
      'othervars',
      'methods',
      'files',
    );
    $match_vars = array();

    // Initialise an array to hold playlist arrays
    $files = array();
    foreach ($match[2] as $key => $passed_parameters) {

      //preg_match_all('/(\w*)=\"(.*?)\"/', $passed_parameters, $match_vars[$key]);
      preg_match_all('/(\\w*)=(?:\\"|&quot;)(.*?)(?:\\"|&quot;)/', $passed_parameters, $match_vars[$key]);

      // $match_vars[0][#] .... fully matched string
      // $match_vars[1][#] .... matched parameter, eg flashvars, params
      // $match_vars[2][#] .... value after the '='
      // Process the parameters onto the $prepared array.
      // Search for standard parameters, parse the values out onto the array.
      foreach ($match_vars[$key][1] as $vars_key => $vars_name) {

        // Switch to swf or swflist, based on file or files
        // Need to tidy up this line, probably use switch/case
        if ($vars_name == 'file') {
          $match[1][$key] = 'swf';
        }
        else {
          if ($vars_name == 'files') {
            $match[1][$key] = 'swflist';
          }
        }
        if ($vars_name == 'file') {
          $prepared[$key][$vars_name] = $match_vars[$key][2][$vars_key];
          unset($match_vars[$key][1][$vars_key]);
        }
        elseif (in_array($vars_name, $swftools_parameters)) {
          $prepared[$key][$vars_name] = swftools_parse_str(str_replace(array(
            '&amp;&amp;',
            '&&',
          ), '&', $match_vars[$key][2][$vars_key]));
          unset($match_vars[$key][1][$vars_key]);
        }
        else {
          $prepared[$key]['othervars'][$vars_name] = $match_vars[$key][2][$vars_key];
        }
      }

      // Search for remaining parameters, map them as elements of the standard parameters.
      if (isset($prepared[$key]['methods']['player'])) {
        $player = strtolower($prepared[$key]['methods']['player']);
      }
      else {
        $player_key = array_search('player', $match_vars[$key][1]);
        if ($player_key !== FALSE) {
          $player = strtolower($match_vars[$key][2][$player_key]);
        }
        else {
          $player = FALSE;
        }
      }
      $prepared[$key]['methods']['player'] = $player;
      if (count($match_vars[$key][1])) {

        // Find out if a player has been set.
        foreach ($match_vars[$key][1] as $vars_key => $vars_name) {
          if ($parent = swftools_get_filter_alias($vars_name, $player)) {
            if ($parent) {
              $prepared[$key][$parent][$vars_name] = $match_vars[$key][2][$vars_key];
            }
          }
        }
      }

      // Just assigning parameters as false if not already set on the $prepared array.
      // Really just to avoid declaration warnings when we call swf and swf_list
      if (count($prepared[$key])) {
        foreach ($swftools_parameters as $swfparameter) {
          if (!isset($prepared[$key][$swfparameter])) {
            $prepared[$key][$swfparameter] = array();
          }
        }
      }

      // Assemble in to an array of options ready to pass
      $options = array();
      $options['params'] = $prepared[$key]['params'];
      $options['flashvars'] = $prepared[$key]['flashvars'];
      $options['othervars'] = $prepared[$key]['othervars'];
      $options['methods'] = $prepared[$key]['methods'];

      // Do not allow override of alternate HTML unless setteings allow it
      if (isset($options['othervars']['html_alt']) && !variable_get('swftools_override_html_alt', 0)) {
        $options['othervars']['html_alt'] = variable_get('swftools_html_alt', SWFTOOLS_DEFAULT_HTML_ALT);
      }

      // Process the filter
      switch ($match[1][$key]) {
        case 'swf':
          $replace = swf($prepared[$key]['file'], $options);
          break;
        case 'swflist':

          // If this filter contains a key called files
          if ($prepared[$key]['files']) {

            // Iterate over the
            foreach ($prepared[$key]['files'] as $name => $filename) {
              if (!$filename) {
                $prepared[$key]['files'][$name] = $name;
              }

              // Put in to proper format for new swftools_prepare_playlist()
              $files[$key][$name]['filepath'] = $prepared[$key]['files'][$name];
            }

            // Get playlist data, but don't determine action if the user specified a player
            $replace = swf($files[$key], $options);
          }
          else {
            $replace = '<!-- No files passed to the playlist -->';
          }
          break;
      }
      $matched[] = $match[0][$key];
      $rewrite[] = $replace;
    }
    return str_replace($matched, $rewrite, $text);
  }
  return $text;
}

/**
 * Implements a hook that extends the parameters that can be passed to the filter
 * so that myvar="value" can be mapped to flashvars, etc.
 */
function swftools_get_filter_alias($var, $player = FALSE) {
  static $general_mapping = array();
  static $player_mapping = array();
  if (!count($general_mapping)) {

    // Build up the mapping arrays.
    $general_mapping = array(
      'action' => 'methods',
      'embed' => 'methods',
      'width' => 'params',
      'height' => 'params',
      'swliveconnect' => 'params',
      'play' => 'params',
      'loop' => 'params',
      'menu' => 'params',
      'quality' => 'params',
      'scale' => 'params',
      'align' => 'params',
      'salign' => 'params',
      'wmode' => 'params',
      'bgcolor' => 'params',
      'base' => 'params',
      'version' => 'params',
      'allowfullscreen' => 'params',
      'allowscriptaccess' => 'params',
    );
    if (!count($player_mapping)) {
      $player_mapping = module_invoke_all('swftools_variable_mapping');
    }
    $combined = array();
    if (count($player_mapping)) {
      foreach ($player_mapping as $mapping) {
        $combined = array_merge($combined, $mapping);
      }
      $general_mapping = array_merge($combined, $general_mapping);
    }
  }

  // Return the parent of the variable.
  if ($player && isset($player_mapping[$player][$var])) {
    return $player_mapping[$player][$var];
  }
  else {
    return isset($general_mapping[$var]) ? $general_mapping[$var] : FALSE;
  }
}

/**
 * Parses a string passed to the input filter in to separate key value pairs.
 *
 * We cannot automatically use parse_str() because things like the list of
 * files are not key-value pairs, but just a list of items.
 *
 * @param string $string
 *   The string to parse.
 *
 * @return array
 *   An array of key/value pairs.
 */
function swftools_parse_str($string) {

  // Initialise the array
  $return = array();

  // Split the string at each &
  $pairs = split('&', $string);

  // Iterate over each piece
  foreach ($pairs as $pair) {

    // Split each piece at =
    $splitpair = split('=', $pair);

    // If there was only one item, or this key is already in the array append the value
    if (!isset($splitpair[1]) || array_key_exists($splitpair[0], $return)) {
      $return[] = $splitpair[0];
    }
    else {
      $return[$splitpair[0]] = $splitpair[1];
    }
  }

  // Return the result
  return $return;
}

/**
 * Implementation of hook_theme().
 */
function swftools_theme() {
  return array(
    // This is called by swf() when it is ready to embed
    'swftools_embed' => array(
      'arguments' => array(
        'data' => NULL,
      ),
      'file' => 'includes/swftools.theme.inc',
    ),
    // This implements the direct embedding method
    'swftools_direct' => array(
      'arguments' => array(
        'file' => NULL,
        'data' => NULL,
      ),
      'file' => 'includes/swftools.core.inc',
    ),
    // This themes the alternate HTML markup
    'swftools_html_alt' => array(
      'arguments' => array(
        'data' => NULL,
      ),
      'file' => 'includes/swftools.core.inc',
    ),
    // These are the SWF Tools CCK formatters
    'swftools_formatter_swftools' => array(
      'arguments' => array(
        'element' => NULL,
        'profile' => NULL,
      ),
      'function' => 'theme_swftools_formatter_swftools',
      'file' => 'includes/swftools.theme.inc',
    ),
    'swftools_formatter_swftools_no_file' => array(
      'arguments' => array(
        'element' => NULL,
      ),
      'function' => 'theme_swftools_formatter_swftools',
      'file' => 'includes/swftools.theme.inc',
    ),
    'swftools_formatter_swftools_playlist' => array(
      'arguments' => array(
        'element' => NULL,
        'profile' => NULL,
      ),
      'function' => 'theme_swftools_formatter_playlist',
      'file' => 'includes/swftools.theme.inc',
    ),
    'swftools_formatter_swftools_thumbnail' => array(
      'arguments' => array(
        'element' => NULL,
        'retrieve' => NULL,
      ),
      'function' => 'theme_swftools_formatter_thumbnail',
      'file' => 'includes/swftools.theme.inc',
    ),
    // This implements the swftools Form API element
    'swftools' => array(
      'arguments' => array(
        'content' => NULL,
      ),
      'file' => 'includes/swftools.core.inc',
    ),
    // This implements the theme for basic pages served from the cache
    'swftools_page' => array(
      'template' => 'swftools-page',
      'arguments' => array(
        'content' => NULL,
      ),
      'path' => drupal_get_path('module', 'swftools') . '/includes',
      'preprocess functions' => array(
        'template_preprocess_page',
      ),
    ),
    // This implements a generic accessible controls handler
    'swftools_accessible_controls' => array(
      'arguments' => array(
        'player' => NULL,
        'id' => NULL,
        'actions' => NULL,
        'visible' => NULL,
      ),
    ),
    // This defines the path to an empty image when no thumbnail is given
    'swftools_empty_image' => array(
      'arguments' => array(
        'data' => NULL,
      ),
      'file' => 'includes/swftools.theme.inc',
    ),
  );
}

/**
 * Implementation of hook_file_download().
 *
 * Allows SWF Tools to work with a private file system that might include files
 * uploaded outside the control of an upload module, e.g. FTP of large video files.
 *
 * If the file is of a supported type, based on extension, then return a valid header.
 * If any other module returns -1 for this file then access will be denied
 * even if SWF Tools tries to allow it. See hook_file_download() for details.
 */
function swftools_file_download($file) {

  // If SWF Tools is allowed to grant access then check to see if access will be allowed
  if (variable_get('swftools_grant_access_to_private_files', SWFTOOLS_PRIVATE_ACCESS_DENIED)) {

    // Get extension of file in question
    $extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));

    // Get list of extensions that SWF Tools can grant access to
    $extensions = variable_get('swftools_grant_access_extensions', SWFTOOLS_PRIVATE_ACCESS_ALLOWED_EXTENSIONS);

    // Need access to the user object
    global $user;

    // Check if SWF Tools should grant access to this extension - skip the check for user #1
    if ($user->uid != 1) {
      $regex = '/\\.(' . ereg_replace(' +', '|', preg_quote($extensions)) . ')$/i';
      if (!preg_match($regex, $file)) {
        return;
      }
    }

    // Build an array of types that SWF Tools can react to
    $mime_types = _swftools_mime_types();

    // If file is one of the above types, based on the extension, return headers
    if (isset($mime_types[$extension])) {
      return array(
        'Content-Type: ' . $mime_types[$extension],
        'Content-Length: ' . filesize(file_create_path($file)),
      );
    }
  }
}

/**
 * Implementation of hook_swftools_methods().
 */
function swftools_swftools_methods() {

  // Module implements swf embedding (action swf)
  $methods['swf']['swf'] = array(
    'module' => 'swftools',
    'title' => t('Display the swf directly on the page'),
  );

  // Add on generic players (we have to call this hook manually as it isn't in a module)
  $methods += swftools_genericplayers_swftools_methods();

  // Return the methods that are native to SWF Tools
  return $methods;
}

/**
 * Helper function to set the size of the swf content in to $options['othervars']['height'] and ['width']
 *
 * @param array &$options
 *   Data array that is being assembled by SWF Tools.
 *
 * @return nothing
 *   Function operates by reference.
 */
function swftools_set_size(&$options) {

  // We use these defaults to filter arrays for their height and width, and assign a fallback value
  $defaults = array(
    'height' => '100%',
    'width' => '100%',
  );

  // If height and width are already set then just return
  if (count(array_intersect_key($options['othervars'], $defaults)) == 2) {
    return;
  }

  // See if we can get height and width from flashvars
  $try = array_intersect_key($options['flashvars'], $defaults);
  $options['othervars'] += $try;

  // See if we can get height and width from player
  $try = array_intersect_key($options['resolved_methods']['player'], $defaults);
  $options['othervars'] += $try;

  // If we have a height and width now then return
  if (count(array_intersect_key($options['othervars'], $defaults)) == 2) {
    return;
  }

  // Try and get size from the file to be embedded, but preserve height or width if just one was set
  $info = swftools_get_info($options['othervars']['filepath']);

  // If sizes were retrieved then use them
  if ($info) {
    $try = array_intersect_key($info, $defaults);
    $options['othervars'] += $try;
  }

  // And if all else fails, assign 100%
  $options['othervars'] += $defaults;
}

/**
 * Implementation of hook_field_formatter_info().
 */
function swftools_field_formatter_info() {
  return array(
    'swftools_no_file' => array(
      'label' => t('SWF Tools - no download link'),
      'field types' => array(
        'filefield',
        'link',
        'text',
      ),
      'multiple values' => CONTENT_HANDLE_CORE,
    ),
    'swftools_playlist' => array(
      'label' => t('SWF Tools - playlist'),
      'field types' => array(
        'filefield',
        'link',
        'text',
      ),
      'multiple values' => CONTENT_HANDLE_MODULE,
    ),
    'swftools' => array(
      'label' => t('SWF Tools - with download link'),
      'field types' => array(
        'filefield',
        'link',
      ),
      'multiple values' => CONTENT_HANDLE_CORE,
    ),
    'swftools_thumbnail' => array(
      'label' => t('SWF Tools - thumbnail'),
      'field types' => array(
        'filefield',
        'link',
        'text',
      ),
      'multiple values' => CONTENT_HANDLE_CORE,
    ),
  );
}

/**
 * Creates a relative path url from a file path, using private or public file system.
 *
 * This is an SWF Tools version of file_create_url(). The only difference is that
 * here we do not output absolute paths as we are only using these paths within the
 * context of a page and therefore relative is fine.
 *
 * @param string $path
 *   Path to the file.
 *
 * @return string
 *   A string with a complete path, relative to the local file system.
 */
function swftools_create_url($path) {

  // Strip file_directory_path from $path. We only include relative paths in urls.
  if (strpos($path, file_directory_path() . '/') === 0) {
    $path = trim(substr($path, strlen(file_directory_path())), '\\/');
  }

  // Output a relative url, using public or private file transfer
  switch (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC)) {
    case FILE_DOWNLOADS_PUBLIC:
      return base_path() . file_directory_path() . '/' . str_replace('\\', '/', $path);
    case FILE_DOWNLOADS_PRIVATE:
      return url('system/files/' . $path);
  }
}

/**
 * Determines the url for a file, and expands its filepath if necessary.
 *
 * This function is necessary because SWF Tools allows flexibility in how the site interprets
 * filenames. If just a filename is provided then this might point to a file on the local system,
 * or it might point to an external location if the remote media path is set. However, for things
 * like auto-detection of sizes to work when the filename is local it must be expanded to include
 * the file path.
 *
 * If $file is a full and valid absolute url then the function returns $file on both keys.
 *
 * If $file is full and valid url on the local system then the function returns $file on both keys.
 *
 * If $file is a path to a local file (sites/default/files/xxx) then src_path will return this,
 * and src will return a full relative url.
 *
 * If $file is just a filename and remote media is active then src and src_path will both be set
 * to the url for the external location.
 *
 * If $file is just a filename and remote media is not active then src_path will return the path
 * to the local system (so xxx becomes sites/default/files/xxx) and src will return the full
 * relative url.
 *
 * @param string $file
 *   A string containing a url or a path to a file.
 *
 * @return array
 *   An array with two keys
 *   - src: The url to the file (relative if on the local system)
 *   - src_path: The path to the file, expanded if necessary
 */
function swftools_get_url_and_path($file) {

  // src will contain a full, or relative, url that is used to render the file
  // src_path will contain a partial path (without webroot), or the original file path
  $ret = array(
    'fileurl' => '',
    'filepath' => $file,
  );

  // If already a valid absolute url simply return it
  if (valid_url($file, TRUE)) {
    $ret['fileurl'] = $file;
    return $ret;
  }

  // If a valid url, and starts with /, then assume to be a local path relative to web root
  // No security check is needed as the result of this is only output to the webpage
  // We strip base_path from the file to create filepath that is valid for image_get_info later.
  // FileField will create paths with spaces in - need to reverse that when testing for valid_url
  $temp = str_replace(' ', '%20', $file);

  //  if (valid_url($file) && strpos($file, '/') === 0) {
  if (valid_url($temp) && strpos($file, '/') === 0) {
    return array(
      'fileurl' => $file,
      'filepath' => str_replace(base_path(), '', $file),
    );
  }

  // If defintely in the local file system return a relative url to the file
  if ($file == file_create_path($file)) {

    // If media checking is active check to see if it actually exists
    if (variable_get('swftools_check_media', TRUE)) {

      // If the file doesn't exist, set an error message and return FALSE to indicate failure
      if (!file_exists($file)) {
        drupal_set_message(t('SWF Tools could not find %file.', array(
          '%file' => $file,
        )), 'error');
        return FALSE;
      }
    }

    // If we got here then return a relative url to the file
    $ret['fileurl'] = swftools_create_url($file);
    return $ret;
  }

  // Retrieve the media url setting
  $media_url = trim(variable_get('swftools_media_url', ''));

  // If a remote path is set build the appropriate url to the file
  if ($media_url) {
    $ret['fileurl'] = $media_url . '/' . $path;
    return $ret;
  }

  // If we got here then expand to a local file path and call again
  return swftools_get_url_and_path(file_create_path($file));
}

/**
 * Returns a string defining a base path for flash to use.
 */
function swftools_get_base() {

  // Cache the result as we might get multiple calls
  static $base = '';

  // If $base is not already defined then set it
  if (!$base) {

    // Retrieve swftools_media_url to see if a remote path has been set
    $base = trim(variable_get('swftools_media_url', ''));

    // If $base is still empty then use local path to file directory
    if (!$base) {
      $base = base_path() . file_directory_path() . '/';
    }
  }

  // Return the base path
  return $base;
}

/**
 * Flatten an array which has sub-arrays in to a single keyed array.
 *
 * If keys in the sub-array are the same as ones seen previously the early key will be over-written.
 *
 * @param array $array
 *   Array to be processed.
 *
 * @return nothing
 *   Manipulate the array directly.
 */
function swftools_array_flatten(&$array) {

  // Only process if we passed an array
  if (is_array($array)) {

    // Iterate over the array
    foreach ($array as $key => $value) {

      // If the value is in itself an array then flatten that too
      if (is_array($value)) {

        // Unset this key as this contains an array
        unset($array[$key]);

        // Flatten the sub-array
        swftools_array_flatten($value);

        // Merge the flattened sub-array in to the rest of the array
        $array = array_merge($array, $value);
      }
    }
  }
}

/**
 * Returns a variable from the relevant profile, or the global settings, or the default values.
 *
 * This is a custom handler to take care of the SWF Tools profile mechanism.
 * If no profile name is given then it simply returns the requested variable,
 * or the default if the variable is not set.
 *
 * If a profile name is given then it will first try to retrive the profiled variable.
 * If that fails it will try to return the global setting, and if that fails then it
 * will return the default. In this way we cascade through the "most relevant" setting.
 *
 * @param string $name
 *   The name of the variable to return.
 * @param mixed $default
 *   The default value to use if this variable has never been set.
 * @param string $profile
 *   (optional) The name of the profile to use.
 *
 * @return mixed
 *   The value of the variable.
 */
function swftools_variable_get($name, $default, $profile = '') {
  if ($profile && ($ret = variable_get('swftools_' . $profile . '_' . $name, SWFTOOLS_UNDEFINED)) != SWFTOOLS_UNDEFINED) {
    return $ret;
  }
  return variable_get($name, $default);
}

/**
 * Serves an xml playlist from the {cache_swftools} table.
 *
 * SWF Tools no longer generates a physical file for the playlist. Instead it
 * places an entry in its internal cache table and then serves the file from
 * there. Pages request the files by accessing swftools/playlist/nnn, where
 * nnn is the cid of the content.
 *
 * @param string $playlist
 *   The name of the playlist being requested.
 *
 * @return mixed
 *   Serve the xml file, or issue drupal_not_found() if it doesn't exist.
 */
function swftools_get_xml($playlist) {
  if (!($data = cache_get($playlist, 'cache_swftools')) || !$data->data['xml']) {
    print drupal_not_found();
  }
  else {
    drupal_set_header('Content-Type: text/xml; charset=utf-8');
    print $data->data['xml'];
  }
}

/**
 * Serves just the swf content from the cache via the path swftools/page/nnnn
 *
 * This feature is experimental - the only access control at the moment is whether
 * the user is generally allowed to view content. Complex permissions will come
 * later.
 *
 * @param string $cid
 *   The cid of the item to retrieve.
 *
 * @return nothing
 *   Output an html page, including headers
 */
function swftools_get_html($cid) {

  // Access global user object
  global $user;

  // User 1 can always access cached content directly, others only if direct serving is enabled
  if (!($user->uid == 1) && !variable_get('swftools_grant_access_to_cache', 0)) {
    print drupal_access_denied();
  }
  elseif (!($content = cache_get($cid, 'cache_swftools'))) {
    print drupal_not_found();
  }
  else {
    print theme('swftools_page', $content->data['html']);
  }
}

/**
 * Creates a cid for the call to swf() and returns its data from the cache when available.
 *
 * To make our cid we create an array from $file and $options. Then we serialize it, and then
 * we run it through md5. This generates a unique cid for that piece of content.
 *
 * Once the cid is created it is attached to $options['othervars']['cid'] so that
 * subsequent functions don't have to rehash the data to generate it again.
 *
 * Within {cache_swftools} we store each item as an associative array.
 *   - html: the actual mark up to place the Flash on the page
 *   - xml: associated xml (for xml based playlists)
 *
 * @param string $file
 *   The $file parameter from the call to swf().
 * @param array $options
 *   The $options parameter from the call to swf().
 *
 * @return mixed
 *   The cached content as a array, or FALSE if it is isn't available.
 */
function swftools_get_from_cache($file, &$options) {

  // Construct a cid for this piece of content
  $cid = md5(serialize(array(
    $file,
    $options,
  )));

  // Set the cid on othervars ready to store this item if we have to render it
  $options['othervars']['cid'] = $cid;

  // If this is in the cache then return it
  if ($ret = cache_get($cid, 'cache_swftools')) {
    return $ret;
  }

  // Indicate that we don't have cached data
  return SWFTOOLS_NOT_CACHED;
}

/**
 * Implementation of hook_flush_caches().
 */
function swftools_flush_caches() {

  // Flush {cache_swftools}
  return array(
    'cache_swftools',
  );
}

/**
 * Returns the default handlers, or customised handlers, for each action.
 */
function swftools_get_players($profile) {

  // These are the standard defaults (key is action, value is handler)
  $defaults = array(
    'video' => 'generic_flv',
    'audio' => 'generic_mp3',
    'swf' => 'swf',
  );

  // Retrieve settings from the database if available
  $settings = swftools_variable_get('swftools_handlers', $defaults, $profile);

  // Return result
  return $settings;
}

/**
 * Merges two multi-dimensional arrays.
 *
 * This function is used by players that filter their settings to strip out
 * blanks or defaults. For the admin page we need a full set of values to prevent
 * errors. Since the arrays might be multi-dimensional we cannot use a regular
 * array_merge(). The values in the first array will be over-written by values in
 * the second, if they exist.
 *
 * @param array $array1
 *   The first array to merge.
 * @param array $array2
 *   The second array to merge.
 *
 * @return array
 *   The result of the merge.
 */
function swftools_array_merge($array1, $array2) {

  // Iterate over $array 2 (this is normally the smaller of the two)
  foreach ($array2 as $key => $value) {

    // If this key is present in $array1 then work out what to do
    if (isset($array1[$key])) {

      // If both keys hold arrays, combine them
      if (is_array($value) && is_array($array1[$key])) {
        $array1[$key] = swftools_array_merge($array1[$key], $value);
      }
      else {

        // Replace value in $array1 with that from $array2
        $array1[$key] = $value;
      }
    }
    else {

      // Simply put this value in $array1 if it isn't already in $array1
      $array1[$key] = $value;
    }
  }

  // Return the result
  return $array1;
}

/**
 * Retrieves the list of actions, and their descriptions, that modules are presenting to SWF Tools.
 *
 * @param bool $reset
 *   When TRUE will reset the cache.
 *
 * @return array
 *   An array of actions.
 */
function swftools_get_actions($reset = FALSE) {

  // Cache actions
  static $actions;

  // If user has requested the cache to be reset then reset it
  if ($reset || !isset($actions)) {
    if (!$reset && ($cached = cache_get('actions', 'cache_swftools'))) {
      $actions = $cached->data;
    }
    else {

      // Build a list of standard actions that SWF Tools knows about from its other modules
      $default_actions = array(
        'swf' => array(
          '#description' => 'a single swf movie',
          '#type' => 'swf movies',
          '#weight' => -8,
        ),
        'video' => array(
          '#description' => 'a single video',
          '#type' => 'videos',
          '#weight' => -7,
        ),
        'video_list' => array(
          '#description' => 'a series of videos',
          '#weight' => -6,
        ),
        'audio' => array(
          '#description' => 'a single audio file',
          '#type' => 'audio',
          '#weight' => -5,
        ),
        'audio_list' => array(
          '#description' => 'a series of audio files',
          '#weight' => -4,
        ),
        'image' => array(
          '#description' => 'a single image',
          '#type' => 'images',
          '#weight' => -3,
        ),
        'image_list' => array(
          '#description' => 'a series of images',
          '#weight' => -2,
        ),
        'media_list' => array(
          '#description' => 'a series of mixed media files',
          '#weight' => -1,
        ),
      );

      // Plan ahead - give other modules the chance to declare an action
      $actions = array();
      foreach (module_implements('swftools_actions') as $module) {
        $function = $module . '_swftools_actions';
        $result = $function();
        if (isset($result) && is_array($result)) {
          $actions = array_merge($actions, $result);
        }
      }

      // Merge additional or new values over the defaults (allows defaults to be renamed)
      $actions = array_merge($default_actions, $actions);

      // Sort the list
      uasort($actions, 'element_sort');

      // Set the cache
      cache_set('actions', $actions, 'cache_swftools');
    }
  }

  // Return the list of available actions
  return $actions;
}

/**
 * Determines the action to be taken, based on the extension of a filename.
 *
 * @param string $extension
 *   The file being queried.
 *
 * @return string
 *   An SWF Tools action if one is associated with the extension, or 'media_list' if we don't know.
 */
function swftools_get_action($file) {

  // Get the array of actions, keyed on extension
  $actions = _swftools_actions();

  // Get the extension for this file
  $extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));

  // If we know the handler for this then use it, otherwise return 'media_list'
  return isset($actions[$extension]) ? $actions[$extension] : 'media_list';
}

/**
 * Returns an array of actions, keyed by file extension.
 */
function _swftools_actions() {

  // Cache this as there may be multiple calls
  static $actions;

  // Do we need to fetch the array of actions?
  if (!$actions) {

    // Defaults to use if no settings have been stored
    $defaults = array(
      'swf' => 'swf',
      'flv' => 'video',
      'f4v' => 'video',
      'mp3' => 'audio',
      'jpg' => 'image',
      'jpeg' => 'image',
      'jpe' => 'image',
      'png' => 'image',
      'gif' => 'image',
    );

    // Use settings from configuration page, or defaults
    $actions = variable_get('swftools_actions', $defaults);
  }

  // Return the result
  return $actions;
}

/**
 * Returns an array of mime types, keyed by file extension.
 */
function _swftools_mime_types() {
  $defaults = array(
    'swf' => 'application/x-shockwave-flash',
    'flv' => 'video/x-flv',
    'mp3' => 'audio/mpeg',
    'jpg' => 'image/jpeg',
    'jpeg' => 'image/jpeg',
    'jpe' => 'image/jpeg',
    'png' => 'image/png',
    'gif' => 'image/gif',
  );

  // Use settings from configuration page, or defaults
  $mime_types = variable_get('swftools_mime_types', $defaults);

  // Return the result
  return $mime_types;
}

/**
 * Implementation of hook_form_FORM_ID_alter().
 *
 * Alters the system_performance_settings form so the SWF Tools cache can be managed along with other caches.
 */
function swftools_form_system_performance_settings_alter(&$form, &$form_state) {
  $form['swftools_cache'] = array(
    '#type' => 'fieldset',
    '#title' => t('SWF Tools cache'),
    '#description' => t('Enabling the SWF Tools cache can offer a performance increase for all users by preventing embedding markup and playlists from being reconstructed on each page load. If the page cache is also enabled, performance increases from enabling the SWF Tools cache will mainly benefit authenticated users.'),
  );
  $form['swftools_cache']['swftools_cache'] = array(
    '#type' => 'radios',
    '#title' => t('SWF Tools cache'),
    '#default_value' => variable_get('swftools_cache', CACHE_NORMAL),
    '#options' => array(
      CACHE_DISABLED => t('Disabled'),
      CACHE_NORMAL => t('Enabled (recommended)'),
    ),
    '#description' => t('During site development it can be helpful to disable the cache and force content to be regenerated on every page call. Note that content being generated via an input filter is always cached by the input filter itself and disabling the SWF Tools cache will not stop the filter cache. Even when the SWF Tools cache is disabled it will continue to store content to allow features such as serving content from %path to function.', array(
      '%path' => base_path() . 'swftools/html/nn',
    )),
  );

  // We want to slot our new section above 'clear cached data' but we can't use weights
  // We use a trick and unset and reset the elements we want lower
  $temp = $form['clear_cache'];
  unset($form['clear_cache']);
  $form['clear_cache'] = $temp;
  $temp = $form['buttons'];
  unset($form['buttons']);
  $form['buttons'] = $temp;
}

/**
 * Implementation of hook_elements().
 */
function swftools_elements() {
  $type['swftools'] = array(
    '#params' => array(),
    '#flashvars' => array(),
    '#othervars' => array(),
    '#methods' => array(),
    '#value' => '',
  );

  // Return the type
  return $type;
}

/**
 * Changes old player names to the new ones so existing content doesn't break.
 *
 * @param string $name
 *   The currently assigned player name.
 *
 * @return string
 *   The corrected player name (which will be unchanged if it is already ok).
 */
function swftools_fix_old_player_names($name) {

  // This is the array to map old names to new names
  $map = array(
    'flowplayer_mediaplayer' => 'flowplayer',
    'flowplayer3_mediaplayer' => 'flowplayer3',
    'wijering_imagerotator' => 'imagerotator',
    'wijering4_mediaplayer' => 'jwplayer4',
  );

  // Attach the supplied action name as both key and value
  $map += array(
    $name => $name,
  );

  // Return the mapped result
  return $map[$name];
}

/**
 * Changes old action names to the new ones so existing content doesn't break.
 *
 * @param string $name
 *   The currently assigned action name.
 *
 * @return string
 *   The corrected action name (which will be unchanged if it is already ok).
 */
function swftools_fix_old_action_names($name) {

  // This is the array to map old names to new names
  $map = array(
    'swftools_swf_display_direct' => 'swf',
    'swftools_flv_display' => 'video',
    'swftools_flv_display_list' => 'video_list',
    'swftools_mp3_display' => 'audio',
    'swftools_mp3_display_list' => 'audio_list',
    'swftools_image_display' => 'image',
    'swftools_image_display_list' => 'image_list',
    'swftools_media_display_list' => 'media_list',
  );

  // Attach the supplied action name as both key and value
  $map += array(
    $name => $name,
  );

  // Return the mapped result
  return $map[$name];
}

/**
 * Implementation of hook_views_api().
 */
function swftools_views_api() {
  return array(
    'api' => 2,
    'path' => drupal_get_path('module', 'swftools') . '/views',
  );
}

/**
 * Outputs a message to the screen and/or the watchdog, according to the configuration settings.
 *
 * Parameters are as watchdog().
 *
 * @see watchdog()
 */
function swftools_set_error($type, $message, $variables = array(), $severity = WATCHDOG_NOTICE, $link = NULL) {

  // Find out where this message should go
  $destination = variable_get('swftools_error_output', SWFTOOLS_ERROR_WATCHDOG_AND_SCREEN);

  // drupal_set_message uses error, warning and status, not severity levels
  $status = array(
    WATCHDOG_EMERG => 'error',
    WATCHDOG_ALERT => 'error',
    WATCHDOG_CRITICAL => 'error',
    WATCHDOG_ERROR => 'error',
    WATCHDOG_WARNING => 'warning',
  );
  $status += array(
    $severity => 'status',
  );

  // Write to screen?
  if ($destination & SWFTOOLS_ERROR_SCREEN) {
    drupal_set_message(t($message, $variables), $status[$severity]);
  }

  // Write to watchdog?
  if ($destination & SWFTOOLS_ERROR_WATCHDOG) {
    watchdog($type, $message, $variables, $severity, $link);
  }
}

/**
 * Replaces the html_alt string with an image tag when rendering an image playlist.
 *
 * This is designed so that if the Flash embed fails the user will see the
 * first image from the image playlist, rather than just an empty message.
 *
 * TODO: Could extend this to substitute thumbnails on audio? Or is that too much!
 *
 * @param array $options
 *   SWF Tools data array.
 *
 * @return nothing
 *   Modifies the array directly.
 */
function swftools_image_html_alt(&$options) {

  // Make sure there is a playlist (not using Flickr etc)
  if ($file = $options['othervars']['playlist_data']['playlist']) {

    // Get the first array element - use array_shift on a copy of the playlist in case there are named keys
    $file = array_shift($file);

    // Get height and width data for the first image
    $info = swftools_get_info($file['filepath']);

    // Initialise an empty array
    $attributes = array();

    // Try to make sure the image height and width don't exceed the player height and width to keep the layout as we expect
    if ($info) {
      $attributes['height'] = $info['height'] > $options['othervars']['height'] ? $options['othervars']['height'] : $info['height'];
      $attributes['width'] = $info['width'] > $options['othervars']['width'] ? $options['othervars']['width'] : $info['width'];
    }

    // Replace html_alt with an image, setting alt text as both alt and title (so when user hovers they see a sensible message)
    $alt = strip_tags(theme('swftools_html_alt', $options));
    $options['othervars']['html_alt'] = theme('image', $file['filepath'], $alt, $alt, $attributes, FALSE);
  }
}

/**
 * Builds a list of accessible controls for the specified player.
 *
 * SWF Tools accessibility scripts use classes of the form
 * !player-accessible-!action-!id.
 * See theme_swftools_wijering4_accessible() for an example of how
 * to implement accessible controls.
 *
 * @param string $player
 *    The player name to be made accessible (e.g. jwplayer4).
 * @param string $id
 *    The id of the player these controls relate to.
 * @param array $actions
 *    The list of actions as an associative array, where the key is the action name,
 *    and the value is the label. The calling function should translate the text first.
 * @param int $visible
 *    Whether the controls should be visible. Options are one the following constants:
 *    - SWFTOOLS_ACCESSIBLE_DISABLED
 *    - SWFTOOLS_ACCESSIBLE_HIDDEN
 *    - SWFTOOLS_ACCESSIBLE_VISIBLE
 *
 * @return string
 *    HTML markup to generate a list.
 *
 * @ingroup swftools
 * @ingroup themeable
 */
function theme_swftools_accessible_controls($player, $id, $actions, $visible) {
  foreach ($actions as $action => $label) {
    $list[] = l($label, '', array(
      'fragment' => ' ',
      'external' => TRUE,
      'attributes' => array(
        'class' => t('!player-accessible-!action-!id', array(
          '!player' => $player,
          '!action' => $action,
          '!id' => $id,
        )),
      ),
    ));
  }
  return theme_item_list($list, '', 'ul', array(
    'class' => $visible == SWFTOOLS_ACCESSIBLE_VISIBLE ? '' : 'swftools-accessible-hidden',
  ));
}

/**
 * Modifies a file path to include the appropriate imagecache preset.
 *
 * @param string $preset
 *   The imagecache preset to be applied.
 * @param string $path
 *   The existing path.
 *
 * @return string
 *   The modified path, or an unaltered path if not on the local file system.
 */
function swftools_imagecache_create_path($preset, $path) {
  if (module_exists('imagecache')) {
    $path = str_replace(file_directory_path(), file_directory_path() . '/imagecache/' . $preset, $path);
  }
  return $path;
}

Functions

Namesort descending Description
swf Processes a file, or an array of files, and returns the relevant mark-up to render a Flash based player.
swftools_array_flatten Flatten an array which has sub-arrays in to a single keyed array.
swftools_array_merge Merges two multi-dimensional arrays.
swftools_create_url Creates a relative path url from a file path, using private or public file system.
swftools_elements Implementation of hook_elements().
swftools_field_formatter_info Implementation of hook_field_formatter_info().
swftools_file_download Implementation of hook_file_download().
swftools_filter Implementation of hook_filter().
swftools_filter_tips Implementation of hook_filter_tips().
swftools_fix_old_action_names Changes old action names to the new ones so existing content doesn't break.
swftools_fix_old_player_names Changes old player names to the new ones so existing content doesn't break.
swftools_flush_caches Implementation of hook_flush_caches().
swftools_form_system_performance_settings_alter Implementation of hook_form_FORM_ID_alter().
swftools_generate_playlist Generates an playlist and places it in {cache_swftools} ready for use.
swftools_get_action Determines the action to be taken, based on the extension of a filename.
swftools_get_actions Retrieves the list of actions, and their descriptions, that modules are presenting to SWF Tools.
swftools_get_base Returns a string defining a base path for flash to use.
swftools_get_filter_alias Implements a hook that extends the parameters that can be passed to the filter so that myvar="value" can be mapped to flashvars, etc.
swftools_get_from_cache Creates a cid for the call to swf() and returns its data from the cache when available.
swftools_get_html Serves just the swf content from the cache via the path swftools/page/nnnn
swftools_get_info Returns information about the specified file.
swftools_get_player Returns the currently configured player for the specified action and profile.
swftools_get_players Returns the default handlers, or customised handlers, for each action.
swftools_get_url_and_path Determines the url for a file, and expands its filepath if necessary.
swftools_get_xml Serves an xml playlist from the {cache_swftools} table.
swftools_imagecache_create_path Modifies a file path to include the appropriate imagecache preset.
swftools_image_html_alt Replaces the html_alt string with an image tag when rendering an image playlist.
swftools_init Implementation of hook_init().
swftools_json_params Converts an array of paramters to JSON and returns them as a string ready for use as a flashvar.
swftools_menu Implementation of hook_menu().
swftools_parse_str Parses a string passed to the input filter in to separate key value pairs.
swftools_perm Implementation of hook_perm().
swftools_prepare_playlist Prepares an array of filenames, or file objects, for use in a playlist.
swftools_set_error Outputs a message to the screen and/or the watchdog, according to the configuration settings.
swftools_set_size Helper function to set the size of the swf content in to $options['othervars']['height'] and ['width']
swftools_swftools_methods Implementation of hook_swftools_methods().
swftools_theme Implementation of hook_theme().
swftools_variable_get Returns a variable from the relevant profile, or the global settings, or the default values.
swftools_views_api Implementation of hook_views_api().
theme_swftools_accessible_controls Builds a list of accessible controls for the specified player.
_swftools_actions Returns an array of actions, keyed by file extension.
_swftools_filter_process_text Processes text obtained from the input filter.
_swftools_mime_types Returns an array of mime types, keyed by file extension.
_swftools_params Returns an array of default values to use as the swf parameters. Parameters are described in the Adobe knowledge base TechNote 12701 http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_12701
_swftools_tf Returns 'true' or 'false' for JavaScript based the supplied value $bool.

Constants

Namesort descending Description
SWFTOOLS_ACCESSIBLE_DISABLED Accessible controls should be disabled.
SWFTOOLS_ACCESSIBLE_HIDDEN Accessible controls should be enabled but hidden.
SWFTOOLS_ACCESSIBLE_VISIBLE Accessible controls should be enabled and visible on the page.
SWFTOOLS_ADMIN_RETRIEVE Settings are being retrieved from the variables table.
SWFTOOLS_ADMIN_STORE Settings are being stored in to the variables table.
SWFTOOLS_ERROR_NONE Don't write any error messages.
SWFTOOLS_ERROR_SCREEN Write error messages to the screen.
SWFTOOLS_ERROR_WATCHDOG Write error messages to the watchdog.
SWFTOOLS_ERROR_WATCHDOG_AND_SCREEN Write error messages to both screen and watchdog.
SWFTOOLS_FULL_SETTINGS The calling function is requesting player settings and wants the full set, including blanks and defaults.
SWFTOOLS_INSTALLED Other modules can query whether SWF Tools is present by checking for this constant.
SWFTOOLS_MINIMUM_SETTINGS The calling function is requesting player settings and only needs settings that are non-default.
SWFTOOLS_NON_XML_PLAYLIST This playlist does not return xml but updates the data array directly.
SWFTOOLS_NOT_CACHED The swf content was not available in the cache.
SWFTOOLS_PRIVATE_ACCESS_ALLOWED_EXTENSIONS When private access via SWF Tools is enabled grant access to these extensions.
SWFTOOLS_PRIVATE_ACCESS_DENIED SWF Tools does not allow access to private files by default.
SWFTOOLS_RETURN_CID SWF Tools should return the cid for the content which was stored in the cache.
SWFTOOLS_RETURN_MARKUP SWF Tools should return mark up to place on the page.
SWFTOOLS_UNDEFINED Used in various places to indicate that the requested item is undefined.