CH-J SM Mobileการจัดการเซิร์ฟเวอร์ผ่าน SSH
เมนู
ซอร์สที่เผยแพร่

CH-J SM Mobile

เรียกดูไดเรกทอรีและไฟล์ของรุ่นแอปพลิเคชันที่ระบุ

ดาวน์โหลด ZIP ของซอร์ส
CH-J / SM Mobile 175 ไฟล์
sm-mobile-20261016T185235Z-8e93ecc1b59a วันที่เพิ่ม: · วันที่บิลด์:
text_codec.dart วันที่เพิ่ม: ไม่ได้บันทึกวันที่ 10.1 KB · 334 บรรทัด
โค้ด ดาวน์โหลดไฟล์
1import 'dart:convert';
2import 'dart:isolate';
3import 'dart:typed_data';
4import 'charset_tables.dart';
6/// Text encodings the editor can read and write without loss.
7enum TextEncoding {
8 utf8('UTF-8'),
9 utf8Bom('UTF-8 BOM'),
10 utf16le('UTF-16 LE'),
11 utf16be('UTF-16 BE'),
12 windows1250('Windows-1250'),
13 windows1252('Windows-1252'),
14 iso88592('ISO-8859-2'),
15 latin1('ISO-8859-1');
17 final String label;
18 const TextEncoding(this.label);
20 /// The byte order mark written before the text, if any.
21 List<int> get bom => switch (this) {
22 utf8Bom => const [0xef, 0xbb, 0xbf],
23 utf16le => const [0xff, 0xfe],
24 utf16be => const [0xfe, 0xff],
25 _ => const [],
26 };
29enum LineBreak {
30 lf('LF', '\n'),
31 crlf('CRLF', '\r\n'),
32 cr('CR', '\r');
34 final String label, value;
35 const LineBreak(this.label, this.value);
38/// A character the target encoding cannot represent.
39class UnencodableText implements Exception {
40 final TextEncoding encoding;
41 final String sample;
42 final int count;
43 const UnencodableText(this.encoding, this.sample, this.count);
44 @override
45 String toString() => 'UnencodableText(${encoding.label}, $sample ×$count)';
48/// Line breaks used in a text.
49class LineBreakInfo {
50 final int lf, crlf, cr;
51 const LineBreakInfo(this.lf, this.crlf, this.cr);
52 bool get mixed => [lf, crlf, cr].where((n) => n > 0).length > 1;
53 LineBreak get dominant {
54 if (crlf >= lf && crlf >= cr && crlf > 0) return LineBreak.crlf;
55 if (cr > lf && cr > 0) return LineBreak.cr;
56 return LineBreak.lf;
57 }
59 static LineBreakInfo of(String text) {
60 var lf = 0, crlf = 0, cr = 0;
61 for (var i = 0; i < text.length; i++) {
62 final c = text.codeUnitAt(i);
63 if (c == 0x0d) {
64 if (i + 1 < text.length && text.codeUnitAt(i + 1) == 0x0a) {
65 crlf++;
66 i++;
67 } else {
68 cr++;
69 }
70 } else if (c == 0x0a) {
71 lf++;
72 }
73 }
74 return LineBreakInfo(lf, crlf, cr);
75 }
78/// The result of reading a file as text.
79class DecodedText {
80 final String text;
81 final TextEncoding encoding;
82 final LineBreakInfo lineBreaks;
83 final bool finalNewline;
85 /// True when the bytes come back unchanged if the text is saved
86 /// unchanged with [encoding] and the dominant line break.
87 final bool exact;
88 const DecodedText(
89 this.text,
90 this.encoding,
91 this.lineBreaks,
92 this.finalNewline, {
93 required this.exact,
94 });
97/// Whether [bytes] are most likely not text: NUL bytes or many control
98/// characters, unless the data is UTF-16.
99bool looksBinary(Uint8List bytes) {
100 final n = bytes.length < 8192 ? bytes.length : 8192;
101 if (n == 0) return false;
102 if (_utf16Guess(bytes) != null) return false;
103 var control = 0;
104 for (var i = 0; i < n; i++) {
105 final b = bytes[i];
106 if (b == 0) return true;
107 if (b < 0x09 || (b > 0x0d && b < 0x20)) control++;
108 }
109 return control * 10 > n;
112bool _startsWith(Uint8List b, List<int> prefix) {
113 if (b.length < prefix.length) return false;
114 for (var i = 0; i < prefix.length; i++) {
115 if (b[i] != prefix[i]) return false;
116 }
117 return true;
120/// UTF-16 without a byte order mark, recognised by NUL bytes in every
121/// other position (mostly ASCII text).
122TextEncoding? _utf16Guess(Uint8List b) {
123 final n = (b.length < 4096 ? b.length : 4096) & ~1;
124 if (n < 4) return null;
125 var evenZero = 0, oddZero = 0;
126 for (var i = 0; i < n; i += 2) {
127 if (b[i] == 0) evenZero++;
128 if (b[i + 1] == 0) oddZero++;
129 }
130 final pairs = n ~/ 2;
131 if (oddZero > pairs * 0.4 && evenZero < pairs * 0.05) {
132 return TextEncoding.utf16le;
133 }
134 if (evenZero > pairs * 0.4 && oddZero < pairs * 0.05) {
135 return TextEncoding.utf16be;
136 }
137 return null;
140/// Detects the encoding: a byte order mark, then valid UTF-8, then UTF-16
141/// without BOM. Returns null when the encoding cannot be known (legacy
142/// 8-bit text); the user then chooses, nothing is converted silently.
143TextEncoding? detectEncoding(Uint8List bytes) {
144 if (_startsWith(bytes, TextEncoding.utf8Bom.bom)) return TextEncoding.utf8Bom;
145 if (_startsWith(bytes, TextEncoding.utf16le.bom)) return TextEncoding.utf16le;
146 if (_startsWith(bytes, TextEncoding.utf16be.bom)) return TextEncoding.utf16be;
147 final utf16 = _utf16Guess(bytes);
148 if (utf16 != null) return utf16;
149 try {
150 utf8.decode(bytes);
151 return TextEncoding.utf8;
152 } on FormatException {
153 return null;
154 }
157String _decodeSingleByte(Uint8List b, List<int>? high) {
158 final units = Uint16List(b.length);
159 for (var i = 0; i < b.length; i++) {
160 final v = b[i];
161 if (v < 0x80 || high == null) {
162 units[i] = v;
163 } else {
164 final c = high[v - 0x80];
165 if (c < 0) {
166 throw FormatException('Byte 0x${v.toRadixString(16)} undefined', b, i);
167 }
168 units[i] = c;
169 }
170 }
171 return String.fromCharCodes(units);
174List<int>? _table(TextEncoding e) => switch (e) {
175 TextEncoding.windows1250 => windows1250High,
176 TextEncoding.windows1252 => windows1252High,
177 TextEncoding.iso88592 => iso88592High,
178 _ => null,
179};
181/// Decodes [bytes] as [encoding]. Throws [FormatException] for bytes that
182/// are not valid in that encoding.
183String decodeText(Uint8List bytes, TextEncoding encoding) {
184 final bom = encoding.bom;
185 final body = _startsWith(bytes, bom)
186 ? Uint8List.sublistView(bytes, bom.length)
187 : bytes;
188 switch (encoding) {
189 case TextEncoding.utf8:
190 case TextEncoding.utf8Bom:
191 return utf8.decode(body);
192 case TextEncoding.utf16le:
193 case TextEncoding.utf16be:
194 if (body.length.isOdd) {
195 throw const FormatException('UTF-16 data has an odd length');
196 }
197 final le = encoding == TextEncoding.utf16le;
198 final units = Uint16List(body.length ~/ 2);
199 for (var i = 0; i < units.length; i++) {
200 final a = body[2 * i], b = body[2 * i + 1];
201 units[i] = le ? a | (b << 8) : (a << 8) | b;
202 }
203 // Unpaired surrogates would not survive a round trip.
204 for (var i = 0; i < units.length; i++) {
205 final u = units[i];
206 if (u >= 0xd800 && u <= 0xdbff) {
207 if (i + 1 >= units.length ||
208 units[i + 1] < 0xdc00 ||
209 units[i + 1] > 0xdfff) {
210 throw FormatException('Unpaired surrogate', body, 2 * i);
211 }
212 i++;
213 } else if (u >= 0xdc00 && u <= 0xdfff) {
214 throw FormatException('Unpaired surrogate', body, 2 * i);
215 }
216 }
217 return String.fromCharCodes(units);
218 case TextEncoding.latin1:
219 return _decodeSingleByte(body, null);
220 case TextEncoding.windows1250:
221 case TextEncoding.windows1252:
222 case TextEncoding.iso88592:
223 return _decodeSingleByte(body, _table(encoding));
224 }
227/// Encodes [text] as [encoding], including its byte order mark. Throws
228/// [UnencodableText] when a character cannot be represented, instead of
229/// replacing it.
230Uint8List encodeText(String text, TextEncoding encoding) {
231 final out = BytesBuilder(copy: false)..add(encoding.bom);
232 switch (encoding) {
233 case TextEncoding.utf8:
234 case TextEncoding.utf8Bom:
235 out.add(utf8.encode(text));
236 case TextEncoding.utf16le:
237 case TextEncoding.utf16be:
238 final le = encoding == TextEncoding.utf16le;
239 final b = Uint8List(text.length * 2);
240 for (var i = 0; i < text.length; i++) {
241 final u = text.codeUnitAt(i);
242 b[2 * i] = le ? u & 0xff : u >> 8;
243 b[2 * i + 1] = le ? u >> 8 : u & 0xff;
244 }
245 out.add(b);
246 case TextEncoding.latin1:
247 case TextEncoding.windows1250:
248 case TextEncoding.windows1252:
249 case TextEncoding.iso88592:
250 final table = _table(encoding);
251 final reverse = <int, int>{
252 if (table != null)
253 for (var i = 0; i < 128; i++)
254 if (table[i] >= 0) table[i]: 0x80 + i,
255 };
256 final b = Uint8List(text.length);
257 String? sample;
258 var bad = 0;
259 for (var i = 0; i < text.length; i++) {
260 final u = text.codeUnitAt(i);
261 int? v;
262 if (u < 0x80) {
263 v = u;
264 } else if (table == null) {
265 v = u <= 0xff ? u : null;
266 } else {
267 v = reverse[u];
268 }
269 if (v == null) {
270 bad++;
271 sample ??= String.fromCharCode(u);
272 v = 0x3f;
273 }
274 b[i] = v;
275 }
276 if (bad > 0) throw UnencodableText(encoding, sample!, bad);
277 out.add(b);
278 }
279 return out.takeBytes();
282bool _sameBytes(Uint8List a, Uint8List b) {
283 if (a.length != b.length) return false;
284 for (var i = 0; i < a.length; i++) {
285 if (a[i] != b[i]) return false;
286 }
287 return true;
290/// Decodes [bytes] for editing and records everything needed to write them
291/// back unchanged. Throws [FormatException] when [encoding] (or the
292/// detected one) does not fit, and [UnknownEncoding] when no encoding
293/// could be detected.
294DecodedText decodeDocument(Uint8List bytes, {TextEncoding? encoding}) {
295 final enc = encoding ?? detectEncoding(bytes);
296 if (enc == null) throw const UnknownEncoding();
297 final text = decodeText(bytes, enc);
298 final breaks = LineBreakInfo.of(text);
299 final finalNewline = text.endsWith('\n') || text.endsWith('\r');
300 bool exact;
301 try {
302 exact = !breaks.mixed && _sameBytes(encodeText(text, enc), bytes);
303 } on UnencodableText {
304 exact = false;
305 }
306 return DecodedText(text, enc, breaks, finalNewline, exact: exact);
309class UnknownEncoding implements Exception {
310 const UnknownEncoding();
313/// Joins editor lines (already split on any line break) with [lineBreak].
314String withLineBreaks(String text, LineBreak lineBreak) {
315 final normalized = text.replaceAll('\r\n', '\n').replaceAll('\r', '\n');
316 return lineBreak == LineBreak.lf
317 ? normalized
318 : normalized.replaceAll('\n', lineBreak.value);
321/// [decodeDocument] on a background isolate for large files. Top-level so
322/// that the closure sent to the isolate captures only its arguments.
323Future<DecodedText> decodeInBackground(
324 Uint8List bytes, {
325 TextEncoding? encoding,
326}) => bytes.length > 256 * 1024
327 ? Isolate.run(() => decodeDocument(bytes, encoding: encoding))
328 : Future.value(decodeDocument(bytes, encoding: encoding));
330/// [encodeText] on a background isolate for large texts.
331Future<Uint8List> encodeInBackground(String text, TextEncoding encoding) =>
332 text.length > 256 * 1024
333 ? Isolate.run(() => encodeText(text, encoding))
334 : Future.value(encodeText(text, encoding));
SHA-2560ad2c36cdc055a4dc3f5f3b416914869e48835e95b7f570e55adbf1188fc33da

CH-J Proprietary Software License 1.14 · ซอร์สโค้ดนี้ให้ไว้ภายใต้ CH-J Proprietary Software License 1.14 การเปิดให้เข้าถึงไม่ได้เปลี่ยนแปลงเงื่อนไขของสัญญาอนุญาตหรือให้สิทธิ์เพิ่มเติม

SHA-256 ของไฟล์บีบอัด46e427a43e87af091004f36145590bda8fe90086dfb0f631afeb5029fb0b5655
ไฟล์