Parsed: 112439

  public function parseMETAdata() {
    $info = &$this->getid3->info;
    do {
      $BlockOffset   = $this->ftell();
      $BlockHeader   = $this->fread(4);
      $LBFBT         = getid3_lib::BigEndian2Int(substr($BlockHeader, 0, 1));  // LBFBT = LastBlockFlag + BlockType
      $LastBlockFlag = (bool) ($LBFBT & 0x80);
      $BlockType     =        ($LBFBT & 0x7F);
      $BlockLength   = getid3_lib::BigEndian2Int(substr($BlockHeader, 1, 3));
      $BlockTypeText = self::metaBlockTypeLookup($BlockType);

      if (($BlockOffset + 4 + $BlockLength) > $info['avdataend']) {
        $this->warning('METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockTypeText.') at offset '.$BlockOffset.' extends beyond end of file');
        break;
      }
      if ($BlockLength < 1) {
        if ($BlockTypeText != 'reserved') {
          // probably supposed to be zero-length
          $this->warning('METADATA_BLOCK_HEADER.BLOCK_LENGTH ('.$BlockTypeText.') at offset '.$BlockOffset.' is zero bytes');
          continue;
        }
        $this->error('METADATA_BLOCK_HEADER.BLOCK_LENGTH ('.$BlockLength.') at offset '.$BlockOffset.' is invalid');
        break;
      }

      $info['flac'][$BlockTypeText]['raw'] = array();
      $BlockTypeText_raw = &$info['flac'][$BlockTypeText]['raw'];

      $BlockTypeText_raw['offset']          = $BlockOffset;
      $BlockTypeText_raw['last_meta_block'] = $LastBlockFlag;
      $BlockTypeText_raw['block_type']      = $BlockType;
      $BlockTypeText_raw['block_type_text'] = $BlockTypeText;
      $BlockTypeText_raw['block_length']    = $BlockLength;
      if ($BlockTypeText_raw['block_type'] != 0x06) { // do not read attachment data automatically
        $BlockTypeText_raw['block_data']  = $this->fread($BlockLength);
      }

      switch ($BlockTypeText) {
        case 'STREAMINFO':     // 0x00
          if (!$this->getid3_flac::parseSTREAMINFO($BlockTypeText_raw['block_data'])) {
            return false;
          }
          break;

        case 'PADDING':        // 0x01
          unset($info['flac']['PADDING']); // ignore
          break;

        case 'APPLICATION':    // 0x02
          if (!$this->getid3_flac::parseAPPLICATION($BlockTypeText_raw['block_data'])) {
            return false;
          }
          break;

        case 'SEEKTABLE':      // 0x03
          if (!$this->getid3_flac::parseSEEKTABLE($BlockTypeText_raw['block_data'])) {
            return false;
          }
          break;

        case 'VORBIS_COMMENT': // 0x04
          if (!$this->getid3_flac::parseVORBIS_COMMENT($BlockTypeText_raw['block_data'])) {
            return false;
          }
          break;

        case 'CUESHEET':       // 0x05
          if (!$this->getid3_flac::parseCUESHEET($BlockTypeText_raw['block_data'])) {
            return false;
          }
          break;

        case 'PICTURE':        // 0x06
          if (!$this->getid3_flac::parsePICTURE()) {
            return false;
          }
          break;

        default:
          $this->warning('Unhandled METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockType.') at offset '.$BlockOffset);
      }

      unset($info['flac'][$BlockTypeText]['raw']);
      $info['avdataoffset'] = $this->ftell();
    }
    while ($LastBlockFlag === false);

    // handle tags
    if (!empty($info['flac']['VORBIS_COMMENT']['comments'])) {
      $info['flac']['comments'] = $info['flac']['VORBIS_COMMENT']['comments'];
    }
    if (!empty($info['flac']['VORBIS_COMMENT']['vendor'])) {
      $info['audio']['encoder'] = str_replace('reference ', '', $info['flac']['VORBIS_COMMENT']['vendor']);
    }

    // copy attachments to 'comments' array if nesesary
    if (isset($info['flac']['PICTURE']) && ($this->getid3->option_save_attachments !== getID3::ATTACHMENTS_NONE)) {
      foreach ($info['flac']['PICTURE'] as $entry) {
        if (!empty($entry['data'])) {
          if (!isset($info['flac']['comments']['picture'])) {
            $info['flac']['comments']['picture'] = array();
          }
          $comments_picture_data = array();
          foreach (array('data', 'image_mime', 'image_width', 'image_height', 'imagetype', 'picturetype', 'description', 'datalength') as $picture_key) {
            if (isset($entry[$picture_key])) {
              $comments_picture_data[$picture_key] = $entry[$picture_key];
            }
          }
          $info['flac']['comments']['picture'][] = $comments_picture_data;
          unset($comments_picture_data);
        }
      }
    }

    if (isset($info['flac']['STREAMINFO'])) {
      if (!$this->isDependencyFor('matroska')) {
        $info['flac']['compressed_audio_bytes'] = $info['avdataend'] - $info['avdataoffset'];
      }
      $info['flac']['uncompressed_audio_bytes'] = $info['flac']['STREAMINFO']['samples_stream'] * $info['flac']['STREAMINFO']['channels'] * ($info['flac']['STREAMINFO']['bits_per_sample'] / 8);
      if ($info['flac']['uncompressed_audio_bytes'] == 0) {
        return $this->error('Corrupt FLAC file: uncompressed_audio_bytes == zero');
      }
      if (!empty($info['flac']['compressed_audio_bytes'])) {
        $info['flac']['compression_ratio'] = $info['flac']['compressed_audio_bytes'] / $info['flac']['uncompressed_audio_bytes'];
      }
    }

    // set md5_data_source - built into flac 0.5+
    if (isset($info['flac']['STREAMINFO']['audio_signature'])) {

      if ($info['flac']['STREAMINFO']['audio_signature'] === str_repeat("\x00", 16)) {
        $this->warning('FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)');
      }
      else {
        $info['md5_data_source'] = '';
        $md5 = $info['flac']['STREAMINFO']['audio_signature'];
        for ($i = 0; $i < strlen($md5); $i++) {
          $info['md5_data_source'] .= str_pad(dechex(ord($md5[$i])), 2, '00', STR_PAD_LEFT);
        }
        if (!preg_match('/^[0-9a-f]{32}$/', $info['md5_data_source'])) {
          unset($info['md5_data_source']);
        }
      }
    }

    if (isset($info['flac']['STREAMINFO']['bits_per_sample'])) {
      $info['audio']['bits_per_sample'] = $info['flac']['STREAMINFO']['bits_per_sample'];
      if ($info['audio']['bits_per_sample'] == 8) {
        // special case
        // must invert sign bit on all data bytes before MD5'ing to match FLAC's calculated value
        // MD5sum calculates on unsigned bytes, but FLAC calculated MD5 on 8-bit audio data as signed
        $this->warning('FLAC calculates MD5 data strangely on 8-bit audio, so the stored md5_data_source value will not match the decoded WAV file');
      }
    }

    return true;
  }