tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

c_bindings.rs (16110B)


      1 #![allow(clippy::missing_safety_doc)]
      2 
      3 use std::{ptr::null_mut, slice};
      4 
      5 use libc::{fclose, fopen, fread, free, malloc, memset, FILE};
      6 
      7 use crate::{
      8    double_to_s15Fixed16Number,
      9    iccread::*,
     10    s15Fixed16Number_to_float,
     11    transform::get_rgb_colorants,
     12    transform::DataType,
     13    transform::{qcms_transform, transform_create},
     14    transform_util,
     15    Intent,
     16 };
     17 
     18 #[no_mangle]
     19 pub extern "C" fn qcms_profile_sRGB() -> *mut Profile {
     20    let profile = Profile::new_sRGB();
     21    Box::into_raw(profile)
     22 }
     23 
     24 #[no_mangle]
     25 pub extern "C" fn qcms_profile_displayP3() -> *mut Profile {
     26    let profile = Profile::new_displayP3();
     27    Box::into_raw(profile)
     28 }
     29 
     30 
     31 //XXX: it would be nice if we had a way of ensuring
     32 // everything in a profile was initialized regardless of how it was created
     33 //XXX: should this also be taking a black_point?
     34 /* similar to CGColorSpaceCreateCalibratedRGB */
     35 #[no_mangle]
     36 pub unsafe extern "C" fn qcms_profile_create_rgb_with_gamma_set(
     37    white_point: qcms_CIE_xyY,
     38    primaries: qcms_CIE_xyYTRIPLE,
     39    redGamma: f32,
     40    greenGamma: f32,
     41    blueGamma: f32,
     42 ) -> *mut Profile {
     43    let profile =
     44        Profile::new_rgb_with_gamma_set(white_point, primaries, redGamma, greenGamma, blueGamma);
     45    profile.map_or_else(null_mut, Box::into_raw)
     46 }
     47 
     48 #[no_mangle]
     49 pub unsafe extern "C" fn qcms_profile_create_gray_with_gamma(gamma: f32) -> *mut Profile {
     50    let profile = Profile::new_gray_with_gamma(gamma);
     51    Box::into_raw(profile)
     52 }
     53 
     54 #[no_mangle]
     55 pub unsafe extern "C" fn qcms_profile_create_rgb_with_gamma(
     56    white_point: qcms_CIE_xyY,
     57    primaries: qcms_CIE_xyYTRIPLE,
     58    gamma: f32,
     59 ) -> *mut Profile {
     60    qcms_profile_create_rgb_with_gamma_set(white_point, primaries, gamma, gamma, gamma)
     61 }
     62 
     63 #[no_mangle]
     64 pub unsafe extern "C" fn qcms_profile_create_rgb_with_table(
     65    white_point: qcms_CIE_xyY,
     66    primaries: qcms_CIE_xyYTRIPLE,
     67    table: *const u16,
     68    num_entries: i32,
     69 ) -> *mut Profile {
     70    let table = slice::from_raw_parts(table, num_entries as usize);
     71    let profile = Profile::new_rgb_with_table(white_point, primaries, table);
     72    profile.map_or_else(null_mut, Box::into_raw)
     73 }
     74 
     75 #[no_mangle]
     76 pub unsafe extern "C" fn qcms_profile_create_cicp(
     77    colour_primaries: u8,
     78    transfer_characteristics: u8,
     79 ) -> *mut Profile {
     80    Profile::new_cicp(colour_primaries.into(), transfer_characteristics.into())
     81        .map_or_else(null_mut, Box::into_raw)
     82 }
     83 
     84 /* qcms_profile_from_memory does not hold a reference to the memory passed in */
     85 #[no_mangle]
     86 pub unsafe extern "C" fn qcms_profile_from_memory(
     87    mem: *const libc::c_void,
     88    size: usize,
     89 ) -> *mut Profile {
     90    let mem = slice::from_raw_parts(mem as *const libc::c_uchar, size);
     91    let profile = Profile::new_from_slice(mem, false);
     92    profile.map_or_else(null_mut, Box::into_raw)
     93 }
     94 
     95 #[no_mangle]
     96 pub unsafe extern "C" fn qcms_profile_from_memory_curves_only(
     97    mem: *const libc::c_void,
     98    size: usize,
     99 ) -> *mut Profile {
    100    let mem = slice::from_raw_parts(mem as *const libc::c_uchar, size);
    101    let profile = Profile::new_from_slice(mem, true);
    102    profile.map_or_else(null_mut, Box::into_raw)
    103 }
    104 
    105 
    106 #[no_mangle]
    107 pub extern "C" fn qcms_profile_get_rendering_intent(profile: &Profile) -> Intent {
    108    profile.rendering_intent
    109 }
    110 #[no_mangle]
    111 pub extern "C" fn qcms_profile_get_color_space(profile: &Profile) -> icColorSpaceSignature {
    112    profile.color_space
    113 }
    114 #[no_mangle]
    115 pub extern "C" fn qcms_profile_is_sRGB(profile: &Profile) -> bool {
    116    profile.is_sRGB()
    117 }
    118 
    119 #[no_mangle]
    120 pub unsafe extern "C" fn qcms_profile_release(profile: *mut Profile) {
    121    drop(Box::from_raw(profile));
    122 }
    123 unsafe extern "C" fn qcms_data_from_file(
    124    file: *mut FILE,
    125    mem: *mut *mut libc::c_void,
    126    size: *mut usize,
    127 ) {
    128    let length: u32;
    129    let remaining_length: u32;
    130    let read_length: usize;
    131    let mut length_be: u32 = 0;
    132    let data: *mut libc::c_void;
    133    *mem = std::ptr::null_mut::<libc::c_void>();
    134    *size = 0;
    135    if fread(
    136        &mut length_be as *mut u32 as *mut libc::c_void,
    137        1,
    138        ::std::mem::size_of::<u32>(),
    139        file,
    140    ) != ::std::mem::size_of::<u32>()
    141    {
    142        return;
    143    }
    144    length = u32::from_be(length_be);
    145    if length > MAX_PROFILE_SIZE as libc::c_uint
    146        || (length as libc::c_ulong) < ::std::mem::size_of::<u32>() as libc::c_ulong
    147    {
    148        return;
    149    }
    150    /* allocate room for the entire profile */
    151    data = malloc(length as usize);
    152    if data.is_null() {
    153        return;
    154    }
    155    /* copy in length to the front so that the buffer will contain the entire profile */
    156    *(data as *mut u32) = length_be;
    157    remaining_length =
    158        (length as libc::c_ulong - ::std::mem::size_of::<u32>() as libc::c_ulong) as u32;
    159    /* read the rest profile */
    160    read_length = fread(
    161        (data as *mut libc::c_uchar).add(::std::mem::size_of::<u32>()) as *mut libc::c_void,
    162        1,
    163        remaining_length as usize,
    164        file,
    165    ) as usize;
    166    if read_length != remaining_length as usize {
    167        free(data);
    168        return;
    169    }
    170    /* successfully get the profile.*/
    171    *mem = data;
    172    *size = length as usize;
    173 }
    174 
    175 #[no_mangle]
    176 pub unsafe extern "C" fn qcms_profile_from_file(file: *mut FILE) -> *mut Profile {
    177    let mut length: usize = 0;
    178    let profile: *mut Profile;
    179    let mut data: *mut libc::c_void = std::ptr::null_mut::<libc::c_void>();
    180    qcms_data_from_file(file, &mut data, &mut length);
    181    if data.is_null() || length == 0 {
    182        return std::ptr::null_mut::<Profile>();
    183    }
    184    profile = qcms_profile_from_memory(data, length);
    185    free(data);
    186    profile
    187 }
    188 #[no_mangle]
    189 pub unsafe extern "C" fn qcms_profile_from_path(path: *const libc::c_char) -> *mut Profile {
    190    if let Ok(Some(boxed_profile)) = std::ffi::CStr::from_ptr(path)
    191        .to_str()
    192        .map(Profile::new_from_path)
    193    {
    194        Box::into_raw(boxed_profile)
    195    } else {
    196        std::ptr::null_mut()
    197    }
    198 }
    199 
    200 #[no_mangle]
    201 pub unsafe extern "C" fn qcms_data_from_path(
    202    path: *const libc::c_char,
    203    mem: *mut *mut libc::c_void,
    204    size: *mut usize,
    205 ) {
    206    *mem = std::ptr::null_mut::<libc::c_void>();
    207    *size = 0;
    208    let file = fopen(path, b"rb\x00" as *const u8 as *const libc::c_char);
    209    if !file.is_null() {
    210        qcms_data_from_file(file, mem, size);
    211        fclose(file);
    212    };
    213 }
    214 
    215 #[cfg(windows)]
    216 extern "C" {
    217    pub fn _wfopen(filename: *const libc::wchar_t, mode: *const libc::wchar_t) -> *mut FILE;
    218 }
    219 
    220 #[cfg(windows)]
    221 #[no_mangle]
    222 pub unsafe extern "C" fn qcms_profile_from_unicode_path(path: *const libc::wchar_t) {
    223    let file = _wfopen(path, ['r' as u16, 'b' as u16, '\0' as u16].as_ptr());
    224    if !file.is_null() {
    225        qcms_profile_from_file(file);
    226        fclose(file);
    227    };
    228 }
    229 
    230 #[cfg(windows)]
    231 #[no_mangle]
    232 pub unsafe extern "C" fn qcms_data_from_unicode_path(
    233    path: *const libc::wchar_t,
    234    mem: *mut *mut libc::c_void,
    235    size: *mut usize,
    236 ) {
    237    *mem = 0 as *mut libc::c_void;
    238    *size = 0;
    239    let file = _wfopen(path, ['r' as u16, 'b' as u16, '\0' as u16].as_ptr());
    240    if !file.is_null() {
    241        qcms_data_from_file(file, mem, size);
    242        fclose(file);
    243    };
    244 }
    245 
    246 #[no_mangle]
    247 pub extern "C" fn qcms_transform_create(
    248    in_0: &Profile,
    249    in_type: DataType,
    250    out: &Profile,
    251    out_type: DataType,
    252    intent: Intent,
    253 ) -> *mut qcms_transform {
    254    let transform = transform_create(in_0, in_type, out, out_type, intent);
    255    match transform {
    256        Some(transform) => Box::into_raw(transform),
    257        None => null_mut(),
    258    }
    259 }
    260 
    261 #[no_mangle]
    262 pub unsafe extern "C" fn qcms_data_create_rgb_with_gamma(
    263    white_point: qcms_CIE_xyY,
    264    primaries: qcms_CIE_xyYTRIPLE,
    265    gamma: f32,
    266    mem: *mut *mut libc::c_void,
    267    size: *mut usize,
    268 ) {
    269    let length: u32;
    270    let mut index: u32;
    271    let xyz_count: u32;
    272    let trc_count: u32;
    273    let mut tag_table_offset: usize;
    274    let mut tag_data_offset: usize;
    275    let data: *mut libc::c_void;
    276 
    277    let TAG_XYZ: [u32; 3] = [TAG_rXYZ, TAG_gXYZ, TAG_bXYZ];
    278    let TAG_TRC: [u32; 3] = [TAG_rTRC, TAG_gTRC, TAG_bTRC];
    279    if mem.is_null() || size.is_null() {
    280        return;
    281    }
    282    *mem = std::ptr::null_mut::<libc::c_void>();
    283    *size = 0;
    284    /*
    285    	* total length = icc profile header(128) + tag count(4) +
    286    	* (tag table item (12) * total tag (6 = 3 rTRC + 3 rXYZ)) + rTRC elements data (3 * 20)
    287    	* + rXYZ elements data (3*16), and all tag data elements must start at the 4-byte boundary.
    288    	*/
    289    xyz_count = 3; // rXYZ, gXYZ, bXYZ
    290    trc_count = 3; // rTRC, gTRC, bTRC
    291    length =
    292        (128 + 4) as libc::c_uint + 12 * (xyz_count + trc_count) + xyz_count * 20 + trc_count * 16;
    293    // reserve the total memory.
    294    data = malloc(length as usize);
    295    if data.is_null() {
    296        return;
    297    }
    298    memset(data, 0, length as usize);
    299    // Part1 : write rXYZ, gXYZ and bXYZ
    300    let colorants = match get_rgb_colorants(white_point, primaries) {
    301        Some(colorants) => colorants,
    302        None => {
    303            free(data);
    304            return;
    305        }
    306    };
    307 
    308    let data = std::slice::from_raw_parts_mut(data as *mut u8, length as usize);
    309    // the position of first tag's signature in tag table
    310    tag_table_offset = (128 + 4) as usize; // the start of tag data elements.
    311    tag_data_offset = ((128 + 4) as libc::c_uint + 12 * (xyz_count + trc_count)) as usize;
    312    index = 0;
    313    while index < xyz_count {
    314        // tag table
    315        write_u32(data, tag_table_offset, TAG_XYZ[index as usize]); // 20 bytes per TAG_(r/g/b)XYZ tag element
    316        write_u32(data, tag_table_offset + 4, tag_data_offset as u32);
    317        write_u32(data, tag_table_offset + 8, 20);
    318        // tag data element
    319        write_u32(data, tag_data_offset, XYZ_TYPE);
    320        // reserved 4 bytes.
    321        write_u32(
    322            data,
    323            tag_data_offset + 8,
    324            double_to_s15Fixed16Number(colorants.m[0][index as usize] as f64) as u32,
    325        );
    326        write_u32(
    327            data,
    328            tag_data_offset + 12,
    329            double_to_s15Fixed16Number(colorants.m[1][index as usize] as f64) as u32,
    330        );
    331        write_u32(
    332            data,
    333            tag_data_offset + 16,
    334            double_to_s15Fixed16Number(colorants.m[2][index as usize] as f64) as u32,
    335        );
    336        tag_table_offset += 12;
    337        tag_data_offset += 20;
    338        index += 1
    339    }
    340    // Part2 : write rTRC, gTRC and bTRC
    341    index = 0;
    342    while index < trc_count {
    343        // tag table
    344        write_u32(data, tag_table_offset, TAG_TRC[index as usize]); // 14 bytes per TAG_(r/g/b)TRC element
    345        write_u32(data, tag_table_offset + 4, tag_data_offset as u32);
    346        write_u32(data, tag_table_offset + 8, 14);
    347        // tag data element
    348        write_u32(data, tag_data_offset, CURVE_TYPE);
    349        // reserved 4 bytes.
    350        write_u32(data, tag_data_offset + 8, 1); // count
    351        write_u16(data, tag_data_offset + 12, float_to_u8Fixed8Number(gamma));
    352        tag_table_offset += 12;
    353        tag_data_offset += 16;
    354        index += 1
    355    }
    356    /* Part3 : write profile header
    357     *
    358     * Important header fields are left empty. This generates a profile for internal use only.
    359     * We should be generating: Profile version (04300000h), Profile signature (acsp),
    360     * PCS illumiant field. Likewise mandatory profile tags are omitted.
    361     */
    362    write_u32(data, 0, length); // the total length of this memory
    363    write_u32(data, 12, DISPLAY_DEVICE_PROFILE); // profile->class_type
    364    write_u32(data, 16, RGB_SIGNATURE); // profile->color_space
    365    write_u32(data, 20, XYZ_TYPE); // profile->pcs
    366    write_u32(data, 64, Intent::Perceptual as u32); // profile->rendering_intent
    367    write_u32(data, 128, 6); // total tag count
    368                             // prepare the result
    369    *mem = data.as_mut_ptr() as *mut libc::c_void;
    370    *size = length as usize;
    371 }
    372 
    373 #[no_mangle]
    374 pub unsafe extern "C" fn qcms_transform_data(
    375    transform: &qcms_transform,
    376    src: *const libc::c_void,
    377    dest: *mut libc::c_void,
    378    length: usize,
    379 ) {
    380    transform.transform_fn.expect("non-null function pointer")(
    381        transform,
    382        src as *const u8,
    383        dest as *mut u8,
    384        length,
    385    );
    386 }
    387 /*
    388 use crate::matrix;
    389 #[repr(C)]
    390 #[derive(Clone, Debug, Default)]
    391 pub struct qcms_mat3r3 {
    392    pub rows: [[f32; 3] ; 3],
    393 }
    394 impl qcms_mat3r3 {
    395    fn from(m: matrix::Matrix) -> qcms_mat3r3 {
    396        qcms_mat3r3{
    397            rows: [
    398                m.row(0),
    399                m.row(1),
    400                m.row(2),
    401            ],
    402        }
    403    }
    404 }
    405 */
    406 #[repr(C)]
    407 #[derive(Clone, Debug, Default)]
    408 #[allow(clippy::upper_case_acronyms)]
    409 pub struct qcms_profile_data {
    410    pub class_type: u32,
    411    pub color_space: u32,
    412    pub pcs: u32,
    413    pub rendering_intent: Intent,
    414    pub red_colorant_xyzd50: [f32; 3],
    415    pub blue_colorant_xyzd50: [f32; 3],
    416    pub green_colorant_xyzd50: [f32; 3],
    417     // Number of samples in the e.g. gamma->linear LUT.
    418    pub linear_from_trc_red_samples: i32,
    419    pub linear_from_trc_blue_samples: i32,
    420    pub linear_from_trc_green_samples: i32,
    421 }
    422 
    423 pub use crate::iccread::Profile as qcms_profile;
    424 
    425 #[no_mangle]
    426 pub extern "C" fn qcms_profile_get_data(
    427    profile: &qcms_profile,
    428    out_data: &mut qcms_profile_data,
    429 ) {
    430    out_data.class_type = profile.class_type;
    431    out_data.color_space = profile.color_space;
    432    out_data.pcs = profile.pcs;
    433    out_data.rendering_intent = profile.rendering_intent;
    434 
    435    fn colorant(c: &XYZNumber) -> [f32;3] {
    436        [c.X, c.Y, c.Z].map(s15Fixed16Number_to_float)
    437    }
    438    out_data.red_colorant_xyzd50 = colorant(&profile.redColorant);
    439    out_data.blue_colorant_xyzd50 = colorant(&profile.blueColorant);
    440    out_data.green_colorant_xyzd50 = colorant(&profile.greenColorant);
    441 
    442    fn trc_to_samples(trc: &Option<Box<curveType>>) -> i32 {
    443        if let Some(ref trc) = *trc {
    444            match &**trc {
    445                curveType::Curve(v) => {
    446                    let len = v.len();
    447                    if len <= 1 {
    448                        -1
    449                    } else {
    450                        len as i32
    451                    }
    452                },
    453                curveType::Parametric(_) => -1,
    454            }
    455        } else {
    456            0
    457        }
    458    }
    459    out_data.linear_from_trc_red_samples = trc_to_samples(&profile.redTRC);
    460    out_data.linear_from_trc_blue_samples = trc_to_samples(&profile.blueTRC);
    461    out_data.linear_from_trc_green_samples = trc_to_samples(&profile.greenTRC);
    462 }
    463 
    464 #[repr(u8)]
    465 pub enum qcms_color_channel {
    466    Red,
    467    Green,
    468    Blue,
    469 }
    470 
    471 #[no_mangle]
    472 pub extern "C" fn qcms_profile_get_lut(
    473    profile: &qcms_profile,
    474    channel: qcms_color_channel, // FYI: UB if you give Rust something out of range!
    475    out_begin: *mut f32,
    476    out_end: *mut f32,
    477 ) {
    478    let out_slice = unsafe {
    479        std::slice::from_raw_parts_mut(out_begin, out_end.offset_from(out_begin) as usize)
    480    };
    481 
    482    let trc = match channel {
    483        qcms_color_channel::Red => &profile.redTRC,
    484        qcms_color_channel::Green => &profile.greenTRC,
    485        qcms_color_channel::Blue => &profile.blueTRC,
    486    };
    487 
    488    let samples_u16 = if let Some(trc) = trc {
    489        let trc = &*trc;
    490        // Yes, sub-optimal, but easier to implement, and these aren't big or hot:
    491        // 1. Ask for a new vec<u16> lut based on the trc.
    492        //   * (eat the extra alloc)
    493        // 2. Convert the u16s back out to f32s in our slice.
    494        //   * (eat the copy and quantization error from f32->u16->f32 roundtrip)
    495        transform_util::build_lut_for_linear_from_tf(trc, Some(out_slice.len()))
    496    } else {
    497        Vec::new()
    498    };
    499 
    500    assert_eq!(samples_u16.len(), out_slice.len());
    501    for (d, s) in out_slice.iter_mut().zip(samples_u16.into_iter()) {
    502        *d = (s as f32) / (u16::MAX as f32);
    503    }
    504 }
    505 
    506 pub type icColorSpaceSignature = u32;
    507 pub const icSigGrayData: icColorSpaceSignature = 0x47524159; // 'GRAY'
    508 pub const icSigRgbData: icColorSpaceSignature = 0x52474220; // 'RGB '
    509 pub const icSigCmykData: icColorSpaceSignature = 0x434d594b; // 'CMYK'
    510 
    511 pub use crate::iccread::qcms_profile_is_bogus;
    512 pub use crate::transform::{
    513    qcms_enable_iccv4, qcms_profile_precache_output_transform, qcms_transform_release,
    514 };