Index: audio_image.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/audio/audio_image.inc,v
retrieving revision 1.9
diff -u -p -r1.9 audio_image.inc
--- audio_image.inc	26 May 2008 17:30:40 -0000	1.9
+++ audio_image.inc	30 Sep 2008 02:10:09 -0000
@@ -78,42 +78,110 @@ function audio_image_type_dirty_array($i
 }
 
 /**
- * Creates an audio image array from a filepath and pic type.
+ * Creates a temporary audio image from a variable.
  *
  * The image is cropped to a square and then resized to the image size setting.
  *
- * @param $filepath
- *   Full path to the image file.
+ * @param $basename
+ *   Name of the audio file this image accompanies.
+ * @param $data
+ *   The raw image data.
+ * @param $mimetype
+ *   The MIME type of the image.
  * @param $pictype
  *   Integer pictype indexes from audio_image_type_clean_array() or
  *   audio_image_type_dirty_array().
  * @return
- *   An array with image info.
+ *   A file object with image info or FALSE on error.
  */
-function audio_image_from_file($filepath, $pictype) {
-  $size = variable_get('audio_image_size', 170);
+function audio_image_save_data($basename, $data, $mimetype, $pictype) {
+  global $user;
+
+  // Gotta have a name to save to.
+  $filepath = _audio_image_filename($basename, $mimetype, $pictype, TRUE);
+  if (!$filepath) {
+    return FALSE;
+  }
+
+  // Save the data.
+  $filepath = file_save_data($data, $filepath, FILE_EXISTS_RENAME);
+  if (!$filepath) {
+    return FALSE;
+  }
 
-  if ($image = image_get_info($filepath)) {
-    image_scale_and_crop($filepath, $filepath, $size, $size);
+  // Make sure it's a valid image.
+  $image = image_get_info($filepath);
+  if (!$image) {
+    file_delete($filepath);
+    return FALSE;
+  }
+
+  // Resize the image
+  $size = variable_get('audio_image_size', 170);
+  if (image_scale_and_crop($filepath, $filepath, $size, $size)) {
     // Changing the image dimensions will affect the file size. Clear out
     // PHP's cached value so we can find the new size.
     clearstatcache();
-
     $image = image_get_info($filepath);
-    return array(
-      'pictype'   => $pictype,
-      'filepath'  => $filepath,
-      'filemime'  => $image['mime_type'],
-      'filesize'  => $image['file_size'],
-      'extension' => $image['extension'],
-      'width'     => $image['width'],
-      'height'    => $image['height'],
-    );
   }
-  return FALSE;
+
+  // Store the file in the database so it can be removed by cron if it's not
+  // used.
+  $file = new stdClass();
+  $file->filepath = $filepath;
+  $file->filename = basename($file->filepath);
+  $file->filemime = $mimetype;
+  $file->filesize = $image['file_size'];
+  $file->uid = $user->uid;
+  $file->status = FILE_STATUS_TEMPORARY;
+  $file->timestamp = time();
+
+  drupal_write_record('files', $file);
+
+  $file->pictype = $pictype;
+  $file->height = $image['height'];
+  $file->width = $image['width'];
+
+  return $file;
 }
 
 /**
+ * If the file is an image it will be resized to meet the audio image size
+ * guidelines.
+ *
+ * @param $file
+ *   A Drupal file object. This function may resize the file affecting its size.
+ * @return
+ *   An array. If the file is an image and did not meet the requirements, it
+ *   will contain an error message.
+ */
+function audio_image_validate_size($file) {
+  $errors = array();
+
+  // Check first that the file is an image.
+  if ($info = image_get_info($file->filepath)) {
+    $size = variable_get('audio_image_size', 170);
+    if ($info['width'] > $size || $info['height'] > $size) {
+      // Try to resize the image to fit the dimensions.
+      if (image_get_toolkit() && image_scale_and_crop($file->filepath, $file->filepath, $size, $size)) {
+        drupal_set_message(t('The image was resized to fit within the maximum allowed dimensions of %height x %width pixels.', array('%height' => $size, '%width' => $size)));
+
+        // Clear the cached filesize and refresh the image information.
+        clearstatcache();
+        $info = image_get_info($file->filepath);
+        $file->filesize = $info['file_size'];
+      }
+      else {
+        $errors[] = t('The image is too large; the maximum dimensions are %dimensions pixels.', array('%dimensions' => $maximum_dimensions));
+      }
+    }
+  }
+
+  return $errors;
+}
+
+
+/**
  * Creates the image's filename in the form directory/prefix_imagetype.ext
  *
  * @param $prefix
@@ -122,13 +190,13 @@ function audio_image_from_file($filepath
  *   The image's mime type. jpeg, png and gif are the only formats allowed.
  * @param $pictype
  *   Integer specifying the picture type.
- * @param $in_tempdir 
+ * @param $in_tempdir
  *   Boolean indicating if the file be in the temp directory.
- * @return 
+ * @return
  *   Full filepath or null in case of an error.
  */
 function _audio_image_filename($prefix, $mimetype, $pictype = 0x03, $in_tempdir = FALSE) {
-  $directory = audio_get_directory() . (($in_tempdir) ? '/temp' : '/images');
+  $directory = $in_tempdir ? file_directory_temp() : audio_get_directory() . '/images';
   file_check_directory($directory, TRUE);
 
   //get the clean image type
Index: images/audio_images.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/audio/images/audio_images.install,v
retrieving revision 1.1
diff -u -p -r1.1 audio_images.install
--- images/audio_images.install	26 May 2008 17:26:13 -0000	1.1
+++ images/audio_images.install	30 Sep 2008 02:10:09 -0000
@@ -19,17 +19,18 @@ function audio_images_schema() {
   $schema['audio_image'] = array(
     'description' => t('Associates an image (such as album artwork) with an audio file.'),
     'fields' => array(
-      'pid' => array(
-        'type' => 'serial',
-        'size' => 'medium',
+      'fid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
         'not null' => TRUE,
+        'description' => t('Primary Key: The {files}.fid.'),
       ),
-      'nid' => array(
+      'vid' => array(
         'type' => 'int',
         'size' => 'medium',
         'not null' => TRUE,
       ),
-      'vid' => array(
+      'nid' => array(
         'type' => 'int',
         'size' => 'medium',
         'not null' => TRUE,
@@ -52,28 +53,10 @@ function audio_images_schema() {
         'not null' => TRUE,
         'default' => 0,
       ),
-      'filemime' => array(
-        'type' => 'varchar',
-        'length' => 20,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'filepath' => array(
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'filesize' => array(
-        'type' => 'int',
-        'size' => 'medium',
-        'not null' => TRUE,
-        'default' => 0,
-      ),
     ),
-    'primary key' => array('pid'),
+    'primary key' => array('vid', 'pictype', 'fid'),
     'indexes' => array(
-      'audio_image_vid_pictype' => array('vid', 'pictype'),
+      'audio_image_fid' => array('fid'),
     ),
   );
   return $schema;
@@ -118,3 +101,38 @@ function audio_images_update_2() {
   );
   return $ret;
 }
+
+/**
+ * Move the majority of our data into the {files} table.
+ */
+function audio_images_update_6000() {
+  $ret = array();
+  $fidfield = array(
+    'type' => 'int',
+    'unsigned' => TRUE,
+    'not null' => TRUE,
+    'description' => t('Primary Key: The {files}.fid.'),
+  );
+  db_add_field($ret, 'audio_image', 'fid', $fidfield);
+  
+  // Load all the distinct filepaths.
+  $result = db_query("SELECT DISTINCT filepath FROM {audio_image} WHERE fid IS NULL OR fid = 0");
+  while ($file = db_fetch_object($result)) {
+    // Then move the data into the files table.
+    db_query("INSERT INTO {files} (uid, filename, filepath, filemime, filesize, status, timestamp) SELECT n.uid, '%s', ai.filepath, ai.filemime, ai.filesize, %d, n.created AS timestamp FROM {node} n INNER JOIN {audio_image} ai ON n.vid = ai.vid WHERE ai.filepath = '%s' LIMIT 1", 
+      basename($file->filepath), FILE_STATUS_PERMANENT, $file->filepath);
+    db_query("UPDATE {audio_image} SET fid = %d WHERE filepath = '%s'", db_last_insert_id('files', 'fid'), $file->filepath);
+  }
+
+  // Remove all the old fields and setup the new indexes.
+  db_drop_field($ret, 'audio_image', 'pid');
+  db_drop_field($ret, 'audio_image', 'filesize');
+  db_drop_field($ret, 'audio_image', 'filepath');
+  db_drop_field($ret, 'audio_image', 'filemime');
+  db_drop_index($ret, 'audio_image', 'audio_image_vid_pictype');
+  db_drop_primary_key($ret, 'audio_image');
+  db_add_primary_key($ret, 'audio_image', array('vid', 'pictype', 'fid'));
+  db_add_index($ret, 'audio_image', 'audio_image_fid', array('fid'));
+
+  return $ret;
+}
Index: images/audio_images.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/audio/images/audio_images.module,v
retrieving revision 1.2
diff -u -p -r1.2 audio_images.module
--- images/audio_images.module	10 Jun 2008 05:23:28 -0000	1.2
+++ images/audio_images.module	30 Sep 2008 02:10:09 -0000
@@ -65,11 +65,9 @@ function audio_images_file_download($fil
  * Here we add our image fields to the audio node form.
  */
 function audio_images_form_alter(&$form, &$form_state, $form_id) {
-  // We only alter audio node edit forms.
-  if ($form_id == 'audio_node_form') {
-    $form['#submit'][] = 'audio_images_node_submit';
-
-    $node = $form['#node'];
+  // We only alter audio node edit forms with a file attached.
+  if ($form_id == 'audio_node_form' && !empty($form['#node']->audio_file['file_path'])) {
+    $form['#validate'][] = 'audio_images_node_form_validate';
 
     $form['audio_images'] = array(
       '#type' => 'fieldset', '#title' => t('Audio Images'),
@@ -79,24 +77,27 @@ function audio_images_form_alter(&$form,
       '#tree' => TRUE,
     );
 
-    if (isset($node->audio_images)) {
+    if (isset($form['#node']->audio_images)) {
       $form['audio_images']['#theme'] = 'audio_images_form';
-      foreach ($node->audio_images as $pid => $image) {
-        $form['audio_images'][$pid]['pid'] = array('#type' => 'value', '#value' => $pid);
-        $form['audio_images'][$pid]['pictype'] = array('#type' => 'value', '#value' => $image['pictype']);
-        $form['audio_images'][$pid]['filepath'] = array('#type' => 'value', '#value' => $image['filepath']);
-        $form['audio_images'][$pid]['filemime'] = array('#type' => 'value', '#value' => $image['filemime']);
-        $form['audio_images'][$pid]['filesize'] = array('#type' => 'value', '#value' => $image['filesize']);
-        $form['audio_images'][$pid]['height'] = array('#type' => 'value', '#value' => $image['height']);
-        $form['audio_images'][$pid]['width'] = array('#type' => 'value', '#value' => $image['width']);
-        $form['audio_images'][$pid]['delete'] = array('#type' => 'checkbox', '#default_value' => isset($image['delete']) ? $image['delete'] : FALSE);
+      foreach ($form['#node']->audio_images as $key => $image) {
+        if ($key == 'delete' || $key == 'new') continue;
+
+        $image = (array) $image;
+        $form['audio_images'][$key] = array(
+         '#type' => 'value',
+         '#value' => $image,
+        );
+        $form['audio_images']['delete'][$key] = array(
+          '#type' => 'checkbox',
+          '#default_value' => isset($image['delete']) ? $image['delete'] : FALSE,
+        );
       }
     }
 
     $form['audio_images']['new']['pictype'] = array(
       '#type' => 'select',
       '#title' => t('New image type'),
-      '#value' => variable_get('audio_image_default_type', 0x03),
+      '#default_value' => variable_get('audio_image_default_type', 0x03),
       '#options' => audio_image_type_dirty_array(),
     );
     $form['audio_images']['new']['audio_image_upload'] = array(
@@ -113,45 +114,48 @@ function audio_images_form_alter(&$form,
  */
 function theme_audio_images_form(&$form) {
   $pictypes = audio_image_type_dirty_array();
+  $header = array(t('Type'), t('MIME Type'), t('Dimensions'), t('Size'), t('Delete'));
   $rows = array();
-  foreach (element_children($form) as $pid) {
-    if ($pid != 'new') {
+  foreach (element_children($form) as $key) {
+    if ($key != 'new' && $key != 'delete') {
+      $image = (array) $form[$key]['#value'];
       $rows[] = array(
-        l($pictypes[$form[$pid]['pictype']['#value']], $form[$pid]['filepath']['#value']),
-        $form[$pid]['filemime']['#value'],
-        $form[$pid]['height']['#value'] .'x'. $form[$pid]['width']['#value'],
-        $form[$pid]['filesize']['#value'],
-        drupal_render($form[$pid]['delete']),
+        l($pictypes[$image['pictype']], $image['filepath']),
+        $image['filemime'],
+        format_size($image['filesize']),
+        $image['height'] .'x'. $image['width'],
+        drupal_render($form['delete'][$key]),
       );
     }
   }
-  $header = array(t('Type'), t('MIME Type'), t('Dimensions'), t('Size'), t('Delete'));
   return theme('table', $header, $rows) . drupal_render($form);
 }
 
 /**
- * Node submit handler
+ * Node validate handler
  */
-function audio_images_node_submit($form, &$form_state) {
-  $node = (object) $form_state['values'];
-
+function audio_images_node_form_validate($form, &$form_state) {
   // Check for an uploaded image.
-  $validators = array('file_validate_is_image' => array());
+  $validators = array(
+    'file_validate_is_image' => array(),
+    'audio_image_validate_size' => array(),
+  );
   if ($file = file_save_upload('audio_image_upload', $validators)) {
-    $pictype = (integer) $form_state['values']['audio_images']['new']['pictype'];
-    if ($image = audio_image_from_file($file->filepath, $pictype)) {
-      $pid = 'new_'. count($form_state['values']['audio_images']);
-      $image['pid'] = $pid;
-      $form_state['values']['audio_images'][$pid] = $image;
-    }
+    $image = image_get_info($file->filepath);
+    $file->height = $image['height'];
+    $file->width = $image['width'];
+    $file->pictype = (int) $form_state['values']['audio_images']['new']['pictype'];
+
+    $form_state['values']['audio_images'][$file->pictype .'-'. $file->fid] = $file;
   }
-  else {
-    foreach ($form_state['values']['audio_images'] as $key => $image) {
-      // If no image has been uploaded clear out the "new" image.
-      if (preg_match('/^new/', $key) && empty($image['filepath'])) {
-        unset($form_state['values']['audio_images'][$key]);
-      }
+  unset($form_state['values']['audio_images']['new']);
+
+  // Move the delete checkbox values to the image
+  if (isset($form_state['values']['audio_images']['delete'])) {
+    foreach ($form_state['values']['audio_images']['delete'] as $key => $value) {
+      $form_state['values']['audio_images'][$key]['delete'] = $value;
     }
+    unset($form_state['values']['audio_images']['delete']);
   }
 }
 
@@ -165,9 +169,6 @@ function audio_images_nodeapi(&$node, $o
     case 'insert':
       return audio_images_nodeapi_insert($node);
     case 'update':
-      if ($node->revision) {
-        return audio_images_nodeapi_insert_revision($node);
-      }
       return audio_images_nodeapi_update($node);
     case 'delete':
       return audio_images_nodeapi_delete($node);
@@ -178,133 +179,94 @@ function audio_images_nodeapi(&$node, $o
 
 function audio_images_nodeapi_load($node) {
   $ret['audio_images'] = array();
-  $result = db_query("SELECT pid, pictype, filemime, width, height, filepath, filesize FROM {audio_image} WHERE vid=%d", $node->vid);
-  while ($img = db_fetch_array($result)) {
-    $ret['audio_images'][$img['pid']] = $img;
+  $result = db_query("SELECT f.fid, f.filemime, f.filepath, f.filesize, ai.nid, ai.vid, ai.pictype, ai.width, ai.height FROM {files} f INNER JOIN {audio_image} ai ON f.fid = ai.fid WHERE ai.vid = %d", $node->vid);
+  while ($img = db_fetch_object($result)) {
+    $ret['audio_images'][$img->pictype .'-'. $img->fid] = $img;
   }
   return $ret;
 }
 
 function audio_images_nodeapi_insert(&$node) {
   // Add new images.
-  foreach ((array)$node->audio_images as $pid => $image) {
-    if (_audio_images_istemp($image['pid'])) {
-      _audio_images_save_new($node, $image);
-    }
-  }
-}
-
-function audio_images_nodeapi_insert_revision(&$node) {
-  foreach ((array)$node->audio_images as $pid => $image) {
-    // Deletions.
-    if ($image['delete']) {
-      _audio_images_delete($pid, $image['filepath']);
-    }
-    // Additions.
-    else if (_audio_images_istemp($image['pid'])) {
-      _audio_images_save_new($node, $image);
-    }
-    // Make copies of unchanged images.
-    else {
-      _audio_images_save_copy($node, $image);
+  foreach ((array) $node->audio_images as $key => $image) {
+    $image = (object) $image;
+    $image->nid = $node->nid;
+    $image->vid = $node->vid;
+
+    if ($image->status & FILE_STATUS_TEMPORARY == FILE_STATUS_TEMPORARY) {
+      $newpath = _audio_image_filename($node->vid, $image->filemime, $image->pictype, FALSE);
+      if (file_move($image, $newpath)) {
+        $image->status = FILE_STATUS_PERMANENT;
+        drupal_write_record('files', $file, array('fid'));
+      }
     }
+    drupal_write_record('audio_image', $image);
+    $node->audio_images[$key] = $image;
   }
 }
 
 function audio_images_nodeapi_update(&$node) {
-  foreach ((array)$node->audio_images as $pid => $image) {
-    // Deletions.
-    if ($image['delete']) {
-      _audio_images_delete($pid, $image['filepath']);
+  foreach ((array) $node->audio_images as $key => $image) {
+    $image = (object) $image;
+    $image->nid = $node->nid;
+    $image->vid = $node->vid;
+
+    if (!empty($image->delete)) {
+      // Delete the image.
+      _audio_images_delete($image);
+      db_query('DELETE FROM {audio_image} WHERE vid = %d AND pictype = %d AND fid = %d', $node->vid, $image->pictype, $image->fid);
+      unset($node->audio_images[$key]);
+    }
+    elseif (($image->status & FILE_STATUS_TEMPORARY) == FILE_STATUS_TEMPORARY) {
+      // New image.
+      $newpath = _audio_image_filename($node->vid, $image->filemime, $image->pictype, FALSE);
+      if (file_move($image, $newpath)) {
+        $image->status |= FILE_STATUS_PERMANENT;
+        drupal_write_record('files', $image, array('fid'));
+      }
+      drupal_write_record('audio_image', $image);
+      $node->audio_images[$key] = $image;
     }
-    // Additions.
-    else if (_audio_images_istemp($image['pid'])) {
-      _audio_images_save_new($node, $image);
+    elseif ($node->revision) {
+      // Make copies of unchanged images when creating a new revision.
+      drupal_write_record('audio_image', $image);
+      $node->audio_images[$key] = $image;
     }
   }
 }
 
 function audio_images_nodeapi_delete(&$node) {
-  // Delete any associated previews.
-  _audio_images_delete_previews($node);
-
   // Delete the image files and remove them from the database.
-  $result = db_query('SELECT filepath FROM {audio_image} WHERE nid = %d', $node->nid);
+  $result = db_query('SELECT ai.fid, f.filepath FROM {audio_image} ai INNER JOIN {files} f ON ai.fid = f.fid WHERE nid = %d', $node->nid);
   while ($file = db_fetch_object($result)) {
-    file_delete($file->filepath);
+    _audio_images_delete($file);
   }
   db_query('DELETE FROM {audio_image} WHERE nid = %d', $node->nid);
 }
 
 function audio_images_nodeapi_delete_revision(&$node) {
-  // Delete any associated previews.
-  _audio_images_delete_previews($node);
-
   // Delete the image files and remove them from the database.
-  $result = db_query('SELECT filepath FROM {audio_image} WHERE vid = %d', $node->vid);
+  $result = db_query('SELECT ai.fid, f.filepath FROM {audio_image} ai INNER JOIN {files} f ON ai.fid = f.fid WHERE vid = %d', $node->vid);
   while ($file = db_fetch_object($result)) {
-    file_delete($file->filepath);
+    _audio_images_delete($file);
   }
   db_query('DELETE FROM {audio_image} WHERE vid = %d', $node->vid);
 }
 
 /**
- * Is an image a temporary preview?
+ * If a file isn't used delete it and remove the {files} table record. The
+ * caller needs to remove record(s) from the {audio_images} table.
  *
- * @param $pid
- *   Mixed, string or integer.
- * @return
- *   Boolean indicating if the image is a temporary preview.
- */
-function _audio_images_istemp($pid) {
-  return (strpos($pid, 'new') !== FALSE);
-}
-
-/**
- * Adds an image to the audio_image table and moves it to the audio/images
- * directory.
+ * @param $file File object
  */
-function _audio_images_save_new(&$node, $image) {
-  $temppath = $image['filepath'];
-  _audio_images_save_copy($node, $image);
-  file_delete($temppath);
-}
-
-/**
- * Save an image to the audio_image table and copies it to the audio/images
- * directory.
- *
- * The caller needs to delete original image file if it was a temporary.
- */
-function _audio_images_save_copy(&$node, $image) {
-  $newpath = _audio_image_filename($node->vid, $image['filemime'], $image['pictype'], FALSE);
-  if (file_copy($image['filepath'], $newpath, FILE_EXISTS_REPLACE)) {
-    $image['nid'] = $node->nid;
-    $image['vid'] = $node->vid;
-    $image['filepath'] = $newpath;
-    $image['filesize'] = filesize($newpath);
-    drupal_write_record('audio_image', $image);
-    $node->audio_images[$image['pid']] = $image;
-  }
-}
-
-function _audio_images_delete($pid, $filepath) {
-  file_delete($filepath);
-  // Delete from the database if it's not a preview.
-  if (!_audio_images_istemp($pid)) {
-    db_query("DELETE FROM {audio_image} WHERE pid = %d", $pid);
-  }
-}
-
-/**
- * Delete any preview images associated with the node.
- */
-function _audio_images_delete_previews(&$node) {
-  foreach ((array)$node->audio_images as $pid => $image) {
-    if (_audio_images_istemp($pid)) {
-      file_delete($image['filepath']);
-      unset($node->audio_images[$pid]);
-    }
+function _audio_images_delete($file) {
+  // Check if the file will be used after this revision is deleted
+  $count = db_result(db_query('SELECT COUNT(fid) FROM {audio_image} WHERE fid = %d', $file->fid));
+
+  // If the file won't be used, delete it.
+  if ($count < 2) {
+    db_query('DELETE FROM {files} WHERE fid = %d', $file->fid);
+    file_delete($file->filepath);
   }
 }
 
@@ -317,9 +279,10 @@ function audio_images_get($audio_images,
   if (is_null($pictype)) {
     $pictype = variable_get('audio_default_image_type', 0x03);
   }
-  if (is_array($audio_images) && count($audio_images)) {
+  if (!empty($audio_images)) {
     foreach ($audio_images as $image) {
-      if ($image['pictype'] == $pictype) {
+      $image = (object) $image;
+      if ($image->pictype == $pictype) {
         return $image;
       }
     }
@@ -345,11 +308,10 @@ function theme_audio_images($audio_image
  * Create an <img> element for an audio image.
  */
 function theme_audio_image($image) {
-  $url = file_create_url($image['filepath']);
-  $alt = audio_image_type_dirty_array($image['pictype']);
+  $image = (object) $image;
 
-  list($width, $height) = @getimagesize($image['filepath']);
+  list($width, $height) = @getimagesize($image->filepath);
   $attributes = array('width' => $width, 'height' => $height);
 
-  return theme('image', $url, $alt, '', $attributes, FALSE);
+  return theme('image', file_create_url($image->filepath), audio_image_type_dirty_array($image->pictype), '', $attributes, FALSE);
 }
