Skip to content

Commit

Permalink
Implement HTML reading
Browse files Browse the repository at this point in the history
  • Loading branch information
DoumanAsh committed Feb 19, 2024
1 parent f288b6b commit 95ce22a
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 4 deletions.
39 changes: 39 additions & 0 deletions src/formats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
use crate::{SysResult, Getter, Setter};
use crate::types::c_uint;

use core::num::NonZeroU32;

///A handle to a bitmap (HBITMAP).
pub const CF_BITMAP: c_uint = 2;
///A memory object containing a <b>BITMAPINFO</b> structure followed by the bitmap bits.
Expand Down Expand Up @@ -166,3 +168,40 @@ impl<T: AsRef<[u8]>> Setter<T> for Bitmap {
crate::raw::set_bitmap(data.as_ref())
}
}

///HTML Foramt
///
///Reference: https://learn.microsoft.com/en-us/windows/win32/dataxchg/html-clipboard-format
pub struct Html(NonZeroU32);

impl Html {
#[inline(always)]
///Creates new instance, if possible
pub fn new() -> Option<Self> {
//utf-16 "HTML Format"
const NAME: [u16; 12] = [72, 84, 77, 76, 32, 70, 111, 114, 109, 97, 116, 0];
unsafe {
crate::raw::register_raw_format(&NAME).map(Self)
}
}

#[inline(always)]
///Gets raw format code
pub fn code(&self) -> u32 {
self.0.get()
}
}

impl Getter<alloc::vec::Vec<u8>> for Html {
#[inline(always)]
fn read_clipboard(&self, out: &mut alloc::vec::Vec<u8>) -> SysResult<usize> {
crate::raw::get_html(self.0.get(), out)
}
}

impl Getter<alloc::string::String> for Html {
#[inline(always)]
fn read_clipboard(&self, out: &mut alloc::string::String) -> SysResult<usize> {
crate::raw::get_html(self.0.get(), unsafe { out.as_mut_vec() })
}
}
3 changes: 3 additions & 0 deletions src/html.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub const SEP: char = ':';
pub const START_FRAGMENT: &str = "StartFragment";
pub const END_FRAGMENT: &str = "EndFragment";
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ extern crate alloc;
mod sys;
pub mod types;
pub mod formats;
mod html;
pub mod raw;
#[cfg(feature = "monitor")]
pub mod monitor;
Expand Down
63 changes: 60 additions & 3 deletions src/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ const CP_UTF8: DWORD = 65001;

use error_code::ErrorCode;

use core::{slice, mem, ptr, cmp};
use core::{slice, mem, ptr, cmp, str, hint};
use core::num::{NonZeroUsize, NonZeroU32};

use alloc::string::String;
use alloc::borrow::ToOwned;
use alloc::format;

use crate::{SysResult, formats};
use crate::{SysResult, html, formats};
use crate::utils::{unlikely_empty_size_result, RawMem};

#[inline(always)]
Expand Down Expand Up @@ -264,6 +264,63 @@ pub fn get_vec(format: u32, out: &mut alloc::vec::Vec<u8>) -> SysResult<usize> {
Ok(result)
}

///Retrieves HTML using format code created by `register_raw_format` or `register_format` with
///argument `HTML Format`
pub fn get_html(format: u32, out: &mut alloc::vec::Vec<u8>) -> SysResult<usize> {
let ptr = RawMem::from_borrowed(get_clipboard_data(format)?);

let result = unsafe {
let (data_ptr, _lock) = ptr.lock()?;
let data_size = GlobalSize(ptr.get()) as usize;

let data = str::from_utf8_unchecked(
slice::from_raw_parts(data_ptr.as_ptr() as *const u8, data_size)
);

let mut start_idx = 0usize;
let mut end_idx = data.len();
for line in data.lines() {
let mut split = line.split(html::SEP);
let key = match split.next() {
Some(key) => key,
None => hint::unreachable_unchecked(),
};
let value = match split.next() {
Some(value) => value,
//Reached HTML
None => break
};
match key {
html::START_FRAGMENT => match value.trim_start_matches('0').parse() {
Ok(value) => {
start_idx = value;
continue;
}
//Should not really happen
Err(_) => break,
},
html::END_FRAGMENT => match value.trim_start_matches('0').parse() {
Ok(value) => {
end_idx = value;
continue;
}
//Should not really happen
Err(_) => break,
},
_ => continue,
}
}
let size = end_idx - start_idx;
out.reserve(size);
let out_cursor = out.len();
ptr::copy_nonoverlapping(data.as_ptr().add(start_idx), out.spare_capacity_mut().as_mut_ptr().add(out_cursor) as _, size);
out.set_len(out_cursor + size);
size
};

Ok(result)
}

/// Copies raw bytes onto clipboard with specified `format`, returning whether it was successful.
///
/// This function empties the clipboard before setting the data.
Expand Down Expand Up @@ -886,7 +943,7 @@ pub fn register_format(name: &str) -> Option<NonZeroU32> {
register_raw_format(&buffer)
}
} else {
let mut buffer = mem::MaybeUninit::<[u16; 52]>::uninit();
let mut buffer = mem::MaybeUninit::<[u16; 52]>::zeroed();
let size = unsafe {
MultiByteToWideChar(CP_UTF8, 0, name.as_ptr() as *const _, name.len() as c_int, buffer.as_mut_ptr() as *mut u16, 51)
};
Expand Down
14 changes: 13 additions & 1 deletion tests/test_clip.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use clipboard_win::{Getter, Setter, Clipboard, is_format_avail, types};
use clipboard_win::formats::{RawData, Unicode, Bitmap, CF_TEXT, CF_UNICODETEXT, CF_BITMAP, FileList, CF_HDROP};
use clipboard_win::formats::{Html, RawData, Unicode, Bitmap, CF_TEXT, CF_UNICODETEXT, CF_BITMAP, FileList, CF_HDROP};

fn should_set_file_list() {
let _clip = Clipboard::new_attempts(10).expect("Open clipboard");
Expand Down Expand Up @@ -120,6 +120,17 @@ fn should_set_owner() {
}
}

fn should_set_get_html() {
let html1 = Html::new().expect("Create html1");
let html2 = Html::new().expect("Create html2");
assert_eq!(html1.code(), html2.code());

let _clip = Clipboard::new_attempts(10).expect("Open clipboard");
let mut out = String::new();
//TODO: need setter for this test to work
html1.read_clipboard(&mut out).expect("read clipboard");
}

macro_rules! run {
($name:ident) => {
println!("Clipboard test: {}...", stringify!($name));
Expand All @@ -139,4 +150,5 @@ fn clipboard_should_work() {
run!(should_work_with_bytes);
run!(should_work_with_set_empty_string);
run!(should_set_owner);
run!(should_set_get_html);
}

0 comments on commit 95ce22a

Please sign in to comment.