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 the MText covered of this interval
248 // and its children. The values are actually (4N +- 1), where N
249 // is a non-negative integer representing a position relative to
250 // the parent interval.
251 private int total_start, total_end;
252 // Stack of MTextProperty
253 private Stack<MTextProperty> stack;
254 // Number of child nodes
256 private MInterval left, right, parent;
260 return (left == null ? total_start : total_start + left.total_end);
266 return (right == null ? total_end : total_start + right.total_start);
270 private MInterval Left {
276 for (interval = left; interval.right != null;
277 interval = interval.right);
281 for (interval = parent;
282 interval != null && interval.total_start == total_start;
283 interval = interval.parent);
289 private MInterval Right {
295 for (interval = right; interval.left != null;
296 interval = interval.left);
300 for (interval = parent;
301 interval != null && interval.total_end == total_end;
302 interval = interval.parent);
308 private static int MakePosition (int pos, bool front_inclusive)
310 return (pos << 2) + (front_inclusive ? -1 : 1);
313 private MInterval (int start, int end)
316 throw new Exception ("Invalid Interval Range");
317 this.total_start = (start << 2) + 1;
318 this.total_end = (end << 2) + -1;
319 this.stack = new Stack<MTextProperty> ();
323 public MInterval (int start, bool front_inclusive,
324 int end, bool rear_inclusive)
327 throw new Exception ("Invalid Interval Range");
328 this.total_start = (start << 2) + (front_inclusive ? -1 : 1);
329 this.total_end = (end << 2) + (rear_inclusive ? 1 : -1);
330 this.stack = new Stack<MTextProperty> ();
334 public void Push (MTextProperty prop, int start, int end)
337 if (prop.FrontSticky)
347 throw new Exception ("Invalid Text Property Range");
349 push (prop, start, end);
352 private MInterval divide_right (int pos)
354 MInterval interval = new MInterval (pos, End);
359 private MInterval divide_left (int pos)
361 MInterval interval = new MInterval (Start, pos);
366 private void push (MTextProperty prop, int start, int end)
368 int this_start = Start;
371 if (start < this_start)
373 if (end <= this_start)
374 Left.push (prop, start, end);
377 Left.push (prop, start, this_start);
387 Right.Push (prop, this_end, end);
391 else if (start < this_end)
393 divide_right (start).Push (prop, start, end);
396 Right.Push (prop, start, end);