Skip to content

Commit e1610ab

Browse files
committed
checkpoint: 2025/08/04 15:54:15
1 parent 08c3aa9 commit e1610ab

1 file changed

Lines changed: 86 additions & 18 deletions

File tree

esim/uicc-parameter/script.mjs

Lines changed: 86 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
const params = new URLSearchParams(location.search);
22

33
const toHex = (val) => val.toString(16).padStart(2, "0").toUpperCase();
4-
const strToHexStream = (str) => str.split("").map((c) => c.charCodeAt(0).toString(16)).join("").toUpperCase();
4+
const strToHexStream = (str) => str.split("").map((c) => c.charCodeAt(0).toString(16).padStart(2, "0")).join("").toUpperCase();
5+
const hexToAscii = (hex) => {
6+
let ascii = "";
7+
for (let i = 0; i < hex.length; i += 2) {
8+
const byte = hex.substr(i, 2);
9+
ascii += String.fromCharCode(parseInt(byte, 16));
10+
}
11+
return ascii;
12+
};
513
// expose to devtool
614
window.toHex = toHex;
715
window.strToHexStream = strToHexStream;
16+
window.hexToAscii = hexToAscii;
817

918
const copyToClipboard = (text) => {
1019
const p = document.createElement("p");
@@ -46,7 +55,7 @@ const App = (props) => {
4655

4756
const [generatedSspWithTag, setGeneratedSspWithTag] = React.useState("");
4857

49-
const [aspTags, setAspTags] = React.useState([{ id: 1, tag: "", payload: "" }]);
58+
const [aspTags, setAspTags] = React.useState([{ id: 1, tag: "", payload: "", payloadMode: "hex" }]);
5059
const [nextTagId, setNextTagId] = React.useState(2);
5160

5261
const [generatedAsp, setGeneratedAsp] = React.useState("");
@@ -64,7 +73,7 @@ const App = (props) => {
6473
adf1Aid,
6574
ramQuota,
6675
nvramQuota,
67-
aspTags: aspTags.map(({tag, payload}) => ({tag, payload}))
76+
aspTags: aspTags.map(({tag, payload, payloadMode}) => ({tag, payload, payloadMode}))
6877
};
6978

7079
const blob = new Blob([JSON.stringify(config, null, 2)], { type: 'application/json' });
@@ -102,9 +111,10 @@ const App = (props) => {
102111
const newTags = config.aspTags.map((tag, index) => ({
103112
id: index + 1,
104113
tag: tag.tag || "",
105-
payload: tag.payload || ""
114+
payload: tag.payload || "",
115+
payloadMode: tag.payloadMode || "hex"
106116
}));
107-
setAspTags(newTags.length > 0 ? newTags : [{ id: 1, tag: "", payload: "" }]);
117+
setAspTags(newTags.length > 0 ? newTags : [{ id: 1, tag: "", payload: "", payloadMode: "hex" }]);
108118
setNextTagId(newTags.length + 1);
109119
}
110120
} catch (error) {
@@ -131,11 +141,12 @@ const App = (props) => {
131141
let asp = "";
132142

133143
// 各タグを処理
134-
aspTags.forEach(({tag, payload}) => {
144+
aspTags.forEach(({tag, payload, payloadMode}) => {
135145
if (tag) {
136146
const tagHex = tag.toUpperCase();
137147
if (payload) {
138-
const payloadHex = payload.toUpperCase();
148+
// asciiモードの場合は変換
149+
const payloadHex = payloadMode === 'ascii' ? strToHexStream(payload).toUpperCase() : payload.toUpperCase();
139150
const ll = toHex(payloadHex.length / 2);
140151
asp += tagHex + ll + payloadHex;
141152
} else {
@@ -154,7 +165,7 @@ const App = (props) => {
154165
}
155166

156167
const addTag = () => {
157-
setAspTags([...aspTags, { id: nextTagId, tag: "", payload: "" }]);
168+
setAspTags([...aspTags, { id: nextTagId, tag: "", payload: "", payloadMode: "hex" }]);
158169
setNextTagId(nextTagId + 1);
159170
}
160171

@@ -427,29 +438,86 @@ const App = (props) => {
427438
})
428439
),
429440
React.createElement('div', null,
430-
React.createElement('label', { className: 'block mb-2 text-sm font-medium text-gray-900 dark:text-white' },
431-
'ペイロード (hex)'
441+
React.createElement('div', { className: 'flex items-center justify-between mb-2' },
442+
React.createElement('label', { className: 'text-sm font-medium text-gray-900 dark:text-white' },
443+
'ペイロード'
444+
),
445+
React.createElement('div', { className: 'flex items-center space-x-4' },
446+
React.createElement('label', { className: 'flex items-center' },
447+
React.createElement('input', {
448+
type: 'radio',
449+
name: `payloadMode-${tagItem.id}`,
450+
value: 'hex',
451+
checked: tagItem.payloadMode === 'hex',
452+
onChange: () => {
453+
// 現在asciiモードの場合、hexに変換
454+
if (tagItem.payloadMode === 'ascii' && tagItem.payload) {
455+
const hexPayload = strToHexStream(tagItem.payload);
456+
setAspTags(aspTags.map(t =>
457+
t.id === tagItem.id ? { ...t, payloadMode: 'hex', payload: hexPayload } : t
458+
));
459+
} else {
460+
updateTag(tagItem.id, 'payloadMode', 'hex');
461+
}
462+
},
463+
className: 'w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600'
464+
}),
465+
React.createElement('span', { className: 'ml-2 text-sm text-gray-900 dark:text-gray-300' }, 'hex')
466+
),
467+
React.createElement('label', { className: 'flex items-center' },
468+
React.createElement('input', {
469+
type: 'radio',
470+
name: `payloadMode-${tagItem.id}`,
471+
value: 'ascii',
472+
checked: tagItem.payloadMode === 'ascii',
473+
onChange: () => {
474+
// 現在hexモードの場合、asciiに変換(有効なhex文字列の場合のみ)
475+
if (tagItem.payloadMode === 'hex' && tagItem.payload && tagItem.payload.length % 2 === 0) {
476+
try {
477+
const ascii = hexToAscii(tagItem.payload);
478+
setAspTags(aspTags.map(t =>
479+
t.id === tagItem.id ? { ...t, payloadMode: 'ascii', payload: ascii } : t
480+
));
481+
} catch (e) {
482+
// 変換できない場合はモードだけ変更
483+
updateTag(tagItem.id, 'payloadMode', 'ascii');
484+
}
485+
} else {
486+
updateTag(tagItem.id, 'payloadMode', 'ascii');
487+
}
488+
},
489+
className: 'w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600'
490+
}),
491+
React.createElement('span', { className: 'ml-2 text-sm text-gray-900 dark:text-gray-300' }, 'ascii')
492+
)
493+
)
432494
),
433495
React.createElement('input', {
434496
type: 'text',
435497
className: 'bg-white border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white',
436498
value: tagItem.payload,
437499
onChange: (e) => {
438-
const value = e.target.value.toUpperCase();
439-
if (/^[0-9A-F]*$/.test(value)) {
440-
updateTag(tagItem.id, 'payload', value);
500+
if (tagItem.payloadMode === 'hex') {
501+
const value = e.target.value.toUpperCase();
502+
if (/^[0-9A-F]*$/.test(value)) {
503+
updateTag(tagItem.id, 'payload', value);
504+
}
505+
} else {
506+
// asciiモードは制限なし
507+
updateTag(tagItem.id, 'payload', e.target.value);
441508
}
442509
},
443-
placeholder: '例: 0123456789ABCDEF'
510+
placeholder: tagItem.payloadMode === 'hex' ? '例: 0123456789ABCDEF' : '例: Hello World'
444511
})
445512
)
446513
),
447514
tagItem.tag && tagItem.payload && React.createElement('div', { className: 'mt-2' },
448515
React.createElement('span', {
449-
className: tagItem.payload.length % 2 !== 0
450-
? 'bg-red-100 text-red-800 text-xs font-medium mr-2 px-2.5 py-0.5 rounded dark:bg-red-900 dark:text-red-300'
451-
: 'bg-blue-100 text-blue-800 text-xs font-medium mr-2 px-2.5 py-0.5 rounded dark:bg-blue-900 dark:text-blue-300'
452-
}, `LL (長さ): ${tagItem.payload.length % 2 === 0 ? toHex(tagItem.payload.length / 2) : (tagItem.payload.length / 2).toFixed(1)}`)
516+
className: 'bg-blue-100 text-blue-800 text-xs font-medium mr-2 px-2.5 py-0.5 rounded dark:bg-blue-900 dark:text-blue-300'
517+
}, `LL (長さ): ${(() => {
518+
const hexPayload = tagItem.payloadMode === 'ascii' ? strToHexStream(tagItem.payload) : tagItem.payload;
519+
return toHex(hexPayload.length / 2);
520+
})()}`)
453521
)
454522
)
455523
),

0 commit comments

Comments
 (0)