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 unmodifiable;
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);
105 mt.sb.Append (mt2.sb);
106 mt.nchars = mt1.nchars + mt2.nchars;
110 public override string ToString ()
112 return sb.ToString ();
115 private static bool surrogate_high_p (char c)
117 return (c >= 0xD800 && c < 0xDC00);
120 private static bool surrogate_low_p (char c)
122 return (c >= 0xDC00 && c < 0xE000);
125 private static int inc_idx (StringBuilder sb, int i)
127 return (i + (surrogate_high_p (sb[i]) ? 2 : 1));
130 private static int dec_idx (StringBuilder sb, int i)
132 return (i - (surrogate_low_p (sb[i - 1]) ? 2 : 1));
135 private static int pos_to_idx (MText mt, int pos)
137 if (pos == mt.cache_pos)
143 if (pos < mt.cache_pos)
145 if (mt.cache_pos == mt.cache_idx)
147 if (pos < mt.cache_pos - pos)
154 p = mt.cache_pos; i = mt.cache_idx;
160 if (mt.nchars - mt.cache_pos == mt.sb.Length - mt.cache_idx)
161 return (mt.cache_idx + pos - mt.cache_pos);
162 if (pos - mt.cache_pos < mt.nchars - pos)
164 p = mt.cache_pos; i = mt.cache_idx;
169 p = mt.nchars; i = mt.sb.Length;
174 for (; p < pos; i = inc_idx (mt.sb, i), p++);
176 for (; p > pos; i = dec_idx (mt.sb, i), p--);
182 private void insert (int pos, MText mt2, int from, int to)
184 int pos_idx = pos_to_idx (this, pos);
185 int from_idx = pos_to_idx (mt2, from);
186 int to_idx = pos_to_idx (mt2, to);
188 sb.Insert (pos_idx, mt2.sb.ToString (from_idx, to_idx - from_idx));
192 public int this[int i]
195 i = pos_to_idx (this, i);
198 if (surrogate_high_p (sb[i]))
200 sb[i] = (char) value;
204 char high = (char) (0xD800 + ((value - 0x10000) >> 10));
205 char low = (char) (0xDC00 + ((value - 0x10000) & 0x3FF));
207 if (! surrogate_high_p (sb[i]))
214 i = pos_to_idx (this, i);
215 return (surrogate_high_p (sb[i])
216 ? ((sb[i] - 0xD800) << 10) + (sb[i + 1] - 0xDC00) + 0x10000
223 return (new MText (sb.ToString ()));
226 public MText ins (int pos, MText mt)
228 insert (pos, mt, 0, mt.nchars);
232 public MText ins (int pos, MText mt, int from, int to)
234 insert (pos, mt, from, to);
238 public MText del (int from, int to)
240 sb.Remove (from, pos_to_idx (this, to) - pos_to_idx (this, from));
245 private class MInterval
247 // Start and end positions of this interval and its children.
248 // If this is the left node, the values are relative to the
249 // parent's total_start. Otherwise, the values are relatie to
250 // the parent's total_end.
251 private int total_start, total_end;
252 // Stack of MTextProperty
253 private Stack<MTextProperty> stack;
255 private MInterval left, right, parent;
257 public MInterval (int start, bool front_inclusive,
258 int end, bool rear_inclusive)
261 throw new Exception ("Invalid Interval Range");
262 this.total_start = (start << 2) + (front_inclusive ? -1 : 1);
263 this.total_end = (end << 2) + (rear_inclusive ? 1 : -1);
264 this.stack = new Stack<MTextProperty> ();
268 private MInterval (int start, int end, Stack<MTextProperty> stack)
270 this.total_start = start;
271 this.total_end = end;
272 this.stack = new Stack<MTextProperty> (stack);
276 private MInterval Copy ()
278 return new MInterval (total_start, total_end, stack);
283 return (left == null ? total_start : total_start + left.total_end);
289 return (right == null ? total_end : total_end + right.total_start);
293 private MInterval Left {
298 for (interval = left;
299 interval.right != null;
300 interval = interval.right);
302 for (interval = parent;
303 interval != null && interval.total_start == 0;
304 interval = interval.parent);
310 private MInterval Right {
315 for (interval = right;
316 interval.left != null;
317 interval = interval.left);
319 for (interval = parent;
320 interval != null && interval.total_start < 0;
321 interval = interval.parent);
327 public void Push (MTextProperty prop, int start, int end)
330 if (prop.FrontSticky)
340 throw new Exception ("Invalid Text Property Range");
342 push (prop, start, end);
345 private MInterval divide_right (int pos)
347 MInterval interval = Copy ();
348 int this_start = Start;
351 if (left == null || (right != null && left.depth < right.depth))
353 interval.left = this;
354 interval.right = right;
355 interval.parent = parent;
358 if (total_start == 0)
359 parent.left = interval;
361 parent.right = interval;
363 interval.depth = depth;
367 total_end = pos - this_start;
371 interval.total_start = pos - this_end;
372 interval.total_end = 0;
374 right.parent = interval;
381 private MInterval divide_left (int pos)
383 MInterval interval = Copy ();
384 int this_start = Start;
387 if (left == null || (right != null && left.depth < right.depth))
389 interval.total_start = 0;
390 interval.total_end = pos - this_start;
392 left.parent = interval;
397 interval.right = this;
398 interval.left = left;
399 interval.parent = parent;
402 if (total_start == 0)
403 parent.left = interval;
405 parent.right = interval;
407 interval.depth = depth;
410 total_start = pos - this_end;
417 private void push (MTextProperty prop, int start, int end)
419 int this_start = Start;
422 if (start < this_start)
424 if (end <= this_start)
425 Left.push (prop, start, end);
428 Left.push (prop, start, this_start);
438 Right.Push (prop, this_end, end);
442 else if (start < this_end)
444 divide_right (start).Push (prop, start, end);
447 Right.Push (prop, start, end);