@kaeawc/auto-mobile 0.0.88 → 0.0.90
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.md.backup +1 -1
- package/dist/build-info.json +13 -9
- package/dist/schemas/test-plan.schema.json +20 -0
- package/dist/src/index.js +1632 -823
- package/mcp-skills/auto-mobile-usage/SKILL.md +45 -0
- package/node_modules/@borewit/text-codec/LICENSE.txt +9 -9
- package/node_modules/@borewit/text-codec/README.md +86 -86
- package/node_modules/@borewit/text-codec/lib/index.js +102 -120
- package/node_modules/@borewit/text-codec/package.json +71 -70
- package/node_modules/strtok3/README.md +25 -1
- package/node_modules/strtok3/lib/AbstractTokenizer.js +12 -4
- package/node_modules/strtok3/lib/BlobTokenizer.js +1 -0
- package/node_modules/strtok3/lib/BufferTokenizer.js +1 -0
- package/node_modules/strtok3/lib/FileTokenizer.js +3 -3
- package/node_modules/strtok3/lib/ReadStreamTokenizer.js +10 -0
- package/node_modules/strtok3/lib/index.js +28 -5
- package/node_modules/strtok3/lib/stream/StreamReader.js +29 -8
- package/node_modules/strtok3/package.json +1 -1
- package/package.json +20 -14
- package/schemas/test-plan.schema.json +20 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: auto-mobile-usage
|
|
3
|
+
description: How to drive Android and iOS devices with AutoMobile MCP tools. Use before acquiring a device, observing a screen, or acting on one, and when a call fails with device_owned_by_other_session, device_service_disabled or capacity_exhausted.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Driving devices with AutoMobile
|
|
7
|
+
|
|
8
|
+
## 1. Get a session first
|
|
9
|
+
|
|
10
|
+
- Acquire a device with `getAndroid` or `getApple`. It finds or boots one and returns a `sessionUuid`.
|
|
11
|
+
- A connection that acquired a device is bound to it, so later calls route to that session without repeating it. A different connection, or a CLI call, passes `sessionUuid` on every call.
|
|
12
|
+
- A device that a session holds takes control calls only from that session (`device_owned_by_other_session` otherwise). Naming someone else's `sessionUuid` never takes the device over.
|
|
13
|
+
- `setActiveDevice` and acquisition are the only calls that change which session an untargeted call uses. With several sessions, pass `sessionUuid` or `deviceId` (`ambiguous_session_selector`).
|
|
14
|
+
- `session_ownership_lost` and `no_active_device_session` are permanent for that session: acquire a new one.
|
|
15
|
+
|
|
16
|
+
## 2. Observe before you act
|
|
17
|
+
|
|
18
|
+
- Call `observe` before the first action and again after each action that can change the screen. Coordinates and Android synthetic `s2-` element ids are valid only for the observation that returned them.
|
|
19
|
+
- Act on what `observe` returned: `tapOn` takes a `selector` (`text`, `elementId`, `testTag`), `swipeOn` scrolls the screen or a container (`lookFor` scrolls until an element appears), `tapAt` takes coordinates, `sendKeys` types into the focused field. Do not guess coordinates.
|
|
20
|
+
- `skeleton` lists only rows you can act on. Static text (a status label, a validation error, a result message) is in `context`; read it there to verify a result. `waitFor` with `text` or `textAny`, or `for: "appear"`/`"textEquals"` with only `text`, matches text in either array.
|
|
21
|
+
- Ask `observe` for a screenshot only when the hierarchy is not enough; images are the largest part of a result.
|
|
22
|
+
|
|
23
|
+
## 3. Resources versus tools
|
|
24
|
+
|
|
25
|
+
- Tools act or run a computation. Resources (`automobile:` URIs) are cheap read-only state: `automobile:tools` lists every tool and whether it is enabled, `automobile:devices/booted` lists booted devices, `automobile:observation/latest` is the latest observation.
|
|
26
|
+
- Read a resource instead of calling a tool when you only need state. A sessionless read never takes a held device.
|
|
27
|
+
- A tool that is gated off does not appear in `tools/list`. Enable it with `setToolEnabled` or the `enableTools` argument of `getAndroid` and `getApple`.
|
|
28
|
+
|
|
29
|
+
## 4. Long operations and Tasks
|
|
30
|
+
|
|
31
|
+
- `executePlan`, `installApp` and `videoRecording` with `action: "stop"` can run as a task when your client declares the Tasks extension. You get a task handle, poll it with `tasks/get`, and cancel with `tasks/cancel`; the work survives a client reconnect.
|
|
32
|
+
- Do not wrap short interaction calls (`tapOn`, `sendKeys`, `pressButton`) in tasks. Without Tasks support the same calls simply block until done.
|
|
33
|
+
|
|
34
|
+
## 5. Typed errors
|
|
35
|
+
|
|
36
|
+
An error result carries a stable `code`. Read `code` and `retryable` instead of the message text.
|
|
37
|
+
|
|
38
|
+
| Code | Meaning and next step |
|
|
39
|
+
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
40
|
+
| `capacity_exhausted` | The platform is at its booted-device limit. Retryable: wait `retryAfterMs`, or shut down a device you hold, then repeat the acquisition. Do not loop faster than `retryAfterMs`. |
|
|
41
|
+
| `device_service_disabled` | A simulator service the tool needs is switched off. Not retryable until you act: follow `howToEnable` in the error (enable it with `setDeviceResources`) or start the simulator without it. |
|
|
42
|
+
| `device_owned_by_other_session` | Another session holds the device. Acquire your own device or pass the right `sessionUuid`. |
|
|
43
|
+
| `plan_execution_in_progress` | A plan is running on the session. Retry when it finishes; reads stay allowed. |
|
|
44
|
+
|
|
45
|
+
Release a device you no longer need so other sessions can use it.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
The MIT License (MIT)
|
|
2
|
-
|
|
3
|
-
Copyright © 2025 Borewit
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
-
|
|
7
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
-
|
|
9
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright © 2025 Borewit
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -1,87 +1,87 @@
|
|
|
1
|
-
[](https://github.com/Borewit/text-codec/actions/workflows/ci.yml)
|
|
2
|
-
[](https://www.npmjs.com/package/@borewit/text-codec)
|
|
3
|
-
[](https://npmcharts.com/compare/@borewit/text-codec?interval=30)
|
|
4
|
-

|
|
5
|
-
[](LICENSE.txt)
|
|
6
|
-
|
|
7
|
-
# `@borewit/text-codec`
|
|
8
|
-
|
|
9
|
-
A **lightweight polyfill for text encoders and decoders** covering a small set of commonly used encodings.
|
|
10
|
-
|
|
11
|
-
Some JavaScript runtimes provide limited or inconsistent encoding support through `TextEncoder` and `TextDecoder`.
|
|
12
|
-
Examples include environments like **Hermes (React Native)** or certain **Node.js builds with limited ICU support**.
|
|
13
|
-
|
|
14
|
-
This module provides **reliable encode/decode support for a small set of encodings that may be missing or unreliable in those environments**.
|
|
15
|
-
|
|
16
|
-
- If a native UTF-8 `TextEncoder` / `TextDecoder` is available, it is used.
|
|
17
|
-
- All other encodings are implemented by this library.
|
|
18
|
-
|
|
19
|
-
## Supported encodings
|
|
20
|
-
|
|
21
|
-
- `utf-8` / `utf8`
|
|
22
|
-
- `utf-16le`
|
|
23
|
-
- `ascii`
|
|
24
|
-
- `latin1` / `iso-8859-1`
|
|
25
|
-
- `windows-1252`
|
|
26
|
-
|
|
27
|
-
These encodings are commonly encountered in metadata formats and legacy text data.
|
|
28
|
-
|
|
29
|
-
## ✨ Features
|
|
30
|
-
|
|
31
|
-
- Encoding and decoding utilities
|
|
32
|
-
- Lightweight
|
|
33
|
-
- Typed API
|
|
34
|
-
|
|
35
|
-
## 📦 Installation
|
|
36
|
-
|
|
37
|
-
```sh
|
|
38
|
-
npm install @borewit/text-codec
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
# 📚 API Documentation
|
|
42
|
-
|
|
43
|
-
## `textDecode(bytes, encoding): string`
|
|
44
|
-
|
|
45
|
-
Decodes binary data into a JavaScript string.
|
|
46
|
-
|
|
47
|
-
**Parameters**
|
|
48
|
-
- `bytes` (`Uint8Array`) — The binary data to decode.
|
|
49
|
-
- `encoding` (`SupportedEncoding`, optional) — Encoding type. Defaults to `"utf-8"`.
|
|
50
|
-
|
|
51
|
-
**Returns**
|
|
52
|
-
- `string` — The decoded text.
|
|
53
|
-
|
|
54
|
-
**Example**
|
|
55
|
-
```js
|
|
56
|
-
import { textDecode } from "@borewit/text-codec";
|
|
57
|
-
|
|
58
|
-
const bytes = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f]);
|
|
59
|
-
const text = textDecode(bytes, "ascii");
|
|
60
|
-
console.log(text); // "Hello"
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## `textEncode(input, encoding): Uint8Array`
|
|
64
|
-
|
|
65
|
-
Encodes a JavaScript string into binary form using the specified encoding.
|
|
66
|
-
|
|
67
|
-
**Parameters**
|
|
68
|
-
|
|
69
|
-
- `input` (`string`) — The string to encode.
|
|
70
|
-
- `encoding` (`SupportedEncoding`, optional) — Encoding type. Defaults to `"utf-8"`.
|
|
71
|
-
|
|
72
|
-
**Returns**
|
|
73
|
-
|
|
74
|
-
`Uint8Array` — The encoded binary data.
|
|
75
|
-
|
|
76
|
-
Example:
|
|
77
|
-
```js
|
|
78
|
-
import { textEncode } from "@borewit/text-codec";
|
|
79
|
-
|
|
80
|
-
const bytes = textEncode("Hello", "utf-16le");
|
|
81
|
-
console.log(bytes); // Uint8Array([...])
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
## 📜 Licence
|
|
85
|
-
|
|
86
|
-
This project is licensed under the [MIT License](LICENSE.txt). Feel free to use, modify, and distribute as needed.
|
|
1
|
+
[](https://github.com/Borewit/text-codec/actions/workflows/ci.yml)
|
|
2
|
+
[](https://www.npmjs.com/package/@borewit/text-codec)
|
|
3
|
+
[](https://npmcharts.com/compare/@borewit/text-codec?interval=30)
|
|
4
|
+

|
|
5
|
+
[](LICENSE.txt)
|
|
6
|
+
|
|
7
|
+
# `@borewit/text-codec`
|
|
8
|
+
|
|
9
|
+
A **lightweight polyfill for text encoders and decoders** covering a small set of commonly used encodings.
|
|
10
|
+
|
|
11
|
+
Some JavaScript runtimes provide limited or inconsistent encoding support through `TextEncoder` and `TextDecoder`.
|
|
12
|
+
Examples include environments like **Hermes (React Native)** or certain **Node.js builds with limited ICU support**.
|
|
13
|
+
|
|
14
|
+
This module provides **reliable encode/decode support for a small set of encodings that may be missing or unreliable in those environments**.
|
|
15
|
+
|
|
16
|
+
- If a native UTF-8 `TextEncoder` / `TextDecoder` is available, it is used.
|
|
17
|
+
- All other encodings are implemented by this library.
|
|
18
|
+
|
|
19
|
+
## Supported encodings
|
|
20
|
+
|
|
21
|
+
- `utf-8` / `utf8`
|
|
22
|
+
- `utf-16le`
|
|
23
|
+
- `ascii`
|
|
24
|
+
- `latin1` / `iso-8859-1`
|
|
25
|
+
- `windows-1252`
|
|
26
|
+
|
|
27
|
+
These encodings are commonly encountered in metadata formats and legacy text data.
|
|
28
|
+
|
|
29
|
+
## ✨ Features
|
|
30
|
+
|
|
31
|
+
- Encoding and decoding utilities
|
|
32
|
+
- Lightweight
|
|
33
|
+
- Typed API
|
|
34
|
+
|
|
35
|
+
## 📦 Installation
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
npm install @borewit/text-codec
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
# 📚 API Documentation
|
|
42
|
+
|
|
43
|
+
## `textDecode(bytes, encoding): string`
|
|
44
|
+
|
|
45
|
+
Decodes binary data into a JavaScript string.
|
|
46
|
+
|
|
47
|
+
**Parameters**
|
|
48
|
+
- `bytes` (`Uint8Array`) — The binary data to decode.
|
|
49
|
+
- `encoding` (`SupportedEncoding`, optional) — Encoding type. Defaults to `"utf-8"`.
|
|
50
|
+
|
|
51
|
+
**Returns**
|
|
52
|
+
- `string` — The decoded text.
|
|
53
|
+
|
|
54
|
+
**Example**
|
|
55
|
+
```js
|
|
56
|
+
import { textDecode } from "@borewit/text-codec";
|
|
57
|
+
|
|
58
|
+
const bytes = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f]);
|
|
59
|
+
const text = textDecode(bytes, "ascii");
|
|
60
|
+
console.log(text); // "Hello"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## `textEncode(input, encoding): Uint8Array`
|
|
64
|
+
|
|
65
|
+
Encodes a JavaScript string into binary form using the specified encoding.
|
|
66
|
+
|
|
67
|
+
**Parameters**
|
|
68
|
+
|
|
69
|
+
- `input` (`string`) — The string to encode.
|
|
70
|
+
- `encoding` (`SupportedEncoding`, optional) — Encoding type. Defaults to `"utf-8"`.
|
|
71
|
+
|
|
72
|
+
**Returns**
|
|
73
|
+
|
|
74
|
+
`Uint8Array` — The encoded binary data.
|
|
75
|
+
|
|
76
|
+
Example:
|
|
77
|
+
```js
|
|
78
|
+
import { textEncode } from "@borewit/text-codec";
|
|
79
|
+
|
|
80
|
+
const bytes = textEncode("Hello", "utf-16le");
|
|
81
|
+
console.log(bytes); // Uint8Array([...])
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## 📜 Licence
|
|
85
|
+
|
|
86
|
+
This project is licensed under the [MIT License](LICENSE.txt). Feel free to use, modify, and distribute as needed.
|
|
87
87
|
|
|
@@ -1,9 +1,31 @@
|
|
|
1
1
|
const WINDOWS_1252_EXTRA = {
|
|
2
|
-
0x80:
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
0x80: '€',
|
|
3
|
+
0x82: '‚',
|
|
4
|
+
0x83: 'ƒ',
|
|
5
|
+
0x84: '„',
|
|
6
|
+
0x85: '…',
|
|
7
|
+
0x86: '†',
|
|
8
|
+
0x87: '‡',
|
|
9
|
+
0x88: 'ˆ',
|
|
10
|
+
0x89: '‰',
|
|
11
|
+
0x8a: 'Š',
|
|
12
|
+
0x8b: '‹',
|
|
13
|
+
0x8c: 'Œ',
|
|
14
|
+
0x8e: 'Ž',
|
|
15
|
+
0x91: '‘',
|
|
16
|
+
0x92: '’',
|
|
17
|
+
0x93: '“',
|
|
18
|
+
0x94: '”',
|
|
19
|
+
0x95: '•',
|
|
20
|
+
0x96: '–',
|
|
21
|
+
0x97: '—',
|
|
22
|
+
0x98: '˜',
|
|
23
|
+
0x99: '™',
|
|
24
|
+
0x9a: 'š',
|
|
25
|
+
0x9b: '›',
|
|
26
|
+
0x9c: 'œ',
|
|
27
|
+
0x9e: 'ž',
|
|
28
|
+
0x9f: 'Ÿ'
|
|
7
29
|
};
|
|
8
30
|
const WINDOWS_1252_REVERSE = {};
|
|
9
31
|
for (const [code, char] of Object.entries(WINDOWS_1252_EXTRA)) {
|
|
@@ -12,80 +34,86 @@ for (const [code, char] of Object.entries(WINDOWS_1252_EXTRA)) {
|
|
|
12
34
|
let _utf8Decoder;
|
|
13
35
|
let _utf8Encoder;
|
|
14
36
|
function utf8Decoder() {
|
|
15
|
-
if (
|
|
16
|
-
|
|
17
|
-
|
|
37
|
+
if (_utf8Decoder === undefined) {
|
|
38
|
+
try {
|
|
39
|
+
_utf8Decoder = typeof globalThis.TextDecoder === 'undefined' ? null : new globalThis.TextDecoder('utf-8');
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
_utf8Decoder = null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return _utf8Decoder !== null && _utf8Decoder !== void 0 ? _utf8Decoder : undefined;
|
|
18
46
|
}
|
|
19
47
|
function utf8Encoder() {
|
|
20
|
-
if (
|
|
21
|
-
|
|
22
|
-
|
|
48
|
+
if (_utf8Encoder === undefined) {
|
|
49
|
+
try {
|
|
50
|
+
_utf8Encoder = typeof globalThis.TextEncoder === 'undefined' ? null : new globalThis.TextEncoder();
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
_utf8Encoder = null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return _utf8Encoder !== null && _utf8Encoder !== void 0 ? _utf8Encoder : undefined;
|
|
23
57
|
}
|
|
24
58
|
const CHUNK = 32 * 1024;
|
|
25
59
|
const REPLACEMENT = 0xfffd;
|
|
26
60
|
/**
|
|
27
61
|
* Decode text from binary data
|
|
28
62
|
*/
|
|
29
|
-
export function textDecode(bytes, encoding =
|
|
63
|
+
export function textDecode(bytes, encoding = 'utf-8') {
|
|
30
64
|
switch (encoding.toLowerCase()) {
|
|
31
|
-
case
|
|
32
|
-
case
|
|
65
|
+
case 'utf-8':
|
|
66
|
+
case 'utf8': {
|
|
33
67
|
const dec = utf8Decoder();
|
|
34
68
|
return dec ? dec.decode(bytes) : decodeUTF8(bytes);
|
|
35
69
|
}
|
|
36
|
-
case
|
|
70
|
+
case 'utf-16le':
|
|
37
71
|
return decodeUTF16LE(bytes);
|
|
38
|
-
case
|
|
39
|
-
case
|
|
72
|
+
case 'us-ascii':
|
|
73
|
+
case 'ascii':
|
|
40
74
|
return decodeASCII(bytes);
|
|
41
|
-
case
|
|
42
|
-
case
|
|
75
|
+
case 'latin1':
|
|
76
|
+
case 'iso-8859-1':
|
|
43
77
|
return decodeLatin1(bytes);
|
|
44
|
-
case
|
|
78
|
+
case 'windows-1252':
|
|
45
79
|
return decodeWindows1252(bytes);
|
|
46
80
|
default:
|
|
47
81
|
throw new RangeError(`Encoding '${encoding}' not supported`);
|
|
48
82
|
}
|
|
49
83
|
}
|
|
50
|
-
export function textEncode(input =
|
|
84
|
+
export function textEncode(input = '', encoding = 'utf-8') {
|
|
51
85
|
switch (encoding.toLowerCase()) {
|
|
52
|
-
case
|
|
53
|
-
case
|
|
86
|
+
case 'utf-8':
|
|
87
|
+
case 'utf8': {
|
|
54
88
|
const enc = utf8Encoder();
|
|
55
89
|
return enc ? enc.encode(input) : encodeUTF8(input);
|
|
56
90
|
}
|
|
57
|
-
case
|
|
91
|
+
case 'utf-16le':
|
|
58
92
|
return encodeUTF16LE(input);
|
|
59
|
-
case
|
|
60
|
-
case
|
|
93
|
+
case 'us-ascii':
|
|
94
|
+
case 'ascii':
|
|
61
95
|
return encodeASCII(input);
|
|
62
|
-
case
|
|
63
|
-
case
|
|
96
|
+
case 'latin1':
|
|
97
|
+
case 'iso-8859-1':
|
|
64
98
|
return encodeLatin1(input);
|
|
65
|
-
case
|
|
99
|
+
case 'windows-1252':
|
|
66
100
|
return encodeWindows1252(input);
|
|
67
101
|
default:
|
|
68
102
|
throw new RangeError(`Encoding '${encoding}' not supported`);
|
|
69
103
|
}
|
|
70
104
|
}
|
|
71
|
-
function appendCodePoint(out, cp) {
|
|
72
|
-
if (cp <= 0xffff) {
|
|
73
|
-
out.push(String.fromCharCode(cp));
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
cp -= 0x10000;
|
|
77
|
-
out.push(String.fromCharCode(0xd800 + (cp >> 10), 0xdc00 + (cp & 0x3ff)));
|
|
78
|
-
}
|
|
79
105
|
function flushChunk(parts, chunk) {
|
|
80
|
-
if (chunk.length === 0)
|
|
106
|
+
if (chunk.length === 0) {
|
|
81
107
|
return;
|
|
108
|
+
}
|
|
82
109
|
parts.push(String.fromCharCode.apply(null, chunk));
|
|
83
110
|
chunk.length = 0;
|
|
84
111
|
}
|
|
85
112
|
function pushCodeUnit(parts, chunk, codeUnit) {
|
|
86
113
|
chunk.push(codeUnit);
|
|
87
|
-
if (chunk.length >= CHUNK)
|
|
114
|
+
if (chunk.length >= CHUNK) {
|
|
88
115
|
flushChunk(parts, chunk);
|
|
116
|
+
}
|
|
89
117
|
}
|
|
90
118
|
function pushCodePoint(parts, chunk, cp) {
|
|
91
119
|
if (cp <= 0xffff) {
|
|
@@ -101,10 +129,7 @@ function decodeUTF8(bytes) {
|
|
|
101
129
|
const chunk = [];
|
|
102
130
|
let i = 0;
|
|
103
131
|
// Match TextDecoder("utf-8") default BOM handling
|
|
104
|
-
if (bytes.length >= 3 &&
|
|
105
|
-
bytes[0] === 0xef &&
|
|
106
|
-
bytes[1] === 0xbb &&
|
|
107
|
-
bytes[2] === 0xbf) {
|
|
132
|
+
if (bytes.length >= 3 && bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf) {
|
|
108
133
|
i = 3;
|
|
109
134
|
}
|
|
110
135
|
while (i < bytes.length) {
|
|
@@ -120,83 +145,38 @@ function decodeUTF8(bytes) {
|
|
|
120
145
|
i++;
|
|
121
146
|
continue;
|
|
122
147
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
continue;
|
|
135
|
-
}
|
|
136
|
-
const cp = ((b1 & 0x1f) << 6) | (b2 & 0x3f);
|
|
137
|
-
pushCodeUnit(parts, chunk, cp);
|
|
138
|
-
i += 2;
|
|
139
|
-
continue;
|
|
140
|
-
}
|
|
141
|
-
// 3-byte sequence
|
|
142
|
-
if (b1 <= 0xef) {
|
|
143
|
-
if (i + 2 >= bytes.length) {
|
|
144
|
-
pushCodeUnit(parts, chunk, REPLACEMENT);
|
|
145
|
-
i++;
|
|
146
|
-
continue;
|
|
148
|
+
const length = b1 <= 0xdf ? 2 : b1 <= 0xef ? 3 : 4;
|
|
149
|
+
let cp = b1 & (0x7f >> length);
|
|
150
|
+
let lower = b1 === 0xe0 ? 0xa0 : b1 === 0xf0 ? 0x90 : 0x80;
|
|
151
|
+
let upper = b1 === 0xed ? 0x9f : b1 === 0xf4 ? 0x8f : 0xbf;
|
|
152
|
+
let consumed = 1;
|
|
153
|
+
i++;
|
|
154
|
+
// Consume only the valid prefix. An interrupting byte starts a new sequence.
|
|
155
|
+
while (consumed < length && i < bytes.length) {
|
|
156
|
+
const next = bytes[i];
|
|
157
|
+
if (next < lower || next > upper) {
|
|
158
|
+
break;
|
|
147
159
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const valid = (b2 & 0xc0) === 0x80 &&
|
|
151
|
-
(b3 & 0xc0) === 0x80 &&
|
|
152
|
-
!(b1 === 0xe0 && b2 < 0xa0) && // overlong
|
|
153
|
-
!(b1 === 0xed && b2 >= 0xa0); // surrogate range
|
|
154
|
-
if (!valid) {
|
|
155
|
-
pushCodeUnit(parts, chunk, REPLACEMENT);
|
|
156
|
-
i++;
|
|
157
|
-
continue;
|
|
158
|
-
}
|
|
159
|
-
const cp = ((b1 & 0x0f) << 12) |
|
|
160
|
-
((b2 & 0x3f) << 6) |
|
|
161
|
-
(b3 & 0x3f);
|
|
162
|
-
pushCodeUnit(parts, chunk, cp);
|
|
163
|
-
i += 3;
|
|
164
|
-
continue;
|
|
165
|
-
}
|
|
166
|
-
// 4-byte sequence
|
|
167
|
-
if (i + 3 >= bytes.length) {
|
|
168
|
-
pushCodeUnit(parts, chunk, REPLACEMENT);
|
|
169
|
-
i++;
|
|
170
|
-
continue;
|
|
171
|
-
}
|
|
172
|
-
const b2 = bytes[i + 1];
|
|
173
|
-
const b3 = bytes[i + 2];
|
|
174
|
-
const b4 = bytes[i + 3];
|
|
175
|
-
const valid = (b2 & 0xc0) === 0x80 &&
|
|
176
|
-
(b3 & 0xc0) === 0x80 &&
|
|
177
|
-
(b4 & 0xc0) === 0x80 &&
|
|
178
|
-
!(b1 === 0xf0 && b2 < 0x90) && // overlong
|
|
179
|
-
!(b1 === 0xf4 && b2 > 0x8f); // > U+10FFFF
|
|
180
|
-
if (!valid) {
|
|
181
|
-
pushCodeUnit(parts, chunk, REPLACEMENT);
|
|
160
|
+
cp = (cp << 6) | (next & 0x3f);
|
|
161
|
+
consumed++;
|
|
182
162
|
i++;
|
|
183
|
-
|
|
163
|
+
lower = 0x80;
|
|
164
|
+
upper = 0xbf;
|
|
184
165
|
}
|
|
185
|
-
|
|
186
|
-
((b2 & 0x3f) << 12) |
|
|
187
|
-
((b3 & 0x3f) << 6) |
|
|
188
|
-
(b4 & 0x3f);
|
|
189
|
-
pushCodePoint(parts, chunk, cp);
|
|
190
|
-
i += 4;
|
|
166
|
+
pushCodePoint(parts, chunk, consumed === length ? cp : REPLACEMENT);
|
|
191
167
|
}
|
|
192
168
|
flushChunk(parts, chunk);
|
|
193
|
-
return parts.join(
|
|
169
|
+
return parts.join('');
|
|
194
170
|
}
|
|
195
171
|
function decodeUTF16LE(bytes) {
|
|
196
172
|
const parts = [];
|
|
197
173
|
const chunk = [];
|
|
198
174
|
const len = bytes.length;
|
|
199
175
|
let i = 0;
|
|
176
|
+
// Match TextDecoder("utf-16le") default BOM handling
|
|
177
|
+
if (len >= 2 && bytes[0] === 0xff && bytes[1] === 0xfe) {
|
|
178
|
+
i = 2;
|
|
179
|
+
}
|
|
200
180
|
while (i + 1 < len) {
|
|
201
181
|
const u1 = bytes[i] | (bytes[i + 1] << 8);
|
|
202
182
|
i += 2;
|
|
@@ -230,7 +210,7 @@ function decodeUTF16LE(bytes) {
|
|
|
230
210
|
pushCodeUnit(parts, chunk, REPLACEMENT);
|
|
231
211
|
}
|
|
232
212
|
flushChunk(parts, chunk);
|
|
233
|
-
return parts.join(
|
|
213
|
+
return parts.join('');
|
|
234
214
|
}
|
|
235
215
|
function decodeASCII(bytes) {
|
|
236
216
|
const parts = [];
|
|
@@ -242,7 +222,7 @@ function decodeASCII(bytes) {
|
|
|
242
222
|
}
|
|
243
223
|
parts.push(String.fromCharCode.apply(null, codes));
|
|
244
224
|
}
|
|
245
|
-
return parts.join(
|
|
225
|
+
return parts.join('');
|
|
246
226
|
}
|
|
247
227
|
function decodeLatin1(bytes) {
|
|
248
228
|
const parts = [];
|
|
@@ -254,23 +234,24 @@ function decodeLatin1(bytes) {
|
|
|
254
234
|
}
|
|
255
235
|
parts.push(String.fromCharCode.apply(null, codes));
|
|
256
236
|
}
|
|
257
|
-
return parts.join(
|
|
237
|
+
return parts.join('');
|
|
258
238
|
}
|
|
259
239
|
function decodeWindows1252(bytes) {
|
|
260
240
|
const parts = [];
|
|
261
|
-
let out =
|
|
241
|
+
let out = '';
|
|
262
242
|
for (let i = 0; i < bytes.length; i++) {
|
|
263
243
|
const b = bytes[i];
|
|
264
244
|
const extra = b >= 0x80 && b <= 0x9f ? WINDOWS_1252_EXTRA[b] : undefined;
|
|
265
245
|
out += extra !== null && extra !== void 0 ? extra : String.fromCharCode(b);
|
|
266
246
|
if (out.length >= CHUNK) {
|
|
267
247
|
parts.push(out);
|
|
268
|
-
out =
|
|
248
|
+
out = '';
|
|
269
249
|
}
|
|
270
250
|
}
|
|
271
|
-
if (out)
|
|
251
|
+
if (out) {
|
|
272
252
|
parts.push(out);
|
|
273
|
-
|
|
253
|
+
}
|
|
254
|
+
return parts.join('');
|
|
274
255
|
}
|
|
275
256
|
function encodeUTF8(str) {
|
|
276
257
|
const out = [];
|
|
@@ -350,14 +331,16 @@ function encodeUTF16LE(str) {
|
|
|
350
331
|
}
|
|
351
332
|
function encodeASCII(str) {
|
|
352
333
|
const out = new Uint8Array(str.length);
|
|
353
|
-
for (let i = 0; i < str.length; i++)
|
|
334
|
+
for (let i = 0; i < str.length; i++) {
|
|
354
335
|
out[i] = str.charCodeAt(i) & 0x7f;
|
|
336
|
+
}
|
|
355
337
|
return out;
|
|
356
338
|
}
|
|
357
339
|
function encodeLatin1(str) {
|
|
358
340
|
const out = new Uint8Array(str.length);
|
|
359
|
-
for (let i = 0; i < str.length; i++)
|
|
341
|
+
for (let i = 0; i < str.length; i++) {
|
|
360
342
|
out[i] = str.charCodeAt(i) & 0xff;
|
|
343
|
+
}
|
|
361
344
|
return out;
|
|
362
345
|
}
|
|
363
346
|
function encodeWindows1252(str) {
|
|
@@ -369,8 +352,7 @@ function encodeWindows1252(str) {
|
|
|
369
352
|
out[i] = WINDOWS_1252_REVERSE[ch];
|
|
370
353
|
continue;
|
|
371
354
|
}
|
|
372
|
-
if ((code >= 0x00 && code <= 0x7f) ||
|
|
373
|
-
(code >= 0xa0 && code <= 0xff)) {
|
|
355
|
+
if ((code >= 0x00 && code <= 0x7f) || (code >= 0xa0 && code <= 0xff)) {
|
|
374
356
|
out[i] = code;
|
|
375
357
|
continue;
|
|
376
358
|
}
|