TfLiteRegistration* Register_LOCAL_RESPONSE_NORM_GENERIC_OPT() {
  static TfLiteRegistration r = {
      nullptr, nullptr, local_response_norm::Prepare,
      local_response_norm::Eval<local_response_norm::kGenericOptimized>};
  return &r;
}


void SelectFree(TfLiteContext* context, void* buffer) {
  delete reinterpret_cast<OpData*>(buffer);
}


T ReInterpretTensor(const TfLiteTensor* tensor) {
  // TODO (chowdhery): check float
  const float* tensor_base = GetTensorData<float>(tensor);
  return reinterpret_cast<T>(tensor_base);
}


TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
  OpData* data = reinterpret_cast<OpData*>(node->user_data);
  auto* params = reinterpret_cast<TfLiteSubParams*>(node->builtin_data);

  TF_LITE_ENSURE_EQ(context, NumInputs(node), 2);
  TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1);

  const TfLiteTensor* input1;
  TF_LITE_ENSURE_OK(context,
                    GetInputSafe(context, node, kInputTensor1, &input1));
  const TfLiteTensor* input2;
  TF_LITE_ENSURE_OK(context,
                    GetInputSafe(context, node, kInputTensor2, &input2));
  TfLiteTensor* output;
  TF_LITE_ENSURE_OK(context,
                    GetOutputSafe(context, node, kOutputTensor, &output));

  TF_LITE_ENSURE_TYPES_EQ(context, input1->type, input2->type);
  output->type = input2->type;

  data->requires_broadcast = !HaveSameShapes(input1, input2);

  TfLiteIntArray* output_size = nullptr;
  if (data->requires_broadcast) {
    TF_LITE_ENSURE_OK(context, CalculateShapeForBroadcast(
                                   context, input1, input2, &output_size));
  } else {
    output_size = TfLiteIntArrayCopy(input1->dims);
  }

  // 8bit -> 8bit general quantized path, with general rescalings
  // as well as, 16bit -> 16bit with general rescalings
  bool pot_scale_int16 = true;

  bool input1_scale_is_pot = false;
  bool input2_scale_is_pot = false;
  bool output_scale_is_pot = false;

  int input1_scale_log2_rounded{0};
  int input2_scale_log2_rounded{0};
  int output_scale_log2_rounded{0};

  if (input1->type == kTfLiteInt16 && input2->type == kTfLiteInt16 &&
      output->type == kTfLiteInt16) {
    // In case of 16-bit, there are two implementation:
    // the scale parameter is a general number
    // the scale parameter is POT and
    // zero_point is zero for inputs/output.
    pot_scale_int16 = (input1->params.zero_point == 0) &&
                      (input2->params.zero_point == 0) &&
                      (output->params.zero_point == 0);

    input1_scale_is_pot =
        CheckedLog2(input1->params.scale, &input1_scale_log2_rounded);

    input2_scale_is_pot =
        CheckedLog2(input2->params.scale, &input2_scale_log2_rounded);

    output_scale_is_pot =
        CheckedLog2(output->params.scale, &output_scale_log2_rounded);

    pot_scale_int16 &=
        input1_scale_is_pot && input2_scale_is_pot && output_scale_is_pot;
  }

  data->pot_scale_int16 = pot_scale_int16;

  if (output->type == kTfLiteUInt8 || output->type == kTfLiteInt8 ||
      !pot_scale_int16) {
    TF_LITE_ENSURE_OK(context, PrepareGeneralSubOp(context, input1, input2,
                                                   output, params, data, -1));
  } else if (output->type == kTfLiteInt16) {
    // LSTM-special case with scale parameter of POT
    TF_LITE_ENSURE_OK(context, PrepareInt16SubOpPOT(context, input1, input2,
                                                    output, params, data));
  }

  return context->ResizeTensor(context, output, output_size);
}


void Free(TfLiteContext* context, void* buffer) {
#if defined(TFLITE_WITH_MULTITHREADED_EIGEN)
  eigen_support::DecrementUsageCounter(context);
#endif
  delete reinterpret_cast<OpData*>(buffer);
}


static int read_probe(const AVProbeData *p)
{
    int cnt = 0;

    for (int i = 0; i < p->buf_size; i++)
        cnt += !!isansicode(p->buf[i]);

    return (cnt * 100LL / p->buf_size) * (cnt > 400) *
        !!av_match_ext(p->filename, tty_extensions);
}


static int efi_read(AVFormatContext *avctx, uint64_t start_pos)
{
    TtyDemuxContext *s = avctx->priv_data;
    AVIOContext *pb = avctx->pb;
    char buf[37];
    int len;

    avio_seek(pb, start_pos, SEEK_SET);
    if (avio_r8(pb) != 0x1A)
        return -1;

#define GET_EFI_META(name,size) \
    len = avio_r8(pb); \
    if (len < 1 || len > size) \
        return -1; \
    if (avio_read(pb, buf, size) == size) { \
        buf[len] = 0; \
        av_dict_set(&avctx->metadata, name, buf, 0); \
    }

    GET_EFI_META("filename", 12)
    GET_EFI_META("title",    36)

    s->fsize = start_pos;
    return 0;
}


sc_oberthur_get_certificate_authority(struct sc_pkcs15_der *der, int *out_authority)
{
#ifdef ENABLE_OPENSSL
	X509	*x;
	BUF_MEM buf_mem;
	BIO *bio = NULL;
	BASIC_CONSTRAINTS *bs = NULL;

	if (!der)
		return SC_ERROR_INVALID_ARGUMENTS;

	buf_mem.data = malloc(der->len);
	if (!buf_mem.data)
		return SC_ERROR_OUT_OF_MEMORY;

	memcpy(buf_mem.data, der->value, der->len);
	buf_mem.max = buf_mem.length = der->len;

	bio = BIO_new(BIO_s_mem());
	if (!bio) {
		free(buf_mem.data);
		return SC_ERROR_OUT_OF_MEMORY;
	}

	BIO_set_mem_buf(bio, &buf_mem, BIO_NOCLOSE);
	x = d2i_X509_bio(bio, 0);
	free(buf_mem.data);
	BIO_free(bio);
	if (!x)
		return SC_ERROR_INVALID_DATA;

	bs = (BASIC_CONSTRAINTS *)X509_get_ext_d2i(x, NID_basic_constraints, NULL, NULL);
	if (out_authority)
		*out_authority = (bs && bs->ca);

	X509_free(x);

	return SC_SUCCESS;
#else
	return SC_ERROR_NOT_SUPPORTED;
#endif
}


  explicit ProductIterator(
      const std::vector<std::unique_ptr<ColumnInterface<InternalType>>>&
          columns,
      int64 batch_index)
      : columns_(columns), batch_index_(batch_index) {
    next_permutation_.resize(columns_.size(), 0);
    // Sets has_next_ to false if any feature column has 0 features.
    has_next_ = true;
    for (int i = 0; i < columns_.size(); i++) {
      if (columns_[i]->FeatureCount(batch_index_) == 0) {
        has_next_ = false;
        break;
      }
    }
  }


int64 CalculateBatchSize(const OpInputList& shapes_list_in,
                         const OpInputList& dense_list_in) {
  if (shapes_list_in.size() > 0) {
    return shapes_list_in[0].vec<int64>()(0);
  }

  if (dense_list_in.size() > 0) {
    return dense_list_in[0].dim_size(0);
  }

  return 0;
}


static int add_sdb_include_dir(Sdb *s, const char *incl, int idx) {
	if (!s || !incl)
		return false;
	return sdb_array_set (s, "includedirs", idx, incl, 0);
}


R_API RList *r_bin_dwarf_parse_aranges(RBin *a, int mode) {
	ut8 *buf;
	int ret;
	size_t len;
	RBinSection *section = getsection (a, "debug_aranges");
	RBinFile *binfile = a ? a->cur: NULL;

	if (binfile && section) {
		len = section->size;
		if (len < 1 || len > ST32_MAX) {
			return NULL;
		}
		buf = calloc (1, len);
		ret = r_buf_read_at (binfile->buf, section->paddr, buf, len);
		if (!ret) {
			free (buf);
			return NULL;
		}
		if (mode == R_CORE_BIN_PRINT) {
			r_bin_dwarf_parse_aranges_raw (buf, len, stdout);
		} else {
			r_bin_dwarf_parse_aranges_raw (buf, len, DBGFD);
		}
		free (buf);
	}
	return NULL;
}


static const ut8 *r_bin_dwarf_parse_lnp_header (
		RBinFile *bf, const ut8 *buf, const ut8 *buf_end,
		RBinDwarfLNPHeader *hdr, FILE *f, int mode) {
	int i;
	Sdb *s;
	size_t count;
	const ut8 *tmp_buf = NULL;

	if (!hdr || !bf || !buf) return NULL;

	hdr->unit_length.part1 = READ (buf, ut32);
	if (hdr->unit_length.part1 == DWARF_INIT_LEN_64) {
		hdr->unit_length.part2 = READ (buf, ut32);
	}

	s = sdb_new (NULL, NULL, 0);

	hdr->version = READ (buf, ut16);

	if (hdr->unit_length.part1 == DWARF_INIT_LEN_64) {
		hdr->header_length = READ (buf, ut64);
	} else {
		hdr->header_length = READ (buf, ut32);
	}

	if (buf_end-buf < 8) {
		sdb_free (s);
		return NULL;
	}
	hdr->min_inst_len = READ (buf, ut8);
	//hdr->max_ops_per_inst = READ (buf, ut8);
	hdr->file_names = NULL;
	hdr->default_is_stmt = READ (buf, ut8);
	hdr->line_base = READ (buf, char);
	hdr->line_range = READ (buf, ut8);
	hdr->opcode_base = READ (buf, ut8);

	if (f) {
		fprintf (f, "DWARF LINE HEADER\n");
		fprintf (f, "  total_length: %d\n", hdr->unit_length.part1);
		fprintf (f, "  version: %d\n", hdr->version);
		fprintf (f, "  header_length: : %"PFMT64d"\n", hdr->header_length);
		fprintf (f, "  mininstlen: %d\n", hdr->min_inst_len);
		fprintf (f, "  is_stmt: %d\n", hdr->default_is_stmt);
		fprintf (f, "  line_base: %d\n", hdr->line_base);
		fprintf (f, "  line_range: %d\n", hdr->line_range);
		fprintf (f, "  opcode_base: %d\n", hdr->opcode_base);
	}

	if (hdr->opcode_base>0) {
		hdr->std_opcode_lengths = calloc(sizeof(ut8), hdr->opcode_base);

		for (i = 1; i <= hdr->opcode_base - 1; i++) {
			if (buf+2>buf_end) break;
			hdr->std_opcode_lengths[i] = READ (buf, ut8);
			if (f) {
				fprintf (f, " op %d %d\n", i, hdr->std_opcode_lengths[i]);
			}
		}
	} else {
		hdr->std_opcode_lengths = NULL;
	}

	i = 0;
	while (buf+1 < buf_end) {
		int maxlen = R_MIN ((size_t)(buf_end-buf)-1, 0xfff);
		int len = r_str_nlen ((const char*)buf, maxlen);
		char *str = r_str_ndup ((const char *)buf, len);
		if (len<1 || len >= 0xfff) {
			buf += 1;
			free (str);
			break;
		}
		if (*str != '/' && *str != '.') {
			// no more paths in here
			free (str);
			break;
		}
		if (f) {
			fprintf (f, "INCLUDEDIR (%s)\n", str);
		}
		add_sdb_include_dir (s, str, i);
		free (str);
		i++;
		buf += len + 1;
	}

	tmp_buf = buf;
	count = 0;
	for (i = 0; i < 2; i++) {
		while (buf+1<buf_end) {
			const char *filename = (const char *)buf;
			int maxlen = R_MIN ((size_t)(buf_end-buf-1), 0xfff);
			ut64 id_idx, mod_time, file_len;
			size_t namelen, len = r_str_nlen (filename, maxlen);

			if (!len) {
				buf++;
				break;
			}
			buf += len + 1;
			if (buf>=buf_end) { buf = NULL; goto beach; }
			buf = r_uleb128 (buf, buf_end-buf, &id_idx);
			if (buf>=buf_end) { buf = NULL; goto beach; }
			buf = r_uleb128 (buf, buf_end-buf, &mod_time);
			if (buf>=buf_end) { buf = NULL; goto beach; }
			buf = r_uleb128 (buf, buf_end-buf, &file_len);
			if (buf>=buf_end) { buf = NULL; goto beach; }

			if (i) {
				char *include_dir = NULL, *comp_dir = NULL;
				char *allocated_id = NULL;
				if (id_idx > 0) {
					include_dir = sdb_array_get (s, "includedirs", id_idx - 1, 0);
					if (include_dir && include_dir[0] != '/') {
						comp_dir = sdb_get (bf->sdb_addrinfo, "DW_AT_comp_dir", 0);
						if (comp_dir) {
							allocated_id = calloc (1, strlen (comp_dir) +
									strlen (include_dir) + 8);
							snprintf (allocated_id, strlen (comp_dir) + strlen (include_dir) + 8,
									"%s/%s/", comp_dir, include_dir);
							include_dir = allocated_id;
						}
					}
				} else {
					include_dir = sdb_get (bf->sdb_addrinfo, "DW_AT_comp_dir", 0);
					if (!include_dir)
						include_dir = "./";
				}

				namelen = len + (include_dir?strlen (include_dir):0) + 8;

				if (hdr->file_names) {
					hdr->file_names[count].name = calloc (sizeof(char), namelen);
					snprintf (hdr->file_names[count].name, namelen - 1,
						"%s/%s", include_dir? include_dir : "", filename);
					hdr->file_names[count].name[namelen - 1] = '\0';
					free (allocated_id);
					hdr->file_names[count].id_idx = id_idx;
					hdr->file_names[count].mod_time = mod_time;
					hdr->file_names[count].file_len = file_len;
				}
			}
			count++;
			if (f && i) {
				fprintf (f, "FILE (%s)\n", filename);
				fprintf (f, "| dir idx %"PFMT64d"\n", id_idx);
				fprintf (f, "| lastmod %"PFMT64d"\n", mod_time);
				fprintf (f, "| filelen %"PFMT64d"\n", file_len);
			}
		}
		if (i == 0) {
			if (count>0) {
				hdr->file_names = calloc(sizeof(file_entry), count);
			} else {
				hdr->file_names = NULL;
			}
			hdr->file_names_count = count;
			buf = tmp_buf;
			count = 0;
		}
	}

beach:
	sdb_free (s);

	return buf;
}


static void r_bin_dwarf_free_debug_info (RBinDwarfDebugInfo *inf) {
	size_t i;
	if (!inf) {
		return;
	}
	for (i = 0; i < inf->length; i++) {
		r_bin_dwarf_free_comp_unit (&inf->comp_units[i]);
	}
	R_FREE (inf->comp_units);
}


static int r_bin_dwarf_init_abbrev_decl(RBinDwarfAbbrevDecl *ad) {
	if (!ad) {
		return -EINVAL;
	}
	ad->specs = calloc (sizeof( RBinDwarfAttrSpec), ABBREV_DECL_CAP);

	if (!ad->specs) {
		return -ENOMEM;
	}

	ad->capacity = ABBREV_DECL_CAP;
	ad->length = 0;

	return 0;
}


static int r_bin_dwarf_expand_die(RBinDwarfDIE* die) {
	RBinDwarfAttrValue *tmp = NULL;
	if (!die || die->capacity == 0) {
		return -EINVAL;
	}
	if (die->capacity != die->length) {
		return -EINVAL;
	}
	tmp = (RBinDwarfAttrValue*)realloc (die->attr_values,
			die->capacity * 2 * sizeof (RBinDwarfAttrValue));
	if (!tmp) {
		return -ENOMEM;
	}
	memset ((ut8*)tmp + die->capacity, 0, die->capacity);
	die->attr_values = tmp;
	die->capacity *= 2;
	return 0;
}


static void FLTRemoveGroupName(FilterEncodingNode *psFilterNode,
                               gmlGroupListObj* groupList)
{
  int i;

  if (psFilterNode) {

    if (psFilterNode->eType == FILTER_NODE_TYPE_PROPERTYNAME) {
      if( psFilterNode->pszValue != NULL )
      {
        const char* pszPropertyName = psFilterNode->pszValue;
        const char* pszSlash = strchr(pszPropertyName, '/');
        if( pszSlash != NULL ) {
          const char* pszColon = strchr(pszPropertyName, ':');
          if( pszColon != NULL && pszColon < pszSlash )
              pszPropertyName = pszColon + 1;
          for(i=0;i<groupList->numgroups;i++) {
            const char* pszGroupName = groupList->groups[i].name;
            size_t nGroupNameLen = strlen(pszGroupName);
            if(strncasecmp(pszPropertyName, pszGroupName, nGroupNameLen) == 0 &&
                            pszPropertyName[nGroupNameLen] == '/') {
              char* pszTmp;
              pszPropertyName = pszPropertyName + nGroupNameLen + 1;
              pszColon = strchr(pszPropertyName, ':');
              if( pszColon != NULL )
                pszPropertyName = pszColon + 1;
              pszTmp = msStrdup(pszPropertyName);
              msFree(psFilterNode->pszValue);
              psFilterNode->pszValue = pszTmp;
              break;
            }
          }
        }
      }
    }

    if (psFilterNode->psLeftNode)
      FLTRemoveGroupName(psFilterNode->psLeftNode, groupList);
    if (psFilterNode->psRightNode)
      FLTRemoveGroupName(psFilterNode->psRightNode, groupList);
  }

}


FilterEncodingNode *FLTCreateFilterEncodingNode(void)
{
  FilterEncodingNode *psFilterNode = NULL;

  psFilterNode =
  (FilterEncodingNode *)malloc(sizeof (FilterEncodingNode));
  psFilterNode->eType = FILTER_NODE_TYPE_UNDEFINED;
  psFilterNode->pszValue = NULL;
  psFilterNode->pOther = NULL;
  psFilterNode->pszSRS = NULL;
  psFilterNode->psLeftNode = NULL;
  psFilterNode->psRightNode = NULL;

  return psFilterNode;
}


int FLTProcessPropertyIsNull(FilterEncodingNode *psFilterNode,
                            mapObj *map, int i)
{
    int status = MS_SUCCESS;

    if (psFilterNode->eType == FILTER_NODE_TYPE_COMPARISON &&
        psFilterNode->psLeftNode != NULL &&
        psFilterNode->psLeftNode->eType == FILTER_NODE_TYPE_PROPERTYNAME &&
        strcmp(psFilterNode->pszValue, "PropertyIsNull") == 0 &&
        !FLTIsGMLDefaultProperty(psFilterNode->psLeftNode->pszValue) )
    {
        layerObj* lp;
        int layerWasOpened;

        lp = GET_LAYER(map, i);
        layerWasOpened = msLayerIsOpen(lp);

        /* Horrible HACK to compensate for the lack of null testing in MapServer */
        if( (lp->connectiontype == MS_POSTGIS ||
             (lp->connectiontype == MS_OGR && msOGRIsSpatialite(lp))) &&
            strcmp(psFilterNode->pszValue, "PropertyIsNull") == 0 )
        {
            msFree(psFilterNode->pszValue);
            psFilterNode->pszValue = msStrdup("PropertyIsEqualTo");
            psFilterNode->psRightNode = FLTCreateBinaryCompFilterEncodingNode();
            psFilterNode->psRightNode->eType = FILTER_NODE_TYPE_LITERAL;
            psFilterNode->psRightNode->pszValue = msStrdup("_MAPSERVER_NULL_");
        }

        if (!layerWasOpened) /* do not close the layer if it has been opened somewhere else (paging?) */
          msLayerClose(lp);
    }

    if (psFilterNode->psLeftNode)
    {
      status = FLTProcessPropertyIsNull(psFilterNode->psLeftNode, map, i);
      if( status == MS_SUCCESS )
      {
        if (psFilterNode->psRightNode)
            status = FLTProcessPropertyIsNull(psFilterNode->psRightNode, map, i);
      }
    }
    return status;
}


char *FLTGetCommonExpression(FilterEncodingNode *psFilterNode, layerObj *lp)
{
  char *pszExpression = NULL;

  if (!psFilterNode)
    return NULL;

  if (psFilterNode->eType == FILTER_NODE_TYPE_COMPARISON) {
    if ( psFilterNode->psLeftNode && psFilterNode->psRightNode) {
      if (FLTIsBinaryComparisonFilterType(psFilterNode->pszValue))
        pszExpression = FLTGetBinaryComparisonCommonExpression(psFilterNode, lp);
      else if (strcasecmp(psFilterNode->pszValue, "PropertyIsLike") == 0)
        pszExpression = FLTGetIsLikeComparisonCommonExpression(psFilterNode);
      else if (strcasecmp(psFilterNode->pszValue, "PropertyIsBetween") == 0)
        pszExpression = FLTGetIsBetweenComparisonCommonExpresssion(psFilterNode, lp);
    }
  } else if (psFilterNode->eType == FILTER_NODE_TYPE_LOGICAL) {
    pszExpression = FLTGetLogicalComparisonCommonExpression(psFilterNode, lp);
  } else if (psFilterNode->eType == FILTER_NODE_TYPE_SPATIAL) {
    pszExpression = FLTGetSpatialComparisonCommonExpression(psFilterNode, lp);
  } else if (psFilterNode->eType ==  FILTER_NODE_TYPE_FEATUREID) {
    pszExpression = FLTGetFeatureIdCommonExpression(psFilterNode, lp);
  } else if (psFilterNode->eType == FILTER_NODE_TYPE_TEMPORAL) {
    pszExpression = FLTGetTimeExpression(psFilterNode, lp);
  }

  return pszExpression;
}


int FLTIsLineFilter(FilterEncodingNode *psFilterNode)
{
  if (!psFilterNode || !psFilterNode->pszValue)
    return 0;

  if (psFilterNode->eType == FILTER_NODE_TYPE_SPATIAL &&
      psFilterNode->psRightNode &&
      psFilterNode->psRightNode->eType == FILTER_NODE_TYPE_GEOMETRY_LINE)
    return 1;

  return 0;
}


int FLTHasSpatialFilter(FilterEncodingNode *psNode)
{
  int bResult = MS_FALSE;

  if (!psNode)
    return MS_FALSE;

  if (psNode->eType == FILTER_NODE_TYPE_LOGICAL) {
    if (psNode->psLeftNode)
      bResult = FLTHasSpatialFilter(psNode->psLeftNode);

    if (bResult)
      return MS_TRUE;

    if (psNode->psRightNode)
      bResult = FLTHasSpatialFilter(psNode->psRightNode);

    if (bResult)
      return MS_TRUE;
  } else if (FLTIsBBoxFilter(psNode) || FLTIsPointFilter(psNode) ||
             FLTIsLineFilter(psNode) || FLTIsPolygonFilter(psNode))
    return MS_TRUE;

  return MS_FALSE;
}


FilterEncodingNode *FLTParseFilterEncoding(const char *szXMLString)
{
  CPLXMLNode *psRoot = NULL, *psChild=NULL, *psFilter=NULL;
  FilterEncodingNode *psFilterNode = NULL;

  if (szXMLString == NULL || strlen(szXMLString) <= 0 ||
      (strstr(szXMLString, "Filter") == NULL))
    return NULL;

  psRoot = CPLParseXMLString(szXMLString);

  if( psRoot == NULL)
    return NULL;

  /* strip namespaces. We srtip all name spaces (#1350)*/
  CPLStripXMLNamespace(psRoot, NULL, 1);

  /* -------------------------------------------------------------------- */
  /*      get the root element (Filter).                                  */
  /* -------------------------------------------------------------------- */
  psFilter = CPLGetXMLNode(psRoot, "=Filter");
  if (!psFilter)
  {
    CPLDestroyXMLNode( psRoot );
    return NULL;
  }

  psChild = psFilter->psChild;
  while (psChild) {
    if (FLTIsSupportedFilterType(psChild)) {
      psFilterNode = FLTCreateFilterEncodingNode();
      FLTInsertElementInNode(psFilterNode, psChild);
      break;
    } else
      psChild = psChild->psNext;
  }

  CPLDestroyXMLNode( psRoot );

  /* -------------------------------------------------------------------- */
  /*      validate the node tree to make sure that all the nodes are valid.*/
  /* -------------------------------------------------------------------- */
  if (!FLTValidFilterNode(psFilterNode)) {
    FLTFreeFilterEncodingNode(psFilterNode);
    return NULL;
  }

  return psFilterNode;
}


int FLTCheckInvalidOperand(FilterEncodingNode *psFilterNode)
{
    int status = MS_SUCCESS;

    if (psFilterNode->eType ==  FILTER_NODE_TYPE_COMPARISON &&
        psFilterNode->psLeftNode != NULL &&
        psFilterNode->psLeftNode->eType == FILTER_NODE_TYPE_PROPERTYNAME)
    {
        if( strcmp(psFilterNode->psLeftNode->pszValue, "gml:boundedBy") == 0 &&
            strcmp(psFilterNode->pszValue, "PropertyIsNull") != 0 &&
            strcmp(psFilterNode->pszValue, "PropertyIsNil") != 0 )
        {
            msSetError(MS_MISCERR, "Operand '%s' is invalid in comparison.",
                       "FLTCheckInvalidOperand()", psFilterNode->psLeftNode->pszValue);
            return MS_FAILURE;
        }
    }
    if (psFilterNode->psLeftNode)
    {
      status = FLTCheckInvalidOperand(psFilterNode->psLeftNode);
      if( status == MS_SUCCESS )
      {
        if (psFilterNode->psRightNode)
            status = FLTCheckInvalidOperand(psFilterNode->psRightNode);
      }
    }
    return status;
}


static void lsr_translate_anim_trans_values(GF_LASeRCodec *lsr, SMIL_AnimateValues *val, u32 transform_type)
{
	u32 count, i, coded_type;
	SVG_Point_Angle *p;
	SVG_Point *pt;
	Fixed *f;
	GF_List *l;
	Bool handled = GF_FALSE;

	coded_type = val->type;
	switch(transform_type) {
	case SVG_TRANSFORM_TRANSLATE:
		val->type = SVG_Transform_Translate_datatype;
		break;
	case SVG_TRANSFORM_SCALE:
		if (coded_type==8) handled = GF_TRUE;
		val->type = SVG_Transform_Scale_datatype;
		break;
	case SVG_TRANSFORM_ROTATE:
		if ((coded_type==8) || (coded_type==1)) handled = GF_TRUE;
		val->type = SVG_Transform_Rotate_datatype;
		break;
	case SVG_TRANSFORM_SKEWX:
		if ((coded_type==1) || (coded_type==4)) handled = GF_TRUE;
		val->type = SVG_Transform_SkewX_datatype;
		break;
	case SVG_TRANSFORM_SKEWY:
		if ((coded_type==1) || (coded_type==4)) handled = GF_TRUE;
		val->type = SVG_Transform_SkewY_datatype;
		break;
	case SVG_TRANSFORM_MATRIX:
		val->type = SVG_Transform_datatype;
		break;
	default:
		GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[SVG Parsing] unknown datatype for animate transform.\n"));
		break;
	}

	if (!handled) {
		while (gf_list_count(val->values)) {
			SMIL_AnimateValue a_val;
			a_val.type = 0;
			a_val.value = gf_list_pop_back(val->values);
			lsr_delete_anim_value(lsr, &a_val, coded_type);
		}
		return;
	}

	count = gf_list_count(val->values);
	if (!count) return;

	if (transform_type==SVG_TRANSFORM_TRANSLATE)
		return;

	for (i=0; i<count; i++) {
		void *a_val = gf_list_get(val->values, i);
		switch (transform_type) {
		case SVG_TRANSFORM_ROTATE:
			GF_SAFEALLOC(p, SVG_Point_Angle);
			if (!p) {
				lsr->last_error = GF_OUT_OF_MEM;
				return;
			}
			if (coded_type==8) {
				l = (GF_List*)a_val;
				f = (Fixed*)gf_list_get(l, 0);
				if (f) p->angle = *f;
				f = (Fixed*)gf_list_get(l, 1);
				if (f) p->x = *f;
				f = (Fixed*)gf_list_get(l, 2);
				if (f) p->y = *f;
				while (gf_list_count(l)) {
					f = (Fixed*)gf_list_last(l);
					gf_list_rem_last(l);
					gf_free(f);
				}
				gf_list_del(l);
			} else if (coded_type==1) {
				p->angle = ((SVG_Number *)a_val)->value;
				gf_free(a_val);
			}
			p->angle = gf_muldiv(p->angle, GF_PI, INT2FIX(180) );
			gf_list_rem(val->values, i);
			gf_list_insert(val->values, p, i);
			break;
		case SVG_TRANSFORM_SKEWX:
		case SVG_TRANSFORM_SKEWY:
			f = (Fixed*)gf_malloc(sizeof(Fixed));
			if (!f) {
				lsr->last_error = GF_OUT_OF_MEM;
			} else {
				*f = ((SVG_Number *)a_val)->value;
			}
			gf_free(a_val);
			gf_list_rem(val->values, i);
			if (f)
				gf_list_insert(val->values, f, i);
			break;
		case SVG_TRANSFORM_SCALE:
			GF_SAFEALLOC(pt, SVG_Point);
			if (!pt)
				lsr->last_error = GF_OUT_OF_MEM;

			l = (GF_List*)a_val;
			if (pt) {
				f = (Fixed*)gf_list_get(l, 0);
				if (f) pt->x = *f;
				f = (Fixed*)gf_list_get(l, 1);
				if (f) pt->y = *f;
				else pt->y = pt->x;
			}

			while (gf_list_count(l)) {
				f = (Fixed*)gf_list_last(l);
				gf_list_rem_last(l);
				gf_free(f);
			}
			gf_list_del(l);
			gf_list_rem(val->values, i);
			if (pt)
				gf_list_insert(val->values, pt, i);
			break;
		default:
			GF_LOG(GF_LOG_ERROR, GF_LOG_CODING, ("[LASeR] unknown transform type %d\n", transform_type));
			break;
		}
	}
}


static void lsr_read_group_content(GF_LASeRCodec *lsr, GF_Node *elt, Bool skip_object_content)
{
	u32 i, count;
	if (lsr->last_error) return;

	if (!skip_object_content) lsr_read_object_content(lsr, (SVG_Element*)elt);

	/*node attributes are all parsed*/
	if (elt->sgprivate->tag!=TAG_SVG_script)
		gf_node_init(elt);

	GF_LSR_READ_INT(lsr, count, 1, "opt_group");
	if (count) {
		GF_ChildNodeItem *last = NULL;
		count = lsr_read_vluimsbf5(lsr, "occ0");
		for (i=0; i<count; i++) {
			GF_Node *n;
			if (lsr->last_error) return;
			n = lsr_read_scene_content_model(lsr, (SVG_Element*)elt);
			if (n) {
				gf_node_register(n, elt);
				gf_node_list_add_child_last(& ((SVG_Element*)elt)->children, n, &last);
				GF_LOG(GF_LOG_DEBUG, GF_LOG_CODING, ("[LASeR] ############## end %s ###########\n", gf_node_get_class_name(n)));
			} else {
				/*either error or text content*/
			}
		}
	}

	if (elt->sgprivate->tag==TAG_SVG_script)
		gf_node_init(elt);
}


static void lsr_read_value_with_units(GF_LASeRCodec *lsr, SVG_Number *n, const char *name)
{
	s32 val;
	GF_LSR_READ_INT(lsr, val, 32, name);
#ifdef GPAC_FIXED_POINT
	n->value = val << 8;
#else
	n->value = INT2FIX(val) / (1<<8);
#endif
	GF_LSR_READ_INT(lsr, val, 3, "units");
	switch (val) {
	case 1:
		n->type = SVG_NUMBER_IN;
		break;
	case 2:
		n->type = SVG_NUMBER_CM;
		break;
	case 3:
		n->type = SVG_NUMBER_MM;
		break;
	case 4:
		n->type = SVG_NUMBER_PT;
		break;
	case 5:
		n->type = SVG_NUMBER_PC;
		break;
	case 6:
		n->type = SVG_NUMBER_PERCENTAGE;
		break;
	default:
		n->type = SVG_NUMBER_VALUE;
		break;
	}
}


Bool gf_laser_decode_has_conditionnals(GF_LASeRCodec *codec)
{
	return codec && codec->has_conditionnals ? GF_TRUE : GF_FALSE;
}


static void lsr_read_path_type(GF_LASeRCodec *lsr, GF_Node *n, u32 tag, SVG_PathData *path, const char *name)
{
#if USE_GF_PATH
	GF_Point2D *pt, *ct1, *ct2, *end;
	GF_Point2D orig, ct_orig;
	u32 i, count, cur_pt, type;
	GF_List *pts = gf_list_new();
	lsr_read_point_sequence(lsr, pts, "seq");

	if (!path) {
		GF_FieldInfo info;
		gf_node_get_attribute_by_tag(n, tag, GF_TRUE, 0, &info);
		path = (SVG_PathData*)info.far_ptr;
	} else {
		gf_path_reset(path);
	}
	/*first MoveTo is skipped in LASeR*/
	pt = (GF_Point2D*)gf_list_get(pts, 0);
	if (pt) {
		ct_orig = orig = *pt;
		gf_path_add_move_to_vec(path, pt);
	} else {
		orig.x = orig.y = 0;
		ct_orig = orig;
		GF_LOG(GF_LOG_DEBUG, GF_LOG_CODING, ("[LASeR] Empty path found.\n"));
	}
	cur_pt = 1;
	count = lsr_read_vluimsbf5(lsr, "nbOfTypes");
	for (i=0; i<count; i++) {
		GF_LSR_READ_INT(lsr, type, 5, name);
		switch (type) {
		case LSR_PATH_COM_h:
		case LSR_PATH_COM_l:
		case LSR_PATH_COM_v:
		case LSR_PATH_COM_H:
		case LSR_PATH_COM_V:
		case LSR_PATH_COM_L:
			pt = (GF_Point2D*)gf_list_get(pts, cur_pt);
			if (!pt) goto err_exit;
			gf_path_add_line_to_vec(path, pt);
			cur_pt++;
			break;
		case LSR_PATH_COM_m:
		case LSR_PATH_COM_M:
			pt = (GF_Point2D*)gf_list_get(pts, cur_pt);
			if (!pt) goto err_exit;
			gf_path_add_move_to_vec(path, pt);
			cur_pt++;
			break;
		case LSR_PATH_COM_q:
		case LSR_PATH_COM_Q:
			ct1 = (GF_Point2D*)gf_list_get(pts, cur_pt);
			end = (GF_Point2D*)gf_list_get(pts, cur_pt+1);
			if (!ct1 || !end) goto err_exit;
			gf_path_add_quadratic_to_vec(path, ct1, end);
			orig = *end;
			cur_pt+=2;
			break;
		case LSR_PATH_COM_c:
		case LSR_PATH_COM_C:
			ct1 = (GF_Point2D*)gf_list_get(pts, cur_pt);
			ct2 = (GF_Point2D*)gf_list_get(pts, cur_pt+1);
			end = (GF_Point2D*)gf_list_get(pts, cur_pt+2);
			if (!ct1 || !ct2 || !end) goto err_exit;
			gf_path_add_cubic_to_vec(path, ct1, ct2, end);
			cur_pt+=3;
			ct_orig = *ct2;
			orig = *end;
			break;
		case LSR_PATH_COM_s:
		case LSR_PATH_COM_S:
			ct_orig.x = 2*orig.x - ct_orig.x;
			ct_orig.y = 2*orig.y - ct_orig.y;
			ct2 = (GF_Point2D*)gf_list_get(pts, cur_pt);
			end = (GF_Point2D*)gf_list_get(pts, cur_pt+1);
			if (!ct2 || !end) goto err_exit;
			gf_path_add_cubic_to_vec(path, &ct_orig, ct2, end);
			ct_orig = *ct2;
			orig = *end;
			cur_pt+=2;
			break;
		case LSR_PATH_COM_t:
		case LSR_PATH_COM_T:
			ct_orig.x = 2*orig.x - ct_orig.x;
			ct_orig.y = 2*orig.y - ct_orig.y;
			end = gf_list_get(pts, cur_pt);
			if (!end) goto err_exit;
			gf_path_add_quadratic_to_vec(path, &ct_orig, end);
			orig = *end;
			break;
		case LSR_PATH_COM_z:
		case LSR_PATH_COM_Z:
			gf_path_close(path);
			break;
		}
		if (lsr->last_error) break;
	}
	goto exit;

err_exit:
	lsr->last_error = GF_NON_COMPLIANT_BITSTREAM;

exit:
	while (gf_list_count(pts)) {
		end = (GF_Point2D*)gf_list_get(pts, 0);
		gf_list_rem(pts, 0);
		gf_free(end);
	}
	gf_list_del(pts);

#else
	u32 i, count, c;
	if (!path) {
		lsr->last_error = GF_BAD_PARAM;
		return;
	}
	lsr_read_point_sequence(lsr, path->points, "seq");
	while (gf_list_count(path->commands)) {
		u8 *v = (u8 *)gf_list_last(path->commands);
		gf_list_rem_last(path->commands);
		gf_free(v);
	}

	count = lsr_read_vluimsbf5(lsr, "nbOfTypes");
	for (i=0; i<count; i++) {
		u8 *type = (u8 *)gf_malloc(sizeof(u8));
		if (!type) {
			lsr->last_error = GF_OUT_OF_MEM;
			return;
		}
		GF_LSR_READ_INT(lsr, c, 5, name);

		switch (c) {
		case LSR_PATH_COM_h:
		case LSR_PATH_COM_l:
		case LSR_PATH_COM_v:
		case LSR_PATH_COM_H:
		case LSR_PATH_COM_V:
		case LSR_PATH_COM_L:
			*type=SVG_PATHCOMMAND_L;
			break;
		case LSR_PATH_COM_m:
		case LSR_PATH_COM_M:
			*type=SVG_PATHCOMMAND_M;
			break;
		case LSR_PATH_COM_q:
		case LSR_PATH_COM_Q:
			*type=SVG_PATHCOMMAND_Q;
			break;
		case LSR_PATH_COM_c:
		case LSR_PATH_COM_C:
			*type=SVG_PATHCOMMAND_C;
			break;
		case LSR_PATH_COM_s:
		case LSR_PATH_COM_S:
			*type=SVG_PATHCOMMAND_S;
			break;
		case LSR_PATH_COM_t:
		case LSR_PATH_COM_T:
			*type=SVG_PATHCOMMAND_T;
			break;
		case LSR_PATH_COM_z:
		case LSR_PATH_COM_Z:
			*type=SVG_PATHCOMMAND_Z;
			break;
		}
		gf_list_add(path->commands, type);
	}
#endif
}


static GF_Node *lsr_read_cursorManager(GF_LASeRCodec *lsr)
{
	GF_Node *elt = gf_node_new(lsr->sg, TAG_LSR_cursorManager);
	lsr_read_id(lsr, elt);
	lsr_read_rare(lsr, elt);
	lsr_read_coordinate_ptr(lsr, elt,TAG_SVG_ATT_x, 1, "x");
	lsr_read_coordinate_ptr(lsr, elt, TAG_SVG_ATT_y, 1, "y");
	lsr_read_href(lsr, elt);
	lsr_read_any_attribute(lsr, elt, 1);
	lsr_read_group_content(lsr, elt, 0);
	return elt;
}


static GF_Node *lsr_read_selector(GF_LASeRCodec *lsr)
{
	u32 flag;
	GF_Node *elt = gf_node_new(lsr->sg, TAG_LSR_selector);
	lsr_read_id(lsr, elt);
	lsr_read_rare_full(lsr, elt);
	lsr_read_fill(lsr, elt);
	lsr_read_stroke(lsr, elt);
	lsr_read_eRR(lsr, elt);
	GF_LSR_READ_INT(lsr, flag, 1, "hasChoice");
	if (flag) {
		GF_FieldInfo info;
		lsr->last_error = gf_node_get_attribute_by_tag(elt, TAG_SVG_ATT_choice, 1, 0, &info);
		GF_LSR_READ_INT(lsr, flag, 1, "choice");
		if (flag) {
			GF_LSR_READ_INT(lsr, ((LASeR_Choice*)info.far_ptr)->type, 1, "type");
		} else {
			GF_LSR_READ_INT(lsr, ((LASeR_Choice*)info.far_ptr)->choice_index, 8, "value");
			((LASeR_Choice*)info.far_ptr)->type = LASeR_CHOICE_N;
		}
	}
	lsr_read_any_attribute(lsr, elt, 1);
	lsr_read_group_content(lsr, elt, 0);
	return elt;
}


static void lsr_read_sync_behavior(GF_LASeRCodec *lsr, GF_Node *n)
{
	u32 flag;
	GF_LSR_READ_INT(lsr, flag, 1, "syncBehavior");
	if (flag) {
		GF_FieldInfo info;
		GF_LSR_READ_INT(lsr, flag, 2, "syncBehavior");
		lsr->last_error = gf_node_get_attribute_by_tag(n, TAG_SVG_ATT_syncBehavior, GF_TRUE, 0, &info);
		*(SMIL_SyncBehavior*)info.far_ptr = flag + 1;
	}
}


static GF_Err lsr_read_command_list(GF_LASeRCodec *lsr, GF_List *com_list, SVG_Element *cond, Bool first_imp)
{
	GF_Node *n;
	GF_Command *com;
	u32 i, type, count;

	if (cond) {
		u32 s_len;
		GF_DOMUpdates *up = gf_dom_add_updates_node((GF_Node*)cond);
		gf_node_set_callback_function((GF_Node*)up, lsr_exec_command_list);
		gf_node_set_private((GF_Node *) up, lsr);

		s_len = lsr_read_vluimsbf5(lsr, NULL/*"encoding-length" - don't log to avoid corrupting the log order!!*/);
		gf_bs_align(lsr->bs);
		/*not in memory mode, direct decode*/
		if (!lsr->memory_dec) {
			com_list = NULL;
			up->data_size = s_len;
			up->data = (char*)gf_malloc(sizeof(char)*s_len);
			if (!up->data) {
				lsr->last_error = GF_OUT_OF_MEM;
			} else {
				gf_bs_read_data(lsr->bs, up->data, s_len);
			}
			goto exit;
		}
		/*memory mode, decode commands*/
		else {
			com_list = up->updates;
		}
	}
	count = lsr_read_vluimsbf5(lsr, "occ0");
	if (first_imp) count++;

	for (i=0; i<count; i++) {
		GF_LSR_READ_INT(lsr, type, 4, "ch4");
		switch (type) {
		case LSR_UPDATE_ADD:
		case LSR_UPDATE_INSERT:
		case LSR_UPDATE_REPLACE:
			lsr_read_add_replace_insert(lsr, com_list, type);
			break;
		case LSR_UPDATE_DELETE:
			lsr_read_delete(lsr, com_list);
			break;
		case LSR_UPDATE_NEW_SCENE:
		case LSR_UPDATE_REFRESH_SCENE: /*TODO FIXME, depends on decoder state*/
			if (type==5) lsr_read_vluimsbf5(lsr, "time");
			lsr_read_any_attribute(lsr, NULL, 1);
			if (com_list) {
				n = lsr_read_svg(lsr, 0);
				if (!n)
					return (lsr->last_error = GF_NON_COMPLIANT_BITSTREAM);
				gf_node_register(n, NULL);
				com = gf_sg_command_new(lsr->sg, (type==5) ? GF_SG_LSR_REFRESH_SCENE : GF_SG_LSR_NEW_SCENE);
				com->node = n;
				gf_list_add(com_list, com);
			} else {
				gf_sg_reset(lsr->sg);
				gf_sg_set_scene_size_info(lsr->sg, 0, 0, 1);
				n = lsr_read_svg(lsr, 1);
				if (!n)
					return (lsr->last_error = GF_NON_COMPLIANT_BITSTREAM);
			}
			break;
		case LSR_UPDATE_TEXT_CONTENT:
			lsr_read_byte_align_string(lsr, NULL, "textContent");
			break;
		case LSR_UPDATE_SEND_EVENT:
			lsr_read_send_event(lsr, com_list);
			break;
		case LSR_UPDATE_RESTORE:
			lsr_read_restore(lsr, com_list);
			break;
		case LSR_UPDATE_SAVE:
			lsr_read_save(lsr, com_list);
			break;
		case LSR_UPDATE_EXTEND:
		{
			u32 extID;
			GF_LSR_READ_INT(lsr, extID, lsr->info->cfg.extensionIDBits, "extensionID");
			/*len = */lsr_read_vluimsbf5(lsr, "len");
			if (extID==2) {
				u32 j, sub_count;
				lsr_read_vluimsbf5(lsr, "reserved");
				sub_count = lsr_read_vluimsbf5(lsr, "occ2");
				for (j=0; j<sub_count; j++) {
					u32 k, occ3;
					GF_LSR_READ_INT(lsr, k, 2, "reserved");
					occ3 = lsr_read_vluimsbf5(lsr, "occ3");
					for (k=0; k<occ3; k++) {
						u32 sub_type, idref;
						GF_LSR_READ_INT(lsr, sub_type, 2, "ch5");
						switch (sub_type) {
						case 1:
						case 2:
							idref = lsr_read_codec_IDREF_command(lsr, "ref");

							n = gf_sg_find_node(lsr->sg, idref);
							if (com_list) {
								com = gf_sg_command_new(lsr->sg, (sub_type==1) ? GF_SG_LSR_ACTIVATE : GF_SG_LSR_DEACTIVATE);
								if (n) {
									com->node = n;
									gf_node_register(n, NULL);
								} else {
									com->RouteID = idref;
								}
								gf_list_add(com_list, com);
							} else if (sub_type==1) {
								if (!n) return GF_NON_COMPLIANT_BITSTREAM;
								gf_node_activate(n);
							} else {
								if (!n) return GF_NON_COMPLIANT_BITSTREAM;
								gf_node_deactivate(n);
							}
							break;
						default:
							lsr_read_private_element_container(lsr);
							break;
						}
						if (lsr->last_error) return lsr->last_error;
					}
				}
			}
		}
		break;
		default:
			return (lsr->last_error = GF_NON_COMPLIANT_BITSTREAM);
		}
		/*same-coding scope is command-based (to check in the spec)*/
		if (cond) {
			lsr->prev_g = NULL;
			lsr->prev_line = NULL;
			lsr->prev_path = NULL;
			lsr->prev_polygon = NULL;
			lsr->prev_rect = NULL;
			lsr->prev_text = NULL;
			lsr->prev_use = NULL;
		}

		if (lsr->last_error)
			return lsr->last_error;
	}
exit:
	/*script is align*/
	if (cond) {
		gf_bs_align(lsr->bs);
		lsr_read_object_content(lsr, (SVG_Element*)cond);
		lsr->prev_g = NULL;
		lsr->prev_line = NULL;
		lsr->prev_path = NULL;
		lsr->prev_polygon = NULL;
		lsr->prev_rect = NULL;
		lsr->prev_text = NULL;
		lsr->prev_use = NULL;
	}
	return GF_OK;
}


static void lsr_read_group_content_post_init(GF_LASeRCodec *lsr, SVG_Element *elt, Bool skip_init)
{
	u32 i, count;
	if (lsr->last_error) return;
	lsr_read_object_content(lsr, elt);

	GF_LSR_READ_INT(lsr, count, 1, "opt_group");
	if (count) {
		GF_ChildNodeItem *last = NULL;
		count = lsr_read_vluimsbf5(lsr, "occ0");
		for (i=0; i<count; i++) {
			GF_Node *n;
			if (lsr->last_error) return;
			n = lsr_read_scene_content_model(lsr, elt);
			if (n) {
				gf_node_register(n, (GF_Node*)elt);
				gf_node_list_add_child_last(&elt->children, n, &last);
				GF_LOG(GF_LOG_DEBUG, GF_LOG_CODING, ("[LASeR] ############## end %s ###########\n", gf_node_get_class_name(n)));
			} else {
				/*either error or text content*/
			}
		}
	}
	if (!skip_init) gf_node_init((GF_Node*)elt);
}


static GF_Node *lsr_read_text(GF_LASeRCodec *lsr, u32 same_type)
{
	u32 flag;
	GF_FieldInfo info;
	GF_Node *elt = gf_node_new(lsr->sg, TAG_SVG_text);
	if (same_type) {
		if (lsr->prev_text) {
			lsr_restore_base(lsr, (SVG_Element *)elt, (SVG_Element *)lsr->prev_text, (same_type==2) ? 1 : 0, 0);
		} else {
			GF_LOG(GF_LOG_WARNING, GF_LOG_CODING, ("[LASeR] sametext coded in bitstream but no text defined !\n"));
		}
		lsr_read_id(lsr, elt);
		if (same_type==2) lsr_read_fill(lsr, elt);
		lsr_read_coord_list(lsr, elt, TAG_SVG_ATT_text_x, "x");
		lsr_read_coord_list(lsr, elt, TAG_SVG_ATT_text_y, "y");
	} else {
		lsr_read_id(lsr, elt);
		lsr_read_rare_full(lsr, elt);
		lsr_read_fill(lsr, elt);
		lsr_read_stroke(lsr, elt);

		GF_LSR_READ_INT(lsr, flag, 1, "editable");
		if (flag) {
			lsr->last_error = gf_node_get_attribute_by_tag(elt, TAG_SVG_ATT_editable, 1, 0, &info);
			*(SVG_Boolean*)info.far_ptr = flag;
		}
		lsr_read_float_list(lsr, elt, TAG_SVG_ATT_text_rotate, NULL, "rotate");
		lsr_read_coord_list(lsr, elt, TAG_SVG_ATT_text_x, "x");
		lsr_read_coord_list(lsr, elt, TAG_SVG_ATT_text_y, "y");
		lsr_read_any_attribute(lsr, elt, 1);
		lsr->prev_text = (SVG_Element*)elt;
	}
	lsr_read_group_content(lsr, elt, same_type);
	return elt;
}


static Fixed lsr_read_fixed_16_8(GF_LASeRCodec *lsr, const char *name)
{
	u32 val;
	GF_LSR_READ_INT(lsr, val, 24, name);
	if (val & (1<<23)) {
		s32 res = val - (1<<24);
#ifdef GPAC_FIXED_POINT
		return res*256;
#else
		return INT2FIX(res) / 256;
#endif
	} else {
#ifdef GPAC_FIXED_POINT
		return val*256;
#else
		return INT2FIX(val) / 256;
#endif
	}
}


static GF_Node *lsr_read_tspan(GF_LASeRCodec *lsr)
{
	GF_Node *elt = gf_node_new(lsr->sg, TAG_SVG_tspan);
	lsr_read_id(lsr, elt);
	lsr_read_rare(lsr, elt);
	lsr_read_fill(lsr, elt);
	lsr_read_stroke(lsr, elt);
	lsr_read_any_attribute(lsr, elt, 1);
	lsr_read_group_content(lsr, elt, 0);
	return elt;
}


static void lsr_read_coordinate_ptr(GF_LASeRCodec *lsr, GF_Node *n, u32 tag, Bool skipable, const char *name)
{
	u32 flag;
	GF_FieldInfo info;
	if (skipable) {
		GF_LSR_READ_INT(lsr, flag, 1, name);
		if (!flag) return;
	}
	lsr->last_error = gf_node_get_attribute_by_tag(n, tag, GF_TRUE, 0, &info);

	((SVG_Number*)info.far_ptr)->type = SVG_NUMBER_VALUE;
	GF_LSR_READ_INT(lsr, flag, lsr->coord_bits, name);
	((SVG_Number*)info.far_ptr)->value = lsr_translate_coords(lsr, flag, lsr->coord_bits);
}


  void Compute(OpKernelContext* context) override {
    const Tensor& prefix = context->input(0);
    const Tensor& tensor_names = context->input(1);
    const Tensor& shape_and_slices = context->input(2);
    ValidateInputs(true /* is save op */, context, prefix, tensor_names,
                   shape_and_slices);
    if (!context->status().ok()) return;

    const int kFixedInputs = 3;  // Prefix, tensor names, shape_and_slices.
    const int num_tensors = static_cast<int>(tensor_names.NumElements());
    const string& prefix_string = prefix.scalar<tstring>()();
    const auto& tensor_names_flat = tensor_names.flat<tstring>();
    const auto& shape_and_slices_flat = shape_and_slices.flat<tstring>();

    BundleWriter writer(Env::Default(), prefix_string);
    OP_REQUIRES_OK(context, writer.status());
    VLOG(1) << "BundleWriter, prefix_string: " << prefix_string;

    for (int i = 0; i < num_tensors; ++i) {
      const string& tensor_name = tensor_names_flat(i);
      const Tensor& tensor = context->input(i + kFixedInputs);
      VLOG(2) << "Starting save of " << tensor_name;

      if (!shape_and_slices_flat(i).empty()) {
        const string& shape_spec = shape_and_slices_flat(i);
        TensorShape shape;
        TensorSlice slice(tensor.dims());
        TensorShape slice_shape;

        OP_REQUIRES_OK(context, checkpoint::ParseShapeAndSlice(
                                    shape_spec, &shape, &slice, &slice_shape));
        OP_REQUIRES(context, slice_shape.IsSameSize(tensor.shape()),
                    errors::InvalidArgument("Slice in shape_and_slice "
                                            "specification does not match the "
                                            "shape of the tensor to  save: ",
                                            shape_spec, ", tensor: ",
                                            tensor.shape().DebugString()));

        OP_REQUIRES_OK(context,
                       writer.AddSlice(tensor_name, shape, slice, tensor));
      } else {
        OP_REQUIRES_OK(context, writer.Add(tensor_name, tensor));
      }

      if (VLOG_IS_ON(5)) {
        if (tensor.dtype() == DT_FLOAT) {
          const float* t_data = tensor.flat<float>().data();
          float min = std::numeric_limits<float>::infinity();
          float max = -std::numeric_limits<float>::infinity();
          double avg = 0.0;
          for (int i = 0; i < tensor.NumElements(); ++i) {
            if (t_data[i] < min) min = t_data[i];
            if (t_data[i] > max) max = t_data[i];
            avg += t_data[i];
          }
          VLOG(5) << " min " << min << " max " << max << " avg "
                  << avg / tensor.NumElements() << " total elts "
                  << tensor.NumElements();
        }
      }

      VLOG(2) << "Done save of " << tensor_name;
    }
    OP_REQUIRES_OK(context, writer.Finish());
    VLOG(1) << "Done BundleWriter, prefix_string: " << prefix_string;
  }


void gf_isom_check_position(GF_Box *s, GF_Box *child, u32 *pos)
{
	if (!s || !s->child_boxes || !child || !pos) return;
	if (s->internal_flags & GF_ISOM_ORDER_FREEZE)
		return;

	s32 cur_pos = gf_list_find(s->child_boxes, child);

	//happens when partially cloning boxes
	if (cur_pos < 0) return;

	if (cur_pos != (s32) *pos) {
		gf_list_del_item(s->child_boxes, child);
		gf_list_insert(s->child_boxes, child, *pos);
	}
	(*pos)++;


local void cut_short(int sig)
{
    (void)sig;
    Trace(("termination by user"));
    if (g.outd != -1 && g.outf != NULL)
        unlink(g.outf);
    log_dump();
    _exit(1);
}


local void yarn_free(void *ptr)
{
    return free_track(&mem_track, ptr);
}


local void free_track(struct mem_track_s *mem, void *ptr)
{
    size_t size;

    if (ptr != NULL) {
        size = MALLOC_SIZE(ptr);
        mem_track_grab(mem);
        mem->num--;
        mem->size -= size;
        mem_track_drop(mem);
        free(ptr);
    }
}


local void defaults(void)
{
    g.level = Z_DEFAULT_COMPRESSION;
    /* default zopfli options as set by ZopfliInitOptions():
        verbose = 0
        numiterations = 15
        blocksplitting = 1
        blocksplittinglast = 0
        blocksplittingmax = 15
     */
    ZopfliInitOptions(&g.zopts);
#ifdef NOTHREAD
    g.procs = 1;
#else
    g.procs = nprocs(8);
#endif
    g.block = 131072UL;             /* 128K */
    g.rsync = 0;                    /* don't do rsync blocking */
    g.setdict = 1;                  /* initialize dictionary each thread */
    g.verbosity = 1;                /* normal message level */
    g.headis = 3;                   /* store/restore name and timestamp */
    g.pipeout = 0;                  /* don't force output to stdout */
    g.sufx = ".gz";                 /* compressed file suffix */
    g.decode = 0;                   /* compress */
    g.list = 0;                     /* compress */
    g.keep = 0;                     /* delete input file once compressed */
    g.force = 0;                    /* don't overwrite, don't compress links */
    g.recurse = 0;                  /* don't go into directories */
    g.form = 0;                     /* use gzip format */
}


local void show_info(int method, unsigned long check, off_t len, int cont)
{
    size_t max;             /* maximum name length for current verbosity */
    size_t n;               /* name length without suffix */
    time_t now;             /* for getting current year */
    char mod[26];           /* modification time in text */
    char tag[NAMEMAX1+1];   /* header or file name, possibly truncated */

    /* create abbreviated name from header file name or actual file name */
    max = g.verbosity > 1 ? NAMEMAX2 : NAMEMAX1;
    memset(tag, 0, max + 1);
    if (cont)
        strncpy(tag, "<...>", max + 1);
    else if (g.hname == NULL) {
        n = strlen(g.inf) - compressed_suffix(g.inf);
        strncpy(tag, g.inf, n > max + 1 ? max + 1 : n);
        if (strcmp(g.inf + n, ".tgz") == 0 && n < max + 1)
            strncpy(tag + n, ".tar", max + 1 - n);
    }
    else
        strncpy(tag, g.hname, max + 1);
    if (tag[max])
        strcpy(tag + max - 3, "...");

    /* convert time stamp to text */
    if (g.stamp) {
        strcpy(mod, ctime(&g.stamp));
        now = time(NULL);
        if (strcmp(mod + 20, ctime(&now) + 20) != 0)
            strcpy(mod + 11, mod + 19);
    }
    else
        strcpy(mod + 4, "------ -----");
    mod[16] = 0;

    /* if first time, print header */
    if (g.first) {
        if (g.verbosity > 1)
            fputs("method    check    timestamp    ", stdout);
        if (g.verbosity > 0)
            puts("compressed   original reduced  name");
        g.first = 0;
    }

    /* print information */
    if (g.verbosity > 1) {
        if (g.form == 3 && !g.decode)
            printf("zip%3d  --------  %s  ", method, mod + 4);
        else if (g.form > 1)
            printf("zip%3d  %08lx  %s  ", method, check, mod + 4);
        else if (g.form == 1)
            printf("zlib%2d  %08lx  %s  ", method, check, mod + 4);
        else if (method == 257)
            printf("lzw     --------  %s  ", mod + 4);
        else
            printf("gzip%2d  %08lx  %s  ", method, check, mod + 4);
    }
    if (g.verbosity > 0) {
        if ((g.form == 3 && !g.decode) ||
            (method == 8 && g.in_tot > (len + (len >> 10) + 12)) ||
            (method == 257 && g.in_tot > len + (len >> 1) + 3))
#if __STDC_VERSION__-0 >= 199901L || __GNUC__-0 >= 3
            printf("%10jd %10jd?  unk    %s\n",
                   (intmax_t)g.in_tot, (intmax_t)len, tag);
        else
            printf("%10jd %10jd %6.1f%%  %s\n",
                   (intmax_t)g.in_tot, (intmax_t)len,
                   len == 0 ? 0 : 100 * (len - g.in_tot)/(double)len,
                   tag);
#else
            printf(sizeof(off_t) == sizeof(long) ?
                   "%10ld %10ld?  unk    %s\n" : "%10lld %10lld?  unk    %s\n",
                   g.in_tot, len, tag);
        else
            printf(sizeof(off_t) == sizeof(long) ?
                   "%10ld %10ld %6.1f%%  %s\n" : "%10lld %10lld %6.1f%%  %s\n",
                   g.in_tot, len,
                   len == 0 ? 0 : 100 * (len - g.in_tot)/(double)len,
                   tag);
#endif
    }
}


local void *malloc_track(struct mem_track_s *mem, size_t size)
{
    void *ptr;

    ptr = malloc(size);
    if (ptr != NULL) {
        size = MALLOC_SIZE(ptr);
        mem_track_grab(mem);
        mem->num++;
        mem->size += size;
        if (mem->size > mem->max)
            mem->max = mem->size;
        mem_track_drop(mem);
    }
    return ptr;
}


local int free_pool(struct pool *pool)
{
    int count;
    struct space *space;

    possess(pool->have);
    count = 0;
    while ((space = pool->head) != NULL) {
        pool->head = space->next;
        FREE(space->buf);
        free_lock(space->use);
        FREE(space);
        count++;
    }
    assert(count == pool->made);
    release(pool->have);
    free_lock(pool->have);
    return count;
}


local void *realloc_track(struct mem_track_s *mem, void *ptr, size_t size)
{
    size_t was;

    if (ptr == NULL)
        return malloc_track(mem, size);
    was = MALLOC_SIZE(ptr);
    ptr = realloc(ptr, size);
    if (ptr != NULL) {
        size = MALLOC_SIZE(ptr);
        mem_track_grab(mem);
        mem->size -= was;
        mem->size += size;
        if (mem->size > mem->max)
            mem->max = mem->size;
        mem_track_drop(mem);
    }
    return ptr;
}


static void vcpu_pause(struct kvm_vcpu *vcpu)
{
	wait_queue_head_t *wq = kvm_arch_vcpu_wq(vcpu);

	wait_event_interruptible(*wq, !vcpu->arch.pause);
}


void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
{
	kvm_arch_vcpu_free(vcpu);
}


static int hyp_init_cpu_notify(struct notifier_block *self,
			       unsigned long action, void *cpu)
{
	switch (action) {
	case CPU_STARTING:
	case CPU_STARTING_FROZEN:
		cpu_init_hyp_mode(NULL);
		break;
	}

	return NOTIFY_OK;
}


int kvm_arch_hardware_enable(void *garbage)
{
	return 0;
}


int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
	int ret;
	sigset_t sigsaved;

	if (unlikely(!kvm_vcpu_initialized(vcpu)))
		return -ENOEXEC;

	ret = kvm_vcpu_first_run_init(vcpu);
	if (ret)
		return ret;

	if (run->exit_reason == KVM_EXIT_MMIO) {
		ret = kvm_handle_mmio_return(vcpu, vcpu->run);
		if (ret)
			return ret;
	}

	if (vcpu->sigset_active)
		sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);

	ret = 1;
	run->exit_reason = KVM_EXIT_UNKNOWN;
	while (ret > 0) {
		/*
		 * Check conditions before entering the guest
		 */
		cond_resched();

		update_vttbr(vcpu->kvm);

		if (vcpu->arch.pause)
			vcpu_pause(vcpu);

		kvm_vgic_flush_hwstate(vcpu);
		kvm_timer_flush_hwstate(vcpu);

		local_irq_disable();

		/*
		 * Re-check atomic conditions
		 */
		if (signal_pending(current)) {
			ret = -EINTR;
			run->exit_reason = KVM_EXIT_INTR;
		}

		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm)) {
			local_irq_enable();
			kvm_timer_sync_hwstate(vcpu);
			kvm_vgic_sync_hwstate(vcpu);
			continue;
		}

		/**************************************************************
		 * Enter the guest
		 */
		trace_kvm_entry(*vcpu_pc(vcpu));
		kvm_guest_enter();
		vcpu->mode = IN_GUEST_MODE;

		ret = kvm_call_hyp(__kvm_vcpu_run, vcpu);

		vcpu->mode = OUTSIDE_GUEST_MODE;
		vcpu->arch.last_pcpu = smp_processor_id();
		kvm_guest_exit();
		trace_kvm_exit(*vcpu_pc(vcpu));
		/*
		 * We may have taken a host interrupt in HYP mode (ie
		 * while executing the guest). This interrupt is still
		 * pending, as we haven't serviced it yet!
		 *
		 * We're now back in SVC mode, with interrupts
		 * disabled.  Enabling the interrupts now will have
		 * the effect of taking the interrupt again, in SVC
		 * mode this time.
		 */
		local_irq_enable();

		/*
		 * Back from guest
		 *************************************************************/

		kvm_timer_sync_hwstate(vcpu);
		kvm_vgic_sync_hwstate(vcpu);

		ret = handle_exit(vcpu, run, ret);
	}

	if (vcpu->sigset_active)
		sigprocmask(SIG_SETMASK, &sigsaved, NULL);
	return ret;
}


rx_cache_find(const struct rx_header *rxh, const struct ip *ip, int sport,
	      int32_t *opcode)
{
	int i;
	struct rx_cache_entry *rxent;
	uint32_t clip;
	uint32_t sip;

	UNALIGNED_MEMCPY(&clip, &ip->ip_dst, sizeof(uint32_t));
	UNALIGNED_MEMCPY(&sip, &ip->ip_src, sizeof(uint32_t));

	/* Start the search where we last left off */

	i = rx_cache_hint;
	do {
		rxent = &rx_cache[i];
		if (rxent->callnum == rxh->callNumber &&
		    rxent->client.s_addr == clip &&
		    rxent->server.s_addr == sip &&
		    rxent->serviceId == rxh->serviceId &&
		    rxent->dport == sport) {

			/* We got a match! */

			rx_cache_hint = i;
			*opcode = rxent->opcode;
			return(1);
		}
		if (++i >= RX_CACHE_SIZE)
			i = 0;
	} while (i != rx_cache_hint);

	/* Our search failed */
	return(0);
}


static void php_imagefontsize(INTERNAL_FUNCTION_PARAMETERS, int arg)
{
	zend_long SIZE;
	gdFontPtr font;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &SIZE) == FAILURE) {
		return;
	}

	font = php_find_gd_font(SIZE);
	RETURN_LONG(arg ? font->h : font->w);
}


static void php_image_filter_smooth(INTERNAL_FUNCTION_PARAMETERS)
{
	zval *SIM;
	zend_long tmp;
	gdImagePtr im_src;
	double weight;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rld", &SIM, &tmp, &weight) == FAILURE) {
		RETURN_FALSE;
	}

	if ((im_src = (gdImagePtr)zend_fetch_resource(Z_RES_P(SIM), "Image", le_gd)) == NULL) {
		RETURN_FALSE;
	}

	if (im_src == NULL) {
		RETURN_FALSE;
	}

	if (gdImageSmooth(im_src, (float)weight)==1) {
		RETURN_TRUE;
	}

	RETURN_FALSE;
}


PHP_FUNCTION(imagedestroy)
{
	zval *IM;
	gdImagePtr im;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &IM) == FAILURE) {
		return;
	}

	if ((im = (gdImagePtr)zend_fetch_resource(Z_RES_P(IM), "Image", le_gd)) == NULL) {
		RETURN_FALSE;
	}

	zend_list_close(Z_RES_P(IM));

	RETURN_TRUE;
}


PHP_FUNCTION(imagearc)
{
	zval *IM;
	zend_long cx, cy, w, h, ST, E, col;
	gdImagePtr im;
	int e, st;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlllllll", &IM, &cx, &cy, &w, &h, &ST, &E, &col) == FAILURE) {
		return;
	}

	if ((im = (gdImagePtr)zend_fetch_resource(Z_RES_P(IM), "Image", le_gd)) == NULL) {
		RETURN_FALSE;
	}

	e = E;
	if (e < 0) {
		e %= 360;
	}

	st = ST;
	if (st < 0) {
		st %= 360;
	}

	gdImageArc(im, cx, cy, w, h, st, e, col);
	RETURN_TRUE;
}


static void php_imagechar(INTERNAL_FUNCTION_PARAMETERS, int mode)
{
	zval *IM;
	zend_long SIZE, X, Y, COL;
	char *C;
	size_t C_len;
	gdImagePtr im;
	int ch = 0, col, x, y, size, i, l = 0;
	unsigned char *str = NULL;
	gdFontPtr font;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlllsl", &IM, &SIZE, &X, &Y, &C, &C_len, &COL) == FAILURE) {
		return;
	}

	if ((im = (gdImagePtr)zend_fetch_resource(Z_RES_P(IM), "Image", le_gd)) == NULL) {
		RETURN_FALSE;
	}

	col = COL;

	if (mode < 2) {
		ch = (int)((unsigned char)*C);
	} else {
		str = (unsigned char *) estrndup(C, C_len);
		l = strlen((char *)str);
	}

	y = Y;
	x = X;
	size = SIZE;

	font = php_find_gd_font(size);

	switch (mode) {
		case 0:
			gdImageChar(im, font, x, y, ch, col);
			break;
		case 1:
			php_gdimagecharup(im, font, x, y, ch, col);
			break;
		case 2:
			for (i = 0; (i < l); i++) {
				gdImageChar(im, font, x, y, (int) ((unsigned char) str[i]), col);
				x += font->w;
			}
			break;
		case 3: {
			for (i = 0; (i < l); i++) {
				/* php_gdimagecharup(im, font, x, y, (int) str[i], col); */
				gdImageCharUp(im, font, x, y, (int) str[i], col);
				y -= font->w;
			}
			break;
		}
	}
	if (str) {
		efree(str);
	}
	RETURN_TRUE;
}


PHP_FUNCTION(imageantialias)
{
	zval *IM;
	zend_bool alias;
	gdImagePtr im;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rb", &IM, &alias) == FAILURE) {
		return;
	}

	if ((im = (gdImagePtr)zend_fetch_resource(Z_RES_P(IM), "Image", le_gd)) == NULL) {
		RETURN_FALSE;
	}
	gdImageAntialias(im, alias);
	RETURN_TRUE;
}


PHP_FUNCTION(imagecolorresolvealpha)
{
	zval *IM;
	zend_long red, green, blue, alpha;
	gdImagePtr im;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rllll", &IM, &red, &green, &blue, &alpha) == FAILURE) {
		return;
	}

	if ((im = (gdImagePtr)zend_fetch_resource(Z_RES_P(IM), "Image", le_gd)) == NULL) {
		RETURN_FALSE;
	}

	RETURN_LONG(gdImageColorResolveAlpha(im, red, green, blue, alpha));
}


static void php_imagepolygon(INTERNAL_FUNCTION_PARAMETERS, int filled)
{
	zval *IM, *POINTS;
	zend_long NPOINTS, COL;
	zval *var = NULL;
	gdImagePtr im;
	gdPointPtr points;
	int npoints, col, nelem, i;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rall", &IM, &POINTS, &NPOINTS, &COL) == FAILURE) {
		return;
	}

	if ((im = (gdImagePtr)zend_fetch_resource(Z_RES_P(IM), "Image", le_gd)) == NULL) {
		RETURN_FALSE;
	}

	npoints = NPOINTS;
	col = COL;

	nelem = zend_hash_num_elements(Z_ARRVAL_P(POINTS));
	if (nelem < 6) {
		php_error_docref(NULL, E_WARNING, "You must have at least 3 points in your array");
		RETURN_FALSE;
	}
	if (npoints <= 0) {
		php_error_docref(NULL, E_WARNING, "You must give a positive number of points");
		RETURN_FALSE;
	}
	if (nelem < npoints * 2) {
		php_error_docref(NULL, E_WARNING, "Trying to use %d points in array with only %d points", npoints, nelem/2);
		RETURN_FALSE;
	}

	points = (gdPointPtr) safe_emalloc(npoints, sizeof(gdPoint), 0);

	for (i = 0; i < npoints; i++) {
		if ((var = zend_hash_index_find(Z_ARRVAL_P(POINTS), (i * 2))) != NULL) {
			points[i].x = zval_get_long(var);
		}
		if ((var = zend_hash_index_find(Z_ARRVAL_P(POINTS), (i * 2) + 1)) != NULL) {
			points[i].y = zval_get_long(var);
		}
	}

	if (filled) {
		gdImageFilledPolygon(im, points, npoints, col);
	} else {
		gdImagePolygon(im, points, npoints, col);
	}

	efree(points);
	RETURN_TRUE;
}


PHP_FUNCTION(imageaffine)
{
	zval *IM;
	gdImagePtr src;
	gdImagePtr dst;
	gdRect rect;
	gdRectPtr pRect = NULL;
	zval *z_rect = NULL;
	zval *z_affine;
	zval *tmp;
	double affine[6];
	int i, nelems;
	zval *zval_affine_elem = NULL;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ra|a", &IM, &z_affine, &z_rect) == FAILURE)  {
		return;
	}

	if ((src = (gdImagePtr)zend_fetch_resource(Z_RES_P(IM), "Image", le_gd)) == NULL) {
		RETURN_FALSE;
	}

	if ((nelems = zend_hash_num_elements(Z_ARRVAL_P(z_affine))) != 6) {
		php_error_docref(NULL, E_WARNING, "Affine array must have six elements");
		RETURN_FALSE;
	}

	for (i = 0; i < nelems; i++) {
		if ((zval_affine_elem = zend_hash_index_find(Z_ARRVAL_P(z_affine), i)) != NULL) {
			switch (Z_TYPE_P(zval_affine_elem)) {
				case IS_LONG:
					affine[i]  = Z_LVAL_P(zval_affine_elem);
					break;
				case IS_DOUBLE:
					affine[i] = Z_DVAL_P(zval_affine_elem);
					break;
				case IS_STRING:
					affine[i] = zval_get_double(zval_affine_elem);
					break;
				default:
					php_error_docref(NULL, E_WARNING, "Invalid type for element %i", i);
					RETURN_FALSE;
			}
		}
	}

	if (z_rect != NULL) {
		if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "x", sizeof("x") - 1)) != NULL) {
			rect.x = zval_get_long(tmp);
		} else {
			php_error_docref(NULL, E_WARNING, "Missing x position");
			RETURN_FALSE;
		}

		if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "y", sizeof("y") - 1)) != NULL) {
			rect.y = zval_get_long(tmp);
		} else {
			php_error_docref(NULL, E_WARNING, "Missing y position");
			RETURN_FALSE;
		}

		if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "width", sizeof("width") - 1)) != NULL) {
			rect.width = zval_get_long(tmp);
		} else {
			php_error_docref(NULL, E_WARNING, "Missing width");
			RETURN_FALSE;
		}

		if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "height", sizeof("height") - 1)) != NULL) {
			rect.height = zval_get_long(tmp);
		} else {
			php_error_docref(NULL, E_WARNING, "Missing height");
			RETURN_FALSE;
		}
		pRect = ▭
	} else {
		rect.x = -1;
		rect.y = -1;
		rect.width = gdImageSX(src);
		rect.height = gdImageSY(src);
		pRect = NULL;
	}

	if (gdTransformAffineGetImage(&dst, src, pRect, affine) != GD_TRUE) {
		RETURN_FALSE;
	}

	if (dst == NULL) {
		RETURN_FALSE;
	} else {
		RETURN_RES(zend_register_resource(dst, le_gd));
	}
}


void gf_bs_skip_bytes(GF_BitStream *bs, u64 nbBytes)
{
	if (!bs || !nbBytes) return;

	gf_bs_align(bs);

	/*special case for file skipping...*/
	if ((bs->bsmode == GF_BITSTREAM_FILE_WRITE) || (bs->bsmode == GF_BITSTREAM_FILE_READ)) {
		if (bs->cache_write)
			bs_flush_write_cache(bs);

		if (bs->cache_read) {
			u32 csize = bs->cache_read_size - bs->cache_read_pos;
			if (csize>=nbBytes) {
				bs->cache_read_pos += (u32) nbBytes;
				bs->position += nbBytes;
				return;
			}
			nbBytes -= csize;
			bs->position += csize;
			bs->cache_read_pos = bs->cache_read_size;
		}
		//weird msys2 bug resulting in broken seek on some files ?!?  -the bug is not happening when doing absolute seek
//		gf_fseek(bs->stream, nbBytes, SEEK_CUR);
		bs->position += nbBytes;
		if (bs->bsmode == GF_BITSTREAM_FILE_READ) {
			if (bs->position > bs->size) bs->position = bs->size;
		}
		gf_fseek(bs->stream, bs->position, SEEK_SET);
		return;
	}

	/*special case for reading*/
	if (bs->bsmode == GF_BITSTREAM_READ) {
		if (bs->remove_emul_prevention_byte) {
			while (nbBytes) {
				gf_bs_read_u8(bs);
				nbBytes--;
			}
		} else {
			bs->position += nbBytes;
		}
		return;
	}
	/*for writing we must do it this way, otherwise pb in dynamic buffers*/
	while (nbBytes) {
		gf_bs_write_int(bs, 0, 8);
		nbBytes--;
	}
}


void gf_bs_write_u64_le(GF_BitStream *bs, u64 val)
{
	gf_bs_write_int(bs, val & 0xFF, 8);
	gf_bs_write_int(bs, (val>>8) & 0xFF, 8);
	gf_bs_write_int(bs, (val>>16) & 0xFF, 8);
	gf_bs_write_int(bs, (val>>24) & 0xFF, 8);
	gf_bs_write_int(bs, (val>>32) & 0xFF, 8);
	gf_bs_write_int(bs, (val>>40) & 0xFF, 8);
	gf_bs_write_int(bs, (val>>48) & 0xFF, 8);
	gf_bs_write_int(bs, (val>>56) & 0xFF, 8);
}


u64 gf_bs_get_refreshed_size(GF_BitStream *bs)
{
	s64 offset;

	switch (bs->bsmode) {
	case GF_BITSTREAM_READ:
	case GF_BITSTREAM_WRITE:
		return bs->size;

	default:
		if (bs->cache_write)
			bs_flush_write_cache(bs);

		if (bs->stream) {
			offset = gf_ftell(bs->stream);
			bs->size = gf_fsize(bs->stream);
			gf_fseek(bs->stream, offset, SEEK_SET);
		}
		return bs->size;
	}
}


u32 gf_bs_peek_bits(GF_BitStream *bs, u32 numBits, u64 byte_offset)
{
	u64 curPos;
	u32 curBits, ret, current, nb_zeros;

	if ( (bs->bsmode != GF_BITSTREAM_READ) && (bs->bsmode != GF_BITSTREAM_FILE_READ)) return 0;
	if (!numBits || (bs->size < bs->position + byte_offset)) return 0;

	/*store our state*/
	curPos = bs->position;
	curBits = bs->nbBits;
	current = bs->current;
	nb_zeros = bs->nb_zeros;

	if (byte_offset) {
		if (bs->remove_emul_prevention_byte) {
			while (byte_offset) {
				gf_bs_read_int(bs, 8);
				byte_offset--;
			}
		} else {
			gf_bs_seek(bs, bs->position + byte_offset);
		}
	}
	ret = gf_bs_read_int(bs, numBits);

	/*restore our cache - position*/
	gf_bs_seek(bs, curPos);
	/*to avoid re-reading our bits ...*/
	bs->nbBits = curBits;
	bs->current = current;
	bs->nb_zeros = nb_zeros;
	return ret;
}


GF_Err gf_isom_vvc_config_update(GF_ISOFile *the_file, u32 trackNumber, u32 DescriptionIndex, GF_VVCConfig *cfg)
{
	return gf_isom_vvc_config_update_ex(the_file, trackNumber, DescriptionIndex, cfg, GF_ISOM_VVCC_UPDATE, GF_FALSE);
}


void gf_bs_get_content(GF_BitStream *bs, u8 **output, u32 *outSize)
{
	gf_bs_get_content_no_truncate(bs, output, outSize, NULL);
}


void gf_bs_rewind_bits(GF_BitStream *bs, u64 nbBits)
{
	u64 nbBytes;
	if (bs->bsmode != GF_BITSTREAM_READ) return;

	nbBits -= (bs->nbBits);
	nbBytes = (nbBits+8)>>3;
	nbBits = nbBytes*8 - nbBits;
	gf_bs_align(bs);
	assert(bs->position >= nbBytes);
	bs->position -= nbBytes + 1;
	gf_bs_read_int(bs, (u32)nbBits);
	return;
}


static u64 do_size_top_boxes(char *inName, char *compress_top_boxes, u32 mode)
{
	FILE *in;
	u64 top_size = 0;
	Bool do_all = GF_FALSE;
	GF_BitStream *bs_in;
	if (!compress_top_boxes) return GF_BAD_PARAM;
	if (!strcmp(compress_top_boxes, "all"))
		do_all = GF_TRUE;

	in = gf_fopen(inName, "rb");
	if (!in) return GF_URL_ERROR;
	bs_in = gf_bs_from_file(in, GF_BITSTREAM_READ);
	while (gf_bs_available(bs_in)) {
		const char *stype;
		u32 hdr_size = 8;
		u64 lsize = gf_bs_read_u32(bs_in);
		u32 type = gf_bs_read_u32(bs_in);

		if (lsize==1) {
			lsize = gf_bs_read_u64(bs_in);
			hdr_size = 16;
		} else if (lsize==0) {
			lsize = gf_bs_available(bs_in) + 8;
		}
		stype = gf_4cc_to_str(type);
		if (do_all || strstr(compress_top_boxes, stype)) {
			//only count boxes
			if (mode==2) {
				top_size += 1;
			} else {
				top_size += lsize;
			}
		}
		gf_bs_skip_bytes(bs_in, lsize - hdr_size);
	}
	gf_bs_del(bs_in);
	gf_fclose(in);
	return top_size;

}


void PrintExtractUsage()
{
	u32 i=0;
	gf_sys_format_help(helpout, help_flags, "# Extracting Options\n"
	"MP4Box can be used to extract media tracks from MP4 files. If you need to convert these tracks however, please check the [filters doc](Filters).\n"
	"  \n"
	"Options:\n"
	);
	while (m4b_extr_args[i].name) {
		GF_GPACArg *arg = &m4b_extr_args[i];
		i++;
		gf_sys_print_arg(helpout, help_flags, arg, "mp4box-extract");
	}
}


GF_Err HintFile(GF_ISOFile *file, u32 MTUSize, u32 max_ptime, u32 rtp_rate, u32 base_flags, Bool copy_data, Bool interleave, Bool regular_iod, Bool single_group, Bool hint_no_offset)
{
	GF_ESD *esd;
	GF_InitialObjectDescriptor *iod;
	u32 i, val, res, streamType;
	u32 sl_mode, prev_ocr, single_ocr, nb_done, tot_bw, bw, flags, spec_type;
	GF_Err e;
	char szPayload[30];
	GF_RTPHinter *hinter;
	Bool copy, has_iod, single_av;
	u8 init_payt = BASE_PAYT;
	u32 mtype;
	GF_SDP_IODProfile iod_mode = GF_SDP_IOD_NONE;
	u32 media_group = 0;
	u8 media_prio = 0;

	tot_bw = 0;
	prev_ocr = 0;
	single_ocr = 1;

	has_iod = 1;
	iod = (GF_InitialObjectDescriptor *) gf_isom_get_root_od(file);
	if (!iod) has_iod = 0;
	else {
		if (!gf_list_count(iod->ESDescriptors)) has_iod = 0;
		gf_odf_desc_del((GF_Descriptor *) iod);
	}

	spec_type = gf_isom_guess_specification(file);
	single_av = single_group ? 1 : gf_isom_is_single_av(file);

	/*first make sure we use a systems track as base OCR*/
	for (i=0; i<gf_isom_get_track_count(file); i++) {
		res = gf_isom_get_media_type(file, i+1);
		if ((res==GF_ISOM_MEDIA_SCENE) || (res==GF_ISOM_MEDIA_OD)) {
			if (gf_isom_is_track_in_root_od(file, i+1)) {
				gf_isom_set_default_sync_track(file, i+1);
				break;
			}
		}
	}

	nb_done = 0;
	for (i=0; i<gf_isom_get_track_count(file); i++) {
		sl_mode = base_flags;
		copy = copy_data;
		/*skip emty tracks (mainly MPEG-4 interaction streams...*/
		if (!gf_isom_get_sample_count(file, i+1)) continue;
		if (!gf_isom_is_track_enabled(file, i+1)) {
			fprintf(stderr, "Track ID %d disabled - skipping hint\n", gf_isom_get_track_id(file, i+1) );
			continue;
		}

		mtype = gf_isom_get_media_type(file, i+1);
		switch (mtype) {
		case GF_ISOM_MEDIA_VISUAL:
			if (single_av) {
				media_group = 2;
				media_prio = 2;
			}
			break;
        case GF_ISOM_MEDIA_AUXV:
            if (single_av) {
                media_group = 2;
                media_prio = 3;
            }
            break;
        case GF_ISOM_MEDIA_PICT:
            if (single_av) {
                media_group = 2;
                media_prio = 4;
            }
            break;
		case GF_ISOM_MEDIA_AUDIO:
			if (single_av) {
				media_group = 2;
				media_prio = 1;
			}
			break;
		case GF_ISOM_MEDIA_HINT:
			continue;
		default:
			/*no hinting of systems track on isma*/
			if (spec_type==GF_ISOM_BRAND_ISMA) continue;
		}
		mtype = gf_isom_get_media_subtype(file, i+1, 1);
		if ((mtype==GF_ISOM_SUBTYPE_MPEG4) || (mtype==GF_ISOM_SUBTYPE_MPEG4_CRYP) ) mtype = gf_isom_get_mpeg4_subtype(file, i+1, 1);

		if (!single_av) {
			/*one media per group only (we should prompt user for group selection)*/
			media_group ++;
			media_prio = 1;
		}

		streamType = 0;
		esd = gf_isom_get_esd(file, i+1, 1);
		if (esd) {
			streamType = esd->decoderConfig->streamType;
			if (!prev_ocr) {
				prev_ocr = esd->OCRESID;
				if (!esd->OCRESID) prev_ocr = esd->ESID;
			} else if (esd->OCRESID && prev_ocr != esd->OCRESID) {
				single_ocr = 0;
			}
			/*OD MUST BE WITHOUT REFERENCES*/
			if (streamType==1) copy = 1;
		}
		gf_odf_desc_del((GF_Descriptor *) esd);

		if (!regular_iod && gf_isom_is_track_in_root_od(file, i+1)) {
			/*single AU - check if base64 would fit in ESD (consider 33% overhead of base64), otherwise stream*/
			if (gf_isom_get_sample_count(file, i+1)==1) {
				GF_ISOSample *samp = gf_isom_get_sample(file, i+1, 1, &val);
				if (streamType) {
					res = gf_hinter_can_embbed_data(samp->data, samp->dataLength, streamType);
				} else {
					/*not a system track, we shall hint it*/
					res = 0;
				}
				if (samp) gf_isom_sample_del(&samp);
				if (res) continue;
			}
		}
		if (interleave) sl_mode |= GP_RTP_PCK_USE_INTERLEAVING;

		hinter = gf_hinter_track_new(file, i+1, MTUSize, max_ptime, rtp_rate, sl_mode, init_payt, copy, media_group, media_prio, &e);

		if (!hinter) {
			if (e) {
				fprintf(stderr, "Cannot create hinter (%s)\n", gf_error_to_string(e));
				if (!nb_done) return e;
			}
			continue;
		}

		if (hint_no_offset)
			gf_hinter_track_force_no_offsets(hinter);

		bw = gf_hinter_track_get_bandwidth(hinter);
		tot_bw += bw;
		flags = gf_hinter_track_get_flags(hinter);

		//set extraction mode for AVC/SVC
		gf_isom_set_nalu_extract_mode(file, i+1, GF_ISOM_NALU_EXTRACT_LAYER_ONLY);

		gf_hinter_track_get_payload_name(hinter, szPayload);
		fprintf(stderr, "Hinting track ID %d - Type \"%s:%s\" (%s) - BW %d kbps\n", gf_isom_get_track_id(file, i+1), gf_4cc_to_str(mtype), gf_4cc_to_str(mtype), szPayload, bw);
		if (flags & GP_RTP_PCK_SYSTEMS_CAROUSEL) fprintf(stderr, "\tMPEG-4 Systems stream carousel enabled\n");
		/*
				if (flags & GP_RTP_PCK_FORCE_MPEG4) fprintf(stderr, "\tMPEG4 transport forced\n");
				if (flags & GP_RTP_PCK_USE_MULTI) fprintf(stderr, "\tRTP aggregation enabled\n");
		*/
		e = gf_hinter_track_process(hinter);

		if (!e) e = gf_hinter_track_finalize(hinter, has_iod);
		gf_hinter_track_del(hinter);

		if (e) {
			fprintf(stderr, "Error while hinting (%s)\n", gf_error_to_string(e));
			if (!nb_done) return e;
		}
		init_payt++;
		nb_done ++;
	}

	if (has_iod) {
		iod_mode = GF_SDP_IOD_ISMA;
		if (regular_iod) iod_mode = GF_SDP_IOD_REGULAR;
	} else {
		iod_mode = GF_SDP_IOD_NONE;
	}
	gf_hinter_finalize(file, iod_mode, tot_bw);

	if (!single_ocr)
		fprintf(stderr, "Warning: at least 2 timelines found in the file\nThis may not be supported by servers/players\n\n");

	return GF_OK;
}