@ddunigma/node 1.1.3 → 1.1.4
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 +62 -74
- package/dist/cjs/encoders/Ddu64.d.ts +0 -37
- package/dist/cjs/encoders/Ddu64.js +142 -349
- package/dist/mjs/encoders/Ddu64.d.ts +0 -37
- package/dist/mjs/encoders/Ddu64.js +138 -350
- package/package.json +1 -1
|
@@ -6,394 +6,187 @@ const types_1 = require("../types");
|
|
|
6
6
|
const charSets_1 = require("../charSets");
|
|
7
7
|
class Ddu64 extends BaseDdu_1.BaseDdu {
|
|
8
8
|
constructor(dduChar, paddingChar, dduOptions) {
|
|
9
|
-
var _a, _b, _c;
|
|
9
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
10
10
|
super();
|
|
11
11
|
this.dduBinaryLookup = new Map();
|
|
12
|
+
const shouldThrowError = (_a = dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.useBuildErrorReturn) !== null && _a !== void 0 ? _a : false;
|
|
13
|
+
const getCharSetFromSymbol = (symbol) => {
|
|
14
|
+
const cs = (0, charSets_1.getCharSet)(symbol);
|
|
15
|
+
if (!cs)
|
|
16
|
+
throw new Error(`CharSet with symbol ${symbol} not found`);
|
|
17
|
+
return cs;
|
|
18
|
+
};
|
|
12
19
|
// charset 초기화
|
|
13
|
-
let
|
|
14
|
-
let finalPadding;
|
|
15
|
-
let requiredLength;
|
|
16
|
-
let bitLength;
|
|
17
|
-
let isPredefined = false;
|
|
20
|
+
let charSet, padding, requiredLength, bitLength, isPredefined;
|
|
18
21
|
try {
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
const finalDduChar = dduChar !== null && dduChar !== void 0 ? dduChar : dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.dduChar;
|
|
23
|
+
const finalPadding = paddingChar !== null && paddingChar !== void 0 ? paddingChar : dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.paddingChar;
|
|
24
|
+
if (finalDduChar) {
|
|
25
|
+
// 커스텀 charset
|
|
26
|
+
if (!finalPadding)
|
|
27
|
+
throw new Error("paddingChar is required when dduChar or dduOptions.dduChar is provided");
|
|
28
|
+
const arr = typeof finalDduChar === "string" ? [...new Set(finalDduChar.trim())] : finalDduChar;
|
|
29
|
+
const len = (_b = dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.requiredLength) !== null && _b !== void 0 ? _b : arr.length;
|
|
30
|
+
if (arr.length < len)
|
|
31
|
+
throw new Error(`dduChar must be at least ${len} characters long. Provided: ${arr.length}`);
|
|
32
|
+
const usePow2 = (dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.usePowerOfTwo) === true || ((dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.usePowerOfTwo) === undefined && len > 0 && (len & (len - 1)) === 0);
|
|
33
|
+
if (usePow2) {
|
|
34
|
+
const exp = this.getLargestPowerOfTwoExponent(len);
|
|
35
|
+
const pow2Len = 1 << exp;
|
|
36
|
+
[charSet, padding, requiredLength, bitLength, isPredefined] = [arr.slice(0, pow2Len), finalPadding, pow2Len, exp, false];
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
[charSet, padding, requiredLength, bitLength, isPredefined] = [arr.slice(0, len), finalPadding, len, this.getBitLength(len), false];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else if (dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.dduSetSymbol) {
|
|
43
|
+
// 미리 정의된 charset
|
|
44
|
+
const cs = getCharSetFromSymbol(dduOptions.dduSetSymbol);
|
|
45
|
+
const usePow2 = (dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.usePowerOfTwo) === true || ((dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.usePowerOfTwo) === undefined && cs.maxRequiredLength > 0 && (cs.maxRequiredLength & (cs.maxRequiredLength - 1)) === 0);
|
|
46
|
+
if (usePow2) {
|
|
47
|
+
const exp = this.getLargestPowerOfTwoExponent(cs.maxRequiredLength);
|
|
48
|
+
const pow2Len = 1 << exp;
|
|
49
|
+
[charSet, padding, requiredLength, bitLength, isPredefined] = [cs.charSet.slice(0, pow2Len), cs.paddingChar, pow2Len, exp, true];
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
[charSet, padding, requiredLength, bitLength, isPredefined] = [cs.charSet, cs.paddingChar, cs.maxRequiredLength, cs.bitLength, true];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
// 기본 charset
|
|
57
|
+
const cs = getCharSetFromSymbol((_c = types_1.dduDefaultConstructorOptions.dduSetSymbol) !== null && _c !== void 0 ? _c : types_1.DduSetSymbol.DDU);
|
|
58
|
+
[charSet, padding, requiredLength, bitLength, isPredefined] = [cs.charSet, cs.paddingChar, cs.maxRequiredLength, cs.bitLength, true];
|
|
59
|
+
}
|
|
25
60
|
}
|
|
26
61
|
catch (error) {
|
|
27
|
-
|
|
28
|
-
if ((_a = dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.useBuildErrorReturn) !== null && _a !== void 0 ? _a : false) {
|
|
62
|
+
if (shouldThrowError)
|
|
29
63
|
throw error;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
requiredLength =
|
|
36
|
-
bitLength = fallbackResult.bitLength;
|
|
37
|
-
isPredefined = true; // fallback도 predefined charset 사용
|
|
64
|
+
// fallback
|
|
65
|
+
const fallbackSymbol = (_e = (_d = dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.dduSetSymbol) !== null && _d !== void 0 ? _d : types_1.dduDefaultConstructorOptions.dduSetSymbol) !== null && _e !== void 0 ? _e : types_1.DduSetSymbol.ONECHARSET;
|
|
66
|
+
const cs = (_f = (0, charSets_1.getCharSet)(fallbackSymbol)) !== null && _f !== void 0 ? _f : (0, charSets_1.getCharSet)(types_1.DduSetSymbol.ONECHARSET);
|
|
67
|
+
if (!cs)
|
|
68
|
+
throw new Error(`Critical: No fallback CharSet available`);
|
|
69
|
+
[charSet, padding, requiredLength, bitLength, isPredefined] = [cs.charSet, cs.paddingChar, cs.maxRequiredLength, cs.bitLength, true];
|
|
38
70
|
}
|
|
39
|
-
|
|
40
|
-
const normalized = this.normalizeCharSet(
|
|
41
|
-
charSet: finalCharSet,
|
|
42
|
-
padding: finalPadding,
|
|
43
|
-
requiredLength,
|
|
44
|
-
bitLength,
|
|
45
|
-
isPredefined,
|
|
46
|
-
shouldThrowError,
|
|
47
|
-
dduOptions,
|
|
48
|
-
});
|
|
71
|
+
// 정규화 및 검증
|
|
72
|
+
const normalized = this.normalizeCharSet(charSet, padding, requiredLength, bitLength, isPredefined, shouldThrowError, dduOptions);
|
|
49
73
|
this.dduChar = normalized.charSet;
|
|
50
74
|
this.paddingChar = normalized.padding;
|
|
51
75
|
this.charLength = normalized.charLength;
|
|
52
76
|
this.bitLength = normalized.bitLength;
|
|
53
77
|
this.isPredefinedCharSet = normalized.isPredefined;
|
|
78
|
+
this.encoding = (_g = dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.encoding) !== null && _g !== void 0 ? _g : this.defaultEncoding;
|
|
54
79
|
const dduLength = this.dduChar.length;
|
|
55
80
|
this.usePowerOfTwo = dduLength > 0 && (dduLength & (dduLength - 1)) === 0;
|
|
56
|
-
this.effectiveBitLength = this.usePowerOfTwo
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
this.binaryChunkToIntFn = (chunk) => {
|
|
62
|
-
let value = 0;
|
|
63
|
-
for (let i = 0; i < chunk.length; i++) {
|
|
64
|
-
value = (value << 1) | (chunk.charCodeAt(i) & 1);
|
|
65
|
-
}
|
|
66
|
-
return value;
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
this.binaryChunkToIntFn = (chunk) => {
|
|
71
|
-
let value = 0;
|
|
72
|
-
for (let i = 0; i < chunk.length; i++) {
|
|
73
|
-
value = value * 2 + (chunk.charCodeAt(i) & 1);
|
|
74
|
-
}
|
|
75
|
-
return value;
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
this.encoding = (_c = dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.encoding) !== null && _c !== void 0 ? _c : this.defaultEncoding;
|
|
79
|
-
this.dduChar.forEach((char, index) => {
|
|
80
|
-
this.dduBinaryLookup.set(char, index);
|
|
81
|
-
});
|
|
81
|
+
this.effectiveBitLength = this.usePowerOfTwo ? this.bitLength : this.getBitLength(dduLength);
|
|
82
|
+
this.binaryChunkToIntFn = this.effectiveBitLength <= 26
|
|
83
|
+
? (chunk) => chunk.split('').reduce((v, c) => (v << 1) | (c.charCodeAt(0) & 1), 0)
|
|
84
|
+
: (chunk) => chunk.split('').reduce((v, c) => v * 2 + (c.charCodeAt(0) & 1), 0);
|
|
85
|
+
this.dduChar.forEach((char, index) => this.dduBinaryLookup.set(char, index));
|
|
82
86
|
if (this.charLength >= 2 && !this.isPredefinedCharSet) {
|
|
83
|
-
this.validateCombinationDuplicates(this.dduChar, this.paddingChar,
|
|
87
|
+
this.validateCombinationDuplicates(this.dduChar, this.paddingChar, dduLength);
|
|
84
88
|
}
|
|
85
89
|
if (this.effectiveBitLength <= 16) {
|
|
86
|
-
const
|
|
87
|
-
this.indexToBinaryCache =
|
|
88
|
-
for (let i = 0; i < cacheSize; i++) {
|
|
89
|
-
this.indexToBinaryCache[i] = i
|
|
90
|
-
.toString(2)
|
|
91
|
-
.padStart(this.effectiveBitLength, "0");
|
|
92
|
-
}
|
|
90
|
+
const size = 1 << this.effectiveBitLength;
|
|
91
|
+
this.indexToBinaryCache = Array.from({ length: size }, (_, i) => i.toString(2).padStart(this.effectiveBitLength, "0"));
|
|
93
92
|
}
|
|
94
93
|
else {
|
|
95
94
|
this.indexToBinaryCache = null;
|
|
96
95
|
}
|
|
97
96
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
*/
|
|
101
|
-
initializeCharSet(dduChar, paddingChar, dduOptions) {
|
|
102
|
-
const finalDduChar = dduChar !== null && dduChar !== void 0 ? dduChar : dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.dduChar;
|
|
103
|
-
const finalPaddingChar = paddingChar !== null && paddingChar !== void 0 ? paddingChar : dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.paddingChar;
|
|
104
|
-
// 1. 커스텀 charset 사용
|
|
105
|
-
if (finalDduChar) {
|
|
106
|
-
return this.processCustomCharSet(finalDduChar, finalPaddingChar, dduOptions);
|
|
107
|
-
}
|
|
108
|
-
// 2. 미리 정의된 charset 사용
|
|
109
|
-
if (dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.dduSetSymbol) {
|
|
110
|
-
return this.processPredefinedCharSet(dduOptions.dduSetSymbol, dduOptions);
|
|
111
|
-
}
|
|
112
|
-
// 3. 기본 charset 사용
|
|
113
|
-
return this.processDefaultCharSet();
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* 커스텀 charset 처리
|
|
117
|
-
*/
|
|
118
|
-
processCustomCharSet(dduChar, paddingChar, dduOptions) {
|
|
119
|
-
var _a;
|
|
120
|
-
if (!paddingChar) {
|
|
121
|
-
throw new Error("paddingChar is required when dduChar or dduOptions.dduChar is provided");
|
|
122
|
-
}
|
|
123
|
-
// string 타입을 배열로 변환
|
|
124
|
-
const dduCharArray = this.convertToCharArray(dduChar);
|
|
125
|
-
const dduCharLength = (_a = dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.requiredLength) !== null && _a !== void 0 ? _a : dduCharArray.length;
|
|
126
|
-
if (dduCharArray.length < dduCharLength) {
|
|
127
|
-
throw new Error(`dduChar must be at least ${dduCharLength} characters long. Provided: ${dduCharArray.length}`);
|
|
128
|
-
}
|
|
129
|
-
// usePowerOfTwo 처리
|
|
130
|
-
// charArray의 길이가 2의 제곱수이거나 option에 usePowerOfTwo가 명시적으로 true일 때만 적용
|
|
131
|
-
const shouldUsePowerOfTwo = (dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.usePowerOfTwo) === true ||
|
|
132
|
-
((dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.usePowerOfTwo) === undefined && this.isPowerOfTwo(dduCharLength));
|
|
133
|
-
const result = this.applyPowerOfTwoOption(dduCharArray, paddingChar, dduCharLength, shouldUsePowerOfTwo);
|
|
134
|
-
return Object.assign(Object.assign({}, result), { isPredefined: false // 커스텀 charset은 검증 필요
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* 미리 정의된 charset 처리
|
|
139
|
-
*/
|
|
140
|
-
processPredefinedCharSet(symbol, dduOptions) {
|
|
141
|
-
const fixedCharSet = (0, charSets_1.getCharSet)(symbol);
|
|
142
|
-
if (!fixedCharSet) {
|
|
143
|
-
throw new Error(`CharSet with symbol ${symbol} not found`);
|
|
144
|
-
}
|
|
145
|
-
const { charSet, paddingChar, maxRequiredLength, bitLength } = fixedCharSet;
|
|
146
|
-
// usePowerOfTwo 처리
|
|
147
|
-
// charArray의 길이가 2의 제곱수이거나 option에 usePowerOfTwo가 명시적으로 true일 때만 적용
|
|
148
|
-
const shouldUsePowerOfTwo = (dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.usePowerOfTwo) === true ||
|
|
149
|
-
((dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.usePowerOfTwo) === undefined && this.isPowerOfTwo(maxRequiredLength));
|
|
150
|
-
if (shouldUsePowerOfTwo) {
|
|
151
|
-
const result = this.applyPowerOfTwoOption(charSet, paddingChar, maxRequiredLength, true);
|
|
152
|
-
return Object.assign(Object.assign({}, result), { isPredefined: true // 미리 정의된 charset은 검증 패스
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
return {
|
|
156
|
-
finalCharSet: charSet,
|
|
157
|
-
finalPadding: paddingChar,
|
|
158
|
-
requiredLength: maxRequiredLength,
|
|
159
|
-
bitLength,
|
|
160
|
-
isPredefined: true // 미리 정의된 charset은 검증 패스
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* 기본 charset 처리
|
|
165
|
-
*/
|
|
166
|
-
processDefaultCharSet() {
|
|
167
|
-
var _a;
|
|
168
|
-
const defaultSymbol = (_a = types_1.dduDefaultConstructorOptions.dduSetSymbol) !== null && _a !== void 0 ? _a : types_1.DduSetSymbol.DDU;
|
|
169
|
-
const fixedCharSet = (0, charSets_1.getCharSet)(defaultSymbol);
|
|
170
|
-
if (!fixedCharSet) {
|
|
171
|
-
throw new Error(`Default CharSet with symbol ${defaultSymbol} not found`);
|
|
172
|
-
}
|
|
173
|
-
return {
|
|
174
|
-
finalCharSet: fixedCharSet.charSet,
|
|
175
|
-
finalPadding: fixedCharSet.paddingChar,
|
|
176
|
-
requiredLength: fixedCharSet.maxRequiredLength,
|
|
177
|
-
bitLength: fixedCharSet.bitLength,
|
|
178
|
-
isPredefined: true // 기본 charset도 미리 정의된 것이므로 검증 패스
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* fallback charset 가져오기
|
|
183
|
-
* 우선순위: dduOptions.dduSetSymbol > dduDefaultConstructorOptions.dduSetSymbol > DduSetSymbol.ONECHARSET
|
|
184
|
-
*/
|
|
185
|
-
getFallbackCharSet(dduOptions) {
|
|
186
|
-
var _a, _b;
|
|
187
|
-
// 우선순위에 따라 fallback symbol 결정
|
|
188
|
-
const fallbackSymbol = (_b = (_a = dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.dduSetSymbol) !== null && _a !== void 0 ? _a : types_1.dduDefaultConstructorOptions.dduSetSymbol) !== null && _b !== void 0 ? _b : types_1.DduSetSymbol.ONECHARSET; // DDU 대신 ONECHARSET 사용
|
|
189
|
-
const fixedCharSet = (0, charSets_1.getCharSet)(fallbackSymbol);
|
|
190
|
-
if (!fixedCharSet) {
|
|
191
|
-
// 최후의 fallback: ONECHARSET
|
|
192
|
-
const lastResort = (0, charSets_1.getCharSet)(types_1.DduSetSymbol.ONECHARSET);
|
|
193
|
-
if (!lastResort) {
|
|
194
|
-
throw new Error(`Critical: No fallback CharSet available`);
|
|
195
|
-
}
|
|
196
|
-
return {
|
|
197
|
-
finalCharSet: lastResort.charSet,
|
|
198
|
-
finalPadding: lastResort.paddingChar,
|
|
199
|
-
requiredLength: lastResort.maxRequiredLength,
|
|
200
|
-
bitLength: lastResort.bitLength,
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
return {
|
|
204
|
-
finalCharSet: fixedCharSet.charSet,
|
|
205
|
-
finalPadding: fixedCharSet.paddingChar,
|
|
206
|
-
requiredLength: fixedCharSet.maxRequiredLength,
|
|
207
|
-
bitLength: fixedCharSet.bitLength,
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
normalizeCharSet(params) {
|
|
211
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
212
|
-
let currentCharSet = [...params.charSet];
|
|
213
|
-
let currentPadding = params.padding;
|
|
214
|
-
let currentRequiredLength = params.requiredLength;
|
|
215
|
-
let currentBitLength = params.bitLength;
|
|
216
|
-
let currentIsPredefined = params.isPredefined;
|
|
217
|
-
const { shouldThrowError, dduOptions } = params;
|
|
218
|
-
let fallbackCache = null;
|
|
219
|
-
const getFallback = () => {
|
|
220
|
-
if (!fallbackCache) {
|
|
221
|
-
const fallback = this.getFallbackCharSet(dduOptions);
|
|
222
|
-
fallbackCache = {
|
|
223
|
-
finalCharSet: [...fallback.finalCharSet],
|
|
224
|
-
finalPadding: fallback.finalPadding,
|
|
225
|
-
requiredLength: fallback.requiredLength,
|
|
226
|
-
bitLength: fallback.bitLength,
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
return fallbackCache;
|
|
230
|
-
};
|
|
97
|
+
normalizeCharSet(charSet, padding, requiredLength, bitLength, isPredefined, shouldThrowError, dduOptions) {
|
|
98
|
+
var _a, _b, _c, _d, _e, _f;
|
|
231
99
|
const applyFallback = () => {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
100
|
+
var _a, _b, _c;
|
|
101
|
+
const fallbackSymbol = (_b = (_a = dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.dduSetSymbol) !== null && _a !== void 0 ? _a : types_1.dduDefaultConstructorOptions.dduSetSymbol) !== null && _b !== void 0 ? _b : types_1.DduSetSymbol.ONECHARSET;
|
|
102
|
+
const cs = (_c = (0, charSets_1.getCharSet)(fallbackSymbol)) !== null && _c !== void 0 ? _c : (0, charSets_1.getCharSet)(types_1.DduSetSymbol.ONECHARSET);
|
|
103
|
+
if (!cs)
|
|
104
|
+
throw new Error(`Critical: No fallback CharSet available`);
|
|
105
|
+
return { charSet: cs.charSet, padding: cs.paddingChar, requiredLength: cs.maxRequiredLength, bitLength: cs.bitLength, isPredefined: true };
|
|
238
106
|
};
|
|
239
|
-
const
|
|
240
|
-
if (
|
|
241
|
-
if (shouldThrowError)
|
|
242
|
-
throw new Error(
|
|
243
|
-
|
|
244
|
-
|
|
107
|
+
const validate = (condition, message) => {
|
|
108
|
+
if (condition) {
|
|
109
|
+
if (shouldThrowError)
|
|
110
|
+
throw new Error(message);
|
|
111
|
+
const fb = applyFallback();
|
|
112
|
+
[charSet, padding, requiredLength, bitLength, isPredefined] = [fb.charSet, fb.padding, fb.requiredLength, fb.bitLength, fb.isPredefined];
|
|
113
|
+
return true;
|
|
245
114
|
}
|
|
115
|
+
return false;
|
|
246
116
|
};
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
117
|
+
// 중복 제거 (커스텀 charset만)
|
|
118
|
+
if (!isPredefined) {
|
|
119
|
+
const uniqueChars = new Set(charSet);
|
|
120
|
+
if (uniqueChars.size !== charSet.length) {
|
|
121
|
+
if (shouldThrowError)
|
|
122
|
+
throw new Error(`Character set contains duplicate characters. Unique: ${uniqueChars.size}, Total: ${charSet.length}`);
|
|
123
|
+
charSet = Array.from(uniqueChars);
|
|
124
|
+
requiredLength = charSet.length;
|
|
254
125
|
}
|
|
255
126
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
if (shouldThrowError) {
|
|
260
|
-
throw new Error(`${this.constructor.name} requires at least ${currentRequiredLength} characters in the character set. Provided: ${currentCharSet.length}`);
|
|
261
|
-
}
|
|
262
|
-
applyFallback();
|
|
263
|
-
charLength = (_d = (_c = currentCharSet[0]) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0;
|
|
127
|
+
// 검증
|
|
128
|
+
if (validate(charSet.length < requiredLength, `${this.constructor.name} requires at least ${requiredLength} characters. Provided: ${charSet.length}`)) {
|
|
129
|
+
return this.normalizeCharSet(charSet, padding, requiredLength, bitLength, isPredefined, shouldThrowError, dduOptions);
|
|
264
130
|
}
|
|
265
|
-
|
|
131
|
+
let charLength = (_b = (_a = charSet[0]) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
|
|
132
|
+
validate(charLength === 0, `${this.constructor.name} requires at least ${requiredLength} characters. Provided: ${charSet.length}`);
|
|
133
|
+
const invalidIndex = charSet.findIndex(char => char.length !== charLength);
|
|
266
134
|
if (invalidIndex !== -1) {
|
|
267
|
-
if (shouldThrowError)
|
|
268
|
-
throw new Error(`All characters must have the same length. Expected: ${charLength}, but
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
throw new Error(`Padding character must have the same length as the characters. Expected: ${charLength}, but padding character has length ${currentPadding.length}`);
|
|
284
|
-
}
|
|
285
|
-
applyFallback();
|
|
286
|
-
charLength = (_k = (_j = currentCharSet[0]) === null || _j === void 0 ? void 0 : _j.length) !== null && _k !== void 0 ? _k : 0;
|
|
287
|
-
}
|
|
288
|
-
const charSetLookup = new Set(currentCharSet);
|
|
289
|
-
if (charSetLookup.has(currentPadding)) {
|
|
290
|
-
if (shouldThrowError) {
|
|
291
|
-
throw new Error(`Padding character "${currentPadding}" cannot be in the character set`);
|
|
292
|
-
}
|
|
293
|
-
currentCharSet = currentCharSet.filter((char) => char !== currentPadding);
|
|
294
|
-
ensureMinLength();
|
|
295
|
-
charLength = (_m = (_l = currentCharSet[0]) === null || _l === void 0 ? void 0 : _l.length) !== null && _m !== void 0 ? _m : 0;
|
|
296
|
-
}
|
|
297
|
-
currentCharSet = currentCharSet.slice(0, currentRequiredLength);
|
|
298
|
-
return {
|
|
299
|
-
charSet: currentCharSet,
|
|
300
|
-
padding: currentPadding,
|
|
301
|
-
requiredLength: currentRequiredLength,
|
|
302
|
-
bitLength: currentBitLength,
|
|
303
|
-
isPredefined: currentIsPredefined,
|
|
304
|
-
charLength,
|
|
305
|
-
};
|
|
135
|
+
if (shouldThrowError)
|
|
136
|
+
throw new Error(`All characters must have the same length. Expected: ${charLength}, but index ${invalidIndex} has length ${charSet[invalidIndex].length}`);
|
|
137
|
+
charSet = charSet.filter(char => char.length === charLength);
|
|
138
|
+
validate(charSet.length < requiredLength, `${this.constructor.name} requires at least ${requiredLength} characters. Provided: ${charSet.length}`);
|
|
139
|
+
charLength = (_d = (_c = charSet[0]) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0;
|
|
140
|
+
}
|
|
141
|
+
validate(!charSet.length, `${this.constructor.name} requires at least ${requiredLength} characters. Provided: 0`);
|
|
142
|
+
validate(padding.length !== charLength, `Padding character must have length ${charLength}, got ${padding.length}`);
|
|
143
|
+
if (new Set(charSet).has(padding)) {
|
|
144
|
+
if (shouldThrowError)
|
|
145
|
+
throw new Error(`Padding character "${padding}" cannot be in the character set`);
|
|
146
|
+
charSet = charSet.filter(char => char !== padding);
|
|
147
|
+
validate(charSet.length < requiredLength, `${this.constructor.name} requires at least ${requiredLength} characters. Provided: ${charSet.length}`);
|
|
148
|
+
charLength = (_f = (_e = charSet[0]) === null || _e === void 0 ? void 0 : _e.length) !== null && _f !== void 0 ? _f : 0;
|
|
149
|
+
}
|
|
150
|
+
return { charSet: charSet.slice(0, requiredLength), padding, requiredLength, bitLength, isPredefined, charLength };
|
|
306
151
|
}
|
|
307
152
|
getBinaryFromIndex(index) {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
return cache[index];
|
|
311
|
-
}
|
|
312
|
-
return index.toString(2).padStart(this.effectiveBitLength, "0");
|
|
313
|
-
}
|
|
314
|
-
/**
|
|
315
|
-
* string 또는 배열을 문자 배열로 변환
|
|
316
|
-
*/
|
|
317
|
-
convertToCharArray(input) {
|
|
318
|
-
if (typeof input === "string") {
|
|
319
|
-
return [...new Set(input.trim())].map((c) => c);
|
|
320
|
-
}
|
|
321
|
-
return input;
|
|
322
|
-
}
|
|
323
|
-
/**
|
|
324
|
-
* 숫자가 2의 제곱수인지 확인
|
|
325
|
-
*/
|
|
326
|
-
isPowerOfTwo(n) {
|
|
327
|
-
return n > 0 && (n & (n - 1)) === 0;
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
|
-
* usePowerOfTwo 옵션 적용
|
|
331
|
-
*/
|
|
332
|
-
applyPowerOfTwoOption(charArray, padding, length, usePowerOfTwo) {
|
|
333
|
-
if (usePowerOfTwo) {
|
|
334
|
-
const powerOfTwoExponent = this.getLargestPowerOfTwoExponent(length);
|
|
335
|
-
const powerOfTwoLength = Math.pow(2, powerOfTwoExponent);
|
|
336
|
-
return {
|
|
337
|
-
finalCharSet: charArray.slice(0, powerOfTwoLength),
|
|
338
|
-
finalPadding: padding,
|
|
339
|
-
requiredLength: powerOfTwoLength,
|
|
340
|
-
bitLength: powerOfTwoExponent,
|
|
341
|
-
};
|
|
342
|
-
}
|
|
343
|
-
return {
|
|
344
|
-
finalCharSet: charArray.slice(0, length),
|
|
345
|
-
finalPadding: padding,
|
|
346
|
-
requiredLength: length,
|
|
347
|
-
bitLength: this.getBitLength(length),
|
|
348
|
-
};
|
|
153
|
+
var _a, _b;
|
|
154
|
+
return (_b = (_a = this.indexToBinaryCache) === null || _a === void 0 ? void 0 : _a[index]) !== null && _b !== void 0 ? _b : index.toString(2).padStart(this.effectiveBitLength, "0");
|
|
349
155
|
}
|
|
350
|
-
/**
|
|
351
|
-
* 2글자 이상의 문자셋에서 조합으로 인한 중복을 검증
|
|
352
|
-
* 예: ["AB", "CD"] + padding "AB" 또는 "A" + "B" = "AB" 같은 경우 감지
|
|
353
|
-
*/
|
|
354
156
|
validateCombinationDuplicates(charSet, paddingChar, requiredLength) {
|
|
355
157
|
const charLength = charSet[0].length;
|
|
356
|
-
const allStrings = new Set();
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
// 조합이 기존 문자와 중복되는지 확인
|
|
365
|
-
if (allStrings.has(combination)) {
|
|
366
|
-
throw new Error(`Combination conflict detected: "${charSet[i]}" + "${charSet[j]}" = "${combination}" already exists in the character set or padding`);
|
|
158
|
+
const allStrings = new Set([...charSet.slice(0, requiredLength), paddingChar]);
|
|
159
|
+
const limit = Math.min(charSet.length, requiredLength);
|
|
160
|
+
// 2개 조합 검사
|
|
161
|
+
for (let i = 0; i < limit; i++) {
|
|
162
|
+
for (let j = 0; j < limit; j++) {
|
|
163
|
+
const combo = charSet[i] + charSet[j];
|
|
164
|
+
if (allStrings.has(combo)) {
|
|
165
|
+
throw new Error(`Combination conflict: "${charSet[i]}" + "${charSet[j]}" = "${combo}" already exists`);
|
|
367
166
|
}
|
|
368
167
|
}
|
|
369
|
-
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
throw new Error(`Combination conflict detected: padding "${paddingChar}" + padding "${paddingChar}" = "${doublePadding}" already exists in the character set`);
|
|
383
|
-
}
|
|
384
|
-
// 4. 3개 이상 조합 검사 (선택적, 성능을 위해 샘플링)
|
|
385
|
-
// 모든 조합을 검사하면 O(n^3)이므로 일부만 샘플링
|
|
168
|
+
const charPad = charSet[i] + paddingChar;
|
|
169
|
+
const padChar = paddingChar + charSet[i];
|
|
170
|
+
if (allStrings.has(charPad))
|
|
171
|
+
throw new Error(`Combination conflict: "${charSet[i]}" + padding "${paddingChar}" = "${charPad}"`);
|
|
172
|
+
if (allStrings.has(padChar))
|
|
173
|
+
throw new Error(`Combination conflict: padding "${paddingChar}" + "${charSet[i]}" = "${padChar}"`);
|
|
174
|
+
}
|
|
175
|
+
// 패딩 + 패딩 조합 검사
|
|
176
|
+
const doublePad = paddingChar + paddingChar;
|
|
177
|
+
if (allStrings.has(doublePad)) {
|
|
178
|
+
throw new Error(`Combination conflict: double padding "${doublePad}" already exists`);
|
|
179
|
+
}
|
|
180
|
+
// 3개 조합 검사 (100개 이하만)
|
|
386
181
|
if (charLength >= 2 && requiredLength <= 100) {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
if (allStrings.has(substring) && substring !== charSet[i] && substring !== charSet[j] && substring !== charSet[k]) {
|
|
396
|
-
throw new Error(`Combination conflict detected: substring "${substring}" from "${charSet[i]}" + "${charSet[j]}" + "${charSet[k]}" conflicts with existing character`);
|
|
182
|
+
for (let i = 0; i < limit; i++) {
|
|
183
|
+
for (let j = 0; j < limit; j++) {
|
|
184
|
+
for (let k = 0; k < limit; k++) {
|
|
185
|
+
const combo = charSet[i] + charSet[j] + charSet[k];
|
|
186
|
+
for (let start = 0; start <= combo.length - charLength; start++) {
|
|
187
|
+
const sub = combo.substring(start, start + charLength);
|
|
188
|
+
if (allStrings.has(sub) && sub !== charSet[i] && sub !== charSet[j] && sub !== charSet[k]) {
|
|
189
|
+
throw new Error(`Combination conflict: substring "${sub}" from "${charSet[i]}" + "${charSet[j]}" + "${charSet[k]}"`);
|
|
397
190
|
}
|
|
398
191
|
}
|
|
399
192
|
}
|
|
@@ -13,45 +13,8 @@ export declare class Ddu64 extends BaseDdu {
|
|
|
13
13
|
private readonly binaryChunkToIntFn;
|
|
14
14
|
private readonly indexToBinaryCache;
|
|
15
15
|
constructor(dduChar?: string[] | string, paddingChar?: string, dduOptions?: DduConstructorOptions);
|
|
16
|
-
/**
|
|
17
|
-
* charset 초기화 (커스텀 또는 미리 정의된 charset)
|
|
18
|
-
*/
|
|
19
|
-
private initializeCharSet;
|
|
20
|
-
/**
|
|
21
|
-
* 커스텀 charset 처리
|
|
22
|
-
*/
|
|
23
|
-
private processCustomCharSet;
|
|
24
|
-
/**
|
|
25
|
-
* 미리 정의된 charset 처리
|
|
26
|
-
*/
|
|
27
|
-
private processPredefinedCharSet;
|
|
28
|
-
/**
|
|
29
|
-
* 기본 charset 처리
|
|
30
|
-
*/
|
|
31
|
-
private processDefaultCharSet;
|
|
32
|
-
/**
|
|
33
|
-
* fallback charset 가져오기
|
|
34
|
-
* 우선순위: dduOptions.dduSetSymbol > dduDefaultConstructorOptions.dduSetSymbol > DduSetSymbol.ONECHARSET
|
|
35
|
-
*/
|
|
36
|
-
private getFallbackCharSet;
|
|
37
16
|
private normalizeCharSet;
|
|
38
17
|
private getBinaryFromIndex;
|
|
39
|
-
/**
|
|
40
|
-
* string 또는 배열을 문자 배열로 변환
|
|
41
|
-
*/
|
|
42
|
-
private convertToCharArray;
|
|
43
|
-
/**
|
|
44
|
-
* 숫자가 2의 제곱수인지 확인
|
|
45
|
-
*/
|
|
46
|
-
private isPowerOfTwo;
|
|
47
|
-
/**
|
|
48
|
-
* usePowerOfTwo 옵션 적용
|
|
49
|
-
*/
|
|
50
|
-
private applyPowerOfTwoOption;
|
|
51
|
-
/**
|
|
52
|
-
* 2글자 이상의 문자셋에서 조합으로 인한 중복을 검증
|
|
53
|
-
* 예: ["AB", "CD"] + padding "AB" 또는 "A" + "B" = "AB" 같은 경우 감지
|
|
54
|
-
*/
|
|
55
18
|
private validateCombinationDuplicates;
|
|
56
19
|
encode(input: Buffer | string, _options?: DduOptions): string;
|
|
57
20
|
decode(input: string, _options?: DduOptions): string;
|