Current File : /home/bdmcricketindia.in/public_html/wp-includes/class-avif-info.php
<?php
/**
 * Copyright (c) 2021, Alliance for Open Media. All rights reserved
 *
 * This source code is subject to the terms of the BSD 2 Clause License and
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
 * was not distributed with this source code in the LICENSE file, you can
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
 * Media Patent License 1.0 was not distributed with this source code in the
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
 *
 * Note: this class is from libavifinfo - https://aomedia.googlesource.com/libavifinfo/+/refs/heads/main/avifinfo.php at f509487.
 * It is used as a fallback to parse AVIF files when the server doesn't support AVIF,
 * primarily to identify the width and height of the image.
 *
 * Note PHP 8.2 added native support for AVIF, so this class can be removed when WordPress requires PHP 8.2.
 */

namespace Avifinfo;

const FOUND     = 0; // Input correctly parsed and information retrieved.
const NOT_FOUND = 1; // Input correctly parsed but information is missing or elsewhere.
const TRUNCATED = 2; // Input correctly parsed until missing bytes to continue.
const ABORTED   = 3; // Input correctly parsed until stopped to avoid timeout or crash.
const INVALID   = 4; // Input incorrectly parsed.

const MAX_SIZE      = 4294967295; // Unlikely to be insufficient to parse AVIF headers.
const MAX_NUM_BOXES = 4096;       // Be reasonable. Avoid timeouts and out-of-memory.
const MAX_VALUE     = 255;
const MAX_TILES     = 16;
const MAX_PROPS     = 32;
const MAX_FEATURES  = 8;
const UNDEFINED     = 0;          // Value was not yet parsed.

/**
 * Reads an unsigned integer with most significant bits first.
 *
 * @param binary string $input     Must be at least $num_bytes-long.
 * @param int           $num_bytes Number of parsed bytes.
 * @return int                     Value.
 */
function read_big_endian( $input, $num_bytes ) {
  if ( $num_bytes == 1 ) {
    return unpack( 'C', $input ) [1];
  } else if ( $num_bytes == 2 ) {
    return unpack( 'n', $input ) [1];
  } else if ( $num_bytes == 3 ) {
    $bytes = unpack( 'C3', $input );
    return ( $bytes[1] << 16 ) | ( $bytes[2] << 8 ) | $bytes[3];
  } else { // $num_bytes is 4
    // This might fail to read unsigned values >= 2^31 on 32-bit systems.
    // See https://www.php.net/manual/en/function.unpack.php#106041
    return unpack( 'N', $input ) [1];
  }
}

/**
 * Reads bytes and advances the stream position by the same count.
 *
 * @param stream               $handle    Bytes will be read from this resource.
 * @param int                  $num_bytes Number of bytes read. Must be greater than 0.
 * @return binary string|false            The raw bytes or false on failure.
 */
function read( $handle, $num_bytes ) {
  $data = fread( $handle, $num_bytes );
  return ( $data !== false && strlen( $data ) >= $num_bytes ) ? $data : false;
}

/**
 * Advances the stream position by the given offset.
 *
 * @param stream $handle    Bytes will be skipped from this resource.
 * @param int    $num_bytes Number of skipped bytes. Can be 0.
 * @return bool             True on success or false on failure.
 */
// Skips 'num_bytes' from the 'stream'. 'num_bytes' can be zero.
function skip( $handle, $num_bytes ) {
  return ( fseek( $handle, $num_bytes, SEEK_CUR ) == 0 );
}

//------------------------------------------------------------------------------
// Features are parsed into temporary property associations.

class Tile { // Tile item id <-> parent item id associations.
  public $tile_item_id;
  public $parent_item_id;
}

class Prop { // Property index <-> item id associations.
  public $property_index;
  public $item_id;
}

class Dim_Prop { // Property <-> features associations.
  public $property_index;
  public $width;
  public $height;
}

class Chan_Prop { // Property <-> features associations.
  public $property_index;
  public $bit_depth;
  public $num_channels;
}

class Features {
  public $has_primary_item = false; // True if "pitm" was parsed.
  public $has_alpha = false; // True if an alpha "auxC" was parsed.
  public $primary_item_id;
  public $primary_item_features = array( // Deduced from the data below.
    'width'        => UNDEFINED, // In number of pixels.
    'height'       => UNDEFINED, // Ignores mirror and rotation.
    'bit_depth'    => UNDEFINED, // Likely 8, 10 or 12 bits per channel per pixel.
    'num_channels' => UNDEFINED  // Likely 1, 2, 3 or 4 channels:
                                          //   (1 monochrome or 3 colors) + (0 or 1 alpha)
  );

  public $tiles = array(); // Tile[]
  public $props = array(); // Prop[]
  public $dim_props = array(); // Dim_Prop[]
  public $chan_props = array(); // Chan_Prop[]

  /**
   * Binds the width, height, bit depth and number of channels from stored internal features.
   *
   * @param int     $target_item_id Id of the item whose features will be bound.
   * @param int     $tile_depth     Maximum recursion to search within tile-parent relations.
   * @return Status                 FOUND on success or NOT_FOUND on failure.
   */
  private function get_item_features( $target_item_id, $tile_depth ) {
    foreach ( $this->props as $prop ) {
      if ( $prop->item_id != $target_item_id ) {
        continue;
      }

      // Retrieve the width and height of the primary item if not already done.
      if ( $target_item_id == $this->primary_item_id &&
           ( $this->primary_item_features['width'] == UNDEFINED ||
             $this->primary_item_features['height'] == UNDEFINED ) ) {
        foreach ( $this->dim_props as $dim_prop ) {
          if ( $dim_prop->property_index != $prop->property_index ) {
            continue;
          }
          $this->primary_item_features['width']  = $dim_prop->width;
          $this->primary_item_features['height'] = $dim_prop->height;
          if ( $this->primary_item_features['bit_depth'] != UNDEFINED &&
               $this->primary_item_features['num_channels'] != UNDEFINED ) {
            return FOUND;
          }
          break;
        }
      }
      // Retrieve the bit depth and number of channels of the target item if not
      // already done.
      if ( $this->primary_item_features['bit_depth'] == UNDEFINED ||
           $this->primary_item_features['num_channels'] == UNDEFINED ) {
        foreach ( $this->chan_props as $chan_prop ) {
          if ( $chan_prop->property_index != $prop->property_index ) {
            continue;
          }
          $this->primary_item_features['bit_depth']    = $chan_prop->bit_depth;
          $this->primary_item_features['num_channels'] = $chan_prop->num_channels;
          if ( $this->primary_item_features['width'] != UNDEFINED &&
              $this->primary_item_features['height'] != UNDEFINED ) {
            return FOUND;
          }
          break;
        }
      }
    }

    // Check for the bit_depth and num_channels in a tile if not yet found.
    if ( $tile_depth < 3 ) {
      foreach ( $this->tiles as $tile ) {
        if ( $tile->parent_item_id != $target_item_id ) {
          continue;
        }
        $status = $this->get_item_features( $tile->tile_item_id, $tile_depth + 1 );
        if ( $status != NOT_FOUND ) {
          return $status;
        }
      }
    }
    return NOT_FOUND;
  }

  /**
   * Finds the width, height, bit depth and number of channels of the primary item.
   *
   * @return Status FOUND on success or NOT_FOUND on failure.
   */
  public function get_primary_item_features() {
    // Nothing to do without the primary item ID.
    if ( !$this->has_primary_item ) {
      return NOT_FOUND;
    }
    // Early exit.
    if ( empty( $this->dim_props ) || empty( $this->chan_props ) ) {
      return NOT_FOUND;
    }
    $status = $this->get_item_features( $this->primary_item_id, /*tile_depth=*/ 0 );
    if ( $status != FOUND ) {
      return $status;
    }

    // "auxC" is parsed before the "ipma" properties so it is known now, if any.
    if ( $this->has_alpha ) {
      ++$this->primary_item_features['num_channels'];
    }
    return FOUND;
  }
}

//------------------------------------------------------------------------------

class Box {
  public $size; // In bytes.
  public $type; // Four characters.
  public $version; // 0 or actual version if this is a full box.
  public $flags; // 0 or actual value if this is a full box.
  public $content_size; // 'size' minus the header size.

  /**
   * Reads the box header.
   *
   * @param stream  $handle              The resource the header will be parsed from.
   * @param int     $num_parsed_boxes    The total number of parsed boxes. Prevents timeouts.
   * @param int     $num_remaining_bytes The number of bytes that should be available from the resource.
   * @return Status                      FOUND on success or an error on failure.
   */
  public function parse( $handle, &$num_parsed_boxes, $num_remaining_bytes = MAX_SIZE ) {
    // See ISO/IEC 14496-12:2012(E) 4.2
    $header_size = 8; // box 32b size + 32b type (at least)
    if ( $header_size > $num_remaining_bytes ) {
      return INVALID;
    }
    if ( !( $data = read( $handle, 8 ) ) ) {
      return TRUNCATED;
    }
    $this->size = read_big_endian( $data, 4 );
    $this->type = substr( $data, 4, 4 );
    // 'box->size==1' means 64-bit size should be read after the box type.
    // 'box->size==0' means this box extends to all remaining bytes.
    if ( $this->size == 1 ) {
      $header_size += 8;
      if ( $header_size > $num_remaining_bytes ) {
        return INVALID;
      }
      if ( !( $data = read( $handle, 8 ) ) ) {
        return TRUNCATED;
      }
      // Stop the parsing if any box has a size greater than 4GB.
      if ( read_big_endian( $data, 4 ) != 0 ) {
        return ABORTED;
      }
      // Read the 32 least-significant bits.
      $this->size = read_big_endian( substr( $data, 4, 4 ), 4 );
    } else if ( $this->size == 0 ) {
      $this->size = $num_remaining_bytes;
    }
    if ( $this->size < $header_size ) {
      return INVALID;
    }
    if ( $this->size > $num_remaining_bytes ) {
      return INVALID;
    }

    $has_fullbox_header = $this->type == 'meta' || $this->type == 'pitm' ||
                          $this->type == 'ipma' || $this->type == 'ispe' ||
                          $this->type == 'pixi' || $this->type == 'iref' ||
                          $this->type == 'auxC';
    if ( $has_fullbox_header ) {
      $header_size += 4;
    }
    if ( $this->size < $header_size ) {
      return INVALID;
    }
    $this->content_size = $this->size - $header_size;
    // Avoid timeouts. The maximum number of parsed boxes is arbitrary.
    ++$num_parsed_boxes;
    if ( $num_parsed_boxes >= MAX_NUM_BOXES ) {
      return ABORTED;
    }

    $this->version = 0;
    $this->flags   = 0;
    if ( $has_fullbox_header ) {
      if ( !( $data = read( $handle, 4 ) ) ) {
        return TRUNCATED;
      }
      $this->version = read_big_endian( $data, 1 );
      $this->flags   = read_big_endian( substr( $data, 1, 3 ), 3 );
      // See AV1 Image File Format (AVIF) 8.1
      // at https://aomediacodec.github.io/av1-avif/#avif-boxes (available when
      // https://github.com/AOMediaCodec/av1-avif/pull/170 is merged).
      $is_parsable = ( $this->type == 'meta' && $this->version <= 0 ) ||
                     ( $this->type == 'pitm' && $this->version <= 1 ) ||
                     ( $this->type == 'ipma' && $this->version <= 1 ) ||
                     ( $this->type == 'ispe' && $this->version <= 0 ) ||
                     ( $this->type == 'pixi' && $this->version <= 0 ) ||
                     ( $this->type == 'iref' && $this->version <= 1 ) ||
                     ( $this->type == 'auxC' && $this->version <= 0 );
      // Instead of considering this file as invalid, skip unparsable boxes.
      if ( !$is_parsable ) {
        $this->type = 'unknownversion';
      }
    }
    // print_r( $this ); // Uncomment to print all boxes.
    return FOUND;
  }
}

//------------------------------------------------------------------------------

class Parser {
  private $handle; // Input stream.
  private $num_parsed_boxes = 0;
  private $data_was_skipped = false;
  public $features;

  function __construct( $handle ) {
    $this->handle   = $handle;
    $this->features = new Features();
  }

  /**
   * Parses an "ipco" box.
   *
   * "ispe" is used for width and height, "pixi" and "av1C" are used for bit depth
   * and number of channels, and "auxC" is used for alpha.
   *
   * @param stream  $handle              The resource the box will be parsed from.
   * @param int     $num_remaining_bytes The number of bytes that should be available from the resource.
   * @return Status                      FOUND on success or an error on failure.
   */
  private function parse_ipco( $num_remaining_bytes ) {
    $box_index = 1; // 1-based index. Used for iterating over properties.
    do {
      $box    = new Box();
      $status = $box->parse( $this->handle, $this->num_parsed_boxes, $num_remaining_bytes );
      if ( $status != FOUND ) {
        return $status;
      }

      if ( $box->type == 'ispe' ) {
        // See ISO/IEC 23008-12:2017(E) 6.5.3.2
        if ( $box->content_size < 8 ) {
          return INVALID;
        }
        if ( !( $data = read( $this->handle, 8 ) ) ) {
          return TRUNCATED;
        }
        $width  = read_big_endian( substr( $data, 0, 4 ), 4 );
        $height = read_big_endian( substr( $data, 4, 4 ), 4 );
        if ( $width == 0 || $height == 0 ) {
          return INVALID;
        }
        if ( count( $this->features->dim_props ) <= MAX_FEATURES &&
             $box_index <= MAX_VALUE ) {
          $dim_prop_count = count( $this->features->dim_props );
          $this->features->dim_props[$dim_prop_count]                 = new Dim_Prop();
          $this->features->dim_props[$dim_prop_count]->property_index = $box_index;
          $this->features->dim_props[$dim_prop_count]->width          = $width;
          $this->features->dim_props[$dim_prop_count]->height         = $height;
        } else {
          $this->data_was_skipped = true;
        }
        if ( !skip( $this->handle, $box->content_size - 8 ) ) {
          return TRUNCATED;
        }
      } else if ( $box->type == 'pixi' ) {
        // See ISO/IEC 23008-12:2017(E) 6.5.6.2
        if ( $box->content_size < 1 ) {
          return INVALID;
        }
        if ( !( $data = read( $this->handle, 1 ) ) ) {
          return TRUNCATED;
        }
        $num_channels = read_big_endian( $data, 1 );
        if ( $num_channels < 1 ) {
          return INVALID;
        }
        if ( $box->content_size < 1 + $num_channels ) {
          return INVALID;
        }
        if ( !( $data = read( $this->handle, 1 ) ) ) {
          return TRUNCATED;
        }
        $bit_depth = read_big_endian( $data, 1 );
        if ( $bit_depth < 1 ) {
          return INVALID;
        }
        for ( $i = 1; $i < $num_channels; ++$i ) {
          if ( !( $data = read( $this->handle, 1 ) ) ) {
            return TRUNCATED;
          }
          // Bit depth should be the same for all channels.
          if ( read_big_endian( $data, 1 ) != $bit_depth ) {
            return INVALID;
          }
          if ( $i > 32 ) {
            return ABORTED; // Be reasonable.
          }
        }
        if ( count( $this->features->chan_props ) <= MAX_FEATURES &&
             $box_index <= MAX_VALUE && $bit_depth <= MAX_VALUE &&
             $num_channels <= MAX_VALUE ) {
          $chan_prop_count = count( $this->features->chan_props );
          $this->features->chan_props[$chan_prop_count]                 = new Chan_Prop();
          $this->features->chan_props[$chan_prop_count]->property_index = $box_index;
          $this->features->chan_props[$chan_prop_count]->bit_depth      = $bit_depth;
          $this->features->chan_props[$chan_prop_count]->num_channels   = $num_channels;
        } else {
          $this->data_was_skipped = true;
        }
        if ( !skip( $this->handle, $box->content_size - ( 1 + $num_channels ) ) ) {
          return TRUNCATED;
        }
      } else if ( $box->type == 'av1C' ) {
        // See AV1 Codec ISO Media File Format Binding 2.3.1
        // at https://aomediacodec.github.io/av1-isobmff/#av1c
        // Only parse the necessary third byte. Assume that the others are valid.
        if ( $box->content_size < 3 ) {
          return INVALID;
        }
        if ( !( $data = read( $this->handle, 3 ) ) ) {
          return TRUNCATED;
        }
        $byte          = read_big_endian( substr( $data, 2, 1 ), 1 );
        $high_bitdepth = ( $byte & 0x40 ) != 0;
        $twelve_bit    = ( $byte & 0x20 ) != 0;
        $monochrome    = ( $byte & 0x10 ) != 0;
        if ( $twelve_bit && !$high_bitdepth ) {
            return INVALID;
        }
        if ( count( $this->features->chan_props ) <= MAX_FEATURES &&
             $box_index <= MAX_VALUE ) {
          $chan_prop_count = count( $this->features->chan_props );
          $this->features->chan_props[$chan_prop_count]                 = new Chan_Prop();
          $this->features->chan_props[$chan_prop_count]->property_index = $box_index;
          $this->features->chan_props[$chan_prop_count]->bit_depth      =
              $high_bitdepth ? $twelve_bit ? 12 : 10 : 8;
          $this->features->chan_props[$chan_prop_count]->num_channels   = $monochrome ? 1 : 3;
        } else {
          $this->data_was_skipped = true;
        }
        if ( !skip( $this->handle, $box->content_size - 3 ) ) {
          return TRUNCATED;
        }
      } else if ( $box->type == 'auxC' ) {
        // See AV1 Image File Format (AVIF) 4
        // at https://aomediacodec.github.io/av1-avif/#auxiliary-images
        $kAlphaStr       = "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha\0";
        $kAlphaStrLength = 44; // Includes terminating character.
        if ( $box->content_size >= $kAlphaStrLength ) {
          if ( !( $data = read( $this->handle, $kAlphaStrLength ) ) ) {
            return TRUNCATED;
          }
          if ( substr( $data, 0, $kAlphaStrLength ) == $kAlphaStr ) {
            // Note: It is unlikely but it is possible that this alpha plane does
            //       not belong to the primary item or a tile. Ignore this issue.
            $this->features->has_alpha = true;
          }
          if ( !skip( $this->handle, $box->content_size - $kAlphaStrLength ) ) {
            return TRUNCATED;
          }
        } else {
          if ( !skip( $this->handle, $box->content_size ) ) {
            return TRUNCATED;
          }
        }
      } else {
        if ( !skip( $this->handle, $box->content_size ) ) {
          return TRUNCATED;
        }
      }
      ++$box_index;
      $num_remaining_bytes -= $box->size;
    } while ( $num_remaining_bytes > 0 );
    return NOT_FOUND;
  }

  /**
   * Parses an "iprp" box.
   *
   * The "ipco" box contain the properties which are linked to items by the "ipma" box.
   *
   * @param stream  $handle              The resource the box will be parsed from.
   * @param int     $num_remaining_bytes The number of bytes that should be available from the resource.
   * @return Status                      FOUND on success or an error on failure.
   */
  private function parse_iprp( $num_remaining_bytes ) {
    do {
      $box    = new Box();
      $status = $box->parse( $this->handle, $this->num_parsed_boxes, $num_remaining_bytes );
      if ( $status != FOUND ) {
        return $status;
      }

      if ( $box->type == 'ipco' ) {
        $status = $this->parse_ipco( $box->content_size );
        if ( $status != NOT_FOUND ) {
          return $status;
        }
      } else if ( $box->type == 'ipma' ) {
        // See ISO/IEC 23008-12:2017(E) 9.3.2
        $num_read_bytes = 4;
        if ( $box->content_size < $num_read_bytes ) {
          return INVALID;
        }
        if ( !( $data = read( $this->handle, $num_read_bytes ) ) ) {
          return TRUNCATED;
        }
        $entry_count        = read_big_endian( $data, 4 );
        $id_num_bytes       = ( $box->version < 1 ) ? 2 : 4;
        $index_num_bytes    = ( $box->flags & 1 ) ? 2 : 1;
        $essential_bit_mask = ( $box->flags & 1 ) ? 0x8000 : 0x80;

        for ( $entry = 0; $entry < $entry_count; ++$entry ) {
          if ( $entry >= MAX_PROPS ||
               count( $this->features->props ) >= MAX_PROPS ) {
            $this->data_was_skipped = true;
            break;
          }
          $num_read_bytes += $id_num_bytes + 1;
          if ( $box->content_size < $num_read_bytes ) {
            return INVALID;
          }
          if ( !( $data = read( $this->handle, $id_num_bytes + 1 ) ) ) {
            return TRUNCATED;
          }
          $item_id           = read_big_endian(
              substr( $data, 0, $id_num_bytes ), $id_num_bytes );
          $association_count = read_big_endian(
              substr( $data, $id_num_bytes, 1 ), 1 );

          for ( $property = 0; $property < $association_count; ++$property ) {
            if ( $property >= MAX_PROPS ||
                 count( $this->features->props ) >= MAX_PROPS ) {
              $this->data_was_skipped = true;
              break;
            }
            $num_read_bytes += $index_num_bytes;
            if ( $box->content_size < $num_read_bytes ) {
              return INVALID;
            }
            if ( !( $data = read( $this->handle, $index_num_bytes ) ) ) {
              return TRUNCATED;
            }
            $value          = read_big_endian( $data, $index_num_bytes );
            // $essential = ($value & $essential_bit_mask);  // Unused.
            $property_index = ( $value & ~$essential_bit_mask );
            if ( $property_index <= MAX_VALUE && $item_id <= MAX_VALUE ) {
              $prop_count = count( $this->features->props );
              $this->features->props[$prop_count]                 = new Prop();
              $this->features->props[$prop_count]->property_index = $property_index;
              $this->features->props[$prop_count]->item_id        = $item_id;
            } else {
              $this->data_was_skipped = true;
            }
          }
          if ( $property < $association_count ) {
            break; // Do not read garbage.
          }
        }

        // If all features are available now, do not look further.
        $status = $this->features->get_primary_item_features();
        if ( $status != NOT_FOUND ) {
          return $status;
        }

        // Mostly if 'data_was_skipped'.
        if ( !skip( $this->handle, $box->content_size - $num_read_bytes ) ) {
          return TRUNCATED;
        }
      } else {
        if ( !skip( $this->handle, $box->content_size ) ) {
          return TRUNCATED;
        }
      }
      $num_remaining_bytes -= $box->size;
    } while ( $num_remaining_bytes > 0 );
    return NOT_FOUND;
  }

  /**
   * Parses an "iref" box.
   *
   * The "dimg" boxes contain links between tiles and their parent items, which
   * can be used to infer bit depth and number of channels for the primary item
   * when the latter does not have these properties.
   *
   * @param stream  $handle              The resource the box will be parsed from.
   * @param int     $num_remaining_bytes The number of bytes that should be available from the resource.
   * @return Status                      FOUND on success or an error on failure.
   */
  private function parse_iref( $num_remaining_bytes ) {
    do {
      $box    = new Box();
      $status = $box->parse( $this->handle, $this->num_parsed_boxes, $num_remaining_bytes );
      if ( $status != FOUND ) {
        return $status;
      }

      if ( $box->type == 'dimg' ) {
        // See ISO/IEC 14496-12:2015(E) 8.11.12.2
        $num_bytes_per_id = ( $box->version == 0 ) ? 2 : 4;
        $num_read_bytes   = $num_bytes_per_id + 2;
        if ( $box->content_size < $num_read_bytes ) {
          return INVALID;
        }
        if ( !( $data = read( $this->handle, $num_read_bytes ) ) ) {
          return TRUNCATED;
        }
        $from_item_id    = read_big_endian( $data, $num_bytes_per_id );
        $reference_count = read_big_endian( substr( $data, $num_bytes_per_id, 2 ), 2 );

        for ( $i = 0; $i < $reference_count; ++$i ) {
          if ( $i >= MAX_TILES ) {
            $this->data_was_skipped = true;
            break;
          }
          $num_read_bytes += $num_bytes_per_id;
          if ( $box->content_size < $num_read_bytes ) {
            return INVALID;
          }
          if ( !( $data = read( $this->handle, $num_bytes_per_id ) ) ) {
            return TRUNCATED;
          }
          $to_item_id = read_big_endian( $data, $num_bytes_per_id );
          $tile_count = count( $this->features->tiles );
          if ( $from_item_id <= MAX_VALUE && $to_item_id <= MAX_VALUE &&
               $tile_count < MAX_TILES ) {
            $this->features->tiles[$tile_count]                 = new Tile();
            $this->features->tiles[$tile_count]->tile_item_id   = $to_item_id;
            $this->features->tiles[$tile_count]->parent_item_id = $from_item_id;
          } else {
            $this->data_was_skipped = true;
          }
        }

        // If all features are available now, do not look further.
        $status = $this->features->get_primary_item_features();
        if ( $status != NOT_FOUND ) {
          return $status;
        }

        // Mostly if 'data_was_skipped'.
        if ( !skip( $this->handle, $box->content_size - $num_read_bytes ) ) {
          return TRUNCATED;
        }
      } else {
        if ( !skip( $this->handle, $box->content_size ) ) {
          return TRUNCATED;
        }
      }
      $num_remaining_bytes -= $box->size;
    } while ( $num_remaining_bytes > 0 );
    return NOT_FOUND;
  }

  /**
   * Parses a "meta" box.
   *
   * It looks for the primary item ID in the "pitm" box and recurses into other boxes
   * to find its features.
   *
   * @param stream  $handle              The resource the box will be parsed from.
   * @param int     $num_remaining_bytes The number of bytes that should be available from the resource.
   * @return Status                      FOUND on success or an error on failure.
   */
  private function parse_meta( $num_remaining_bytes ) {
    do {
      $box    = new Box();
      $status = $box->parse( $this->handle, $this->num_parsed_boxes, $num_remaining_bytes );
      if ( $status != FOUND ) {
        return $status;
      }

      if ( $box->type == 'pitm' ) {
        // See ISO/IEC 14496-12:2015(E) 8.11.4.2
        $num_bytes_per_id = ( $box->version == 0 ) ? 2 : 4;
        if ( $num_bytes_per_id > $num_remaining_bytes ) {
          return INVALID;
        }
        if ( !( $data = read( $this->handle, $num_bytes_per_id ) ) ) {
          return TRUNCATED;
        }
        $primary_item_id = read_big_endian( $data, $num_bytes_per_id );
        if ( $primary_item_id > MAX_VALUE ) {
          return ABORTED;
        }
        $this->features->has_primary_item = true;
        $this->features->primary_item_id  = $primary_item_id;
        if ( !skip( $this->handle, $box->content_size - $num_bytes_per_id ) ) {
          return TRUNCATED;
        }
      } else if ( $box->type == 'iprp' ) {
        $status = $this->parse_iprp( $box->content_size );
        if ( $status != NOT_FOUND ) {
          return $status;
        }
      } else if ( $box->type == 'iref' ) {
        $status = $this->parse_iref( $box->content_size );
        if ( $status != NOT_FOUND ) {
          return $status;
        }
      } else {
        if ( !skip( $this->handle, $box->content_size ) ) {
          return TRUNCATED;
        }
      }
      $num_remaining_bytes -= $box->size;
    } while ( $num_remaining_bytes != 0 );
    // According to ISO/IEC 14496-12:2012(E) 8.11.1.1 there is at most one "meta".
    return INVALID;
  }

  /**
   * Parses a file stream.
   *
   * The file type is checked through the "ftyp" box.
   *
   * @return bool True if the input stream is an AVIF bitstream or false.
   */
  public function parse_ftyp() {
    $box    = new Box();
    $status = $box->parse( $this->handle, $this->num_parsed_boxes );
    if ( $status != FOUND ) {
      return false;
    }

    if ( $box->type != 'ftyp' ) {
      return false;
    }
    // Iterate over brands. See ISO/IEC 14496-12:2012(E) 4.3.1
    if ( $box->content_size < 8 ) {
      return false;
    }
    for ( $i = 0; $i + 4 <= $box->content_size; $i += 4 ) {
      if ( !( $data = read( $this->handle, 4 ) ) ) {
        return false;
      }
      if ( $i == 4 ) {
        continue; // Skip minor_version.
      }
      if ( substr( $data, 0, 4 ) == 'avif' || substr( $data, 0, 4 ) == 'avis' ) {
        return skip( $this->handle, $box->content_size - ( $i + 4 ) );
      }
      if ( $i > 32 * 4 ) {
        return false; // Be reasonable.
      }

    }
    return false; // No AVIF brand no good.
  }

  /**
   * Parses a file stream.
   *
   * Features are extracted from the "meta" box.
   *
   * @return bool True if the main features of the primary item were parsed or false.
   */
  public function parse_file() {
    $box = new Box();
    while ( $box->parse( $this->handle, $this->num_parsed_boxes ) == FOUND ) {
      if ( $box->type === 'meta' ) {
        if ( $this->parse_meta( $box->content_size ) != FOUND ) {
          return false;
        }
        return true;
      }
      if ( !skip( $this->handle, $box->content_size ) ) {
        return false;
      }
    }
    return false; // No "meta" no good.
  }
}
Is Bizzo Casino the Ultimate Online Gaming Experience_21

Is Bizzo Casino the Ultimate Online Gaming Experience_21

Is Bizzo Casino the Ultimate Online Gaming Experience?

Online gaming has witnessed an exponential rise in popularity over the past decade, with countless platforms vying for the attention of enthusiastic players. Among these platforms, Bizzo Casino has emerged as a formidable contender, promising a unique blend of exciting games, enticing bonuses, and an overall engaging user experience. As prospective players consider which platform to trust for their gaming experience, assessing each option’s offerings becomes crucial in making an informed decision.

Bizzo Casino sets itself apart by establishing a comprehensive set of features tailored to meet both casual players and seasoned gamers’ needs. With thousands of games spanning various genres, an intuitive interface, and dedicated customer support, players are treated to a holistic gaming environment. But does it truly live up to the hype? This article delves deeper into the various aspects of Bizzo Casino, evaluating everything from game variety and software developers to payment options and user experience.

As we explore the captivating world of Bizzo Casino, it becomes essential to dissect all the vital elements that combine to create its reputation. Factors such as licensing, security measures, and mobile compatibility also play a significant role in shaping user perceptions and experiences. Above all, we will determine if Bizzo Casino indeed stands out as the ultimate online gaming destination amidst the growing competition.

In the following sections, we will explore the platform’s extensive game library, bonuses, promotions, and other critical features that contribute to an enjoyable gaming experience. Each segment will offer insights into how Bizzo Casino manages to cater to its audience effectively, assisting players in making the best choices for their gaming endeavors.

Ultimately, the goal is to evaluate whether Bizzo Casino lives up to expectations and solidifies itself as a premier choice for enthusiasts seeking entertainment and rewards in the online gaming landscape. Let’s dive into the details and see what makes Bizzo Casino a noteworthy destination for players everywhere.

Understanding Bizzo Casino’s Game Library

One of the most enticing aspects of any online casino is its game library, and Bizzo Casino certainly does not disappoint. With hundreds of games available, players are greeted with an impressive array of options. From classic table games such as blackjack and poker to exciting slot machines boasting stunning graphics and immersive storylines, the variety is astonishing.

In order to provide players with the best possible experience, Bizzo Casino collaborates with some of the most reputable software developers in the industry. This ensures that the games are not only high-quality but also fair and secure. Players can find popular titles from renowned providers such as Microgaming, NetEnt, and Evolution Gaming, among others.

Game Type
Popular Titles
Slots Starburst, Book of Dead
Table Games Blackjack, Roulette
Live Casino Live Blackjack, Live Roulette

Another crucial aspect of Bizzo Casino’s offerings is the inclusion of live dealer games, which provide players with an immersive gambling experience. Engaging with professional dealers in real-time adds a sense of authenticity that many players find appealing. These live games are designed to recreate the thrill of a traditional casino while maintaining the convenience of online play.

Variety of Slots and Table Games

Slots are undoubtedly one of the main attractions at Bizzo Casino. With an extensive collection that includes hundreds of titles, players can always find something that piques their interest. Slots can vary widely in themes, features, and potential payouts, making them attractive to a diverse audience. The incorporation of progressive jackpots also offers opportunities for substantial winnings, setting the stage for thrilling gaming experiences.

In addition to slots, Bizzo Casino boasts a range of classic table games. Players can indulge in favorites like poker, blackjack, and baccarat, each coming with various versions to cater to different preferences. New players can easily grasp the basic rules while seasoned gamers can delve into more complex variations to enhance their overall experience.

Live Casino Experience

The live casino segment of Bizzo Casino is one area where the platform truly shines. With state-of-the-art technology, players can engage in real-time gameplay with professional dealers. This adds an interactive element, allowing players to communicate and experience the atmosphere of a physical casino from the comfort of their homes.

The live games offered cover various categories, including traditional card games and modern variations appealing to younger audiences. By utilizing high-definition streaming and user-friendly interfaces, Bizzo Casino ensures a smooth experience for players looking to enjoy live dealer gaming.

Bonuses and Promotions Offered by Bizzo Casino

When it comes to attracting and retaining players, generous bonuses and promotions are key strategies for online casinos. Bizzo Casino excels in this aspect by offering an enticing selection of incentives to both new and existing players. These bonuses can significantly enhance the gaming experience and provide extra chances to win.

New players are often greeted with a welcome bonus that typically includes a deposit match and free spins. This promotional strategy encourages players to start exploring the game library and testing their luck. However, it’s essential for players to read the terms and conditions associated with these offers to maximize their benefits.

  • Welcome Bonus: A generous sign-up bonus for new players.
  • Free Spins: Additional spins to try selected slot games.
  • Weekly Promotions: Ongoing offers for regular players.
  • Loyalty Rewards: Rewards program for frequent players.

Additionally, Bizzo Casino features regular promotions and loyalty rewards programs designed to create a sense of community among its players. These initiatives encourage players to engage with the platform consistently, making it a go-to choice for online gaming.

Understanding Wagering Requirements

While bonuses can be enticing, it is important for players to familiarize themselves with wagering requirements. These requirements often dictate how many times a player needs to wager their bonus before being eligible to withdraw any winnings. It’s advisable to read the fine print to avoid surprises later on.

Bizzo Casino generally strives to maintain reasonable wagering requirements, but players should double-check current promotions, as they may vary. Staying informed will help players navigate their bonus options more effectively.

Exclusive VIP Programs

The VIP experience at Bizzo Casino is yet another incentive that attracts players to remain loyal. VIP members can enjoy exclusive perks, including personalized account managers, special bonuses, and faster withdrawals. These benefits are designed to create a more tailored gaming experience for committed players, ensuring they are valued for their loyalty.

By incentivizing players to rise through the ranks of the loyalty program, Bizzo Casino fosters a sense of belonging and appreciation. This ultimately enhances player satisfaction, leading to a more invested community.

Payment Methods and Security Standards

For any online casino, offering a wide range of secure payment methods is vital for attracting and retaining players. Bizzo Casino recognizes this need and provides numerous options for deposits and withdrawals, catering to various preferences and geographical locations. Players can choose from traditional bank transfers, credit cards, and popular e-wallets, ensuring that their transactions are seamless.

Security also plays a critical role in establishing trust. Bizzo Casino utilizes advanced encryption technology to protect players’ personal and financial data. This commitment to maintaining high security standards contributes to a safer gaming environment, allowing players to focus on enjoying their gaming experience without anxiety about their information being compromised.

Payment Method
Type
Visa Credit/Debit Card
PayPal E-Wallet
Bitcoin Cryptocurrency

To ensure a smooth deposit experience, players should take advantage of the various payment options available. Additionally, understanding withdrawal processing times and any associated fees is crucial for a satisfactory gaming experience. Bizzo Casino’s efforts to maintain transparency in its payment processes help build a relationship of trust with its players.

Deposits and Withdrawals

Players can deposit funds into their Bizzo Casino accounts through several convenient methods. The process is typically fast and hassle-free, allowing players to begin gaming without unnecessary delays. Once players are ready to withdraw their winnings, understanding the processing time associated with different methods is important. Some options may take longer than others, so being aware of this will help set expectations for players.

In most cases, e-wallets facilitate quicker withdrawals, making them the preferred option for many players. However, traditional bank methods may require longer processing times before winnings appear in players’ accounts.

Safety Protocols in Place

Bizzo Casino’s commitment to player security is evident through its safety protocols. Using SSL encryption, the platform safeguards sensitive information, ensuring that players can enjoy their gaming experience without fear of data breaches. Additionally, the casino is licensed and regulated by recognized authorities, further bolstering its credibility.

By implementing robust security measures, Bizzo Casino enhances player confidence, enabling them to focus on the fun rather than concerns about safety. This aspect is essential in a rapidly evolving gaming landscape, where security breaches remain a pressing issue.

User Experience and Interface

The user experience at Bizzo Casino is crafted with player needs in mind. The website features an intuitive interface that allows players to navigate effortlessly through various sections. Whether they are searching for specific games or exploring promotions, the layout is designed to facilitate a pleasant user experience.

Mobile compatibility is another critical aspect of the user experience. With an increasing number of players opting for mobile gaming, Bizzo Casino ensures that its platform is fully optimized for smartphones and tablets. This adaptation allows for seamless gaming on the go, catering to players’ busy lifestyles while still delivering high-quality gameplay.

  • Responsive Design: Mobile-friendly interface for seamless gaming.
  • Intuitive Navigation: Easy access to games and promotions.
  • Customer Support: Available via multiple channels for player convenience.
  • Quick Loading Times: Optimized performance for a smooth gaming experience.

Furthermore, Bizzo Casino offers multiple customer support options, including live chat, email, and an extensive FAQ section. This dedication to providing assistance ensures that players can receive help when needed, enhancing their overall experience.

Customer Support Availability

Having effective customer support available is crucial for online gaming platforms. Bizzo Casino recognizes this importance and gives players access to a supportive team ready to address any inquiries or concerns. The live chat feature stands out as the quickest way to receive assistance.

The FAQ section is also a valuable resource, offering detailed answers to common questions. By providing comprehensive support options, Bizzo Casino demonstrates its commitment to player satisfaction and experience, effectively building loyalty among its users.

Loading Speed and Performance

In today’s fast-paced world, players expect online platforms to deliver rapidly. Bizzo Casino understands the importance of performance and ensures that the website loads quickly, providing seamless gameplay. Whether on a PC or a mobile device, players can enjoy their favorite games without frustrating delays.

The focus on performance translates directly into player satisfaction, as gamers can enjoy uninterrupted fun. Regular updates and optimization are part of Bizzo Casino’s strategy to deliver an exceptional overall experience to its users.

The Mobile Gaming Advantage

The mobile gaming experience has dramatically transformed the industry, making it essential for casinos to adapt. Bizzo Casino has embraced this trend, optimizing their platform for mobile devices. Players can access a wide range of games, bonuses, and features while on the go, demonstrating the casino’s commitment to catering to contemporary gamers.

Mobile gaming offers numerous advantages, including convenience and flexibility. Players can engage in their favorite casino activities anytime and anywhere, enhancing their overall gaming experience. This accessibility is particularly appealing to those with busy schedules or who prefer gaming while traveling.

  1. Convenience: Play anywhere at any time with mobile access.
  2. Broad Game Variety: Access numerous games optimized for mobile play.
  3. Instant Updates: Receive the latest promotions and game releases on mobile.

Moreover, the mobile version of Bizzo Casino retains all the features of the desktop platform, ensuring players receive a consistent experience regardless of the device. In addition, mobile players often receive special promotions, attracting even more users to play on their smartphones.

Features of the Mobile Site

The mobile site is designed to provide a seamless experience with a user-friendly interface that displays well on various screen sizes. Navigating through games and promotions is quick and simple, making it easy for players to find their favorites. The mobile platform also maintains the same level of security as the desktop version, ensuring confidential information remains well-protected.

Furthermore, as mobile gaming continues to expand, Bizzo Casino remains proactive in enhancing its mobile offerings, regularly implementing updates and improvements to cater to evolving player preferences.

The Future of Mobile Gaming at Bizzo Casino

As mobile technology continues to advance, Bizzo Casino will likely adopt new innovations to improve their gaming experience further. Staying abreast of industry trends, the casino aims to remain competitive in a crowded marketplace. By incorporating new technologies and features, Bizzo Casino can create unique gaming opportunities for both new and existing players.

Ultimately, the future of mobile gaming at Bizzo Casino looks promising, positioning the platform as a leader in the ever-evolving landscape of online gaming.

Conclusion

In conclusion, Bizzo Casino presents a well-rounded online gaming experience that caters to various player preferences. With an extensive game library, generous bonuses, and a commitment to security and customer support, it stands out as a formidable player in the online gaming landscape. While no platform is without its challenges, Bizzo Casino appears well-equipped to meet the demands of modern players.

As gaming technology continues to evolve, staying attuned to player needs will be crucial for maintaining and enhancing the overall experience. If you are considering an online casino that offers a broad selection of games, engaging promotions, and a secure environment, Bizzo Casino may very well be the ultimate destination for your online gaming adventures.

Check Also

Améliorez vos gains avec des stratégies innovantes et attrayantes.

Améliorez vos gains avec des stratégies innovantes et attrayantes. Comprendre le terrain de jeu Recherchez …