Commit message: None
CVE: CVE-2016-10218
CWE: CWE-476
Vulnerability description: The pdf14_pop_transparency_group function in base/gdevp14.c in the PDF Transparency module in Artifex Software, Inc. Ghostscript 9.20 allows remote attackers to cause a denial of service (NULL pointer dereference and application crash) via a crafted file.

Project: ghostscript
File: gdevp14.c

pdf14_tile_pattern_fill(gx_device * pdev, const gs_gstate * pgs,
                        gx_path * ppath, const gx_fill_params * params,
                        const gx_device_color * pdevc,
                        const gx_clip_path * pcpath)
{
    int code;
    gs_gstate *pgs_noconst = (gs_gstate *)pgs; /* Break const. */
    gs_fixed_rect clip_box;
    gs_fixed_rect outer_box;
    pdf14_device * p14dev = (pdf14_device *)pdev;
    gs_int_rect rect;
    gx_clip_rect *curr_clip_rect;
    gx_color_tile *ptile = NULL;
    int k;
    gx_pattern_trans_t *fill_trans_buffer = NULL;
    gs_int_point phase;  /* Needed during clist rendering for band offset */
    int n_chan_tile;
    gx_clip_path cpath_intersection;
    gx_path path_ttrans;
    gs_blend_mode_t blend_mode;

    if (ppath == NULL)
        return_error(gs_error_unknownerror);	/* should not happen */
    if (pcpath != NULL) {
        code = gx_cpath_init_local_shared_nested(&cpath_intersection, pcpath, ppath->memory, 1);
    } else {
        (*dev_proc(pdev, get_clipping_box)) (pdev, &clip_box);
        gx_cpath_init_local(&cpath_intersection, ppath->memory);
        code = gx_cpath_from_rectangle(&cpath_intersection, &clip_box);
    }
    if (code < 0)
        return code;
    code = gx_cpath_intersect_with_params(&cpath_intersection, ppath,
                                          params->rule, pgs_noconst, params);
    if (code < 0)
        return code;
    /* One (common) case worth optimising for is where we have a pattern that
     * is positioned such that only one repeat of the tile is actually
     * visible. In this case, we can restrict the size of the blending group
     * we need to produce to be that of the actual area of the tile that is
     * used. */
    ptile = pdevc->colors.pattern.p_tile;
    if (ptile->ttrans != NULL)
    {
        if ((cpath_intersection.outer_box.p.x < 0) ||
            (cpath_intersection.outer_box.p.y < 0) ||
            (cpath_intersection.outer_box.q.x > int2fixed(ptile->ttrans->width)) ||
            (cpath_intersection.outer_box.q.y > int2fixed(ptile->ttrans->height)))
        {
            /* More than one repeat of the tile would be visible, so we can't
             * use the optimisation here. (Actually, this test isn't quite
             * right - it actually tests whether more than the '0th' repeat
             * of the tile is visible. A better test would test if just one
             * repeat of the tile was visible, irrespective of which one.
             * This is (hopefully) relatively rare, and would make the code
             * below more complex too, so we're ignoring that for now. If it
             * becomes evident that it's a case that matters we can revisit
             * it.) */
        } else {
            /* Only the 0th repeat is visible. Restrict the size further to
             * just the used area of that patch. */
            gx_path_init_local(&path_ttrans, ppath->memory);
            gx_path_add_rectangle(&path_ttrans,
                                  int2fixed(ptile->ttrans->rect.p.x),
                                  int2fixed(ptile->ttrans->rect.p.y),
                                  int2fixed(ptile->ttrans->rect.q.x),
                                  int2fixed(ptile->ttrans->rect.q.y));
            code = gx_cpath_intersect(&cpath_intersection, &path_ttrans,
                                      params->rule, pgs_noconst);
        }
    }
    /* Now let us push a transparency group into which we are
     * going to tile the pattern.  */
    if (ppath != NULL && code >= 0) {

        gx_cpath_outer_box(&cpath_intersection, &outer_box);
        rect.p.x = fixed2int(outer_box.p.x);
        rect.p.y = fixed2int(outer_box.p.y);
        rect.q.x = fixed2int_ceiling(outer_box.q.x);
        rect.q.y = fixed2int_ceiling(outer_box.q.y);

        /* The color space of this group must be the same as that of the
           tile.  Then when we pop the group, if there is a mismatch between
           the tile color space and the current context we will do the proper
           conversion.  In this way, we ensure that if the tile has any overlapping
           occuring it will be blended in the proper manner i.e in the tile
           underlying color space. */
        if (ptile->cdev == NULL) {
            if (ptile->ttrans == NULL)
                return_error(gs_error_unknownerror);	/* should not happen */
            n_chan_tile = ptile->ttrans->n_chan;
        } else {
            n_chan_tile = ptile->cdev->common.color_info.num_components+1;
        }
        blend_mode = ptile->blending_mode;
        code = pdf14_push_transparency_group(p14dev->ctx, &rect, 1, 0, 255,255,
                                             blend_mode, 0, 0, n_chan_tile-1,
                                             false, NULL, NULL, pgs_noconst,
                                             pdev);
        if (code < 0)
            return code;

        /* Set the blending procs and the is_additive setting based
           upon the number of channels */
        if (ptile->cdev == NULL) {
            if (n_chan_tile-1 < 4) {
                ptile->ttrans->blending_procs = &rgb_blending_procs;
                ptile->ttrans->is_additive = true;
            } else {
                ptile->ttrans->blending_procs = &cmyk_blending_procs;
                ptile->ttrans->is_additive = false;
            }
        }
        /* Now lets go through the rect list and fill with the pattern */
        /* First get the buffer that we will be filling */
        if (ptile->cdev == NULL) {
            fill_trans_buffer = new_pattern_trans_buff(pgs->memory);
            pdf14_get_buffer_information(pdev, fill_trans_buffer, NULL, false);
            /* Based upon if the tiles overlap pick the type of rect fill that we will
               want to use */
            if (ptile->has_overlap) {
                /* This one does blending since there is tile overlap */
                ptile->ttrans->pat_trans_fill = &tile_rect_trans_blend;
            } else {
                /* This one does no blending since there is no tile overlap */
                ptile->ttrans->pat_trans_fill = &tile_rect_trans_simple;
            }
            /* fill the rectangles */
            phase.x = pdevc->phase.x;
            phase.y = pdevc->phase.y;
            if (cpath_intersection.rect_list->list.head != NULL){
                curr_clip_rect = cpath_intersection.rect_list->list.head->next;
                for( k = 0; k< cpath_intersection.rect_list->list.count; k++){
                    if_debug5m('v', pgs->memory,
                               "[v]pdf14_tile_pattern_fill, (%d, %d), %d x %d pat_id %d \n",
                               curr_clip_rect->xmin, curr_clip_rect->ymin,
                               curr_clip_rect->xmax-curr_clip_rect->xmin,
                               curr_clip_rect->ymax-curr_clip_rect->ymin, (int)ptile->id);
                    gx_trans_pattern_fill_rect(curr_clip_rect->xmin, curr_clip_rect->ymin,
                                curr_clip_rect->xmax, curr_clip_rect->ymax, ptile,
                                fill_trans_buffer, phase, pdev, pdevc);
                    curr_clip_rect = curr_clip_rect->next;
                }
            } else if (cpath_intersection.rect_list->list.count == 1) {
                /* The case when there is just a single rect */
                if_debug5m('v', pgs->memory,
                           "[v]pdf14_tile_pattern_fill, (%d, %d), %d x %d pat_id %d \n",
                           cpath_intersection.rect_list->list.single.xmin,
                           cpath_intersection.rect_list->list.single.ymin,
                           cpath_intersection.rect_list->list.single.xmax-
                              cpath_intersection.rect_list->list.single.xmin,
                           cpath_intersection.rect_list->list.single.ymax-
                              cpath_intersection.rect_list->list.single.ymin,
                           (int)ptile->id);
                gx_trans_pattern_fill_rect(cpath_intersection.rect_list->list.single.xmin,
                                                cpath_intersection.rect_list->list.single.ymin,
                                                cpath_intersection.rect_list->list.single.xmax,
                                                cpath_intersection.rect_list->list.single.ymax,
                                                ptile, fill_trans_buffer, phase, pdev, pdevc);
            }
        } else {
            /* Clist pattern with transparency.  Create a clip device from our
               cpath_intersection.  The above non-clist case could probably be
               done this way too, which will reduce the amount of code here.
               That is for another day though due to time constraints*/
            gx_device *dev;
            gx_device_clip clipdev;

            gx_make_clip_device_on_stack(&clipdev, &cpath_intersection, pdev);
            dev = (gx_device *)&clipdev;
            phase.x = pdevc->phase.x;
            phase.y = pdevc->phase.y;
            gx_trans_pattern_fill_rect(rect.p.x, rect.p.y, rect.q.x, rect.q.y,
                                            ptile, fill_trans_buffer, phase,
                                            dev, pdevc);
        }
        /* free our buffer object */
        if (fill_trans_buffer != NULL) {
            gs_free_object(pgs->memory, fill_trans_buffer, "pdf14_tile_pattern_fill");
            ptile->ttrans->fill_trans_buffer = NULL;  /* Avoid GC issues */
        }
        /* pop our transparency group which will force the blending.
           This was all needed for Bug 693498 */
        code = pdf14_pop_transparency_group(pgs_noconst, p14dev->ctx,
                                            p14dev->blend_procs,
                                            p14dev->color_info.num_components,
                                            p14dev->icc_struct->device_profile[0],
                                            pdev);
    }
    return code;
}

Project: ghostscript
File: gdevp14.c

pdf14_update_device_color_procs(gx_device *dev,
                              gs_transparency_color_t group_color,
                              int64_t icc_hashcode, gs_gstate *pgs,
                              cmm_profile_t *iccprofile, bool is_mask)
{
    pdf14_device *pdevproto = NULL;
    pdf14_device *pdev = (pdf14_device *)dev;
    const pdf14_procs_t *new_14procs = NULL;
    pdf14_parent_color_t *parent_color_info;
    gx_color_polarity_t new_polarity;
    uchar new_num_comps;
    bool new_additive;
    gx_device_clist_reader *pcrdev;
    byte comp_bits[GX_DEVICE_COLOR_MAX_COMPONENTS];
    byte comp_shift[GX_DEVICE_COLOR_MAX_COMPONENTS];
    int k;
    bool has_tags = dev->graphics_type_tag & GS_DEVICE_ENCODES_TAGS;
    gsicc_rendering_param_t render_cond;
    cmm_dev_profile_t *dev_profile;

    if (pdev->ctx->stack != NULL){
        parent_color_info = pdev->ctx->stack->parent_color_info_procs;
    } else {
        /* This should not occur */
        return_error(gs_error_undefined);
    }
    if_debug0m('v', dev->memory, "[v]pdf14_update_device_color_procs\n");

    memset(comp_bits, 0, GX_DEVICE_COLOR_MAX_COMPONENTS);
    memset(comp_shift, 0, GX_DEVICE_COLOR_MAX_COMPONENTS);

    /* Update the device procs at this stage.  Many of the procs are based upon
       the color space of the device.  We want to remain in the color space
       defined by the color space of the soft mask or transparency group as
       opposed to the device color space. Later, when we pop the softmask we will
       collapse it to a single band and then compose with it to the device color
       space (or the parent layer space).  In the case where we pop an isolated
       transparency group, we will do the blending in the proper color space and
       then transform the data when we pop the group. Remember that only isolated
       groups can have color spaces that are different than their parent.
       Separation devices that have to maintain separate spot color planes need
       special handling here */
    parent_color_info->get_cmap_procs = NULL;
    parent_color_info->parent_color_mapping_procs = NULL;
    parent_color_info->parent_color_comp_index = NULL;

    switch (group_color) {
        case GRAY_SCALE:
            new_polarity = GX_CINFO_POLARITY_ADDITIVE;
            new_num_comps = 1;
            pdevproto = (pdf14_device *)&gs_pdf14_Gray_device;
            new_additive = true;
            new_14procs = &gray_pdf14_procs;
            comp_bits[0] = 8;
            comp_shift[0] = 0;
            break;
        case DEVICE_RGB:
        case CIE_XYZ:
            new_polarity = GX_CINFO_POLARITY_ADDITIVE;
            new_num_comps = 3;
            pdevproto = (pdf14_device *)&gs_pdf14_RGB_device;
            new_additive = true;
            new_14procs = &rgb_pdf14_procs;
            for (k = 0; k < 3; k++) {
                comp_bits[k] = 8;
                comp_shift[k] = (2 - k) * 8;
            }
            break;
        case DEVICE_CMYK:
            new_polarity = GX_CINFO_POLARITY_SUBTRACTIVE;
            new_num_comps = 4;
            pdevproto = (pdf14_device *)&gs_pdf14_CMYK_device;
            new_additive = false;
            /* This is needed due to the mismatched compressed encode decode
                between the device procs and the pdf14 procs */
            if (dev->color_info.num_components > 4){
                new_14procs = &cmykspot_pdf14_procs;
            } else {
                new_14procs = &cmyk_pdf14_procs;
            }
            for (k = 0; k < 4; k++) {
                comp_bits[k] = 8;
                comp_shift[k] = (3 - k) * 8;
            }
            break;
        case ICC:
            /* If we are coming from the clist reader, then we need to get
                the ICC data now  */
            if (iccprofile == NULL && pdev->pclist_device != NULL) {
                /* Get the serialized data from the clist.  Not the whole
                    profile. */
                pcrdev = (gx_device_clist_reader *)(pdev->pclist_device);
                iccprofile = gsicc_read_serial_icc((gx_device *) pcrdev,
                                                    icc_hashcode);
                if (iccprofile == NULL)
                    return gs_throw(gs_error_unknownerror, "ICC data not found in clist");
                /* Keep a pointer to the clist device */
                iccprofile->dev = (gx_device *) pcrdev;
            } else {
                /* Go ahead and rc increment right now.  This way when
                    we pop, we will make sure to decrement and avoid a
                    leak for the above profile that we just created */
                if (iccprofile == NULL)
                    return gs_throw(gs_error_unknownerror, "ICC data unknown");
                rc_increment(iccprofile);
            }
            new_num_comps = iccprofile->num_comps;
            if (new_num_comps == 4) {
                new_additive = false;
                new_polarity = GX_CINFO_POLARITY_SUBTRACTIVE;
            } else {
                new_additive = true;
                new_polarity = GX_CINFO_POLARITY_ADDITIVE;
            }
            switch (new_num_comps) {
                case 1:
                    if (pdev->sep_device && !is_mask) {
                        pdevproto = (pdf14_device *)&gs_pdf14_Grayspot_device;
                        new_14procs = &grayspot_pdf14_procs;
                    } else {
                        pdevproto = (pdf14_device *)&gs_pdf14_Gray_device;
                        new_14procs = &gray_pdf14_procs;
                    }
                    comp_bits[0] = 8;
                    comp_shift[0] = 0;
                    break;
                case 3:
                    if (pdev->sep_device) {
                        pdevproto = (pdf14_device *)&gs_pdf14_RGBspot_device;
                        new_14procs = &rgbspot_pdf14_procs;
                    }
                    else {
                        pdevproto = (pdf14_device *)&gs_pdf14_RGB_device;
                        new_14procs = &rgb_pdf14_procs;
                    }
                    for (k = 0; k < 3; k++) {
                        comp_bits[k] = 8;
                        comp_shift[k] = (2 - k) * 8;
                    }
                    break;
                case 4:
                    if (pdev->sep_device) {
                        pdevproto = (pdf14_device *)&gs_pdf14_CMYKspot_device;
                        new_14procs = &cmykspot_pdf14_procs;
                    } else {
                        pdevproto = (pdf14_device *)&gs_pdf14_CMYK_device;
                        new_14procs = &cmyk_pdf14_procs;
                    }
                    for (k = 0; k < 4; k++) {
                        comp_bits[k] = 8;
                        comp_shift[k] = (3 - k) * 8;
                    }
                    break;
                default:
                    return_error(gs_error_rangecheck);
                    break;
            }
            break;
        default:
            return_error(gs_error_rangecheck);
            break;
        }
    if_debug2m('v', pdev->memory,
                "[v]pdf14_update_device_color_procs,num_components_old = %d num_components_new = %d\n",
                pdev->color_info.num_components,new_num_comps);

    /* Save the old information */
    parent_color_info->get_cmap_procs = pgs->get_cmap_procs;
    parent_color_info->parent_color_mapping_procs =
        pdev->procs.get_color_mapping_procs;
    parent_color_info->parent_color_comp_index =
        pdev->procs.get_color_comp_index;
    parent_color_info->parent_blending_procs = pdev->blend_procs;
    parent_color_info->polarity =              pdev->color_info.polarity;
    parent_color_info->num_components =        pdev->color_info.num_components;
    parent_color_info->isadditive =            pdev->ctx->additive;
    parent_color_info->unpack_procs =          pdev->pdf14_procs;
    parent_color_info->depth =                 pdev->color_info.depth;
    parent_color_info->max_color =             pdev->color_info.max_color;
    parent_color_info->max_gray =              pdev->color_info.max_gray;
    parent_color_info->encode =                pdev->procs.encode_color;
    parent_color_info->decode =                pdev->procs.decode_color;
    memcpy(&(parent_color_info->comp_bits), &(pdev->color_info.comp_bits),
        GX_DEVICE_COLOR_MAX_COMPONENTS);
    memcpy(&(parent_color_info->comp_shift), &(pdev->color_info.comp_shift),
        GX_DEVICE_COLOR_MAX_COMPONENTS);

    /* Don't increment the space since we are going to remove it from the
        ICC manager anyway.  */
    if (group_color == ICC && iccprofile != NULL) {
        dev_proc(dev, get_profile)(dev, &dev_profile);
        gsicc_extract_profile(GS_UNKNOWN_TAG, dev_profile,
                                &(parent_color_info->icc_profile), &render_cond);
    }
    /* Set new information */
    /* If we are a sep device and this is not a softmask, ensure we maintain the
       spot colorants and know how to index into them */
    if (pdev->sep_device && !is_mask) {
        int num_spots = parent_color_info->num_components -
            parent_color_info->icc_profile->num_comps;

        if (num_spots > 0) {
            new_num_comps += num_spots;
            for (k = 0; k < new_num_comps; k++) {
                comp_bits[k] = 8;
                comp_shift[k] = (new_num_comps - k - 1) * 8;
            }
        }
    }

    pdev->procs.get_color_mapping_procs =
        pdevproto->static_procs->get_color_mapping_procs;
    pdev->procs.get_color_comp_index =
        pdevproto->static_procs->get_color_comp_index;
    pdev->blend_procs = pdevproto->blend_procs;
    pdev->color_info.polarity = new_polarity;
    pdev->color_info.num_components = new_num_comps;
    pdev->ctx->additive = new_additive;
    pdev->pdf14_procs = new_14procs;
    pdev->color_info.depth = new_num_comps * 8;
    if (has_tags) {
        pdev->color_info.depth += 8;
    }
    memset(&(pdev->color_info.comp_bits), 0, GX_DEVICE_COLOR_MAX_COMPONENTS);
    memset(&(pdev->color_info.comp_shift), 0, GX_DEVICE_COLOR_MAX_COMPONENTS);
    memcpy(&(pdev->color_info.comp_bits), comp_bits, 4);
    memcpy(&(pdev->color_info.comp_shift), comp_shift, 4);
    pdev->color_info.max_color = 255;
    pdev->color_info.max_gray = 255;
    /* If the CS was ICC based, we need to update the device ICC profile
        in the ICC manager, since that is the profile that is used for the
        PDF14 device */
    if (group_color == ICC && iccprofile != NULL) {
        /* iccprofile was incremented above if we had not just created it.
           When we do the pop we will decrement and if we just created it, it
           will be destroyed */
        dev->icc_struct->device_profile[0] = iccprofile;
        rc_increment(parent_color_info->icc_profile);
    }
    return 1;  /* Lets us detect that we did do an update */
}

Project: ghostscript
File: gdevp14.c

pdf14_update_device_color_procs_push_c(gx_device *dev,
                              gs_transparency_color_t group_color, int64_t icc_hashcode,
                              gs_gstate *pgs, cmm_profile_t *icc_profile, bool is_mask)
{
    pdf14_device *pdevproto;
    pdf14_device *pdev = (pdf14_device *)dev;
    gx_device_clist_writer * cldev = (gx_device_clist_writer *)pdev->pclist_device;
    const pdf14_procs_t *new_14procs;
    bool update_color_info;
    gx_color_polarity_t new_polarity;
    int new_num_comps;
    bool new_additive = false;
    byte new_depth;
    byte comp_bits[GX_DEVICE_COLOR_MAX_COMPONENTS];
    byte comp_shift[GX_DEVICE_COLOR_MAX_COMPONENTS];
    int k;
    bool has_tags = dev->graphics_type_tag & GS_DEVICE_ENCODES_TAGS;
    cmm_profile_t *icc_profile_dev;
    gsicc_rendering_param_t render_cond;
    cmm_dev_profile_t *dev_profile;

    memset(comp_bits, 0, GX_DEVICE_COLOR_MAX_COMPONENTS);
    memset(comp_shift, 0, GX_DEVICE_COLOR_MAX_COMPONENTS);

    if (group_color == ICC && icc_profile == NULL)
        return gs_throw(gs_error_undefinedresult, "Missing ICC data");
    if_debug0m('v', cldev->memory, "[v]pdf14_update_device_color_procs_push_c\n");
   /* Check if we need to alter the device procs at this stage.  Many of the procs
      are based upon the color space of the device.  We want to remain in the
      color space defined by the color space of the soft mask or transparency
      group as opposed to the device color space. Later, when we pop the softmask
      we will collapse it to a single band and then compose with it to the device
      color space (or the parent layer space).  In the case where we pop an
      isolated transparency group, we will do the blending in the proper color
      space and then transform the data when we pop the group.  Remember that only
      isolated groups can have color spaces that are different than their parent. */
        update_color_info = false;
        switch (group_color) {
            case GRAY_SCALE:
                  if (pdev->color_info.num_components != 1){
                    update_color_info = true;
                    new_polarity = GX_CINFO_POLARITY_ADDITIVE;
                    new_num_comps = 1;
                    pdevproto = (pdf14_device *)&gs_pdf14_Gray_device;
                    new_additive = true;
                    new_14procs = &gray_pdf14_procs;
                    new_depth = 8;
                    comp_bits[0] = 8;
                    comp_shift[0] = 0;
                }
                break;
            case DEVICE_RGB:
            case CIE_XYZ:
                if (pdev->color_info.num_components != 3){
                    update_color_info = true;
                    new_polarity = GX_CINFO_POLARITY_ADDITIVE;
                    new_num_comps = 3;
                    pdevproto = (pdf14_device *)&gs_pdf14_RGB_device;
                    new_additive = true;
                    new_14procs = &rgb_pdf14_procs;
                    new_depth = 24;
                    for (k = 0; k < 3; k++) {
                        comp_bits[k] = 8;
                        comp_shift[k] = (2-k)*8;
                    }
                }
                break;
            case DEVICE_CMYK:
                if (pdev->color_info.num_components != 4){
                    update_color_info = true;
                    new_polarity = GX_CINFO_POLARITY_SUBTRACTIVE;
                    new_num_comps = 4;
                    pdevproto = (pdf14_device *)&gs_pdf14_CMYK_device;
                    new_additive = false;
                /* This is needed due to the mismatched compressed encode decode
                   between the device procs and the pdf14 procs */
                    if (dev->color_info.num_components > 4){
                        new_14procs = &cmykspot_pdf14_procs;
                    } else {
                        new_14procs = &cmyk_pdf14_procs;
                    }
                    new_depth = 32;
                    for (k = 0; k < 4; k++) {
                        comp_bits[k] = 8;
                        comp_shift[k] = (3-k)*8;
                    }
                }
                break;
            case ICC:
                /* Check if the profile is different. */
                dev_proc(dev, get_profile)(dev,  &dev_profile);
                gsicc_extract_profile(GS_UNKNOWN_TAG, dev_profile,
                                      &icc_profile_dev, &render_cond);
                if (icc_profile_dev->hashcode != icc_profile->hashcode) {
                    update_color_info = true;
                    new_num_comps = icc_profile->num_comps;
                    new_depth = icc_profile->num_comps * 8;
                    switch (new_num_comps) {
                    case 1:
                        if (pdev->sep_device && !is_mask) {
                            pdevproto = (pdf14_device *)&gs_pdf14_Grayspot_device;
                            new_14procs = &grayspot_pdf14_procs;
                        } else {
                            pdevproto = (pdf14_device *)&gs_pdf14_Gray_device;
                            new_14procs = &gray_pdf14_procs;
                        }
                        new_polarity = GX_CINFO_POLARITY_ADDITIVE;
                        new_additive = true;
                        comp_bits[0] = 8;
                        comp_shift[0] = 0;
                        break;
                    case 3:
                        if (pdev->sep_device) {
                            pdevproto = (pdf14_device *)&gs_pdf14_RGBspot_device;
                            new_14procs = &rgbspot_pdf14_procs;
                        } else {
                            pdevproto = (pdf14_device *)&gs_pdf14_RGB_device;
                            new_14procs = &rgb_pdf14_procs;
                        }
                        new_polarity = GX_CINFO_POLARITY_ADDITIVE;
                        new_additive = true;
                        for (k = 0; k < 3; k++) {
                            comp_bits[k] = 8;
                            comp_shift[k] = (2-k)*8;
                        }
                        break;
                    case 4:
                        if (pdev->sep_device) {
                            pdevproto = (pdf14_device *)&gs_pdf14_CMYKspot_device;
                            new_14procs = &cmykspot_pdf14_procs;
                        } else {
                            pdevproto = (pdf14_device *)&gs_pdf14_CMYK_device;
                            new_14procs = &cmyk_pdf14_procs;
                        }
                        new_polarity = GX_CINFO_POLARITY_SUBTRACTIVE;
                        new_additive = false;
                        for (k = 0; k < 4; k++) {
                            comp_bits[k] = 8;
                            comp_shift[k] = (3-k)*8;
                        }
                        break;
                    default:
                        return gs_throw(gs_error_undefinedresult,
                                        "ICC Number of colorants illegal");
                    }
                }
                break;
            case UNKNOWN:
                return 0;
                break;
            default:
                return_error(gs_error_rangecheck);
                break;
         }
         if (update_color_info){
             if (pdev->sep_device && !is_mask) {
                 int num_spots = pdev->color_info.num_components -
                     icc_profile_dev->num_comps;
                 if (num_spots > 0) {
                     new_num_comps += num_spots;
                     for (k = 0; k < new_num_comps; k++) {
                         comp_bits[k] = 8;
                         comp_shift[k] = (new_num_comps - k - 1) * 8;

                     }
                 }
             }
             if (has_tags) {
                 new_depth += 8;
             }
            if_debug2m('v', pdev->memory,
                       "[v]pdf14_update_device_color_procs_push_c,num_components_old = %d num_components_new = %d\n",
                       pdev->color_info.num_components,new_num_comps);
            /* Set new information in the device */
            pdev->procs.get_color_mapping_procs =
                pdevproto->static_procs->get_color_mapping_procs;
            pdev->procs.get_color_comp_index =
                pdevproto->static_procs->get_color_comp_index;
            pdev->blend_procs = pdevproto->blend_procs;
            pdev->color_info.polarity = new_polarity;
            pdev->color_info.num_components = new_num_comps;
            pdev->color_info.max_color = 255;
            pdev->color_info.max_gray = 255;
            pdev->pdf14_procs = new_14procs;
            pdev->color_info.depth = new_num_comps * 8;
            memset(&(pdev->color_info.comp_bits),0,GX_DEVICE_COLOR_MAX_COMPONENTS);
            memset(&(pdev->color_info.comp_shift),0,GX_DEVICE_COLOR_MAX_COMPONENTS);
            memcpy(&(pdev->color_info.comp_bits),comp_bits,4);
            memcpy(&(pdev->color_info.comp_shift),comp_shift,4);
            /* If we have a compressed color codec, and we are doing a soft mask
               push operation then go ahead and update the color encode and
               decode for the pdf14 device to not used compressed color
               encoding while in the soft mask.  We will just check for gray
               and compressed.  Note that we probably don't have_tags if we
               are dealing with compressed color.  But is is possible so
               we add it in to catch for future use. */
            cldev->clist_color_info.depth = pdev->color_info.depth;
            cldev->clist_color_info.polarity = pdev->color_info.polarity;
            cldev->clist_color_info.num_components = pdev->color_info.num_components;
            cldev->clist_color_info.max_color = pdev->color_info.max_color;
            cldev->clist_color_info.max_gray = pdev->color_info.max_gray;
            /* For the ICC profiles, we want to update the ICC profile for the
               device in the ICC manager.  We already stored in in pdf14_parent_color_t.
               That will be stored in the clist and restored during the reading phase. */
           if (group_color == ICC) {
                dev->icc_struct->device_profile[0] = icc_profile;
            }
            if (pdev->ctx) {
               pdev->ctx->additive = new_additive;
            }
            return(1);  /* Lets us detect that we did do an update */
         }
         if_debug0m('v', pdev->memory, "[v]procs not updated\n");
         return 0;
}

Project: ghostscript
File: gdevp14.c

put_param_pdf14_spot_names(gx_device * pdev,
                gs_separations * pseparations, gs_param_list * plist)
{
    int code, num_spot_colors, i;
    gs_param_string str;

    /* Check if the given keyname is present. */
    code = param_read_int(plist, PDF14NumSpotColorsParamName,
                                                &num_spot_colors);
    switch (code) {
        default:
            param_signal_error(plist, PDF14NumSpotColorsParamName, code);
            break;
        case 1:
            return 0;
        case 0:
            if (num_spot_colors < 1 ||
                num_spot_colors > GX_DEVICE_COLOR_MAX_COMPONENTS)
                return_error(gs_error_rangecheck);
            for (i = 0; i < num_spot_colors; i++) {
                char buff[20];
                byte * sep_name;

                gs_sprintf(buff, "PDF14SpotName_%d", i);
                code = param_read_string(plist, buff, &str);
                switch (code) {
                    default:
                        param_signal_error(plist, buff, code);
                        break;
                    case 0:
                        sep_name = gs_alloc_bytes(pdev->memory,
                                str.size, "put_param_pdf14_spot_names");
                        memcpy(sep_name, str.data, str.size);
                        pseparations->names[i].size = str.size;
                        pseparations->names[i].data = sep_name;
                }
            }
            pseparations->num_separations = num_spot_colors;
            break;
    }
    return 0;;
}

Project: ghostscript
File: gdevp14.c

rc_pdf14_maskbuf_free(gs_memory_t * mem, void *ptr_in, client_name_t cname)
{
    /* Ending the mask buffer. */
    pdf14_rcmask_t *rcmask = (pdf14_rcmask_t * ) ptr_in;
    /* free the pdf14 buffer. */
    if ( rcmask->mask_buf != NULL ){
        pdf14_buf_free(rcmask->mask_buf, mem);
    }
    gs_free_object(mem, rcmask, "rc_pdf14_maskbuf_free");
}

Project: ghostscript
File: gdevp14.c

send_pdf14trans(gs_gstate	* pgs, gx_device * dev,
    gx_device * * pcdev, gs_pdf14trans_params_t * pparams, gs_memory_t * mem)
{
    gs_composite_t * pct = NULL;
    int code;

    pparams->ctm = ctm_only(pgs);
    code = gs_create_pdf14trans(&pct, pparams, mem);
    if (code < 0)
        return code;
    code = dev_proc(dev, create_compositor) (dev, pcdev, pct, pgs, mem, NULL);
    if (code == gs_error_handled)
        code = 0;

    gs_free_object(pgs->memory, pct, "send_pdf14trans");

    return code;
}