3 using System.Collections;
4 using System.Collections.Generic;
10 public enum MTextFormat
12 MTEXT_FORMAT_US_ASCII,
14 MTEXT_FORMAT_UTF_16BE,
15 MTEXT_FORMAT_UTF_16LE,
16 MTEXT_FORMAT_UTF_32BE,
17 MTEXT_FORMAT_UTF_32LE,
21 public class MTextProperty
23 internal MProperty prop;
24 internal bool front_sticky;
25 internal bool rear_sticky;
26 internal bool merginable;
27 public MProperty Prop { get { return prop; } }
28 public bool FrontSticky { get { return front_sticky; } }
29 public bool RearSticky { get { return rear_sticky; } }
30 public bool Merginable { get { return merginable; } }
32 public MTextProperty (bool front_sticky, bool rear_sticky)
34 this.front_sticky = front_sticky;
35 this.rear_sticky = rear_sticky;
37 public MTextProperty (bool front_sticky, bool rear_sticky, bool merginable)
39 this.front_sticky = front_sticky;
40 this.rear_sticky = rear_sticky;
41 this.merginable = merginable;
48 public enum MTextFormat format;
51 private StringBuilder sb;
53 private int cache_pos;
54 private int cache_idx;
55 private MInterval root_interval;
56 private bool read_only;
58 private static UTF8Encoding utf8 = new UTF8Encoding ();
60 private static int count_chars (String str)
62 int len = str.Length, n = 0;
64 for (int i = 0; i < len; i++)
65 n += surrogate_high_p (str[i]) ? 2 : 1;
69 private static int count_chars (StringBuilder str)
71 int len = str.Length, n = 0;
73 for (int i = 0; i < len; i++)
74 n += surrogate_high_p (str[i]) ? 2 : 1;
80 sb = new StringBuilder ();
83 public MText (byte[] str)
85 sb = new StringBuilder (utf8.GetString (str));
86 nchars = count_chars (sb);
89 public MText (String str)
91 sb = new StringBuilder (str);
92 nchars = count_chars (str);
95 public MText (StringBuilder str)
98 nchars = count_chars (str);
101 public static MText operator+ (MText mt1, MText mt2)
103 MText mt = new MText (mt1.sb.ToString);
105 mt.sb.Append (mt2.sb);
106 mt.nchars = mt1.nchars + mt2.nchars;
110 public bool ReadOnly { get { return read_only; } }
112 public override string ToString ()
114 return sb.ToString ();
117 private static bool surrogate_high_p (char c)
119 return (c >= 0xD800 && c < 0xDC00);
122 private static bool surrogate_low_p (char c)
124 return (c >= 0xDC00 && c < 0xE000);
127 private static int inc_idx (StringBuilder sb, int i)
129 return (i + (surrogate_high_p (sb[i]) ? 2 : 1));
132 private static int dec_idx (StringBuilder sb, int i)
134 return (i - (surrogate_low_p (sb[i - 1]) ? 2 : 1));
137 private static int pos_to_idx (MText mt, int pos)
139 if (pos == mt.cache_pos)
145 if (pos < mt.cache_pos)
147 if (mt.cache_pos == mt.cache_idx)
149 if (pos < mt.cache_pos - pos)
156 p = mt.cache_pos; i = mt.cache_idx;
162 if (mt.nchars - mt.cache_pos == mt.sb.Length - mt.cache_idx)
163 return (mt.cache_idx + pos - mt.cache_pos);
164 if (pos - mt.cache_pos < mt.nchars - pos)
166 p = mt.cache_pos; i = mt.cache_idx;
171 p = mt.nchars; i = mt.sb.Length;
176 for (; p < pos; i = inc_idx (mt.sb, i), p++);
178 for (; p > pos; i = dec_idx (mt.sb, i), p--);
184 private void insert (int pos, MText mt2, int from, int to)
186 int pos_idx = pos_to_idx (this, pos);
187 int from_idx = pos_to_idx (mt2, from);
188 int to_idx = pos_to_idx (mt2, to);
190 sb.Insert (pos_idx, mt2.sb.ToString (from_idx, to_idx - from_idx));
194 public int this[int i]
197 i = pos_to_idx (this, i);
200 if (surrogate_high_p (sb[i]))
202 sb[i] = (char) value;
206 char high = (char) (0xD800 + ((value - 0x10000) >> 10));
207 char low = (char) (0xDC00 + ((value - 0x10000) & 0x3FF));
209 if (! surrogate_high_p (sb[i]))
216 i = pos_to_idx (this, i);
217 return (surrogate_high_p (sb[i])
218 ? ((sb[i] - 0xD800) << 10) + (sb[i + 1] - 0xDC00) + 0x10000
225 return (new MText (sb.ToString ()));
228 public MText ins (int pos, MText mt)
230 insert (pos, mt, 0, mt.nchars);
234 public MText ins (int pos, MText mt, int from, int to)
236 insert (pos, mt, from, to);
240 public MText del (int from, int to)
242 sb.Remove (from, pos_to_idx (this, to) - pos_to_idx (this, from));
247 public void PushProp (int from, int to, MTextProperty prop)
249 if (root_interval == null)
250 root_interval = new MInterval (0, true, sb.Length, true);
251 root_interval.Push (from, to, prop);
254 private class MInterval
256 // Start and end positions of this interval and its children.
257 // If this is the left node, the values are relative to the
258 // parent's total_start. Otherwise, the values are relatie to
259 // the parent's total_end.
260 private int total_start, total_end;
261 // Stack of MTextProperty
262 private Stack<MTextProperty> stack;
264 private MInterval left, right, parent;
266 public MInterval (int start, bool front_inclusive,
267 int end, bool rear_inclusive)
270 throw new Exception ("Invalid Interval Range");
271 this.total_start = (start << 2) + (front_inclusive ? -1 : 1);
272 this.total_end = (end << 2) + (rear_inclusive ? 1 : -1);
273 this.stack = new Stack<MTextProperty> ();
277 private MInterval (int start, int end, Stack<MTextProperty> stack)
279 this.total_start = start;
280 this.total_end = end;
281 this.stack = new Stack<MTextProperty> (stack);
285 private MInterval Copy ()
287 return new MInterval (total_start, total_end, stack);
292 return (left == null ? total_start : total_start + left.total_end);
298 return (right == null ? total_end : total_end + right.total_start);
302 private MInterval Left {
307 for (interval = left;
308 interval.right != null;
309 interval = interval.right);
311 for (interval = parent;
312 interval != null && interval.total_start == 0;
313 interval = interval.parent);
319 private MInterval Right {
324 for (interval = right;
325 interval.left != null;
326 interval = interval.left);
328 for (interval = parent;
329 interval != null && interval.total_start < 0;
330 interval = interval.parent);
336 public void Push (int start, int end, MTextProperty prop)
339 if (prop.FrontSticky)
349 throw new Exception ("Invalid Text Property Range");
351 push (start, end, prop);
354 private MInterval divide_right (int pos)
356 MInterval interval = Copy ();
357 int this_start = Start;
360 if (left == null || (right != null && left.depth < right.depth))
362 interval.left = this;
363 interval.right = right;
364 interval.parent = parent;
367 if (total_start == 0)
368 parent.left = interval;
370 parent.right = interval;
372 interval.depth = depth;
376 total_end = pos - this_start;
380 interval.total_start = pos - this_end;
381 interval.total_end = 0;
383 right.parent = interval;
390 private MInterval divide_left (int pos)
392 MInterval interval = Copy ();
393 int this_start = Start;
396 if (left == null || (right != null && left.depth < right.depth))
398 interval.total_start = 0;
399 interval.total_end = pos - this_start;
401 left.parent = interval;
406 interval.right = this;
407 interval.left = left;
408 interval.parent = parent;
411 if (total_start == 0)
412 parent.left = interval;
414 parent.right = interval;
416 interval.depth = depth;
419 total_start = pos - this_end;
426 private void push (int start, int end, MTextProperty prop)
428 int this_start = Start;
431 if (start < this_start)
433 if (end <= this_start)
435 Left.push (start, end, prop);
438 Left.push (start, this_start, prop);
443 if (this_end < start)
445 Right.push (start, end, prop);
448 Right.push (this_end, end, prop);
451 if (this_start < start)