static OPJ_BOOL opj_jp2_read_pclr(opj_jp2_t *jp2,
                                  OPJ_BYTE * p_pclr_header_data,
                                  OPJ_UINT32 p_pclr_header_size,
                                  opj_event_mgr_t * p_manager
                                 )
{
    opj_jp2_pclr_t *jp2_pclr;
    OPJ_BYTE *channel_size, *channel_sign;
    OPJ_UINT32 *entries;
    OPJ_UINT16 nr_entries, nr_channels;
    OPJ_UINT16 i, j;
    OPJ_UINT32 l_value;
    OPJ_BYTE *orig_header_data = p_pclr_header_data;

    /* preconditions */
    assert(p_pclr_header_data != 00);
    assert(jp2 != 00);
    assert(p_manager != 00);
    (void)p_pclr_header_size;

    if (jp2->color.jp2_pclr) {
        return OPJ_FALSE;
    }

    if (p_pclr_header_size < 3) {
        return OPJ_FALSE;
    }

    opj_read_bytes(p_pclr_header_data, &l_value, 2);    /* NE */
    p_pclr_header_data += 2;
    nr_entries = (OPJ_UINT16) l_value;
    if ((nr_entries == 0U) || (nr_entries > 1024U)) {
        opj_event_msg(p_manager, EVT_ERROR, "Invalid PCLR box. Reports %d entries\n",
                      (int)nr_entries);
        return OPJ_FALSE;
    }

    opj_read_bytes(p_pclr_header_data, &l_value, 1);    /* NPC */
    ++p_pclr_header_data;
    nr_channels = (OPJ_UINT16) l_value;
    if (nr_channels == 0U) {
        opj_event_msg(p_manager, EVT_ERROR,
                      "Invalid PCLR box. Reports 0 palette columns\n");
        return OPJ_FALSE;
    }

    if (p_pclr_header_size < 3 + (OPJ_UINT32)nr_channels) {
        return OPJ_FALSE;
    }

    entries = (OPJ_UINT32*) opj_malloc(sizeof(OPJ_UINT32) * nr_channels *
                                       nr_entries);
    if (!entries) {
        return OPJ_FALSE;
    }
    channel_size = (OPJ_BYTE*) opj_malloc(nr_channels);
    if (!channel_size) {
        opj_free(entries);
        return OPJ_FALSE;
    }
    channel_sign = (OPJ_BYTE*) opj_malloc(nr_channels);
    if (!channel_sign) {
        opj_free(entries);
        opj_free(channel_size);
        return OPJ_FALSE;
    }

    jp2_pclr = (opj_jp2_pclr_t*)opj_malloc(sizeof(opj_jp2_pclr_t));
    if (!jp2_pclr) {
        opj_free(entries);
        opj_free(channel_size);
        opj_free(channel_sign);
        return OPJ_FALSE;
    }

    jp2_pclr->channel_sign = channel_sign;
    jp2_pclr->channel_size = channel_size;
    jp2_pclr->entries = entries;
    jp2_pclr->nr_entries = nr_entries;
    jp2_pclr->nr_channels = (OPJ_BYTE) l_value;
    jp2_pclr->cmap = NULL;

    jp2->color.jp2_pclr = jp2_pclr;

    for (i = 0; i < nr_channels; ++i) {
        opj_read_bytes(p_pclr_header_data, &l_value, 1);    /* Bi */
        ++p_pclr_header_data;

        channel_size[i] = (OPJ_BYTE)((l_value & 0x7f) + 1);
        channel_sign[i] = (l_value & 0x80) ? 1 : 0;
    }

    for (j = 0; j < nr_entries; ++j) {
        for (i = 0; i < nr_channels; ++i) {
            OPJ_UINT32 bytes_to_read = (OPJ_UINT32)((channel_size[i] + 7) >> 3);

            if (bytes_to_read > sizeof(OPJ_UINT32)) {
                bytes_to_read = sizeof(OPJ_UINT32);
            }
            if ((ptrdiff_t)p_pclr_header_size < (ptrdiff_t)(p_pclr_header_data -
                    orig_header_data) + (ptrdiff_t)bytes_to_read) {
                return OPJ_FALSE;
            }

            opj_read_bytes(p_pclr_header_data, &l_value, bytes_to_read);    /* Cji */
            p_pclr_header_data += bytes_to_read;
            *entries = (OPJ_UINT32) l_value;
            entries++;
        }
    }

    return OPJ_TRUE;
}