win32-clipboard 0.6.3 → 0.6.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,232 +1,232 @@
1
- # The Win32 module serves as a namespace only.
2
- #
3
- module Win32
4
-
5
- # The HtmlClipboard class is a subclass of Clipboard that explicitly
6
- # handles text in HTML format.
7
- #
8
- class HtmlClipboard < Clipboard
9
-
10
- private
11
-
12
- # Marker block output
13
- #--
14
- # Version: Version of the clipboard.
15
- #
16
- # StartHTML: bytecount from the beginning of the clipboard to the
17
- # start of the context, or -1 if no context.
18
- #
19
- # EndHTML: bytecount from the beginning of the clipboard to the end
20
- # of the context, or -1 if no context.
21
- #
22
- # StartFragment: bytecount from the beginning of the clipboard to
23
- # the start of the fragment.
24
- #
25
- # EndFragment: bytecount from the beginning of the clipboard to the
26
- # end of the fragment.
27
- #
28
- # StartSelection: bytecount from the beginning of the clipboard to
29
- # the start of the selection.
30
- #
31
- # EndSelection: bytecount from the beginning of the clipboard to the
32
- # end of the selection.
33
- #
34
- MARKER_BLOCK_OUTPUT =
35
- "Version:1.0\r\n" \
36
- "StartHTML:%09d\r\n" \
37
- "EndHTML:%09d\r\n" \
38
- "StartFragment:%09d\r\n" \
39
- "EndFragment:%09d\r\n" \
40
- "StartSelection:%09d\r\n" \
41
- "EndSelection:%09d\r\n" \
42
- "SourceURL:%s\r\n"
43
-
44
- # Extended marker block
45
- MARKER_BLOCK_EX =
46
- 'Version:(\S+)\s+' \
47
- 'StartHTML:(\d+)\s+' \
48
- 'EndHTML:(\d+)\s+' \
49
- 'StartFragment:(\d+)\s+' \
50
- 'EndFragment:(\d+)\s+' \
51
- 'StartSelection:(\d+)\s+' \
52
- 'EndSelection:(\d+)\s+' \
53
- 'SourceURL:(\S+)'
54
-
55
- # Regular expression for extended marker block
56
- MARKER_BLOCK_EX_RE = Regexp.new(MARKER_BLOCK_EX, Regexp::MULTILINE) # :nodoc:
57
-
58
- # Standard marker block
59
- MARKER_BLOCK =
60
- 'Version:(\S+)\s+' \
61
- 'StartHTML:(\d+)\s+' \
62
- 'EndHTML:(\d+)\s+' \
63
- 'StartFragment:(\d+)\s+' \
64
- 'EndFragment:(\d+)\s+' \
65
- 'SourceURL:(\S+)'
66
-
67
- # Regular expression for the standard marker block
68
- MARKER_BLOCK_RE = Regexp.new(MARKER_BLOCK, Regexp::MULTILINE)
69
-
70
- # Default HTML body
71
- DEFAULT_HTML_BODY =
72
- "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r\n" \
73
- "<HTML><BODY><!--StartFragment-->%s<!--EndFragment--></BODY></HTML>"
74
-
75
- public
76
-
77
- # Clipboard format value
78
- CF_HTML = RegisterClipboardFormat("HTML Format")
79
-
80
- def initialize # :nodoc:
81
- @html = nil
82
- @fragment = nil
83
- @selection = nil
84
- @source = nil
85
- @version = nil
86
- end
87
-
88
- # Returns a boolean indicating whether or not the clipboard contains
89
- # data in HTML format.
90
- #
91
- def self.html_format?
92
- format_available?(CF_HTML)
93
- end
94
-
95
- # This method is nearly identical to the Clipboard.data method, but
96
- # it decodes the data to preserve the HTML formatting.
97
- #
98
- def self.data
99
- begin
100
- self.open
101
- if IsClipboardFormatAvailable(CF_HTML)
102
- handle = GetClipboardData(CF_HTML)
103
- size = GlobalSize(handle)
104
- ptr = FFI::Pointer.new(:char, handle)
105
-
106
- clip_data = decode_data(ptr.read_bytes(size))
107
- else
108
- clip_data = ''
109
- end
110
- ensure
111
- self.close
112
- end
113
- clip_data
114
- end
115
-
116
- # Returns the block marker information for the HTML, or an empty
117
- # string if there is no clipboard data.
118
- #
119
- def self.data_details
120
- clip_data = data
121
- string = ""
122
- unless clip_data.empty?
123
- string << "prefix=>>>#{@prefix}<<<END"
124
- string << "version=>>>#{@version}<<<END"
125
- string << "selection=>>>#{@selection}<<<END"
126
- string << "fragment=>>>#{@fragment}<<<END"
127
- string << "html=>>>#{@html}<<<END"
128
- string << "source=>>>#{@source}<<<END"
129
- end
130
- string
131
- end
132
-
133
- # Put a well-formed fragment of HTML on the clipboard.
134
- #
135
- # The +selection+, if provided, must be a literal string within a
136
- # fragment.
137
- #
138
- # The +html+ value, if provided, must be a well formed HTML document
139
- # that textually contains a fragment and its required markers.
140
- #
141
- # The +source+, if provided, should include a scheme (file, http, or
142
- # https) plus a file name. The default is file:// + __FILE__.
143
- #
144
- def self.set_data(fragment, selection=nil, html=nil, source=nil)
145
- selection ||= fragment
146
- html ||= DEFAULT_HTML_BODY % fragment
147
- source ||= 'file://' + __FILE__
148
-
149
- fragment_start = html.index(fragment)
150
- fragment_end = fragment_start + fragment.length
151
- selection_start = html.index(selection)
152
- selection_end = selection_start + selection.length
153
-
154
- clip_data = encode_data(
155
- html,
156
- fragment_start,
157
- fragment_end,
158
- selection_start,
159
- selection_end,
160
- source
161
- )
162
-
163
- self.open
164
- EmptyClipboard()
165
-
166
- # Global Allocate a movable piece of memory.
167
- hmem = GlobalAlloc(GHND, clip_data.length + 4)
168
- mem = GlobalLock(hmem)
169
- mem.write_bytes(clip_data, 0, clip_data.size)
170
-
171
- clip_data2 = fragment.gsub(/<[^>]+?>/,'')
172
- hmem2 = GlobalAlloc(GHND, clip_data2.length + 4)
173
- mem2 = GlobalLock(hmem2)
174
- mem2.write_bytes(clip_data2, 0, clip_data2.size)
175
-
176
- # Set the new data
177
- begin
178
- if SetClipboardData(CF_HTML, hmem) == 0
179
- raise SystemCallError.new('SetClipboardData', FFI.errno)
180
- end
181
-
182
- if SetClipboardData(CF_TEXT, hmem2) == 0
183
- raise SystemCallError.new('SetClipboardData', FFI.errno)
184
- end
185
- ensure
186
- GlobalFree(hmem)
187
- GlobalFree(hmem2)
188
- self.close
189
- end
190
- self
191
- end
192
-
193
- private
194
-
195
- # Encode the data markers into the HTML data
196
- def self.encode_data(html,frag_start,frag_end,select_start,select_end,src)
197
- dummy_prefix = MARKER_BLOCK_OUTPUT % [0,0,0,0,0,0,src]
198
- len_prefix = dummy_prefix.length
199
- prefix = MARKER_BLOCK_OUTPUT % [len_prefix, html.length + len_prefix,
200
- frag_start + len_prefix, frag_end + len_prefix,
201
- select_start + len_prefix, select_end + len_prefix, src]
202
- prefix + html
203
- end
204
-
205
- # Decode the given string to figure out the details of the HTML
206
- # that's on the string.
207
- #--
208
- # Try the extended format first, which has an explicit selection.
209
- # If that fails, try the version without a selection.
210
- #
211
- def self.decode_data(src)
212
- if (matches = MARKER_BLOCK_EX_RE.match(src))
213
- @prefix = matches[0]
214
- @version = matches[1]
215
- @html = src[matches[2].to_i ... matches[3].to_i]
216
- @fragment = src[matches[4].to_i ... matches[5].to_i]
217
- @selection = src[matches[6].to_i ... matches[7].to_i]
218
- @source = matches[8]
219
- elsif (matches = MARKER_BLOCK_RE.match(src))
220
- @prefix = matches[0]
221
- @version = matches[1]
222
- @html = src[matches[2].to_i ... matches[3].to_i]
223
- @fragment = src[matches[4].to_i ... matches[5].to_i]
224
- @source = matches[6]
225
- @selection = @fragment
226
- else
227
- raise 'failed to match block markers'
228
- end
229
- @fragment
230
- end
231
- end
232
- end
1
+ # The Win32 module serves as a namespace only.
2
+ #
3
+ module Win32
4
+
5
+ # The HtmlClipboard class is a subclass of Clipboard that explicitly
6
+ # handles text in HTML format.
7
+ #
8
+ class HtmlClipboard < Clipboard
9
+
10
+ private
11
+
12
+ # Marker block output
13
+ #--
14
+ # Version: Version of the clipboard.
15
+ #
16
+ # StartHTML: bytecount from the beginning of the clipboard to the
17
+ # start of the context, or -1 if no context.
18
+ #
19
+ # EndHTML: bytecount from the beginning of the clipboard to the end
20
+ # of the context, or -1 if no context.
21
+ #
22
+ # StartFragment: bytecount from the beginning of the clipboard to
23
+ # the start of the fragment.
24
+ #
25
+ # EndFragment: bytecount from the beginning of the clipboard to the
26
+ # end of the fragment.
27
+ #
28
+ # StartSelection: bytecount from the beginning of the clipboard to
29
+ # the start of the selection.
30
+ #
31
+ # EndSelection: bytecount from the beginning of the clipboard to the
32
+ # end of the selection.
33
+ #
34
+ MARKER_BLOCK_OUTPUT =
35
+ "Version:1.0\r\n" \
36
+ "StartHTML:%09d\r\n" \
37
+ "EndHTML:%09d\r\n" \
38
+ "StartFragment:%09d\r\n" \
39
+ "EndFragment:%09d\r\n" \
40
+ "StartSelection:%09d\r\n" \
41
+ "EndSelection:%09d\r\n" \
42
+ "SourceURL:%s\r\n"
43
+
44
+ # Extended marker block
45
+ MARKER_BLOCK_EX =
46
+ 'Version:(\S+)\s+' \
47
+ 'StartHTML:(\d+)\s+' \
48
+ 'EndHTML:(\d+)\s+' \
49
+ 'StartFragment:(\d+)\s+' \
50
+ 'EndFragment:(\d+)\s+' \
51
+ 'StartSelection:(\d+)\s+' \
52
+ 'EndSelection:(\d+)\s+' \
53
+ 'SourceURL:(\S+)'
54
+
55
+ # Regular expression for extended marker block
56
+ MARKER_BLOCK_EX_RE = Regexp.new(MARKER_BLOCK_EX, Regexp::MULTILINE) # :nodoc:
57
+
58
+ # Standard marker block
59
+ MARKER_BLOCK =
60
+ 'Version:(\S+)\s+' \
61
+ 'StartHTML:(\d+)\s+' \
62
+ 'EndHTML:(\d+)\s+' \
63
+ 'StartFragment:(\d+)\s+' \
64
+ 'EndFragment:(\d+)\s+' \
65
+ 'SourceURL:(\S+)'
66
+
67
+ # Regular expression for the standard marker block
68
+ MARKER_BLOCK_RE = Regexp.new(MARKER_BLOCK, Regexp::MULTILINE)
69
+
70
+ # Default HTML body
71
+ DEFAULT_HTML_BODY =
72
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r\n" \
73
+ "<HTML><BODY><!--StartFragment-->%s<!--EndFragment--></BODY></HTML>"
74
+
75
+ public
76
+
77
+ # Clipboard format value
78
+ CF_HTML = RegisterClipboardFormat("HTML Format")
79
+
80
+ def initialize # :nodoc:
81
+ @html = nil
82
+ @fragment = nil
83
+ @selection = nil
84
+ @source = nil
85
+ @version = nil
86
+ end
87
+
88
+ # Returns a boolean indicating whether or not the clipboard contains
89
+ # data in HTML format.
90
+ #
91
+ def self.html_format?
92
+ format_available?(CF_HTML)
93
+ end
94
+
95
+ # This method is nearly identical to the Clipboard.data method, but
96
+ # it decodes the data to preserve the HTML formatting.
97
+ #
98
+ def self.data
99
+ begin
100
+ self.open
101
+ if IsClipboardFormatAvailable(CF_HTML)
102
+ handle = GetClipboardData(CF_HTML)
103
+ size = GlobalSize(handle)
104
+ ptr = FFI::Pointer.new(:char, handle)
105
+
106
+ clip_data = decode_data(ptr.read_bytes(size))
107
+ else
108
+ clip_data = ''
109
+ end
110
+ ensure
111
+ self.close
112
+ end
113
+ clip_data
114
+ end
115
+
116
+ # Returns the block marker information for the HTML, or an empty
117
+ # string if there is no clipboard data.
118
+ #
119
+ def self.data_details
120
+ clip_data = data
121
+ string = ""
122
+ unless clip_data.empty?
123
+ string << "prefix=>>>#{@prefix}<<<END"
124
+ string << "version=>>>#{@version}<<<END"
125
+ string << "selection=>>>#{@selection}<<<END"
126
+ string << "fragment=>>>#{@fragment}<<<END"
127
+ string << "html=>>>#{@html}<<<END"
128
+ string << "source=>>>#{@source}<<<END"
129
+ end
130
+ string
131
+ end
132
+
133
+ # Put a well-formed fragment of HTML on the clipboard.
134
+ #
135
+ # The +selection+, if provided, must be a literal string within a
136
+ # fragment.
137
+ #
138
+ # The +html+ value, if provided, must be a well formed HTML document
139
+ # that textually contains a fragment and its required markers.
140
+ #
141
+ # The +source+, if provided, should include a scheme (file, http, or
142
+ # https) plus a file name. The default is file:// + __FILE__.
143
+ #
144
+ def self.set_data(fragment, selection=nil, html=nil, source=nil)
145
+ selection ||= fragment
146
+ html ||= DEFAULT_HTML_BODY % fragment
147
+ source ||= 'file://' + __FILE__
148
+
149
+ fragment_start = html.index(fragment)
150
+ fragment_end = fragment_start + fragment.length
151
+ selection_start = html.index(selection)
152
+ selection_end = selection_start + selection.length
153
+
154
+ clip_data = encode_data(
155
+ html,
156
+ fragment_start,
157
+ fragment_end,
158
+ selection_start,
159
+ selection_end,
160
+ source
161
+ )
162
+
163
+ self.open
164
+ EmptyClipboard()
165
+
166
+ # Global Allocate a movable piece of memory.
167
+ hmem = GlobalAlloc(GHND, clip_data.length + 4)
168
+ mem = GlobalLock(hmem)
169
+ mem.write_bytes(clip_data, 0, clip_data.size)
170
+
171
+ clip_data2 = fragment.gsub(/<[^>]+?>/,'')
172
+ hmem2 = GlobalAlloc(GHND, clip_data2.length + 4)
173
+ mem2 = GlobalLock(hmem2)
174
+ mem2.write_bytes(clip_data2, 0, clip_data2.size)
175
+
176
+ # Set the new data
177
+ begin
178
+ if SetClipboardData(CF_HTML, hmem) == 0
179
+ raise SystemCallError.new('SetClipboardData', FFI.errno)
180
+ end
181
+
182
+ if SetClipboardData(CF_TEXT, hmem2) == 0
183
+ raise SystemCallError.new('SetClipboardData', FFI.errno)
184
+ end
185
+ ensure
186
+ GlobalFree(hmem)
187
+ GlobalFree(hmem2)
188
+ self.close
189
+ end
190
+ self
191
+ end
192
+
193
+ private
194
+
195
+ # Encode the data markers into the HTML data
196
+ def self.encode_data(html,frag_start,frag_end,select_start,select_end,src)
197
+ dummy_prefix = MARKER_BLOCK_OUTPUT % [0,0,0,0,0,0,src]
198
+ len_prefix = dummy_prefix.length
199
+ prefix = MARKER_BLOCK_OUTPUT % [len_prefix, html.length + len_prefix,
200
+ frag_start + len_prefix, frag_end + len_prefix,
201
+ select_start + len_prefix, select_end + len_prefix, src]
202
+ prefix + html
203
+ end
204
+
205
+ # Decode the given string to figure out the details of the HTML
206
+ # that's on the string.
207
+ #--
208
+ # Try the extended format first, which has an explicit selection.
209
+ # If that fails, try the version without a selection.
210
+ #
211
+ def self.decode_data(src)
212
+ if (matches = MARKER_BLOCK_EX_RE.match(src))
213
+ @prefix = matches[0]
214
+ @version = matches[1]
215
+ @html = src[matches[2].to_i ... matches[3].to_i]
216
+ @fragment = src[matches[4].to_i ... matches[5].to_i]
217
+ @selection = src[matches[6].to_i ... matches[7].to_i]
218
+ @source = matches[8]
219
+ elsif (matches = MARKER_BLOCK_RE.match(src))
220
+ @prefix = matches[0]
221
+ @version = matches[1]
222
+ @html = src[matches[2].to_i ... matches[3].to_i]
223
+ @fragment = src[matches[4].to_i ... matches[5].to_i]
224
+ @source = matches[6]
225
+ @selection = @fragment
226
+ else
227
+ raise 'failed to match block markers'
228
+ end
229
+ @fragment
230
+ end
231
+ end
232
+ end