OPJ_BOOL opj_t2_decode_packets(opj_tcd_t* tcd,
                               opj_t2_t *p_t2,
                               OPJ_UINT32 p_tile_no,
                               opj_tcd_tile_t *p_tile,
                               OPJ_BYTE *p_src,
                               OPJ_UINT32 * p_data_read,
                               OPJ_UINT32 p_max_len,
                               opj_codestream_index_t *p_cstr_index,
                               opj_event_mgr_t *p_manager)
{
    OPJ_BYTE *l_current_data = p_src;
    opj_pi_iterator_t *l_pi = 00;
    OPJ_UINT32 pino;
    opj_image_t *l_image = p_t2->image;
    opj_cp_t *l_cp = p_t2->cp;
    opj_tcp_t *l_tcp = &(p_t2->cp->tcps[p_tile_no]);
    OPJ_UINT32 l_nb_bytes_read;
    OPJ_UINT32 l_nb_pocs = l_tcp->numpocs + 1;
    opj_pi_iterator_t *l_current_pi = 00;
#ifdef TODO_MSD
    OPJ_UINT32 curtp = 0;
    OPJ_UINT32 tp_start_packno;
#endif
    opj_packet_info_t *l_pack_info = 00;
    opj_image_comp_t* l_img_comp = 00;

    OPJ_ARG_NOT_USED(p_cstr_index);

#ifdef TODO_MSD
    if (p_cstr_index) {
        l_pack_info = p_cstr_index->tile_index[p_tile_no].packet;
    }
#endif

    /* create a packet iterator */
    l_pi = opj_pi_create_decode(l_image, l_cp, p_tile_no);
    if (!l_pi) {
        return OPJ_FALSE;
    }

    l_current_pi = l_pi;

    for (pino = 0; pino <= l_tcp->numpocs; ++pino) {

        /* if the resolution needed is too low, one dim of the tilec could be equal to zero
         * and no packets are used to decode this resolution and
         * l_current_pi->resno is always >= p_tile->comps[l_current_pi->compno].minimum_num_resolutions
         * and no l_img_comp->resno_decoded are computed
         */
        OPJ_BOOL* first_pass_failed = NULL;

        if (l_current_pi->poc.prg == OPJ_PROG_UNKNOWN) {
            /* TODO ADE : add an error */
            opj_pi_destroy(l_pi, l_nb_pocs);
            return OPJ_FALSE;
        }

        first_pass_failed = (OPJ_BOOL*)opj_malloc(l_image->numcomps * sizeof(OPJ_BOOL));
        if (!first_pass_failed) {
            opj_pi_destroy(l_pi, l_nb_pocs);
            return OPJ_FALSE;
        }
        memset(first_pass_failed, OPJ_TRUE, l_image->numcomps * sizeof(OPJ_BOOL));

        while (opj_pi_next(l_current_pi)) {
            OPJ_BOOL skip_packet = OPJ_FALSE;
            JAS_FPRINTF(stderr,
                        "packet offset=00000166 prg=%d cmptno=%02d rlvlno=%02d prcno=%03d lyrno=%02d\n\n",
                        l_current_pi->poc.prg1, l_current_pi->compno, l_current_pi->resno,
                        l_current_pi->precno, l_current_pi->layno);

            /* If the packet layer is greater or equal than the maximum */
            /* number of layers, skip the packet */
            if (l_current_pi->layno >= l_tcp->num_layers_to_decode) {
                skip_packet = OPJ_TRUE;
            }
            /* If the packet resolution number is greater than the minimum */
            /* number of resolution allowed, skip the packet */
            else if (l_current_pi->resno >=
                     p_tile->comps[l_current_pi->compno].minimum_num_resolutions) {
                skip_packet = OPJ_TRUE;
            } else {
                /* If no precincts of any band intersects the area of interest, */
                /* skip the packet */
                OPJ_UINT32 bandno;
                opj_tcd_tilecomp_t *tilec = &p_tile->comps[l_current_pi->compno];
                opj_tcd_resolution_t *res = &tilec->resolutions[l_current_pi->resno];

                skip_packet = OPJ_TRUE;
                for (bandno = 0; bandno < res->numbands; ++bandno) {
                    opj_tcd_band_t* band = &res->bands[bandno];
                    opj_tcd_precinct_t* prec = &band->precincts[l_current_pi->precno];

                    if (opj_tcd_is_subband_area_of_interest(tcd,
                                                            l_current_pi->compno,
                                                            l_current_pi->resno,
                                                            band->bandno,
                                                            (OPJ_UINT32)prec->x0,
                                                            (OPJ_UINT32)prec->y0,
                                                            (OPJ_UINT32)prec->x1,
                                                            (OPJ_UINT32)prec->y1)) {
                        skip_packet = OPJ_FALSE;
                        break;
                    }
                }
                /*
                                printf("packet cmptno=%02d rlvlno=%02d prcno=%03d lyrno=%02d -> %s\n",
                                    l_current_pi->compno, l_current_pi->resno,
                                    l_current_pi->precno, l_current_pi->layno, skip_packet ? "skipped" : "kept");
                */
            }

            if (!skip_packet) {
                l_nb_bytes_read = 0;

                first_pass_failed[l_current_pi->compno] = OPJ_FALSE;

                if (! opj_t2_decode_packet(p_t2, p_tile, l_tcp, l_current_pi, l_current_data,
                                           &l_nb_bytes_read, p_max_len, l_pack_info, p_manager)) {
                    opj_pi_destroy(l_pi, l_nb_pocs);
                    opj_free(first_pass_failed);
                    return OPJ_FALSE;
                }

                l_img_comp = &(l_image->comps[l_current_pi->compno]);
                l_img_comp->resno_decoded = opj_uint_max(l_current_pi->resno,
                                            l_img_comp->resno_decoded);
            } else {
                l_nb_bytes_read = 0;
                if (! opj_t2_skip_packet(p_t2, p_tile, l_tcp, l_current_pi, l_current_data,
                                         &l_nb_bytes_read, p_max_len, l_pack_info, p_manager)) {
                    opj_pi_destroy(l_pi, l_nb_pocs);
                    opj_free(first_pass_failed);
                    return OPJ_FALSE;
                }
            }

            if (first_pass_failed[l_current_pi->compno]) {
                l_img_comp = &(l_image->comps[l_current_pi->compno]);
                if (l_img_comp->resno_decoded == 0) {
                    l_img_comp->resno_decoded =
                        p_tile->comps[l_current_pi->compno].minimum_num_resolutions - 1;
                }
            }

            l_current_data += l_nb_bytes_read;
            p_max_len -= l_nb_bytes_read;

            /* INDEX >> */
#ifdef TODO_MSD
            if (p_cstr_info) {
                opj_tile_info_v2_t *info_TL = &p_cstr_info->tile[p_tile_no];
                opj_packet_info_t *info_PK = &info_TL->packet[p_cstr_info->packno];
                tp_start_packno = 0;
                if (!p_cstr_info->packno) {
                    info_PK->start_pos = info_TL->end_header + 1;
                } else if (info_TL->packet[p_cstr_info->packno - 1].end_pos >=
                           (OPJ_INT32)
                           p_cstr_info->tile[p_tile_no].tp[curtp].tp_end_pos) { /* New tile part */
                    info_TL->tp[curtp].tp_numpacks = p_cstr_info->packno -
                                                     tp_start_packno; /* Number of packets in previous tile-part */
                    tp_start_packno = p_cstr_info->packno;
                    curtp++;
                    info_PK->start_pos = p_cstr_info->tile[p_tile_no].tp[curtp].tp_end_header + 1;
                } else {
                    info_PK->start_pos = (l_cp->m_specific_param.m_enc.m_tp_on &&
                                          info_PK->start_pos) ? info_PK->start_pos : info_TL->packet[p_cstr_info->packno -
                                                                      1].end_pos + 1;
                }
                info_PK->end_pos = info_PK->start_pos + l_nb_bytes_read - 1;
                info_PK->end_ph_pos += info_PK->start_pos -
                                       1;  /* End of packet header which now only represents the distance */
                ++p_cstr_info->packno;
            }
#endif
            /* << INDEX */
        }
        ++l_current_pi;

        opj_free(first_pass_failed);
    }
    /* INDEX >> */
#ifdef TODO_MSD
    if
    (p_cstr_info) {
        p_cstr_info->tile[p_tile_no].tp[curtp].tp_numpacks = p_cstr_info->packno -
                tp_start_packno; /* Number of packets in last tile-part */
    }
#endif
    /* << INDEX */

    /* don't forget to release pi */
    opj_pi_destroy(l_pi, l_nb_pocs);
    *p_data_read = (OPJ_UINT32)(l_current_data - p_src);
    return OPJ_TRUE;
}


static OPJ_BOOL opj_pi_next_rlcp(opj_pi_iterator_t * pi)
{
    opj_pi_comp_t *comp = NULL;
    opj_pi_resolution_t *res = NULL;
    OPJ_UINT32 index = 0;

    if (!pi->first) {
        comp = &pi->comps[pi->compno];
        res = &comp->resolutions[pi->resno];
        goto LABEL_SKIP;
    } else {
        pi->first = 0;
    }

    for (pi->resno = pi->poc.resno0; pi->resno < pi->poc.resno1; pi->resno++) {
        for (pi->layno = pi->poc.layno0; pi->layno < pi->poc.layno1; pi->layno++) {
            for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) {
                comp = &pi->comps[pi->compno];
                if (pi->resno >= comp->numresolutions) {
                    continue;
                }
                res = &comp->resolutions[pi->resno];
                if (!pi->tp_on) {
                    pi->poc.precno1 = res->pw * res->ph;
                }
                for (pi->precno = pi->poc.precno0; pi->precno < pi->poc.precno1; pi->precno++) {
                    index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno *
                            pi->step_c + pi->precno * pi->step_p;
                    if (index >= pi->include_size) {
                        opj_pi_emit_error(pi, "Invalid access to pi->include");
                        return OPJ_FALSE;
                    }
                    if (!pi->include[index]) {
                        pi->include[index] = 1;
                        return OPJ_TRUE;
                    }
LABEL_SKIP:
                    ;
                }
            }
        }
    }

    return OPJ_FALSE;
}


int main(int argc, char **argv)
{

    opj_cparameters_t parameters;   /* compression parameters */

    opj_stream_t *l_stream = 00;
    opj_codec_t* l_codec = 00;
    opj_image_t *image = NULL;
    raw_cparameters_t raw_cp;
    OPJ_SIZE_T num_compressed_files = 0;

    char indexfilename[OPJ_PATH_LEN];   /* index file name */

    unsigned int i, num_images, imageno;
    img_fol_t img_fol;
    dircnt_t *dirptr = NULL;

    int ret = 0;

    OPJ_BOOL bSuccess;
    OPJ_BOOL bUseTiles = OPJ_FALSE; /* OPJ_TRUE */
    OPJ_UINT32 l_nb_tiles = 4;
    int framerate = 0;
    OPJ_FLOAT64 t = opj_clock();

    /* set encoding parameters to default values */
    opj_set_default_encoder_parameters(&parameters);

    /* Initialize indexfilename and img_fol */
    *indexfilename = 0;
    memset(&img_fol, 0, sizeof(img_fol_t));

    /* raw_cp initialization */
    raw_cp.rawBitDepth = 0;
    raw_cp.rawComp = 0;
    raw_cp.rawComps = 0;
    raw_cp.rawHeight = 0;
    raw_cp.rawSigned = 0;
    raw_cp.rawWidth = 0;

    /* parse input and get user encoding parameters */
    parameters.tcp_mct = (char)
                         255; /* This will be set later according to the input image or the provided option */
    if (parse_cmdline_encoder(argc, argv, &parameters, &img_fol, &raw_cp,
                              indexfilename, sizeof(indexfilename), &framerate) == 1) {
        ret = 1;
        goto fin;
    }

    /* Read directory if necessary */
    if (img_fol.set_imgdir == 1) {
        num_images = get_num_images(img_fol.imgdirpath);
        dirptr = (dircnt_t*)malloc(sizeof(dircnt_t));
        if (dirptr) {
            dirptr->filename_buf = (char*)malloc(num_images * OPJ_PATH_LEN * sizeof(
                    char)); /* Stores at max 10 image file names*/
            dirptr->filename = (char**) malloc(num_images * sizeof(char*));
            if (!dirptr->filename_buf) {
                ret = 0;
                goto fin;
            }
            for (i = 0; i < num_images; i++) {
                dirptr->filename[i] = dirptr->filename_buf + i * OPJ_PATH_LEN;
            }
        }
        if (load_images(dirptr, img_fol.imgdirpath) == 1) {
            ret = 0;
            goto fin;
        }
        if (num_images == 0) {
            fprintf(stdout, "Folder is empty\n");
            ret = 0;
            goto fin;
        }
    } else {
        num_images = 1;
    }
    /*Encoding image one by one*/
    for (imageno = 0; imageno < num_images; imageno++) {
        image = NULL;
        fprintf(stderr, "\n");

        if (img_fol.set_imgdir == 1) {
            if (get_next_file((int)imageno, dirptr, &img_fol, &parameters)) {
                fprintf(stderr, "skipping file...\n");
                continue;
            }
        }

        switch (parameters.decod_format) {
        case PGX_DFMT:
            break;
        case PXM_DFMT:
            break;
        case BMP_DFMT:
            break;
        case TIF_DFMT:
            break;
        case RAW_DFMT:
        case RAWL_DFMT:
            break;
        case TGA_DFMT:
            break;
        case PNG_DFMT:
            break;
        default:
            fprintf(stderr, "skipping file...\n");
            continue;
        }

        /* decode the source image */
        /* ----------------------- */

        switch (parameters.decod_format) {
        case PGX_DFMT:
            image = pgxtoimage(parameters.infile, &parameters);
            if (!image) {
                fprintf(stderr, "Unable to load pgx file\n");
                ret = 1;
                goto fin;
            }
            break;

        case PXM_DFMT:
            image = pnmtoimage(parameters.infile, &parameters);
            if (!image) {
                fprintf(stderr, "Unable to load pnm file\n");
                ret = 1;
                goto fin;
            }
            break;

        case BMP_DFMT:
            image = bmptoimage(parameters.infile, &parameters);
            if (!image) {
                fprintf(stderr, "Unable to load bmp file\n");
                ret = 1;
                goto fin;
            }
            break;

#ifdef OPJ_HAVE_LIBTIFF
        case TIF_DFMT:
            image = tiftoimage(parameters.infile, &parameters);
            if (!image) {
                fprintf(stderr, "Unable to load tiff file\n");
                ret = 1;
                goto fin;
            }
            break;
#endif /* OPJ_HAVE_LIBTIFF */

        case RAW_DFMT:
            image = rawtoimage(parameters.infile, &parameters, &raw_cp);
            if (!image) {
                fprintf(stderr, "Unable to load raw file\n");
                ret = 1;
                goto fin;
            }
            break;

        case RAWL_DFMT:
            image = rawltoimage(parameters.infile, &parameters, &raw_cp);
            if (!image) {
                fprintf(stderr, "Unable to load raw file\n");
                ret = 1;
                goto fin;
            }
            break;

        case TGA_DFMT:
            image = tgatoimage(parameters.infile, &parameters);
            if (!image) {
                fprintf(stderr, "Unable to load tga file\n");
                ret = 1;
                goto fin;
            }
            break;

#ifdef OPJ_HAVE_LIBPNG
        case PNG_DFMT:
            image = pngtoimage(parameters.infile, &parameters);
            if (!image) {
                fprintf(stderr, "Unable to load png file\n");
                ret = 1;
                goto fin;
            }
            break;
#endif /* OPJ_HAVE_LIBPNG */
        }

        /* Can happen if input file is TIFF or PNG
        * and OPJ_HAVE_LIBTIF or OPJ_HAVE_LIBPNG is undefined
        */
        if (!image) {
            fprintf(stderr, "Unable to load file: got no image\n");
            ret = 1;
            goto fin;
        }

        /* Decide if MCT should be used */
        if (parameters.tcp_mct == (char)
                255) { /* mct mode has not been set in commandline */
            parameters.tcp_mct = (image->numcomps >= 3) ? 1 : 0;
        } else {            /* mct mode has been set in commandline */
            if ((parameters.tcp_mct == 1) && (image->numcomps < 3)) {
                fprintf(stderr, "RGB->YCC conversion cannot be used:\n");
                fprintf(stderr, "Input image has less than 3 components\n");
                ret = 1;
                goto fin;
            }
            if ((parameters.tcp_mct == 2) && (!parameters.mct_data)) {
                fprintf(stderr, "Custom MCT has been set but no array-based MCT\n");
                fprintf(stderr, "has been provided. Aborting.\n");
                ret = 1;
                goto fin;
            }
        }

        if (OPJ_IS_IMF(parameters.rsiz) && framerate > 0) {
            const int mainlevel = OPJ_GET_IMF_MAINLEVEL(parameters.rsiz);
            if (mainlevel > 0 && mainlevel <= OPJ_IMF_MAINLEVEL_MAX) {
                const int limitMSamplesSec[] = {
                    0,
                    OPJ_IMF_MAINLEVEL_1_MSAMPLESEC,
                    OPJ_IMF_MAINLEVEL_2_MSAMPLESEC,
                    OPJ_IMF_MAINLEVEL_3_MSAMPLESEC,
                    OPJ_IMF_MAINLEVEL_4_MSAMPLESEC,
                    OPJ_IMF_MAINLEVEL_5_MSAMPLESEC,
                    OPJ_IMF_MAINLEVEL_6_MSAMPLESEC,
                    OPJ_IMF_MAINLEVEL_7_MSAMPLESEC,
                    OPJ_IMF_MAINLEVEL_8_MSAMPLESEC,
                    OPJ_IMF_MAINLEVEL_9_MSAMPLESEC,
                    OPJ_IMF_MAINLEVEL_10_MSAMPLESEC,
                    OPJ_IMF_MAINLEVEL_11_MSAMPLESEC
                };
                OPJ_UINT32 avgcomponents = image->numcomps;
                double msamplespersec;
                if (image->numcomps == 3 &&
                        image->comps[1].dx == 2 &&
                        image->comps[1].dy == 2) {
                    avgcomponents = 2;
                }
                msamplespersec = (double)image->x1 * image->y1 * avgcomponents * framerate /
                                 1e6;
                if (msamplespersec > limitMSamplesSec[mainlevel]) {
                    fprintf(stderr,
                            "Warning: MSamples/sec is %f, whereas limit is %d.\n",
                            msamplespersec,
                            limitMSamplesSec[mainlevel]);
                }
            }
        }

        /* encode the destination image */
        /* ---------------------------- */

        switch (parameters.cod_format) {
        case J2K_CFMT: { /* JPEG-2000 codestream */
            /* Get a decoder handle */
            l_codec = opj_create_compress(OPJ_CODEC_J2K);
            break;
        }
        case JP2_CFMT: { /* JPEG 2000 compressed image data */
            /* Get a decoder handle */
            l_codec = opj_create_compress(OPJ_CODEC_JP2);
            break;
        }
        default:
            fprintf(stderr, "skipping file..\n");
            opj_stream_destroy(l_stream);
            continue;
        }

        /* catch events using our callbacks and give a local context */
        opj_set_info_handler(l_codec, info_callback, 00);
        opj_set_warning_handler(l_codec, warning_callback, 00);
        opj_set_error_handler(l_codec, error_callback, 00);

        if (bUseTiles) {
            parameters.cp_tx0 = 0;
            parameters.cp_ty0 = 0;
            parameters.tile_size_on = OPJ_TRUE;
            parameters.cp_tdx = 512;
            parameters.cp_tdy = 512;
        }
        if (! opj_setup_encoder(l_codec, &parameters, image)) {
            fprintf(stderr, "failed to encode image: opj_setup_encoder\n");
            opj_destroy_codec(l_codec);
            opj_image_destroy(image);
            ret = 1;
            goto fin;
        }

        /* open a byte stream for writing and allocate memory for all tiles */
        l_stream = opj_stream_create_default_file_stream(parameters.outfile, OPJ_FALSE);
        if (! l_stream) {
            ret = 1;
            goto fin;
        }

        /* encode the image */
        bSuccess = opj_start_compress(l_codec, image, l_stream);
        if (!bSuccess)  {
            fprintf(stderr, "failed to encode image: opj_start_compress\n");
        }
        if (bSuccess && bUseTiles) {
            OPJ_BYTE *l_data;
            OPJ_UINT32 l_data_size = 512 * 512 * 3;
            l_data = (OPJ_BYTE*) calloc(1, l_data_size);
            if (l_data == NULL) {
                ret = 1;
                goto fin;
            }
            for (i = 0; i < l_nb_tiles; ++i) {
                if (! opj_write_tile(l_codec, i, l_data, l_data_size, l_stream)) {
                    fprintf(stderr, "ERROR -> test_tile_encoder: failed to write the tile %d!\n",
                            i);
                    opj_stream_destroy(l_stream);
                    opj_destroy_codec(l_codec);
                    opj_image_destroy(image);
                    ret = 1;
                    goto fin;
                }
            }
            free(l_data);
        } else {
            bSuccess = bSuccess && opj_encode(l_codec, l_stream);
            if (!bSuccess)  {
                fprintf(stderr, "failed to encode image: opj_encode\n");
            }
        }
        bSuccess = bSuccess && opj_end_compress(l_codec, l_stream);
        if (!bSuccess)  {
            fprintf(stderr, "failed to encode image: opj_end_compress\n");
        }

        if (!bSuccess)  {
            opj_stream_destroy(l_stream);
            opj_destroy_codec(l_codec);
            opj_image_destroy(image);
            fprintf(stderr, "failed to encode image\n");
            remove(parameters.outfile);
            ret = 1;
            goto fin;
        }

        num_compressed_files++;
        fprintf(stdout, "[INFO] Generated outfile %s\n", parameters.outfile);
        /* close and free the byte stream */
        opj_stream_destroy(l_stream);

        /* free remaining compression structures */
        opj_destroy_codec(l_codec);

        /* free image data */
        opj_image_destroy(image);

    }

    t = opj_clock() - t;
    if (num_compressed_files) {
        fprintf(stdout, "encode time: %d ms \n",
                (int)((t * 1000.0) / (OPJ_FLOAT64)num_compressed_files));
    }

    ret = 0;

fin:
    if (parameters.cp_comment) {
        free(parameters.cp_comment);
    }
    if (parameters.cp_matrice) {
        free(parameters.cp_matrice);
    }
    if (raw_cp.rawComps) {
        free(raw_cp.rawComps);
    }
    if (img_fol.imgdirpath) {
        free(img_fol.imgdirpath);
    }
    if (dirptr) {
        if (dirptr->filename_buf) {
            free(dirptr->filename_buf);
        }
        if (dirptr->filename) {
            free(dirptr->filename);
        }
        free(dirptr);
    }
    return ret;
}


static OPJ_BOOL opj_pi_next_cprl(opj_pi_iterator_t * pi)
{
    opj_pi_comp_t *comp = NULL;
    opj_pi_resolution_t *res = NULL;
    OPJ_UINT32 index = 0;

    if (pi->poc.compno0 >= pi->numcomps ||
            pi->poc.compno1 >= pi->numcomps + 1) {
        opj_event_msg(pi->manager, EVT_ERROR,
                      "opj_pi_next_cprl(): invalid compno0/compno1");
        return OPJ_FALSE;
    }

    if (!pi->first) {
        comp = &pi->comps[pi->compno];
        goto LABEL_SKIP;
    } else {
        pi->first = 0;
    }

    for (pi->compno = pi->poc.compno0; pi->compno < pi->poc.compno1; pi->compno++) {
        OPJ_UINT32 resno;
        comp = &pi->comps[pi->compno];
        pi->dx = 0;
        pi->dy = 0;
        for (resno = 0; resno < comp->numresolutions; resno++) {
            OPJ_UINT32 dx, dy;
            res = &comp->resolutions[resno];
            if (res->pdx + comp->numresolutions - 1 - resno < 32 &&
                    comp->dx <= UINT_MAX / (1u << (res->pdx + comp->numresolutions - 1 - resno))) {
                dx = comp->dx * (1u << (res->pdx + comp->numresolutions - 1 - resno));
                pi->dx = !pi->dx ? dx : opj_uint_min(pi->dx, dx);
            }
            if (res->pdy + comp->numresolutions - 1 - resno < 32 &&
                    comp->dy <= UINT_MAX / (1u << (res->pdy + comp->numresolutions - 1 - resno))) {
                dy = comp->dy * (1u << (res->pdy + comp->numresolutions - 1 - resno));
                pi->dy = !pi->dy ? dy : opj_uint_min(pi->dy, dy);
            }
        }
        if (pi->dx == 0 || pi->dy == 0) {
            return OPJ_FALSE;
        }
        if (!pi->tp_on) {
            pi->poc.ty0 = pi->ty0;
            pi->poc.tx0 = pi->tx0;
            pi->poc.ty1 = pi->ty1;
            pi->poc.tx1 = pi->tx1;
        }
        for (pi->y = (OPJ_UINT32)pi->poc.ty0; pi->y < (OPJ_UINT32)pi->poc.ty1;
                pi->y += (pi->dy - (pi->y % pi->dy))) {
            for (pi->x = (OPJ_UINT32)pi->poc.tx0; pi->x < (OPJ_UINT32)pi->poc.tx1;
                    pi->x += (pi->dx - (pi->x % pi->dx))) {
                for (pi->resno = pi->poc.resno0;
                        pi->resno < opj_uint_min(pi->poc.resno1, comp->numresolutions); pi->resno++) {
                    OPJ_UINT32 levelno;
                    OPJ_UINT32 trx0, try0;
                    OPJ_UINT32 trx1, try1;
                    OPJ_UINT32 rpx, rpy;
                    OPJ_UINT32 prci, prcj;
                    res = &comp->resolutions[pi->resno];
                    levelno = comp->numresolutions - 1 - pi->resno;
                    /* Avoids division by zero on id_000004,sig_06,src_000679,op_arith8,pos_49,val_-17 */
                    /* of  https://github.com/uclouvain/openjpeg/issues/938 */
                    if (levelno >= 32 ||
                            ((comp->dx << levelno) >> levelno) != comp->dx ||
                            ((comp->dy << levelno) >> levelno) != comp->dy) {
                        continue;
                    }
                    if ((comp->dx << levelno) > INT_MAX ||
                            (comp->dy << levelno) > INT_MAX) {
                        continue;
                    }
                    trx0 = opj_uint_ceildiv(pi->tx0, (comp->dx << levelno));
                    try0 = opj_uint_ceildiv(pi->ty0, (comp->dy << levelno));
                    trx1 = opj_uint_ceildiv(pi->tx1, (comp->dx << levelno));
                    try1 = opj_uint_ceildiv(pi->ty1, (comp->dy << levelno));
                    rpx = res->pdx + levelno;
                    rpy = res->pdy + levelno;

                    /* To avoid divisions by zero / undefined behaviour on shift */
                    /* in below tests */
                    /* Fixes reading id:000019,sig:08,src:001098,op:flip1,pos:49 */
                    /* of https://github.com/uclouvain/openjpeg/issues/938 */
                    if (rpx >= 31 || ((comp->dx << rpx) >> rpx) != comp->dx ||
                            rpy >= 31 || ((comp->dy << rpy) >> rpy) != comp->dy) {
                        continue;
                    }

                    /* See ISO-15441. B.12.1.5 Component-position-resolution level-layer progression */
                    if (!((pi->y % (comp->dy << rpy) == 0) || ((pi->y == pi->ty0) &&
                            ((try0 << levelno) % (1U << rpy))))) {
                        continue;
                    }
                    if (!((pi->x % (comp->dx << rpx) == 0) || ((pi->x == pi->tx0) &&
                            ((trx0 << levelno) % (1U << rpx))))) {
                        continue;
                    }

                    if ((res->pw == 0) || (res->ph == 0)) {
                        continue;
                    }

                    if ((trx0 == trx1) || (try0 == try1)) {
                        continue;
                    }

                    prci = opj_uint_floordivpow2(opj_uint_ceildiv(pi->x,
                                                 (comp->dx << levelno)), res->pdx)
                           - opj_uint_floordivpow2(trx0, res->pdx);
                    prcj = opj_uint_floordivpow2(opj_uint_ceildiv(pi->y,
                                                 (comp->dy << levelno)), res->pdy)
                           - opj_uint_floordivpow2(try0, res->pdy);
                    pi->precno = (OPJ_UINT32)(prci + prcj * res->pw);
                    for (pi->layno = pi->poc.layno0; pi->layno < pi->poc.layno1; pi->layno++) {
                        index = pi->layno * pi->step_l + pi->resno * pi->step_r + pi->compno *
                                pi->step_c + pi->precno * pi->step_p;
                        if (index >= pi->include_size) {
                            opj_event_msg(pi->manager, EVT_ERROR, "Invalid access to pi->include");
                            return OPJ_FALSE;
                        }
                        if (!pi->include[index]) {
                            pi->include[index] = 1;
                            return OPJ_TRUE;
                        }
LABEL_SKIP:
                        ;
                    }
                }
            }
        }
    }

    return OPJ_FALSE;
}


miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
{
    const struct pkt_metadata *md = &packet->md;
    const void *data = dp_packet_data(packet);
    size_t size = dp_packet_size(packet);
    ovs_be32 packet_type = packet->packet_type;
    uint64_t *values = miniflow_values(dst);
    struct mf_ctx mf = { FLOWMAP_EMPTY_INITIALIZER, values,
                         values + FLOW_U64S };
    const char *frame;
    ovs_be16 dl_type = OVS_BE16_MAX;
    uint8_t nw_frag, nw_tos, nw_ttl, nw_proto;
    uint8_t *ct_nw_proto_p = NULL;
    ovs_be16 ct_tp_src = 0, ct_tp_dst = 0;

    /* Metadata. */
    if (flow_tnl_dst_is_set(&md->tunnel)) {
        miniflow_push_words(mf, tunnel, &md->tunnel,
                            offsetof(struct flow_tnl, metadata) /
                            sizeof(uint64_t));

        if (!(md->tunnel.flags & FLOW_TNL_F_UDPIF)) {
            if (md->tunnel.metadata.present.map) {
                miniflow_push_words(mf, tunnel.metadata, &md->tunnel.metadata,
                                    sizeof md->tunnel.metadata /
                                    sizeof(uint64_t));
            }
        } else {
            if (md->tunnel.metadata.present.len) {
                miniflow_push_words(mf, tunnel.metadata.present,
                                    &md->tunnel.metadata.present, 1);
                miniflow_push_words(mf, tunnel.metadata.opts.gnv,
                                    md->tunnel.metadata.opts.gnv,
                                    DIV_ROUND_UP(md->tunnel.metadata.present.len,
                                                 sizeof(uint64_t)));
            }
        }
    }
    if (md->skb_priority || md->pkt_mark) {
        miniflow_push_uint32(mf, skb_priority, md->skb_priority);
        miniflow_push_uint32(mf, pkt_mark, md->pkt_mark);
    }
    miniflow_push_uint32(mf, dp_hash, md->dp_hash);
    miniflow_push_uint32(mf, in_port, odp_to_u32(md->in_port.odp_port));
    if (md->ct_state) {
        miniflow_push_uint32(mf, recirc_id, md->recirc_id);
        miniflow_push_uint8(mf, ct_state, md->ct_state);
        ct_nw_proto_p = miniflow_pointer(mf, ct_nw_proto);
        miniflow_push_uint8(mf, ct_nw_proto, 0);
        miniflow_push_uint16(mf, ct_zone, md->ct_zone);
    } else if (md->recirc_id) {
        miniflow_push_uint32(mf, recirc_id, md->recirc_id);
        miniflow_pad_to_64(mf, recirc_id);
    }

    if (md->ct_state) {
        miniflow_push_uint32(mf, ct_mark, md->ct_mark);
        miniflow_push_be32(mf, packet_type, packet_type);

        if (!ovs_u128_is_zero(md->ct_label)) {
            miniflow_push_words(mf, ct_label, &md->ct_label,
                                sizeof md->ct_label / sizeof(uint64_t));
        }
    } else {
        miniflow_pad_from_64(mf, packet_type);
        miniflow_push_be32(mf, packet_type, packet_type);
    }

    /* Initialize packet's layer pointer and offsets. */
    frame = data;
    dp_packet_reset_offsets(packet);

    if (packet_type == htonl(PT_ETH)) {
        /* Must have full Ethernet header to proceed. */
        if (OVS_UNLIKELY(size < sizeof(struct eth_header))) {
            goto out;
        } else {
            /* Link layer. */
            ASSERT_SEQUENTIAL(dl_dst, dl_src);
            miniflow_push_macs(mf, dl_dst, data);

            /* VLAN */
            union flow_vlan_hdr vlans[FLOW_MAX_VLAN_HEADERS];
            size_t num_vlans = parse_vlan(&data, &size, vlans);

            dl_type = parse_ethertype(&data, &size);
            miniflow_push_be16(mf, dl_type, dl_type);
            miniflow_pad_to_64(mf, dl_type);
            if (num_vlans > 0) {
                miniflow_push_words_32(mf, vlans, vlans, num_vlans);
            }

        }
    } else {
        /* Take dl_type from packet_type. */
        dl_type = pt_ns_type_be(packet_type);
        miniflow_pad_from_64(mf, dl_type);
        miniflow_push_be16(mf, dl_type, dl_type);
        /* Do not push vlan_tci, pad instead */
        miniflow_pad_to_64(mf, dl_type);
    }

    /* Parse mpls. */
    if (OVS_UNLIKELY(eth_type_mpls(dl_type))) {
        int count;
        const void *mpls = data;

        packet->l2_5_ofs = (char *)data - frame;
        count = parse_mpls(&data, &size);
        miniflow_push_words_32(mf, mpls_lse, mpls, count);
    }

    /* Network layer. */
    packet->l3_ofs = (char *)data - frame;

    nw_frag = 0;
    if (OVS_LIKELY(dl_type == htons(ETH_TYPE_IP))) {
        const struct ip_header *nh = data;
        int ip_len;
        uint16_t tot_len;

        if (OVS_UNLIKELY(size < IP_HEADER_LEN)) {
            goto out;
        }
        ip_len = IP_IHL(nh->ip_ihl_ver) * 4;

        if (OVS_UNLIKELY(ip_len < IP_HEADER_LEN)) {
            goto out;
        }
        if (OVS_UNLIKELY(size < ip_len)) {
            goto out;
        }
        tot_len = ntohs(nh->ip_tot_len);
        if (OVS_UNLIKELY(tot_len > size || ip_len > tot_len)) {
            goto out;
        }
        if (OVS_UNLIKELY(size - tot_len > UINT8_MAX)) {
            goto out;
        }
        dp_packet_set_l2_pad_size(packet, size - tot_len);
        size = tot_len;   /* Never pull padding. */

        /* Push both source and destination address at once. */
        miniflow_push_words(mf, nw_src, &nh->ip_src, 1);
        if (ct_nw_proto_p && !md->ct_orig_tuple_ipv6) {
            *ct_nw_proto_p = md->ct_orig_tuple.ipv4.ipv4_proto;
            if (*ct_nw_proto_p) {
                miniflow_push_words(mf, ct_nw_src,
                                    &md->ct_orig_tuple.ipv4.ipv4_src, 1);
                ct_tp_src = md->ct_orig_tuple.ipv4.src_port;
                ct_tp_dst = md->ct_orig_tuple.ipv4.dst_port;
            }
        }

        miniflow_push_be32(mf, ipv6_label, 0); /* Padding for IPv4. */

        nw_tos = nh->ip_tos;
        nw_ttl = nh->ip_ttl;
        nw_proto = nh->ip_proto;
        if (OVS_UNLIKELY(IP_IS_FRAGMENT(nh->ip_frag_off))) {
            nw_frag = FLOW_NW_FRAG_ANY;
            if (nh->ip_frag_off & htons(IP_FRAG_OFF_MASK)) {
                nw_frag |= FLOW_NW_FRAG_LATER;
            }
        }
        data_pull(&data, &size, ip_len);
    } else if (dl_type == htons(ETH_TYPE_IPV6)) {
        const struct ovs_16aligned_ip6_hdr *nh;
        ovs_be32 tc_flow;
        uint16_t plen;

        if (OVS_UNLIKELY(size < sizeof *nh)) {
            goto out;
        }
        nh = data_pull(&data, &size, sizeof *nh);

        plen = ntohs(nh->ip6_plen);
        if (OVS_UNLIKELY(plen > size)) {
            goto out;
        }
        /* Jumbo Payload option not supported yet. */
        if (OVS_UNLIKELY(size - plen > UINT8_MAX)) {
            goto out;
        }
        dp_packet_set_l2_pad_size(packet, size - plen);
        size = plen;   /* Never pull padding. */

        miniflow_push_words(mf, ipv6_src, &nh->ip6_src,
                            sizeof nh->ip6_src / 8);
        miniflow_push_words(mf, ipv6_dst, &nh->ip6_dst,
                            sizeof nh->ip6_dst / 8);
        if (ct_nw_proto_p && md->ct_orig_tuple_ipv6) {
            *ct_nw_proto_p = md->ct_orig_tuple.ipv6.ipv6_proto;
            if (*ct_nw_proto_p) {
                miniflow_push_words(mf, ct_ipv6_src,
                                    &md->ct_orig_tuple.ipv6.ipv6_src,
                                    2 *
                                    sizeof md->ct_orig_tuple.ipv6.ipv6_src / 8);
                ct_tp_src = md->ct_orig_tuple.ipv6.src_port;
                ct_tp_dst = md->ct_orig_tuple.ipv6.dst_port;
            }
        }

        tc_flow = get_16aligned_be32(&nh->ip6_flow);
        nw_tos = ntohl(tc_flow) >> 20;
        nw_ttl = nh->ip6_hlim;
        nw_proto = nh->ip6_nxt;

        if (!parse_ipv6_ext_hdrs__(&data, &size, &nw_proto, &nw_frag)) {
            goto out;
        }

        /* This needs to be after the parse_ipv6_ext_hdrs__() call because it
         * leaves the nw_frag word uninitialized. */
        ASSERT_SEQUENTIAL(ipv6_label, nw_frag);
        ovs_be32 label = tc_flow & htonl(IPV6_LABEL_MASK);
        miniflow_push_be32(mf, ipv6_label, label);
    } else {
        if (dl_type == htons(ETH_TYPE_ARP) ||
            dl_type == htons(ETH_TYPE_RARP)) {
            struct eth_addr arp_buf[2];
            const struct arp_eth_header *arp = (const struct arp_eth_header *)
                data_try_pull(&data, &size, ARP_ETH_HEADER_LEN);

            if (OVS_LIKELY(arp) && OVS_LIKELY(arp->ar_hrd == htons(1))
                && OVS_LIKELY(arp->ar_pro == htons(ETH_TYPE_IP))
                && OVS_LIKELY(arp->ar_hln == ETH_ADDR_LEN)
                && OVS_LIKELY(arp->ar_pln == 4)) {
                miniflow_push_be32(mf, nw_src,
                                   get_16aligned_be32(&arp->ar_spa));
                miniflow_push_be32(mf, nw_dst,
                                   get_16aligned_be32(&arp->ar_tpa));

                /* We only match on the lower 8 bits of the opcode. */
                if (OVS_LIKELY(ntohs(arp->ar_op) <= 0xff)) {
                    miniflow_push_be32(mf, ipv6_label, 0); /* Pad with ARP. */
                    miniflow_push_be32(mf, nw_frag, htonl(ntohs(arp->ar_op)));
                }

                /* Must be adjacent. */
                ASSERT_SEQUENTIAL(arp_sha, arp_tha);

                arp_buf[0] = arp->ar_sha;
                arp_buf[1] = arp->ar_tha;
                miniflow_push_macs(mf, arp_sha, arp_buf);
                miniflow_pad_to_64(mf, arp_tha);
            }
        } else if (dl_type == htons(ETH_TYPE_NSH)) {
            struct ovs_key_nsh nsh;

            if (OVS_LIKELY(parse_nsh(&data, &size, &nsh))) {
                miniflow_push_words(mf, nsh, &nsh,
                                    sizeof(struct ovs_key_nsh) /
                                    sizeof(uint64_t));
            }
        }
        goto out;
    }

    packet->l4_ofs = (char *)data - frame;
    miniflow_push_be32(mf, nw_frag,
                       bytes_to_be32(nw_frag, nw_tos, nw_ttl, nw_proto));

    if (OVS_LIKELY(!(nw_frag & FLOW_NW_FRAG_LATER))) {
        if (OVS_LIKELY(nw_proto == IPPROTO_TCP)) {
            if (OVS_LIKELY(size >= TCP_HEADER_LEN)) {
                const struct tcp_header *tcp = data;

                miniflow_push_be32(mf, arp_tha.ea[2], 0);
                miniflow_push_be32(mf, tcp_flags,
                                   TCP_FLAGS_BE32(tcp->tcp_ctl));
                miniflow_push_be16(mf, tp_src, tcp->tcp_src);
                miniflow_push_be16(mf, tp_dst, tcp->tcp_dst);
                miniflow_push_be16(mf, ct_tp_src, ct_tp_src);
                miniflow_push_be16(mf, ct_tp_dst, ct_tp_dst);
            }
        } else if (OVS_LIKELY(nw_proto == IPPROTO_UDP)) {
            if (OVS_LIKELY(size >= UDP_HEADER_LEN)) {
                const struct udp_header *udp = data;

                miniflow_push_be16(mf, tp_src, udp->udp_src);
                miniflow_push_be16(mf, tp_dst, udp->udp_dst);
                miniflow_push_be16(mf, ct_tp_src, ct_tp_src);
                miniflow_push_be16(mf, ct_tp_dst, ct_tp_dst);
            }
        } else if (OVS_LIKELY(nw_proto == IPPROTO_SCTP)) {
            if (OVS_LIKELY(size >= SCTP_HEADER_LEN)) {
                const struct sctp_header *sctp = data;

                miniflow_push_be16(mf, tp_src, sctp->sctp_src);
                miniflow_push_be16(mf, tp_dst, sctp->sctp_dst);
                miniflow_push_be16(mf, ct_tp_src, ct_tp_src);
                miniflow_push_be16(mf, ct_tp_dst, ct_tp_dst);
            }
        } else if (OVS_LIKELY(nw_proto == IPPROTO_ICMP)) {
            if (OVS_LIKELY(size >= ICMP_HEADER_LEN)) {
                const struct icmp_header *icmp = data;

                miniflow_push_be16(mf, tp_src, htons(icmp->icmp_type));
                miniflow_push_be16(mf, tp_dst, htons(icmp->icmp_code));
                miniflow_push_be16(mf, ct_tp_src, ct_tp_src);
                miniflow_push_be16(mf, ct_tp_dst, ct_tp_dst);
            }
        } else if (OVS_LIKELY(nw_proto == IPPROTO_IGMP)) {
            if (OVS_LIKELY(size >= IGMP_HEADER_LEN)) {
                const struct igmp_header *igmp = data;

                miniflow_push_be16(mf, tp_src, htons(igmp->igmp_type));
                miniflow_push_be16(mf, tp_dst, htons(igmp->igmp_code));
                miniflow_push_be16(mf, ct_tp_src, ct_tp_src);
                miniflow_push_be16(mf, ct_tp_dst, ct_tp_dst);
                miniflow_push_be32(mf, igmp_group_ip4,
                                   get_16aligned_be32(&igmp->group));
                miniflow_pad_to_64(mf, igmp_group_ip4);
            }
        } else if (OVS_LIKELY(nw_proto == IPPROTO_ICMPV6)) {
            if (OVS_LIKELY(size >= sizeof(struct icmp6_hdr))) {
                const struct in6_addr *nd_target;
                struct eth_addr arp_buf[2];
                const struct icmp6_hdr *icmp = data_pull(&data, &size,
                                                         sizeof *icmp);
                if (parse_icmpv6(&data, &size, icmp, &nd_target, arp_buf)) {
                    if (nd_target) {
                        miniflow_push_words(mf, nd_target, nd_target,
                                            sizeof *nd_target / sizeof(uint64_t));
                    }
                    miniflow_push_macs(mf, arp_sha, arp_buf);
                    miniflow_pad_to_64(mf, arp_tha);
                    miniflow_push_be16(mf, tp_src, htons(icmp->icmp6_type));
                    miniflow_push_be16(mf, tp_dst, htons(icmp->icmp6_code));
                    miniflow_pad_to_64(mf, tp_dst);
                } else {
                    /* ICMPv6 but not ND. */
                    miniflow_push_be16(mf, tp_src, htons(icmp->icmp6_type));
                    miniflow_push_be16(mf, tp_dst, htons(icmp->icmp6_code));
                    miniflow_push_be16(mf, ct_tp_src, ct_tp_src);
                    miniflow_push_be16(mf, ct_tp_dst, ct_tp_dst);
                }
            }
        }
    }
 out:
    dst->map = mf.map;
}


static void esp_do_dma(ESPState *s)
{
    uint32_t len, cmdlen;
    int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
    uint8_t buf[ESP_CMDFIFO_SZ];

    len = esp_get_tc(s);
    if (s->do_cmd) {
        /*
         * handle_ti_cmd() case: esp_do_dma() is called only from
         * handle_ti_cmd() with do_cmd != NULL (see the assert())
         */
        cmdlen = fifo8_num_used(&s->cmdfifo);
        trace_esp_do_dma(cmdlen, len);
        if (s->dma_memory_read) {
            s->dma_memory_read(s->dma_opaque, buf, len);
            fifo8_push_all(&s->cmdfifo, buf, len);
        } else {
            s->pdma_cb = do_dma_pdma_cb;
            esp_raise_drq(s);
            return;
        }
        trace_esp_handle_ti_cmd(cmdlen);
        s->ti_size = 0;
        if ((s->rregs[ESP_RSTAT] & 7) == STAT_CD) {
            /* No command received */
            if (s->cmdfifo_cdb_offset == fifo8_num_used(&s->cmdfifo)) {
                return;
            }

            /* Command has been received */
            s->do_cmd = 0;
            do_cmd(s);
        } else {
            /*
             * Extra message out bytes received: update cmdfifo_cdb_offset
             * and then switch to commmand phase
             */
            s->cmdfifo_cdb_offset = fifo8_num_used(&s->cmdfifo);
            s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
            s->rregs[ESP_RSEQ] = SEQ_CD;
            s->rregs[ESP_RINTR] |= INTR_BS;
            esp_raise_irq(s);
        }
        return;
    }
    if (s->async_len == 0) {
        /* Defer until data is available.  */
        return;
    }
    if (len > s->async_len) {
        len = s->async_len;
    }
    if (to_device) {
        if (s->dma_memory_read) {
            s->dma_memory_read(s->dma_opaque, s->async_buf, len);
        } else {
            s->pdma_cb = do_dma_pdma_cb;
            esp_raise_drq(s);
            return;
        }
    } else {
        if (s->dma_memory_write) {
            s->dma_memory_write(s->dma_opaque, s->async_buf, len);
        } else {
            /* Adjust TC for any leftover data in the FIFO */
            if (!fifo8_is_empty(&s->fifo)) {
                esp_set_tc(s, esp_get_tc(s) - fifo8_num_used(&s->fifo));
            }

            /* Copy device data to FIFO */
            len = MIN(len, fifo8_num_free(&s->fifo));
            fifo8_push_all(&s->fifo, s->async_buf, len);
            s->async_buf += len;
            s->async_len -= len;
            s->ti_size -= len;

            /*
             * MacOS toolbox uses a TI length of 16 bytes for all commands, so
             * commands shorter than this must be padded accordingly
             */
            if (len < esp_get_tc(s) && esp_get_tc(s) <= ESP_FIFO_SZ) {
                while (fifo8_num_used(&s->fifo) < ESP_FIFO_SZ) {
                    esp_fifo_push(s, 0);
                    len++;
                }
            }

            esp_set_tc(s, esp_get_tc(s) - len);
            s->pdma_cb = do_dma_pdma_cb;
            esp_raise_drq(s);

            /* Indicate transfer to FIFO is complete */
            s->rregs[ESP_RSTAT] |= STAT_TC;
            return;
        }
    }
    esp_set_tc(s, esp_get_tc(s) - len);
    s->async_buf += len;
    s->async_len -= len;
    if (to_device) {
        s->ti_size += len;
    } else {
        s->ti_size -= len;
    }
    if (s->async_len == 0) {
        scsi_req_continue(s->current_req);
        /*
         * If there is still data to be read from the device then
         * complete the DMA operation immediately.  Otherwise defer
         * until the scsi layer has completed.
         */
        if (to_device || esp_get_tc(s) != 0 || s->ti_size == 0) {
            return;
        }
    }

    /* Partially filled a scsi buffer. Complete immediately.  */
    esp_dma_done(s);
    esp_lower_drq(s);
}


static int sco_sock_getsockopt(struct socket *sock, int level, int optname,
			       char __user *optval, int __user *optlen)
{
	struct sock *sk = sock->sk;
	int len, err = 0;
	struct bt_voice voice;
	u32 phys;
	int pkt_status;

	BT_DBG("sk %p", sk);

	if (level == SOL_SCO)
		return sco_sock_getsockopt_old(sock, optname, optval, optlen);

	if (get_user(len, optlen))
		return -EFAULT;

	lock_sock(sk);

	switch (optname) {

	case BT_DEFER_SETUP:
		if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
			err = -EINVAL;
			break;
		}

		if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags),
			     (u32 __user *)optval))
			err = -EFAULT;

		break;

	case BT_VOICE:
		voice.setting = sco_pi(sk)->setting;

		len = min_t(unsigned int, len, sizeof(voice));
		if (copy_to_user(optval, (char *)&voice, len))
			err = -EFAULT;

		break;

	case BT_PHY:
		if (sk->sk_state != BT_CONNECTED) {
			err = -ENOTCONN;
			break;
		}

		phys = hci_conn_get_phy(sco_pi(sk)->conn->hcon);

		if (put_user(phys, (u32 __user *) optval))
			err = -EFAULT;
		break;

	case BT_PKT_STATUS:
		pkt_status = (sco_pi(sk)->cmsg_mask & SCO_CMSG_PKT_STATUS);

		if (put_user(pkt_status, (int __user *)optval))
			err = -EFAULT;
		break;

	case BT_SNDMTU:
	case BT_RCVMTU:
		if (put_user(sco_pi(sk)->conn->mtu, (u32 __user *)optval))
			err = -EFAULT;
		break;

	default:
		err = -ENOPROTOOPT;
		break;
	}

	release_sock(sk);
	return err;
}


PHPAPI php_url *php_url_parse_ex2(char const *str, size_t length, zend_bool *has_port)
{
	char port_buf[6];
	php_url *ret = ecalloc(1, sizeof(php_url));
	char const *s, *e, *p, *pp, *ue;

	*has_port = 0;
	s = str;
	ue = s + length;

	/* parse scheme */
	if ((e = memchr(s, ':', length)) && e != s) {
		/* validate scheme */
		p = s;
		while (p < e) {
			/* scheme = 1*[ lowalpha | digit | "+" | "-" | "." ] */
			if (!isalpha(*p) && !isdigit(*p) && *p != '+' && *p != '.' && *p != '-') {
				if (e + 1 < ue && e < binary_strcspn(s, ue, "?#")) {
					goto parse_port;
				} else if (s + 1 < ue && *s == '/' && *(s + 1) == '/') { /* relative-scheme URL */
					s += 2;
					e = 0;
					goto parse_host;
				} else {
					goto just_path;
				}
			}
			p++;
		}

		if (e + 1 == ue) { /* only scheme is available */
			ret->scheme = zend_string_init(s, (e - s), 0);
			php_replace_controlchars_ex(ZSTR_VAL(ret->scheme), ZSTR_LEN(ret->scheme));
			return ret;
		}

		/*
		 * certain schemas like mailto: and zlib: may not have any / after them
		 * this check ensures we support those.
		 */
		if (*(e+1) != '/') {
			/* check if the data we get is a port this allows us to
			 * correctly parse things like a.com:80
			 */
			p = e + 1;
			while (p < ue && isdigit(*p)) {
				p++;
			}

			if ((p == ue || *p == '/') && (p - e) < 7) {
				goto parse_port;
			}

			ret->scheme = zend_string_init(s, (e-s), 0);
			php_replace_controlchars_ex(ZSTR_VAL(ret->scheme), ZSTR_LEN(ret->scheme));

			s = e + 1;
			goto just_path;
		} else {
			ret->scheme = zend_string_init(s, (e-s), 0);
			php_replace_controlchars_ex(ZSTR_VAL(ret->scheme), ZSTR_LEN(ret->scheme));

			if (e + 2 < ue && *(e + 2) == '/') {
				s = e + 3;
				if (zend_string_equals_literal_ci(ret->scheme, "file")) {
					if (e + 3 < ue && *(e + 3) == '/') {
						/* support windows drive letters as in:
						   file:///c:/somedir/file.txt
						*/
						if (e + 5 < ue && *(e + 5) == ':') {
							s = e + 4;
						}
						goto just_path;
					}
				}
			} else {
				s = e + 1;
				goto just_path;
			}
		}
	} else if (e) { /* no scheme; starts with colon: look for port */
		parse_port:
		p = e + 1;
		pp = p;

		while (pp < ue && pp - p < 6 && isdigit(*pp)) {
			pp++;
		}

		if (pp - p > 0 && pp - p < 6 && (pp == ue || *pp == '/')) {
			zend_long port;
			char *end;
			memcpy(port_buf, p, (pp - p));
			port_buf[pp - p] = '\0';
			port = ZEND_STRTOL(port_buf, &end, 10);
			if (port >= 0 && port <= 65535 && end != port_buf) {
				*has_port = 1;
				ret->port = (unsigned short) port;
				if (s + 1 < ue && *s == '/' && *(s + 1) == '/') { /* relative-scheme URL */
				    s += 2;
				}
			} else {
				php_url_free(ret);
				return NULL;
			}
		} else if (p == pp && pp == ue) {
			php_url_free(ret);
			return NULL;
		} else if (s + 1 < ue && *s == '/' && *(s + 1) == '/') { /* relative-scheme URL */
			s += 2;
		} else {
			goto just_path;
		}
	} else if (s + 1 < ue && *s == '/' && *(s + 1) == '/') { /* relative-scheme URL */
		s += 2;
	} else {
		goto just_path;
	}

parse_host:
	e = binary_strcspn(s, ue, "/?#");

	/* check for login and password */
	if ((p = zend_memrchr(s, '@', (e-s)))) {
		if ((pp = memchr(s, ':', (p-s)))) {
			ret->user = zend_string_init(s, (pp-s), 0);
			php_replace_controlchars_ex(ZSTR_VAL(ret->user), ZSTR_LEN(ret->user));

			pp++;
			ret->pass = zend_string_init(pp, (p-pp), 0);
			php_replace_controlchars_ex(ZSTR_VAL(ret->pass), ZSTR_LEN(ret->pass));
		} else {
            if (!is_userinfo_valid(s, p-s)) {
                goto check_port;
            }
            ret->user = zend_string_init(s, (p-s), 0);
			php_replace_controlchars_ex(ZSTR_VAL(ret->user), ZSTR_LEN(ret->user));
		}

		s = p + 1;
	}

check_port:
	/* check for port */
	if (s < ue && *s == '[' && *(e-1) == ']') {
		/* Short circuit portscan,
		   we're dealing with an
		   IPv6 embedded address */
		p = NULL;
	} else {
		p = zend_memrchr(s, ':', (e-s));
	}

	if (p) {
		if (!ret->port) {
			p++;
			if (e-p > 5) { /* port cannot be longer then 5 characters */
				php_url_free(ret);
				return NULL;
			} else if (e - p > 0) {
				zend_long port;
				char *end;
				memcpy(port_buf, p, (e - p));
				port_buf[e - p] = '\0';
				port = ZEND_STRTOL(port_buf, &end, 10);
				if (port >= 0 && port <= 65535 && end != port_buf) {
					*has_port = 1;
					ret->port = (unsigned short)port;
				} else {
					php_url_free(ret);
					return NULL;
				}
			}
			p--;
		}
	} else {
		p = e;
	}

	/* check if we have a valid host, if we don't reject the string as url */
	if ((p-s) < 1) {
		php_url_free(ret);
		return NULL;
	}

	ret->host = zend_string_init(s, (p-s), 0);
	php_replace_controlchars_ex(ZSTR_VAL(ret->host), ZSTR_LEN(ret->host));

	if (e == ue) {
		return ret;
	}

	s = e;

	just_path:

	e = ue;
	p = memchr(s, '#', (e - s));
	if (p) {
		p++;
		if (p < e) {
			ret->fragment = zend_string_init(p, (e - p), 0);
			php_replace_controlchars_ex(ZSTR_VAL(ret->fragment), ZSTR_LEN(ret->fragment));
		}
		e = p-1;
	}

	p = memchr(s, '?', (e - s));
	if (p) {
		p++;
		if (p < e) {
			ret->query = zend_string_init(p, (e - p), 0);
			php_replace_controlchars_ex(ZSTR_VAL(ret->query), ZSTR_LEN(ret->query));
		}
		e = p-1;
	}

	if (s < e || s == ue) {
		ret->path = zend_string_init(s, (e - s), 0);
		php_replace_controlchars_ex(ZSTR_VAL(ret->path), ZSTR_LEN(ret->path));
	}

	return ret;
}


int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t bytes) {
    TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
    char *filename = "tempfile.tif";
    char *mode = "r";
    TIFF *tiff;

    /* buffer is the encoded file, bytes is the length of the encoded file */
    /*     it all ends up in state->buffer, which is a uint8* from Imaging.h */

    TRACE(("in decoder: bytes %d\n", bytes));
    TRACE(("State: count %d, state %d, x %d, y %d, ystep %d\n", state->count, state->state,
           state->x, state->y, state->ystep));
    TRACE(("State: xsize %d, ysize %d, xoff %d, yoff %d \n", state->xsize, state->ysize,
           state->xoff, state->yoff));
    TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes));
    TRACE(("Buffer: %p: %c%c%c%c\n", buffer, (char)buffer[0], (char)buffer[1],(char)buffer[2], (char)buffer[3]));
    TRACE(("State->Buffer: %c%c%c%c\n", (char)state->buffer[0], (char)state->buffer[1],(char)state->buffer[2], (char)state->buffer[3]));
    TRACE(("Image: mode %s, type %d, bands: %d, xsize %d, ysize %d \n",
           im->mode, im->type, im->bands, im->xsize, im->ysize));
    TRACE(("Image: image8 %p, image32 %p, image %p, block %p \n",
           im->image8, im->image32, im->image, im->block));
    TRACE(("Image: pixelsize: %d, linesize %d \n",
           im->pixelsize, im->linesize));

    dump_state(clientstate);
    clientstate->size = bytes;
    clientstate->eof = clientstate->size;
    clientstate->loc = 0;
    clientstate->data = (tdata_t)buffer;
    clientstate->flrealloc = 0;
    dump_state(clientstate);

    TIFFSetWarningHandler(NULL);
    TIFFSetWarningHandlerExt(NULL);

    if (clientstate->fp) {
        TRACE(("Opening using fd: %d\n",clientstate->fp));
        lseek(clientstate->fp,0,SEEK_SET); // Sometimes, I get it set to the end.
        tiff = TIFFFdOpen(fd_to_tiff_fd(clientstate->fp), filename, mode);
    } else {
        TRACE(("Opening from string\n"));
        tiff = TIFFClientOpen(filename, mode,
                              (thandle_t) clientstate,
                              _tiffReadProc, _tiffWriteProc,
                              _tiffSeekProc, _tiffCloseProc, _tiffSizeProc,
                              _tiffMapProc, _tiffUnmapProc);
    }

    if (!tiff){
        TRACE(("Error, didn't get the tiff\n"));
        state->errcode = IMAGING_CODEC_BROKEN;
        return -1;
    }

    if (clientstate->ifd){
        int rv;
        uint32 ifdoffset = clientstate->ifd;
        TRACE(("reading tiff ifd %u\n", ifdoffset));
        rv = TIFFSetSubDirectory(tiff, ifdoffset);
        if (!rv){
            TRACE(("error in TIFFSetSubDirectory"));
            return -1;
        }
    }

    if (TIFFIsTiled(tiff)) {
        INT32 x, y, tile_y;
        UINT32 tile_width, tile_length, current_tile_width, row_byte_size;
        UINT8 *new_data;

        TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tile_width);
        TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tile_length);

        /* overflow check for row_byte_size calculation */
        if ((UINT32) INT_MAX / state->bits < tile_width) {
            state->errcode = IMAGING_CODEC_MEMORY;
            TIFFClose(tiff);
            return -1;
        }

        // We could use TIFFTileSize, but for YCbCr data it returns subsampled data size
        row_byte_size = (tile_width * state->bits + 7) / 8;

        /* overflow check for realloc */
        if (INT_MAX / row_byte_size < tile_length) {
            state->errcode = IMAGING_CODEC_MEMORY;
            TIFFClose(tiff);
            return -1;
        }

        state->bytes = row_byte_size * tile_length;

        if (TIFFTileSize(tiff) > state->bytes) {
            // If the strip size as expected by LibTiff isn't what we're expecting, abort.
            state->errcode = IMAGING_CODEC_MEMORY;
            TIFFClose(tiff);
            return -1;
        }

        /* realloc to fit whole tile */
        /* malloc check above */
        new_data = realloc (state->buffer, state->bytes);
        if (!new_data) {
            state->errcode = IMAGING_CODEC_MEMORY;
            TIFFClose(tiff);
            return -1;
        }

        state->buffer = new_data;

        TRACE(("TIFFTileSize: %d\n", state->bytes));

        for (y = state->yoff; y < state->ysize; y += tile_length) {
            for (x = state->xoff; x < state->xsize; x += tile_width) {
                if (ReadTile(tiff, x, y, (UINT32*) state->buffer) == -1) {
                    TRACE(("Decode Error, Tile at %dx%d\n", x, y));
                    state->errcode = IMAGING_CODEC_BROKEN;
                    TIFFClose(tiff);
                    return -1;
                }

                TRACE(("Read tile at %dx%d; \n\n", x, y));

                current_tile_width = min((INT32) tile_width, state->xsize - x);

                // iterate over each line in the tile and stuff data into image
                for (tile_y = 0; tile_y < min((INT32) tile_length, state->ysize - y); tile_y++) {
                    TRACE(("Writing tile data at %dx%d using tile_width: %d; \n", tile_y + y, x, current_tile_width));

                    // UINT8 * bbb = state->buffer + tile_y * row_byte_size;
                    // TRACE(("chars: %x%x%x%x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3]));

                    state->shuffle((UINT8*) im->image[tile_y + y] + x * im->pixelsize,
                       state->buffer + tile_y * row_byte_size,
                       current_tile_width
                    );
                }
            }
        }
    } else {
        INT32 strip_row;
        UINT8 *new_data;
        UINT32 rows_per_strip, row_byte_size;
        int ret;

        ret = TIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_strip);
        if (ret != 1) {
            rows_per_strip = state->ysize;
        }
        TRACE(("RowsPerStrip: %u \n", rows_per_strip));

        // We could use TIFFStripSize, but for YCbCr data it returns subsampled data size
        row_byte_size = (state->xsize * state->bits + 7) / 8;

        /* overflow check for realloc */
        if (INT_MAX / row_byte_size < rows_per_strip) {
            state->errcode = IMAGING_CODEC_MEMORY;
            TIFFClose(tiff);
            return -1;
        }

        state->bytes = rows_per_strip * row_byte_size;

        TRACE(("StripSize: %d \n", state->bytes));

        if (TIFFStripSize(tiff) > state->bytes) {
            // If the strip size as expected by LibTiff isn't what we're expecting, abort.
            // man:   TIFFStripSize returns the equivalent size for a strip of data as it would be returned in a
            //        call to TIFFReadEncodedStrip ...

            state->errcode = IMAGING_CODEC_MEMORY;
            TIFFClose(tiff);
            return -1;
        }

        /* realloc to fit whole strip */
        /* malloc check above */
        new_data = realloc (state->buffer, state->bytes);
        if (!new_data) {
            state->errcode = IMAGING_CODEC_MEMORY;
            TIFFClose(tiff);
            return -1;
        }

        state->buffer = new_data;

        for (; state->y < state->ysize; state->y += rows_per_strip) {
            if (ReadStrip(tiff, state->y, (UINT32 *)state->buffer) == -1) {
                TRACE(("Decode Error, strip %d\n", TIFFComputeStrip(tiff, state->y, 0)));
                state->errcode = IMAGING_CODEC_BROKEN;
                TIFFClose(tiff);
                return -1;
            }

            TRACE(("Decoded strip for row %d \n", state->y));

            // iterate over each row in the strip and stuff data into image
            for (strip_row = 0; strip_row < min((INT32) rows_per_strip, state->ysize - state->y); strip_row++) {
                TRACE(("Writing data into line %d ; \n", state->y + strip_row));

                // UINT8 * bbb = state->buffer + strip_row * (state->bytes / rows_per_strip);
                // TRACE(("chars: %x %x %x %x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3]));

                state->shuffle((UINT8*) im->image[state->y + state->yoff + strip_row] +
                               state->xoff * im->pixelsize,
                               state->buffer + strip_row * row_byte_size,
                               state->xsize);
            }
        }
    }

    TIFFClose(tiff);
    TRACE(("Done Decoding, Returning \n"));
    // Returning -1 here to force ImageFile.load to break, rather than
    // even think about looping back around.
    return -1;
}


handle_spawn (PortalFlatpak         *object,
              GDBusMethodInvocation *invocation,
              GUnixFDList           *fd_list,
              const gchar           *arg_cwd_path,
              const gchar *const    *arg_argv,
              GVariant              *arg_fds,
              GVariant              *arg_envs,
              guint                  arg_flags,
              GVariant              *arg_options)
{
  g_autoptr(GError) error = NULL;
  ChildSetupData child_setup_data = { NULL };
  GPid pid;
  PidData *pid_data;
  InstanceIdReadData *instance_id_read_data = NULL;
  gsize i, j, n_fds, n_envs;
  const gint *fds = NULL;
  gint fds_len = 0;
  g_autofree FdMapEntry *fd_map = NULL;
  gchar **env;
  gint32 max_fd;
  GKeyFile *app_info;
  g_autoptr(GPtrArray) flatpak_argv = g_ptr_array_new_with_free_func (g_free);
  g_autofree char *app_id = NULL;
  g_autofree char *branch = NULL;
  g_autofree char *arch = NULL;
  g_autofree char *app_commit = NULL;
  g_autofree char *runtime_ref = NULL;
  g_auto(GStrv) runtime_parts = NULL;
  g_autofree char *runtime_commit = NULL;
  g_autofree char *instance_path = NULL;
  g_auto(GStrv) extra_args = NULL;
  g_auto(GStrv) shares = NULL;
  g_auto(GStrv) sockets = NULL;
  g_auto(GStrv) devices = NULL;
  g_auto(GStrv) sandbox_expose = NULL;
  g_auto(GStrv) sandbox_expose_ro = NULL;
  g_autoptr(GVariant) sandbox_expose_fd = NULL;
  g_autoptr(GVariant) sandbox_expose_fd_ro = NULL;
  g_autoptr(GOutputStream) instance_id_out_stream = NULL;
  guint sandbox_flags = 0;
  gboolean sandboxed;
  gboolean expose_pids;
  gboolean share_pids;
  gboolean notify_start;
  gboolean devel;
  g_autoptr(GString) env_string = g_string_new ("");

  child_setup_data.instance_id_fd = -1;
  child_setup_data.env_fd = -1;

  if (fd_list != NULL)
    fds = g_unix_fd_list_peek_fds (fd_list, &fds_len);

  app_info = g_object_get_data (G_OBJECT (invocation), "app-info");
  g_assert (app_info != NULL);

  app_id = g_key_file_get_string (app_info,
                                  FLATPAK_METADATA_GROUP_APPLICATION,
                                  FLATPAK_METADATA_KEY_NAME, NULL);
  g_assert (app_id != NULL);

  g_debug ("spawn() called from app: '%s'", app_id);
  if (*app_id == 0)
    {
      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
                                             G_DBUS_ERROR_INVALID_ARGS,
                                             "org.freedesktop.portal.Flatpak.Spawn only works in a flatpak");
      return G_DBUS_METHOD_INVOCATION_HANDLED;
    }

  if (*arg_cwd_path == 0)
    arg_cwd_path = NULL;

  if (arg_argv == NULL || *arg_argv == NULL)
    {
      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
                                             G_DBUS_ERROR_INVALID_ARGS,
                                             "No command given");
      return G_DBUS_METHOD_INVOCATION_HANDLED;
    }

  if ((arg_flags & ~FLATPAK_SPAWN_FLAGS_ALL) != 0)
    {
      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
                                             "Unsupported flags enabled: 0x%x", arg_flags & ~FLATPAK_SPAWN_FLAGS_ALL);
      return G_DBUS_METHOD_INVOCATION_HANDLED;
    }

  runtime_ref = g_key_file_get_string (app_info,
                                       FLATPAK_METADATA_GROUP_APPLICATION,
                                       FLATPAK_METADATA_KEY_RUNTIME, NULL);
  if (runtime_ref == NULL)
    {
      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
                                             "No runtime found");
      return G_DBUS_METHOD_INVOCATION_HANDLED;
    }

  runtime_parts = g_strsplit (runtime_ref, "/", -1);

  branch = g_key_file_get_string (app_info,
                                  FLATPAK_METADATA_GROUP_INSTANCE,
                                  FLATPAK_METADATA_KEY_BRANCH, NULL);
  instance_path = g_key_file_get_string (app_info,
                                         FLATPAK_METADATA_GROUP_INSTANCE,
                                         FLATPAK_METADATA_KEY_INSTANCE_PATH, NULL);
  arch = g_key_file_get_string (app_info,
                                FLATPAK_METADATA_GROUP_INSTANCE,
                                FLATPAK_METADATA_KEY_ARCH, NULL);
  extra_args = g_key_file_get_string_list (app_info,
                                           FLATPAK_METADATA_GROUP_INSTANCE,
                                           FLATPAK_METADATA_KEY_EXTRA_ARGS, NULL, NULL);
  app_commit = g_key_file_get_string (app_info,
                                      FLATPAK_METADATA_GROUP_INSTANCE,
                                      FLATPAK_METADATA_KEY_APP_COMMIT, NULL);
  runtime_commit = g_key_file_get_string (app_info,
                                          FLATPAK_METADATA_GROUP_INSTANCE,
                                          FLATPAK_METADATA_KEY_RUNTIME_COMMIT, NULL);
  shares = g_key_file_get_string_list (app_info, FLATPAK_METADATA_GROUP_CONTEXT,
                                       FLATPAK_METADATA_KEY_SHARED, NULL, NULL);
  sockets = g_key_file_get_string_list (app_info, FLATPAK_METADATA_GROUP_CONTEXT,
                                       FLATPAK_METADATA_KEY_SOCKETS, NULL, NULL);
  devices = g_key_file_get_string_list (app_info, FLATPAK_METADATA_GROUP_CONTEXT,
                                        FLATPAK_METADATA_KEY_DEVICES, NULL, NULL);

  devel = g_key_file_get_boolean (app_info, FLATPAK_METADATA_GROUP_INSTANCE,
                                  FLATPAK_METADATA_KEY_DEVEL, NULL);

  g_variant_lookup (arg_options, "sandbox-expose", "^as", &sandbox_expose);
  g_variant_lookup (arg_options, "sandbox-expose-ro", "^as", &sandbox_expose_ro);
  g_variant_lookup (arg_options, "sandbox-flags", "u", &sandbox_flags);
  sandbox_expose_fd = g_variant_lookup_value (arg_options, "sandbox-expose-fd", G_VARIANT_TYPE ("ah"));
  sandbox_expose_fd_ro = g_variant_lookup_value (arg_options, "sandbox-expose-fd-ro", G_VARIANT_TYPE ("ah"));

  if ((sandbox_flags & ~FLATPAK_SPAWN_SANDBOX_FLAGS_ALL) != 0)
    {
      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
                                             "Unsupported sandbox flags enabled: 0x%x", arg_flags & ~FLATPAK_SPAWN_SANDBOX_FLAGS_ALL);
      return G_DBUS_METHOD_INVOCATION_HANDLED;
    }

  if (instance_path == NULL &&
      ((sandbox_expose != NULL && sandbox_expose[0] != NULL) ||
       (sandbox_expose_ro != NULL && sandbox_expose_ro[0] != NULL)))
    {
      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
                                             G_DBUS_ERROR_INVALID_ARGS,
                                             "Invalid sandbox expose, caller has no instance path");
      return G_DBUS_METHOD_INVOCATION_HANDLED;
    }

  for (i = 0; sandbox_expose != NULL && sandbox_expose[i] != NULL; i++)
    {
      const char *expose = sandbox_expose[i];

      g_debug ("exposing %s", expose);
      if (!is_valid_expose (expose, &error))
        {
          g_dbus_method_invocation_return_gerror (invocation, error);
          return G_DBUS_METHOD_INVOCATION_HANDLED;
        }
    }

  for (i = 0; sandbox_expose_ro != NULL && sandbox_expose_ro[i] != NULL; i++)
    {
      const char *expose = sandbox_expose_ro[i];
      g_debug ("exposing %s", expose);
      if (!is_valid_expose (expose, &error))
        {
          g_dbus_method_invocation_return_gerror (invocation, error);
          return G_DBUS_METHOD_INVOCATION_HANDLED;
        }
    }

  g_debug ("Running spawn command %s", arg_argv[0]);

  n_fds = 0;
  if (fds != NULL)
    n_fds = g_variant_n_children (arg_fds);
  fd_map = g_new0 (FdMapEntry, n_fds);

  child_setup_data.fd_map = fd_map;
  child_setup_data.fd_map_len = n_fds;

  max_fd = -1;
  for (i = 0; i < n_fds; i++)
    {
      gint32 handle, dest_fd;
      int handle_fd;

      g_variant_get_child (arg_fds, i, "{uh}", &dest_fd, &handle);

      if (handle >= fds_len || handle < 0)
        {
          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
                                                 G_DBUS_ERROR_INVALID_ARGS,
                                                 "No file descriptor for handle %d",
                                                 handle);
          return G_DBUS_METHOD_INVOCATION_HANDLED;
        }

      handle_fd = fds[handle];

      fd_map[i].to = dest_fd;
      fd_map[i].from = handle_fd;
      fd_map[i].final = fd_map[i].to;

      /* If stdin/out/err is a tty we try to set it as the controlling
         tty for the app, this way we can use this to run in a terminal. */
      if ((dest_fd == 0 || dest_fd == 1 || dest_fd == 2) &&
          !child_setup_data.set_tty &&
          isatty (handle_fd))
        {
          child_setup_data.set_tty = TRUE;
          child_setup_data.tty = handle_fd;
        }

      max_fd = MAX (max_fd, fd_map[i].to);
      max_fd = MAX (max_fd, fd_map[i].from);
    }

  /* We make a second pass over the fds to find if any "to" fd index
     overlaps an already in use fd (i.e. one in the "from" category
     that are allocated randomly). If a fd overlaps "to" fd then its
     a caller issue and not our fault, so we ignore that. */
  for (i = 0; i < n_fds; i++)
    {
      int to_fd = fd_map[i].to;
      gboolean conflict = FALSE;

      /* At this point we're fine with using "from" values for this
         value (because we handle to==from in the code), or values
         that are before "i" in the fd_map (because those will be
         closed at this point when dup:ing). However, we can't
         reuse a fd that is in "from" for j > i. */
      for (j = i + 1; j < n_fds; j++)
        {
          int from_fd = fd_map[j].from;
          if (from_fd == to_fd)
            {
              conflict = TRUE;
              break;
            }
        }

      if (conflict)
        fd_map[i].to = ++max_fd;
    }

  /* TODO: Ideally we should let `flatpak run` inherit the portal's
   * environment, in case e.g. a LD_LIBRARY_PATH is needed to be able
   * to run `flatpak run`, but tell it to start from a blank environment
   * when running the Flatpak app; but this isn't currently possible, so
   * for now we preserve existing behaviour. */
  if (arg_flags & FLATPAK_SPAWN_FLAGS_CLEAR_ENV)
    {
      char *empty[] = { NULL };
      env = g_strdupv (empty);
    }
  else
    env = g_get_environ ();

  /* Let the environment variables given by the caller override the ones
   * from extra_args. Don't add them to @env, because they are controlled
   * by our caller, which might be trying to use them to inject code into
   * flatpak(1); add them to the environment block instead.
   *
   * We don't use --env= here, so that if the values are something that
   * should not be exposed to other uids, they can remain confidential. */
  n_envs = g_variant_n_children (arg_envs);
  for (i = 0; i < n_envs; i++)
    {
      const char *var = NULL;
      const char *val = NULL;
      g_variant_get_child (arg_envs, i, "{&s&s}", &var, &val);

      if (var[0] == '\0')
        {
          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
                                                 G_DBUS_ERROR_INVALID_ARGS,
                                                 "Environment variable cannot have empty name");
          return G_DBUS_METHOD_INVOCATION_HANDLED;
        }

      if (strchr (var, '=') != NULL)
        {
          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
                                                 G_DBUS_ERROR_INVALID_ARGS,
                                                 "Environment variable name cannot contain '='");
          return G_DBUS_METHOD_INVOCATION_HANDLED;
        }

      g_string_append (env_string, var);
      g_string_append_c (env_string, '=');
      g_string_append (env_string, val);
      g_string_append_c (env_string, '\0');
    }

  g_ptr_array_add (flatpak_argv, g_strdup ("flatpak"));
  g_ptr_array_add (flatpak_argv, g_strdup ("run"));

  sandboxed = (arg_flags & FLATPAK_SPAWN_FLAGS_SANDBOX) != 0;

  if (sandboxed)
    {
      g_ptr_array_add (flatpak_argv, g_strdup ("--sandbox"));

      if (sandbox_flags & FLATPAK_SPAWN_SANDBOX_FLAGS_SHARE_DISPLAY)
        {
          if (sockets != NULL && g_strv_contains ((const char * const *) sockets, "wayland"))
            g_ptr_array_add (flatpak_argv, g_strdup ("--socket=wayland"));
          if (sockets != NULL && g_strv_contains ((const char * const *) sockets, "fallback-x11"))
            g_ptr_array_add (flatpak_argv, g_strdup ("--socket=fallback-x11"));
          if (sockets != NULL && g_strv_contains ((const char * const *) sockets, "x11"))
            g_ptr_array_add (flatpak_argv, g_strdup ("--socket=x11"));
          if (shares != NULL && g_strv_contains ((const char * const *) shares, "ipc") &&
              sockets != NULL && (g_strv_contains ((const char * const *) sockets, "fallback-x11") ||
                                  g_strv_contains ((const char * const *) sockets, "x11")))
            g_ptr_array_add (flatpak_argv, g_strdup ("--share=ipc"));
        }
      if (sandbox_flags & FLATPAK_SPAWN_SANDBOX_FLAGS_SHARE_SOUND)
        {
          if (sockets != NULL && g_strv_contains ((const char * const *) sockets, "pulseaudio"))
            g_ptr_array_add (flatpak_argv, g_strdup ("--socket=pulseaudio"));
        }
      if (sandbox_flags & FLATPAK_SPAWN_SANDBOX_FLAGS_SHARE_GPU)
        {
          if (devices != NULL &&
              (g_strv_contains ((const char * const *) devices, "dri") ||
               g_strv_contains ((const char * const *) devices, "all")))
            g_ptr_array_add (flatpak_argv, g_strdup ("--device=dri"));
        }
      if (sandbox_flags & FLATPAK_SPAWN_SANDBOX_FLAGS_ALLOW_DBUS)
        g_ptr_array_add (flatpak_argv, g_strdup ("--session-bus"));
      if (sandbox_flags & FLATPAK_SPAWN_SANDBOX_FLAGS_ALLOW_A11Y)
        g_ptr_array_add (flatpak_argv, g_strdup ("--a11y-bus"));
    }
  else
    {
      for (i = 0; extra_args != NULL && extra_args[i] != NULL; i++)
        {
          if (g_str_has_prefix (extra_args[i], "--env="))
            {
              const char *var_val = extra_args[i] + strlen ("--env=");

              if (var_val[0] == '\0' || var_val[0] == '=')
                {
                  g_warning ("Environment variable in extra-args has empty name");
                  continue;
                }

              if (strchr (var_val, '=') == NULL)
                {
                  g_warning ("Environment variable in extra-args has no value");
                  continue;
                }

              g_string_append (env_string, var_val);
              g_string_append_c (env_string, '\0');
            }
          else
            {
              g_ptr_array_add (flatpak_argv, g_strdup (extra_args[i]));
            }
        }
    }

  if (env_string->len > 0)
    {
      g_auto(GLnxTmpfile) env_tmpf  = { 0, };

      if (!flatpak_buffer_to_sealed_memfd_or_tmpfile (&env_tmpf, "environ",
                                                      env_string->str,
                                                      env_string->len, &error))
        {
          g_dbus_method_invocation_return_gerror (invocation, error);
          return G_DBUS_METHOD_INVOCATION_HANDLED;
        }

      child_setup_data.env_fd = glnx_steal_fd (&env_tmpf.fd);
      g_ptr_array_add (flatpak_argv,
                       g_strdup_printf ("--env-fd=%d",
                                        child_setup_data.env_fd));
    }

  expose_pids = (arg_flags & FLATPAK_SPAWN_FLAGS_EXPOSE_PIDS) != 0;
  share_pids = (arg_flags & FLATPAK_SPAWN_FLAGS_SHARE_PIDS) != 0;

  if (expose_pids || share_pids)
    {
      g_autofree char *instance_id = NULL;
      int sender_pid1 = 0;

      if (!(supports & FLATPAK_SPAWN_SUPPORT_FLAGS_EXPOSE_PIDS))
        {
          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
                                                 G_DBUS_ERROR_NOT_SUPPORTED,
                                                 "Expose pids not supported with setuid bwrap");
          return G_DBUS_METHOD_INVOCATION_HANDLED;
        }

      instance_id = g_key_file_get_string (app_info,
                                           FLATPAK_METADATA_GROUP_INSTANCE,
                                           FLATPAK_METADATA_KEY_INSTANCE_ID, NULL);

      if (instance_id)
        {
          g_autoptr(FlatpakInstance) instance = flatpak_instance_new_for_id (instance_id);
          sender_pid1 = flatpak_instance_get_child_pid (instance);
        }

      if (sender_pid1 == 0)
        {
          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
                                                 G_DBUS_ERROR_INVALID_ARGS,
                                                 "Could not find requesting pid");
          return G_DBUS_METHOD_INVOCATION_HANDLED;
        }

      g_ptr_array_add (flatpak_argv, g_strdup_printf ("--parent-pid=%d", sender_pid1));

      if (share_pids)
        g_ptr_array_add (flatpak_argv, g_strdup ("--parent-share-pids"));
      else
        g_ptr_array_add (flatpak_argv, g_strdup ("--parent-expose-pids"));
    }

  notify_start = (arg_flags & FLATPAK_SPAWN_FLAGS_NOTIFY_START) != 0;
  if (notify_start)
    {
      int pipe_fds[2];
      if (pipe (pipe_fds) == -1)
        {
          int errsv = errno;
          g_dbus_method_invocation_return_error (invocation, G_IO_ERROR,
                                                 g_io_error_from_errno (errsv),
                                                 "Failed to create instance ID pipe: %s",
                                                 g_strerror (errsv));
          return G_DBUS_METHOD_INVOCATION_HANDLED;
        }

      GInputStream *in_stream = G_INPUT_STREAM (g_unix_input_stream_new (pipe_fds[0], TRUE));
      /* This is saved to ensure the portal's end gets closed after the exec. */
      instance_id_out_stream = G_OUTPUT_STREAM (g_unix_output_stream_new (pipe_fds[1], TRUE));

      instance_id_read_data = g_new0 (InstanceIdReadData, 1);

      g_input_stream_read_async (in_stream, instance_id_read_data->buffer,
                                 INSTANCE_ID_BUFFER_SIZE - 1, G_PRIORITY_DEFAULT, NULL,
                                 instance_id_read_finish, instance_id_read_data);

      g_ptr_array_add (flatpak_argv, g_strdup_printf ("--instance-id-fd=%d", pipe_fds[1]));
      child_setup_data.instance_id_fd = pipe_fds[1];
    }

  if (devel)
    g_ptr_array_add (flatpak_argv, g_strdup ("--devel"));

  /* Inherit launcher network access from launcher, unless
     NO_NETWORK set. */
  if (shares != NULL && g_strv_contains ((const char * const *) shares, "network") &&
      !(arg_flags & FLATPAK_SPAWN_FLAGS_NO_NETWORK))
    g_ptr_array_add (flatpak_argv, g_strdup ("--share=network"));
  else
    g_ptr_array_add (flatpak_argv, g_strdup ("--unshare=network"));

  if (instance_path)
    {
      for (i = 0; sandbox_expose != NULL && sandbox_expose[i] != NULL; i++)
        g_ptr_array_add (flatpak_argv,
                         filesystem_sandbox_arg (instance_path, sandbox_expose[i], FALSE));
      for (i = 0; sandbox_expose_ro != NULL && sandbox_expose_ro[i] != NULL; i++)
        g_ptr_array_add (flatpak_argv,
                         filesystem_sandbox_arg (instance_path, sandbox_expose_ro[i], TRUE));
    }

  for (i = 0; sandbox_expose_ro != NULL && sandbox_expose_ro[i] != NULL; i++)
    {
      const char *expose = sandbox_expose_ro[i];
      g_debug ("exposing %s", expose);
    }

  if (sandbox_expose_fd != NULL)
    {
      gsize len = g_variant_n_children (sandbox_expose_fd);
      for (i = 0; i < len; i++)
        {
          gint32 handle;
          g_variant_get_child (sandbox_expose_fd, i, "h", &handle);
          if (handle >= 0 && handle < fds_len)
            {
              int handle_fd = fds[handle];
              g_autofree char *path = NULL;
              gboolean writable = FALSE;

              path = get_path_for_fd (handle_fd, &writable, &error);

              if (path)
                {
                  g_ptr_array_add (flatpak_argv, filesystem_arg (path, !writable));
                }
              else
                {
                  g_debug ("unable to get path for sandbox-exposed fd %d, ignoring: %s",
                           handle_fd, error->message);
                  g_clear_error (&error);
                }
            }
          else
            {
              g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
                                                     G_DBUS_ERROR_INVALID_ARGS,
                                                     "No file descriptor for handle %d",
                                                     handle);
              return G_DBUS_METHOD_INVOCATION_HANDLED;
            }
        }
    }

  if (sandbox_expose_fd_ro != NULL)
    {
      gsize len = g_variant_n_children (sandbox_expose_fd_ro);
      for (i = 0; i < len; i++)
        {
          gint32 handle;
          g_variant_get_child (sandbox_expose_fd_ro, i, "h", &handle);
          if (handle >= 0 && handle < fds_len)
            {
              int handle_fd = fds[handle];
              g_autofree char *path = NULL;
              gboolean writable = FALSE;

              path = get_path_for_fd (handle_fd, &writable, &error);

              if (path)
                {
                  g_ptr_array_add (flatpak_argv, filesystem_arg (path, TRUE));
                }
              else
                {
                  g_debug ("unable to get path for sandbox-exposed fd %d, ignoring: %s",
                           handle_fd, error->message);
                  g_clear_error (&error);
                }
            }
          else
            {
              g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
                                                     G_DBUS_ERROR_INVALID_ARGS,
                                                     "No file descriptor for handle %d",
                                                     handle);
              return G_DBUS_METHOD_INVOCATION_HANDLED;
            }
        }
    }

  g_ptr_array_add (flatpak_argv, g_strdup_printf ("--runtime=%s", runtime_parts[1]));
  g_ptr_array_add (flatpak_argv, g_strdup_printf ("--runtime-version=%s", runtime_parts[3]));

  if ((arg_flags & FLATPAK_SPAWN_FLAGS_LATEST_VERSION) == 0)
    {
      if (app_commit)
        g_ptr_array_add (flatpak_argv, g_strdup_printf ("--commit=%s", app_commit));
      if (runtime_commit)
        g_ptr_array_add (flatpak_argv, g_strdup_printf ("--runtime-commit=%s", runtime_commit));
    }

  if (arg_cwd_path != NULL)
    g_ptr_array_add (flatpak_argv, g_strdup_printf ("--cwd=%s", arg_cwd_path));

  if (arg_argv[0][0] != 0)
    g_ptr_array_add (flatpak_argv, g_strdup_printf ("--command=%s", arg_argv[0]));

  g_ptr_array_add (flatpak_argv, g_strdup_printf ("%s/%s/%s", app_id, arch ? arch : "", branch ? branch : ""));
  for (i = 1; arg_argv[i] != NULL; i++)
    g_ptr_array_add (flatpak_argv, g_strdup (arg_argv[i]));
  g_ptr_array_add (flatpak_argv, NULL);

  if (opt_verbose)
    {
      g_autoptr(GString) cmd = g_string_new ("");

      for (i = 0; flatpak_argv->pdata[i] != NULL; i++)
        {
          if (i > 0)
            g_string_append (cmd, " ");
          g_string_append (cmd, flatpak_argv->pdata[i]);
        }

      g_debug ("Starting: %s\n", cmd->str);
    }

  /* We use LEAVE_DESCRIPTORS_OPEN to work around dead-lock, see flatpak_close_fds_workaround */
  if (!g_spawn_async_with_pipes (NULL,
                                 (char **) flatpak_argv->pdata,
                                 env,
                                 G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_LEAVE_DESCRIPTORS_OPEN,
                                 child_setup_func, &child_setup_data,
                                 &pid,
                                 NULL,
                                 NULL,
                                 NULL,
                                 &error))
    {
      gint code = G_DBUS_ERROR_FAILED;
      if (g_error_matches (error, G_SPAWN_ERROR, G_SPAWN_ERROR_ACCES))
        code = G_DBUS_ERROR_ACCESS_DENIED;
      else if (g_error_matches (error, G_SPAWN_ERROR, G_SPAWN_ERROR_NOENT))
        code = G_DBUS_ERROR_FILE_NOT_FOUND;
      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, code,
                                             "Failed to start command: %s",
                                             error->message);
      return G_DBUS_METHOD_INVOCATION_HANDLED;
    }

  if (instance_id_read_data)
    instance_id_read_data->pid = pid;

  pid_data = g_new0 (PidData, 1);
  pid_data->pid = pid;
  pid_data->client = g_strdup (g_dbus_method_invocation_get_sender (invocation));
  pid_data->watch_bus = (arg_flags & FLATPAK_SPAWN_FLAGS_WATCH_BUS) != 0;
  pid_data->expose_or_share_pids = (expose_pids || share_pids);
  pid_data->child_watch = g_child_watch_add_full (G_PRIORITY_DEFAULT,
                                                  pid,
                                                  child_watch_died,
                                                  pid_data,
                                                  NULL);

  g_debug ("Client Pid is %d", pid_data->pid);

  g_hash_table_replace (client_pid_data_hash, GUINT_TO_POINTER (pid_data->pid),
                        pid_data);

  portal_flatpak_complete_spawn (object, invocation, NULL, pid);
  return G_DBUS_METHOD_INVOCATION_HANDLED;
}


static void read_multiple_complete_cb(struct gatt_db_attribute *attr, int err,
					const uint8_t *value, size_t len,
					void *user_data)
{
	struct read_mult_data *data = user_data;
	struct gatt_db_attribute *next_attr;
	uint16_t handle = gatt_db_attribute_get_handle(attr);
	uint8_t ecode;
	uint16_t length;

	if (err != 0) {
		ecode = err;
		goto error;
	}

	length = data->opcode == BT_ATT_OP_READ_MULT_VL_REQ ?
			MIN(len, MAX(data->mtu - data->length, 3) - 3) :
			MIN(len, data->mtu - data->length - 1);

	if (data->opcode == BT_ATT_OP_READ_MULT_VL_REQ) {
		/* The Length Value Tuple List may be truncated within the first
		 * two octets of a tuple due to the size limits of the current
		 * ATT_MTU, but the first two octets cannot be separated.
		 */
		if (data->mtu - data->length >= 3) {
			put_le16(len, data->rsp_data + data->length);
			data->length += 2;
		}
	}

	memcpy(data->rsp_data + data->length, value, length);
	data->length += length;

	data->cur_handle++;

	if (data->cur_handle == data->num_handles) {
		bt_att_chan_send_rsp(data->chan, data->opcode + 1,
						data->rsp_data, data->length);
		read_mult_data_free(data);
		return;
	}

	handle = data->handles[data->cur_handle];

	util_debug(data->server->debug_callback, data->server->debug_data,
				"%s Req - #%zu of %zu: 0x%04x",
				data->opcode == BT_ATT_OP_READ_MULT_REQ ?
				"Read Multiple" :
				"Read Multiple Variable Length",
				data->cur_handle + 1, data->num_handles,
				handle);

	next_attr = gatt_db_get_attribute(data->server->db, handle);

	if (!next_attr) {
		ecode = BT_ATT_ERROR_INVALID_HANDLE;
		goto error;
	}

	ecode = check_permissions(data->server, next_attr, BT_ATT_PERM_READ |
						BT_ATT_PERM_READ_AUTHEN |
						BT_ATT_PERM_READ_ENCRYPT);
	if (ecode)
		goto error;

	if (gatt_db_attribute_read(next_attr, 0, data->opcode,
					data->server->att,
					read_multiple_complete_cb, data))
		return;

	ecode = BT_ATT_ERROR_UNLIKELY;

error:
	bt_att_chan_send_error_rsp(data->chan, data->opcode, handle, ecode);
	read_mult_data_free(data);
}


static int uvc_scan_chain_backward(struct uvc_video_chain *chain,
	struct uvc_entity **_entity)
{
	struct uvc_entity *entity = *_entity;
	struct uvc_entity *term;
	int id = -EINVAL, i;

	switch (UVC_ENTITY_TYPE(entity)) {
	case UVC_VC_EXTENSION_UNIT:
	case UVC_VC_PROCESSING_UNIT:
		id = entity->baSourceID[0];
		break;

	case UVC_VC_SELECTOR_UNIT:
		/* Single-input selector units are ignored. */
		if (entity->bNrInPins == 1) {
			id = entity->baSourceID[0];
			break;
		}

		if (uvc_trace_param & UVC_TRACE_PROBE)
			printk(KERN_CONT " <- IT");

		chain->selector = entity;
		for (i = 0; i < entity->bNrInPins; ++i) {
			id = entity->baSourceID[i];
			term = uvc_entity_by_id(chain->dev, id);
			if (term == NULL || !UVC_ENTITY_IS_ITERM(term)) {
				uvc_trace(UVC_TRACE_DESCR, "Selector unit %d "
					"input %d isn't connected to an "
					"input terminal\n", entity->id, i);
				return -1;
			}

			if (uvc_trace_param & UVC_TRACE_PROBE)
				printk(KERN_CONT " %d", term->id);

			list_add_tail(&term->chain, &chain->entities);
			uvc_scan_chain_forward(chain, term, entity);
		}

		if (uvc_trace_param & UVC_TRACE_PROBE)
			printk(KERN_CONT "\n");

		id = 0;
		break;

	case UVC_ITT_VENDOR_SPECIFIC:
	case UVC_ITT_CAMERA:
	case UVC_ITT_MEDIA_TRANSPORT_INPUT:
	case UVC_OTT_VENDOR_SPECIFIC:
	case UVC_OTT_DISPLAY:
	case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
	case UVC_TT_STREAMING:
		id = UVC_ENTITY_IS_OTERM(entity) ? entity->baSourceID[0] : 0;
		break;
	}

	if (id <= 0) {
		*_entity = NULL;
		return id;
	}

	entity = uvc_entity_by_id(chain->dev, id);
	if (entity == NULL) {
		uvc_trace(UVC_TRACE_DESCR, "Found reference to "
			"unknown entity %d.\n", id);
		return -EINVAL;
	}

	*_entity = entity;
	return 0;
}


static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,
				   struct pinctrl_dev *pctldev,
				   struct pinctrl_map *map, unsigned num_maps)
{
	int i;
	struct pinctrl_dt_map *dt_map;

	/* Initialize common mapping table entry fields */
	for (i = 0; i < num_maps; i++) {
		map[i].dev_name = dev_name(p->dev);
		map[i].name = statename;
		if (pctldev)
			map[i].ctrl_dev_name = dev_name(pctldev->dev);
	}

	/* Remember the converted mapping table entries */
	dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL);
	if (!dt_map) {
		dt_free_map(pctldev, map, num_maps);
		return -ENOMEM;
	}

	dt_map->pctldev = pctldev;
	dt_map->map = map;
	dt_map->num_maps = num_maps;
	list_add_tail(&dt_map->node, &p->dt_maps);

	return pinctrl_register_map(map, num_maps, false);
}


decompress_none(tvbuff_t *tvb, packet_info *pinfo _U_, int offset, guint32 length _U_, tvbuff_t **decompressed_tvb, int *decompressed_offset)
{
    *decompressed_tvb = tvb;
    *decompressed_offset = offset;
    return 1;
}


decompress_snappy(tvbuff_t *tvb, packet_info *pinfo, int offset, guint32 length, tvbuff_t **decompressed_tvb, int *decompressed_offset)
{
    guint8 *data = (guint8*)tvb_memdup(wmem_packet_scope(), tvb, offset, length);
    size_t uncompressed_size;
    snappy_status rc = SNAPPY_OK;
    tvbuff_t *composite_tvb = NULL;
    int ret = 0;

    if (tvb_memeql(tvb, offset, kafka_xerial_header, sizeof(kafka_xerial_header)) == 0) {

        /* xerial framing format */
        guint32 chunk_size, pos = 16;

        while (pos < length) {
            if (pos > length-4) {
                // XXX - this is presumably an error, as the chunk size
                // doesn't fully fit in the data, so an error should be
                // reported.
                goto end;
            }
            chunk_size = tvb_get_ntohl(tvb, offset+pos);
            pos += 4;
            if (chunk_size > length) {
                // XXX - this is presumably an error, as the chunk to be
                // decompressed doesn't fully fit in the data, so an error
                // should be reported.
                goto end;
            }
            if (pos > length-chunk_size) {
                // XXX - this is presumably an error, as the chunk to be
                // decompressed doesn't fully fit in the data, so an error
                // should be reported.
                goto end;
            }
            rc = snappy_uncompressed_length(&data[pos], chunk_size, &uncompressed_size);
            if (rc != SNAPPY_OK) {
                goto end;
            }
            guint8 *decompressed_buffer = (guint8*)wmem_alloc(pinfo->pool, uncompressed_size);
            rc = snappy_uncompress(&data[pos], chunk_size, decompressed_buffer, &uncompressed_size);
            if (rc != SNAPPY_OK) {
                goto end;
            }

            if (!composite_tvb) {
                composite_tvb = tvb_new_composite();
            }
            tvb_composite_append(composite_tvb,
                      tvb_new_child_real_data(tvb, decompressed_buffer, (guint)uncompressed_size, (gint)uncompressed_size));
            pos += chunk_size;
        }

    } else {

        /* unframed format */
        rc = snappy_uncompressed_length(data, length, &uncompressed_size);
        if (rc != SNAPPY_OK) {
            goto end;
        }

        guint8 *decompressed_buffer = (guint8*)wmem_alloc(pinfo->pool, uncompressed_size);

        rc = snappy_uncompress(data, length, decompressed_buffer, &uncompressed_size);
        if (rc != SNAPPY_OK) {
            goto end;
        }

        *decompressed_tvb = tvb_new_child_real_data(tvb, decompressed_buffer, (guint)uncompressed_size, (gint)uncompressed_size);
        *decompressed_offset = 0;

    }
    ret = 1;
end:
    if (composite_tvb) {
        tvb_composite_finalize(composite_tvb);
        if (ret == 1) {
            *decompressed_tvb = composite_tvb;
            *decompressed_offset = 0;
        }
    }
    if (ret == 0) {
        col_append_str(pinfo->cinfo, COL_INFO, " [snappy decompression failed]");
    }
    return ret;
}


dissect_usb_hid_data(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_)
{
    guint offset = 0;
    proto_item *hid_ti;
    proto_tree _U_ *hid_tree;
    guint remaining = tvb_reported_length_remaining(tvb, offset);

    if (remaining) {
        hid_ti = proto_tree_add_item(tree, hf_usbhid_data, tvb, offset, -1, ENC_NA);
        hid_tree = proto_item_add_subtree(hid_ti, ett_usb_hid_data);
        offset += remaining;
    }

    return offset;
}


static guint coherent_set_key_hash_by_key(gconstpointer key) {
  GBytes * coherent_set_object_key_bytes = NULL;
  coherent_set_object_key_bytes = g_bytes_new(key, sizeof(coherent_set_key));
  return g_bytes_hash(coherent_set_object_key_bytes);
}


static int ep_loop_check_proc(void *priv, void *cookie, int call_nests)
{
	int error = 0;
	struct file *file = priv;
	struct eventpoll *ep = file->private_data;
	struct eventpoll *ep_tovisit;
	struct rb_node *rbp;
	struct epitem *epi;

	mutex_lock_nested(&ep->mtx, call_nests + 1);
	ep->visited = 1;
	list_add(&ep->visited_list_link, &visited_list);
	for (rbp = rb_first_cached(&ep->rbr); rbp; rbp = rb_next(rbp)) {
		epi = rb_entry(rbp, struct epitem, rbn);
		if (unlikely(is_file_epoll(epi->ffd.file))) {
			ep_tovisit = epi->ffd.file->private_data;
			if (ep_tovisit->visited)
				continue;
			error = ep_call_nested(&poll_loop_ncalls,
					ep_loop_check_proc, epi->ffd.file,
					ep_tovisit, current);
			if (error != 0)
				break;
		} else {
			/*
			 * If we've reached a file that is not associated with
			 * an ep, then we need to check if the newly added
			 * links are going to add too many wakeup paths. We do
			 * this by adding it to the tfile_check_list, if it's
			 * not already there, and calling reverse_path_check()
			 * during ep_insert().
			 */
			if (list_empty(&epi->ffd.file->f_tfile_llink))
				list_add(&epi->ffd.file->f_tfile_llink,
					 &tfile_check_list);
		}
	}
	mutex_unlock(&ep->mtx);

	return error;
}