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;
45 public class MText : IEnumerable, IComparable<MText>, IEquatable<MText>
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++, n++)
65 if (surrogate_high_p (str[i]))
70 private static int count_chars (StringBuilder str)
72 int len = str.Length, n = 0;
74 for (int i = 0; i < len; i++, n++)
75 if (surrogate_high_p (str[i]))
82 sb = new StringBuilder ();
85 public MText (byte[] str)
87 sb = new StringBuilder (utf8.GetString (str));
88 nchars = count_chars (sb);
91 public MText (String str)
93 sb = new StringBuilder (str);
94 nchars = count_chars (str);
97 public MText (StringBuilder str)
100 nchars = count_chars (str);
103 public static MText operator+ (MText mt1, MText mt2)
105 MText mt = new MText ();
107 mt.sb.Append (mt1.sb);
108 mt.sb.Append (mt2.sb);
109 mt.nchars = mt1.nchars + mt2.nchars;
113 public bool ReadOnly { get { return read_only; } }
114 public int Length { get { return nchars; } }
116 public int CompareTo (MText other)
118 return this.sb.ToString ().CompareTo (other.sb.ToString ());
121 public bool Equals (MText other)
123 return this.sb.Equals (other.sb);
126 public override String ToString ()
128 return sb.ToString ();
131 private static bool surrogate_high_p (char c)
133 return (c >= 0xD800 && c < 0xDC00);
136 private static bool surrogate_low_p (char c)
138 return (c >= 0xDC00 && c < 0xE000);
141 private static int inc_idx (StringBuilder sb, int i)
143 return (i + (surrogate_high_p (sb[i]) ? 2 : 1));
146 private static int dec_idx (StringBuilder sb, int i)
148 return (i - (surrogate_low_p (sb[i - 1]) ? 2 : 1));
151 private static int pos_to_idx (MText mt, int pos)
153 if (pos == mt.cache_pos)
159 if (pos < mt.cache_pos)
161 if (mt.cache_pos == mt.cache_idx)
163 if (pos < mt.cache_pos - pos)
170 p = mt.cache_pos; i = mt.cache_idx;
176 if (mt.nchars - mt.cache_pos == mt.sb.Length - mt.cache_idx)
177 return (mt.cache_idx + pos - mt.cache_pos);
178 if (pos - mt.cache_pos < mt.nchars - pos)
180 p = mt.cache_pos; i = mt.cache_idx;
185 p = mt.nchars; i = mt.sb.Length;
190 for (; p < pos; i = inc_idx (mt.sb, i), p++);
192 for (; p > pos; i = dec_idx (mt.sb, i), p--);
198 private void insert (int pos, MText mt2, int from, int to)
200 int pos_idx = pos_to_idx (this, pos);
201 int from_idx = pos_to_idx (mt2, from);
202 int to_idx = pos_to_idx (mt2, to);
204 sb.Insert (pos_idx, mt2.sb.ToString (from_idx, to_idx - from_idx));
208 public int this[int i]
211 i = pos_to_idx (this, i);
214 if (surrogate_high_p (sb[i]))
216 sb[i] = (char) value;
220 char high = (char) (0xD800 + ((value - 0x10000) >> 10));
221 char low = (char) (0xDC00 + ((value - 0x10000) & 0x3FF));
223 if (! surrogate_high_p (sb[i]))
230 i = pos_to_idx (this, i);
231 return (surrogate_high_p (sb[i])
232 ? ((sb[i] - 0xD800) << 10) + (sb[i + 1] - 0xDC00) + 0x10000
239 return (new MText (sb.ToString ()));
242 public MText ins (int pos, MText mt)
244 insert (pos, mt, 0, mt.nchars);
248 public MText ins (int pos, MText mt, int from, int to)
250 insert (pos, mt, from, to);
254 public MText del (int from, int to)
256 sb.Remove (from, pos_to_idx (this, to) - pos_to_idx (this, from));
261 public void PushProp (int from, int to, MTextProperty prop)
263 if (root_interval == null)
264 root_interval = new MInterval (0, true, sb.Length, true);
265 root_interval.Push (from, to, prop);
268 public IEnumerator GetEnumerator()
270 return new MTextEnum (this);
273 private class MInterval
275 // Start and end positions of this interval and its children.
276 // If this is the left node, the values are relative to the
277 // parent's total_start. Otherwise, the values are relatie to
278 // the parent's total_end.
279 private int total_start, total_end;
280 // Stack of MTextProperty
281 private Stack<MTextProperty> stack;
283 private MInterval left, right, parent;
285 public MInterval (int start, bool front_inclusive,
286 int end, bool rear_inclusive)
289 throw new Exception ("Invalid Interval Range");
290 this.total_start = (start << 2) + (front_inclusive ? -1 : 1);
291 this.total_end = (end << 2) + (rear_inclusive ? 1 : -1);
292 this.stack = new Stack<MTextProperty> ();
296 private MInterval (int start, int end, Stack<MTextProperty> stack)
298 this.total_start = start;
299 this.total_end = end;
300 this.stack = new Stack<MTextProperty> (stack);
304 private MInterval Copy ()
306 return new MInterval (total_start, total_end, stack);
311 return (left == null ? total_start : total_start + left.total_end);
317 return (right == null ? total_end : total_end + right.total_start);
321 private MInterval Left {
326 for (interval = left;
327 interval.right != null;
328 interval = interval.right);
330 for (interval = parent;
331 interval != null && interval.total_start == 0;
332 interval = interval.parent);
338 private MInterval Right {
343 for (interval = right;
344 interval.left != null;
345 interval = interval.left);
347 for (interval = parent;
348 interval != null && interval.total_start < 0;
349 interval = interval.parent);
355 public void Push (int start, int end, MTextProperty prop)
358 if (prop.FrontSticky)
368 throw new Exception ("Invalid Text Property Range");
370 push (start, end, prop);
373 private MInterval divide_right (int pos)
375 MInterval interval = Copy ();
376 int this_start = Start;
379 if (left == null || (right != null && left.depth < right.depth))
381 interval.left = this;
382 interval.right = right;
383 interval.parent = parent;
386 if (total_start == 0)
387 parent.left = interval;
389 parent.right = interval;
391 interval.depth = depth;
395 total_end = pos - this_start;
399 interval.total_start = pos - this_end;
400 interval.total_end = 0;
402 right.parent = interval;
409 private MInterval divide_left (int pos)
411 MInterval interval = Copy ();
412 int this_start = Start;
415 if (left == null || (right != null && left.depth < right.depth))
417 interval.total_start = 0;
418 interval.total_end = pos - this_start;
420 left.parent = interval;
425 interval.right = this;
426 interval.left = left;
427 interval.parent = parent;
430 if (total_start == 0)
431 parent.left = interval;
433 parent.right = interval;
435 interval.depth = depth;
438 total_start = pos - this_end;
445 private void push (int start, int end, MTextProperty prop)
447 int this_start = Start;
450 if (start < this_start)
452 if (end <= this_start)
454 Left.push (start, end, prop);
457 Left.push (start, this_start, prop);
462 if (this_end < start)
464 Right.push (start, end, prop);
467 Right.push (this_end, end, prop);
470 if (this_start < start)
478 private class MTextEnum : IEnumerator
481 private int pos = -1;
483 public MTextEnum (MText mt)
488 public bool MoveNext ()
491 return (pos < mt.nchars);
499 public object Current
502 //if (pos < 0 || pos >= mt.nchars)
503 //throw new InvalidOperationException ();