@ddunigma/node 1.0.27 → 1.1.0
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/dist/cjs/base/BaseDdu.d.ts +38 -0
- package/dist/cjs/base/BaseDdu.js +78 -0
- package/dist/cjs/base/index.d.ts +1 -0
- package/dist/cjs/base/index.js +5 -0
- package/dist/cjs/charSets/index.d.ts +4 -0
- package/dist/cjs/charSets/index.js +4341 -0
- package/dist/cjs/encoders/Ddu64.d.ts +49 -0
- package/dist/cjs/encoders/Ddu64.js +355 -0
- package/dist/cjs/encoders/index.d.ts +1 -0
- package/dist/cjs/encoders/index.js +6 -0
- package/dist/cjs/index.d.ts +4 -5
- package/dist/cjs/index.js +10 -11
- package/dist/cjs/types/DduDefaultTypes.d.ts +3 -0
- package/dist/cjs/types/DduDefaultTypes.js +12 -0
- package/dist/cjs/types/DduEnums.d.ts +6 -0
- package/dist/cjs/types/DduEnums.js +10 -0
- package/dist/cjs/types/DduInterface.d.ts +24 -0
- package/dist/cjs/types/DduInterface.js +2 -0
- package/dist/cjs/types/index.d.ts +3 -0
- package/dist/cjs/types/index.js +19 -0
- package/dist/mjs/base/BaseDdu.d.ts +38 -0
- package/dist/mjs/base/BaseDdu.js +72 -0
- package/dist/mjs/base/index.d.ts +1 -0
- package/dist/mjs/base/index.js +1 -0
- package/dist/mjs/charSets/index.d.ts +4 -0
- package/dist/mjs/charSets/index.js +4336 -0
- package/dist/mjs/encoders/Ddu64.d.ts +49 -0
- package/dist/mjs/encoders/Ddu64.js +358 -0
- package/dist/mjs/encoders/index.d.ts +1 -0
- package/dist/mjs/encoders/index.js +2 -0
- package/dist/mjs/index.d.ts +4 -5
- package/dist/mjs/index.js +6 -5
- package/dist/mjs/types/DduDefaultTypes.d.ts +3 -0
- package/dist/mjs/types/DduDefaultTypes.js +9 -0
- package/dist/mjs/types/DduEnums.d.ts +6 -0
- package/dist/mjs/types/DduEnums.js +7 -0
- package/dist/mjs/types/DduInterface.d.ts +24 -0
- package/dist/mjs/types/DduInterface.js +1 -0
- package/dist/mjs/types/index.d.ts +3 -0
- package/dist/mjs/types/index.js +3 -0
- package/package.json +3 -2
- package/dist/cjs/Custom64.d.ts +0 -29
- package/dist/cjs/Custom64.js +0 -205
- package/dist/cjs/Ddu1024.d.ts +0 -26
- package/dist/cjs/Ddu1024.js +0 -262
- package/dist/cjs/Ddu128.d.ts +0 -26
- package/dist/cjs/Ddu128.js +0 -150
- package/dist/cjs/Ddu512.d.ts +0 -26
- package/dist/cjs/Ddu512.js +0 -198
- package/dist/cjs/Ddu64.d.ts +0 -29
- package/dist/cjs/Ddu64.js +0 -149
- package/dist/mjs/Custom64.d.ts +0 -29
- package/dist/mjs/Custom64.js +0 -203
- package/dist/mjs/Ddu1024.d.ts +0 -26
- package/dist/mjs/Ddu1024.js +0 -261
- package/dist/mjs/Ddu128.d.ts +0 -26
- package/dist/mjs/Ddu128.js +0 -149
- package/dist/mjs/Ddu512.d.ts +0 -26
- package/dist/mjs/Ddu512.js +0 -197
- package/dist/mjs/Ddu64.d.ts +0 -29
- package/dist/mjs/Ddu64.js +0 -147
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { BaseDdu } from "../base/BaseDdu";
|
|
2
|
+
import { DduConstructorOptions, DduOptions } from "../types";
|
|
3
|
+
export declare class Ddu64 extends BaseDdu {
|
|
4
|
+
protected readonly dduChar: string[];
|
|
5
|
+
protected readonly paddingChar: string;
|
|
6
|
+
protected readonly charLength: number;
|
|
7
|
+
protected readonly bitLength: number;
|
|
8
|
+
protected readonly usePowerOfTwo: boolean;
|
|
9
|
+
protected readonly encoding: BufferEncoding;
|
|
10
|
+
protected readonly dduBinaryLookup: Map<string, number>;
|
|
11
|
+
private readonly isPredefinedCharSet;
|
|
12
|
+
private readonly binaryToIntLookup;
|
|
13
|
+
constructor(dduChar?: string[] | string, paddingChar?: string, dduOptions?: DduConstructorOptions);
|
|
14
|
+
/**
|
|
15
|
+
* charset 초기화 (커스텀 또는 미리 정의된 charset)
|
|
16
|
+
*/
|
|
17
|
+
private initializeCharSet;
|
|
18
|
+
/**
|
|
19
|
+
* 커스텀 charset 처리
|
|
20
|
+
*/
|
|
21
|
+
private processCustomCharSet;
|
|
22
|
+
/**
|
|
23
|
+
* 미리 정의된 charset 처리
|
|
24
|
+
*/
|
|
25
|
+
private processPredefinedCharSet;
|
|
26
|
+
/**
|
|
27
|
+
* 기본 charset 처리
|
|
28
|
+
*/
|
|
29
|
+
private processDefaultCharSet;
|
|
30
|
+
/**
|
|
31
|
+
* fallback charset 가져오기
|
|
32
|
+
*/
|
|
33
|
+
private getFallbackCharSet;
|
|
34
|
+
/**
|
|
35
|
+
* string 또는 배열을 문자 배열로 변환
|
|
36
|
+
*/
|
|
37
|
+
private convertToCharArray;
|
|
38
|
+
/**
|
|
39
|
+
* usePowerOfTwo 옵션 적용
|
|
40
|
+
*/
|
|
41
|
+
private applyPowerOfTwoOption;
|
|
42
|
+
/**
|
|
43
|
+
* 2글자 이상의 문자셋에서 조합으로 인한 중복을 검증
|
|
44
|
+
* 예: ["AB", "CD"] + padding "AB" 또는 "A" + "B" = "AB" 같은 경우 감지
|
|
45
|
+
*/
|
|
46
|
+
private validateCombinationDuplicates;
|
|
47
|
+
encode(input: Buffer | string, _options?: DduOptions): string;
|
|
48
|
+
decode(input: string, _options?: DduOptions): string;
|
|
49
|
+
}
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Ddu64 = void 0;
|
|
4
|
+
const BaseDdu_1 = require("../base/BaseDdu");
|
|
5
|
+
const types_1 = require("../types");
|
|
6
|
+
const charSets_1 = require("../charSets");
|
|
7
|
+
class Ddu64 extends BaseDdu_1.BaseDdu {
|
|
8
|
+
constructor(dduChar, paddingChar, dduOptions) {
|
|
9
|
+
var _a, _b, _c;
|
|
10
|
+
super();
|
|
11
|
+
this.dduBinaryLookup = new Map();
|
|
12
|
+
this.binaryToIntLookup = new Map();
|
|
13
|
+
// charset 초기화
|
|
14
|
+
let finalCharSet;
|
|
15
|
+
let finalPadding;
|
|
16
|
+
let requiredLength;
|
|
17
|
+
let bitLength;
|
|
18
|
+
let isPredefined = false;
|
|
19
|
+
try {
|
|
20
|
+
const result = this.initializeCharSet(dduChar, paddingChar, dduOptions);
|
|
21
|
+
finalCharSet = result.finalCharSet;
|
|
22
|
+
finalPadding = result.finalPadding;
|
|
23
|
+
requiredLength = result.requiredLength;
|
|
24
|
+
bitLength = result.bitLength;
|
|
25
|
+
isPredefined = result.isPredefined;
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
// useBuildErrorReturn이 true일 경우 에러를 그대로 throw
|
|
29
|
+
if ((_a = dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.useBuildErrorReturn) !== null && _a !== void 0 ? _a : false) {
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
// fallback 처리
|
|
33
|
+
const fallbackResult = this.getFallbackCharSet(dduOptions);
|
|
34
|
+
finalCharSet = fallbackResult.finalCharSet;
|
|
35
|
+
finalPadding = fallbackResult.finalPadding;
|
|
36
|
+
requiredLength = fallbackResult.requiredLength;
|
|
37
|
+
bitLength = fallbackResult.bitLength;
|
|
38
|
+
isPredefined = true; // fallback도 predefined charset 사용
|
|
39
|
+
}
|
|
40
|
+
// 유효성 검사: 최소 requiredLength개 이상의 문자 필요
|
|
41
|
+
if (finalCharSet.length < requiredLength) {
|
|
42
|
+
throw new Error(`${this.constructor.name} requires at least ${requiredLength} characters in the character set. Provided: ${finalCharSet.length}`);
|
|
43
|
+
}
|
|
44
|
+
// 첫 번째 문자의 길이를 기준으로 설정
|
|
45
|
+
this.charLength = finalCharSet[0].length;
|
|
46
|
+
// 모든 문자의 길이가 동일한지 검사
|
|
47
|
+
for (let i = 0; i < finalCharSet.length; i++) {
|
|
48
|
+
if (finalCharSet[i].length !== this.charLength) {
|
|
49
|
+
throw new Error(`All characters must have the same length. Expected: ${this.charLength}, but character at index ${i} ("${finalCharSet[i]}") has length ${finalCharSet[i].length}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// 패딩 문자 길이 검사
|
|
53
|
+
if (finalPadding.length !== this.charLength) {
|
|
54
|
+
throw new Error(`Padding character must have the same length as the characters. Expected: ${this.charLength}, but padding character has length ${finalPadding.length}`);
|
|
55
|
+
}
|
|
56
|
+
// 중복 검사
|
|
57
|
+
const uniqueChars = new Set(finalCharSet);
|
|
58
|
+
if (uniqueChars.size !== finalCharSet.length) {
|
|
59
|
+
throw new Error(`Character set contains duplicate characters. Unique: ${uniqueChars.size}, Total: ${finalCharSet.length}`);
|
|
60
|
+
}
|
|
61
|
+
// 패딩 문자가 문자셋에 포함되어 있는지 검사
|
|
62
|
+
if (uniqueChars.has(finalPadding)) {
|
|
63
|
+
throw new Error(`Padding character "${finalPadding}" cannot be in the character set`);
|
|
64
|
+
}
|
|
65
|
+
// 2글자 이상의 문자셋인 경우 조합 중복 검사 (미리 정의된 charset은 건너뜀)
|
|
66
|
+
if (this.charLength >= 2 && !isPredefined) {
|
|
67
|
+
this.validateCombinationDuplicates(finalCharSet, finalPadding, requiredLength);
|
|
68
|
+
}
|
|
69
|
+
// 앞에서부터 정확히 requiredLength개만 사용
|
|
70
|
+
this.dduChar = finalCharSet.slice(0, requiredLength);
|
|
71
|
+
this.paddingChar = finalPadding;
|
|
72
|
+
this.bitLength = bitLength;
|
|
73
|
+
this.isPredefinedCharSet = isPredefined;
|
|
74
|
+
// requiredLength가 2의 제곱수인 경우 자동으로 usePowerOfTwo 활성화
|
|
75
|
+
const isPowerOfTwo = (requiredLength & (requiredLength - 1)) === 0 && requiredLength > 0;
|
|
76
|
+
this.usePowerOfTwo = isPowerOfTwo || ((_b = dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.usePowerOfTwo) !== null && _b !== void 0 ? _b : true);
|
|
77
|
+
// encoding 설정
|
|
78
|
+
this.encoding = (_c = dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.encoding) !== null && _c !== void 0 ? _c : this.defaultEncoding;
|
|
79
|
+
// 룩업 테이블 생성
|
|
80
|
+
this.dduChar.forEach((char, index) => this.dduBinaryLookup.set(char, index));
|
|
81
|
+
// parseInt 최적화: 이진수 문자열 → 정수 룩업 테이블 생성
|
|
82
|
+
// 가능한 모든 비트 패턴을 미리 계산
|
|
83
|
+
// 성능 최적화: bitLength가 12 이하일 때만 룩업 테이블 사용 (4096 엔트리 이하)
|
|
84
|
+
// 그 이상은 parseInt가 더 효율적 (캐시 미스 감소)
|
|
85
|
+
const dduLength = this.dduChar.length;
|
|
86
|
+
const effectiveBitLength = this.usePowerOfTwo
|
|
87
|
+
? this.bitLength
|
|
88
|
+
: this.getBitLength(dduLength);
|
|
89
|
+
if (effectiveBitLength <= 12) {
|
|
90
|
+
const maxValue = Math.pow(2, effectiveBitLength);
|
|
91
|
+
for (let i = 0; i < maxValue; i++) {
|
|
92
|
+
const binaryStr = i.toString(2).padStart(effectiveBitLength, "0");
|
|
93
|
+
this.binaryToIntLookup.set(binaryStr, i);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// effectiveBitLength > 12인 경우 룩업 테이블을 생성하지 않음 (parseInt 사용)
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* charset 초기화 (커스텀 또는 미리 정의된 charset)
|
|
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, _b;
|
|
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
|
+
const result = this.applyPowerOfTwoOption(dduCharArray, paddingChar, dduCharLength, (_b = dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.usePowerOfTwo) !== null && _b !== void 0 ? _b : true);
|
|
131
|
+
return Object.assign(Object.assign({}, result), { isPredefined: false // 커스텀 charset은 검증 필요
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* 미리 정의된 charset 처리
|
|
136
|
+
*/
|
|
137
|
+
processPredefinedCharSet(symbol, dduOptions) {
|
|
138
|
+
var _a;
|
|
139
|
+
const fixedCharSet = (0, charSets_1.getCharSet)(symbol);
|
|
140
|
+
if (!fixedCharSet) {
|
|
141
|
+
throw new Error(`CharSet with symbol ${symbol} not found`);
|
|
142
|
+
}
|
|
143
|
+
const { charSet, paddingChar, maxRequiredLength, bitLength } = fixedCharSet;
|
|
144
|
+
// usePowerOfTwo 처리
|
|
145
|
+
if ((_a = dduOptions === null || dduOptions === void 0 ? void 0 : dduOptions.usePowerOfTwo) !== null && _a !== void 0 ? _a : true) {
|
|
146
|
+
const result = this.applyPowerOfTwoOption(charSet, paddingChar, maxRequiredLength, true);
|
|
147
|
+
return Object.assign(Object.assign({}, result), { isPredefined: true // 미리 정의된 charset은 검증 패스
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
finalCharSet: charSet,
|
|
152
|
+
finalPadding: paddingChar,
|
|
153
|
+
requiredLength: maxRequiredLength,
|
|
154
|
+
bitLength,
|
|
155
|
+
isPredefined: true // 미리 정의된 charset은 검증 패스
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* 기본 charset 처리
|
|
160
|
+
*/
|
|
161
|
+
processDefaultCharSet() {
|
|
162
|
+
var _a;
|
|
163
|
+
const defaultSymbol = (_a = types_1.dduDefaultConstructorOptions.dduSetSymbol) !== null && _a !== void 0 ? _a : types_1.DduSetSymbol.DDU;
|
|
164
|
+
const fixedCharSet = (0, charSets_1.getCharSet)(defaultSymbol);
|
|
165
|
+
if (!fixedCharSet) {
|
|
166
|
+
throw new Error(`Default CharSet with symbol ${defaultSymbol} not found`);
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
finalCharSet: fixedCharSet.charSet,
|
|
170
|
+
finalPadding: fixedCharSet.paddingChar,
|
|
171
|
+
requiredLength: fixedCharSet.maxRequiredLength,
|
|
172
|
+
bitLength: fixedCharSet.bitLength,
|
|
173
|
+
isPredefined: true // 기본 charset도 미리 정의된 것이므로 검증 패스
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* fallback charset 가져오기
|
|
178
|
+
*/
|
|
179
|
+
getFallbackCharSet(dduOptions) {
|
|
180
|
+
var _a, _b;
|
|
181
|
+
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.DDU;
|
|
182
|
+
const fixedCharSet = (0, charSets_1.getCharSet)(fallbackSymbol);
|
|
183
|
+
if (!fixedCharSet) {
|
|
184
|
+
throw new Error(`Fallback CharSet with symbol ${fallbackSymbol} not found`);
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
finalCharSet: fixedCharSet.charSet,
|
|
188
|
+
finalPadding: fixedCharSet.paddingChar,
|
|
189
|
+
requiredLength: fixedCharSet.maxRequiredLength,
|
|
190
|
+
bitLength: fixedCharSet.bitLength,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* string 또는 배열을 문자 배열로 변환
|
|
195
|
+
*/
|
|
196
|
+
convertToCharArray(input) {
|
|
197
|
+
if (typeof input === "string") {
|
|
198
|
+
return [...new Set(input.trim())].map((c) => c);
|
|
199
|
+
}
|
|
200
|
+
return input;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* usePowerOfTwo 옵션 적용
|
|
204
|
+
*/
|
|
205
|
+
applyPowerOfTwoOption(charArray, padding, length, usePowerOfTwo) {
|
|
206
|
+
if (usePowerOfTwo) {
|
|
207
|
+
const powerOfTwoExponent = this.getLargestPowerOfTwoExponent(length);
|
|
208
|
+
const powerOfTwoLength = Math.pow(2, powerOfTwoExponent);
|
|
209
|
+
return {
|
|
210
|
+
finalCharSet: charArray.slice(0, powerOfTwoLength),
|
|
211
|
+
finalPadding: padding,
|
|
212
|
+
requiredLength: powerOfTwoLength,
|
|
213
|
+
bitLength: powerOfTwoExponent,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
finalCharSet: charArray.slice(0, length),
|
|
218
|
+
finalPadding: padding,
|
|
219
|
+
requiredLength: length,
|
|
220
|
+
bitLength: this.getBitLength(length),
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* 2글자 이상의 문자셋에서 조합으로 인한 중복을 검증
|
|
225
|
+
* 예: ["AB", "CD"] + padding "AB" 또는 "A" + "B" = "AB" 같은 경우 감지
|
|
226
|
+
*/
|
|
227
|
+
validateCombinationDuplicates(charSet, paddingChar, requiredLength) {
|
|
228
|
+
const charLength = charSet[0].length;
|
|
229
|
+
const allStrings = new Set();
|
|
230
|
+
// 1. 기본 문자셋과 패딩 문자 추가
|
|
231
|
+
charSet.slice(0, requiredLength).forEach((char) => allStrings.add(char));
|
|
232
|
+
allStrings.add(paddingChar);
|
|
233
|
+
// 2. 2개 조합 검사 (charLength * 2 길이)
|
|
234
|
+
for (let i = 0; i < Math.min(charSet.length, requiredLength); i++) {
|
|
235
|
+
for (let j = 0; j < Math.min(charSet.length, requiredLength); j++) {
|
|
236
|
+
const combination = charSet[i] + charSet[j];
|
|
237
|
+
// 조합이 기존 문자와 중복되는지 확인
|
|
238
|
+
if (allStrings.has(combination)) {
|
|
239
|
+
throw new Error(`Combination conflict detected: "${charSet[i]}" + "${charSet[j]}" = "${combination}" already exists in the character set or padding`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
// 문자 + 패딩 조합 검사
|
|
243
|
+
const charPlusPadding = charSet[i] + paddingChar;
|
|
244
|
+
const paddingPlusChar = paddingChar + charSet[i];
|
|
245
|
+
if (allStrings.has(charPlusPadding)) {
|
|
246
|
+
throw new Error(`Combination conflict detected: "${charSet[i]}" + padding "${paddingChar}" = "${charPlusPadding}" already exists in the character set`);
|
|
247
|
+
}
|
|
248
|
+
if (allStrings.has(paddingPlusChar)) {
|
|
249
|
+
throw new Error(`Combination conflict detected: padding "${paddingChar}" + "${charSet[i]}" = "${paddingPlusChar}" already exists in the character set`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
// 3. 패딩 + 패딩 조합 검사
|
|
253
|
+
const doublePadding = paddingChar + paddingChar;
|
|
254
|
+
if (allStrings.has(doublePadding)) {
|
|
255
|
+
throw new Error(`Combination conflict detected: padding "${paddingChar}" + padding "${paddingChar}" = "${doublePadding}" already exists in the character set`);
|
|
256
|
+
}
|
|
257
|
+
// 4. 3개 이상 조합 검사 (선택적, 성능을 위해 샘플링)
|
|
258
|
+
// 모든 조합을 검사하면 O(n^3)이므로 일부만 샘플링
|
|
259
|
+
if (charLength >= 2 && requiredLength <= 100) {
|
|
260
|
+
// 100개 이하일 때만 전체 검사
|
|
261
|
+
for (let i = 0; i < Math.min(charSet.length, requiredLength); i++) {
|
|
262
|
+
for (let j = 0; j < Math.min(charSet.length, requiredLength); j++) {
|
|
263
|
+
for (let k = 0; k < Math.min(charSet.length, requiredLength); k++) {
|
|
264
|
+
const combination = charSet[i] + charSet[j] + charSet[k];
|
|
265
|
+
// 조합의 부분 문자열이 기존 문자와 중복되는지 확인
|
|
266
|
+
for (let start = 0; start < combination.length - charLength + 1; start++) {
|
|
267
|
+
const substring = combination.substring(start, start + charLength);
|
|
268
|
+
if (allStrings.has(substring) && substring !== charSet[i] && substring !== charSet[j] && substring !== charSet[k]) {
|
|
269
|
+
throw new Error(`Combination conflict detected: substring "${substring}" from "${charSet[i]}" + "${charSet[j]}" + "${charSet[k]}" conflicts with existing character`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
encode(input, _options) {
|
|
278
|
+
var _a;
|
|
279
|
+
// options는 구버전 호환성을 위해 유지하지만 사용하지 않음
|
|
280
|
+
const bufferInput = typeof input === "string" ? Buffer.from(input, this.encoding) : input;
|
|
281
|
+
// 생성자에서 설정된 값 사용
|
|
282
|
+
const dduLength = this.dduChar.length;
|
|
283
|
+
const effectiveBitLength = this.usePowerOfTwo
|
|
284
|
+
? this.bitLength
|
|
285
|
+
: this.getBitLength(dduLength);
|
|
286
|
+
const { dduBinary, padding } = this.bufferToDduBinary(bufferInput, effectiveBitLength);
|
|
287
|
+
// 문자열 연결 최적화: Array + join 사용
|
|
288
|
+
const resultParts = new Array(dduBinary.length);
|
|
289
|
+
// 각 비트 청크를 변환
|
|
290
|
+
for (let i = 0; i < dduBinary.length; i++) {
|
|
291
|
+
const binaryChunk = dduBinary[i];
|
|
292
|
+
// parseInt 최적화: 룩업 테이블 사용
|
|
293
|
+
const charInt = (_a = this.binaryToIntLookup.get(binaryChunk)) !== null && _a !== void 0 ? _a : parseInt(binaryChunk, 2);
|
|
294
|
+
if (this.charLength === 1 && !this.usePowerOfTwo) {
|
|
295
|
+
// 가변 길이 조합 인코딩
|
|
296
|
+
const quotient = Math.floor(charInt / dduLength);
|
|
297
|
+
const remainder = charInt % dduLength;
|
|
298
|
+
resultParts[i] = this.dduChar[quotient] + this.dduChar[remainder];
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
// 고정 길이 직접 매핑
|
|
302
|
+
resultParts[i] = this.dduChar[charInt];
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
let resultString = resultParts.join("");
|
|
306
|
+
// 패딩 비트 정보를 padChar + 패딩비트수 형태로 추가
|
|
307
|
+
if (padding > 0) {
|
|
308
|
+
resultString += this.paddingChar + padding;
|
|
309
|
+
}
|
|
310
|
+
return resultString;
|
|
311
|
+
}
|
|
312
|
+
decode(input, _options) {
|
|
313
|
+
// options는 구버전 호환성을 위해 유지하지만 사용하지 않음
|
|
314
|
+
// 패딩 정보 추출
|
|
315
|
+
let paddingBits = 0;
|
|
316
|
+
const padCharIndex = input.indexOf(this.paddingChar);
|
|
317
|
+
if (padCharIndex >= 0) {
|
|
318
|
+
const paddingStr = input.substring(padCharIndex + this.paddingChar.length);
|
|
319
|
+
paddingBits = parseInt(paddingStr) || 0;
|
|
320
|
+
input = input.substring(0, padCharIndex);
|
|
321
|
+
}
|
|
322
|
+
let dduBinary = "";
|
|
323
|
+
// 생성자에서 설정된 값 사용
|
|
324
|
+
const dduLength = this.dduChar.length;
|
|
325
|
+
const effectiveBitLength = this.usePowerOfTwo
|
|
326
|
+
? this.bitLength
|
|
327
|
+
: this.getBitLength(dduLength);
|
|
328
|
+
if (this.charLength === 1 && !this.usePowerOfTwo) {
|
|
329
|
+
// 가변 길이 조합 디코딩 (2개씩 읽음)
|
|
330
|
+
for (let i = 0; i < input.length; i += 2) {
|
|
331
|
+
const firstChar = input[i];
|
|
332
|
+
const secondChar = input[i + 1];
|
|
333
|
+
const firstIndex = this.dduBinaryLookup.get(firstChar);
|
|
334
|
+
const secondIndex = this.dduBinaryLookup.get(secondChar);
|
|
335
|
+
if (firstIndex === undefined || secondIndex === undefined)
|
|
336
|
+
throw new Error(`Invalid character: ${firstChar} or ${secondChar}`);
|
|
337
|
+
const value = firstIndex * dduLength + secondIndex;
|
|
338
|
+
dduBinary += value.toString(2).padStart(effectiveBitLength, "0");
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
// 고정 길이 직접 매핑 (charLength만큼씩 읽음)
|
|
343
|
+
for (let i = 0; i < input.length; i += this.charLength) {
|
|
344
|
+
const charChunk = input.slice(i, i + this.charLength);
|
|
345
|
+
const charIndex = this.dduBinaryLookup.get(charChunk);
|
|
346
|
+
if (charIndex === undefined)
|
|
347
|
+
throw new Error(`Invalid character: ${charChunk}`);
|
|
348
|
+
dduBinary += charIndex.toString(2).padStart(effectiveBitLength, "0");
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
const decoded = this.dduBinaryToBuffer(dduBinary, paddingBits);
|
|
352
|
+
return decoded.toString(this.encoding);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
exports.Ddu64 = Ddu64;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Ddu64 } from "./Ddu64";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Ddu64 = void 0;
|
|
4
|
+
// Unified encoder (supports both fixed and variable length via usePowerOfTwo option)
|
|
5
|
+
var Ddu64_1 = require("./Ddu64");
|
|
6
|
+
Object.defineProperty(exports, "Ddu64", { enumerable: true, get: function () { return Ddu64_1.Ddu64; } });
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
5
|
-
export { Ddu1024 } from "./Ddu1024.js";
|
|
1
|
+
export type { DduOptions, BufferToDduBinaryResult, DduConstructorOptions, } from "./types";
|
|
2
|
+
export { DduSetSymbol } from "./types";
|
|
3
|
+
export { BaseDdu } from "./base";
|
|
4
|
+
export { Ddu64 } from "./encoders";
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
var
|
|
9
|
-
Object.defineProperty(exports, "
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Object.defineProperty(exports, "Ddu1024", { enumerable: true, get: function () { return Ddu1024_js_1.Ddu1024; } });
|
|
3
|
+
exports.Ddu64 = exports.BaseDdu = exports.DduSetSymbol = void 0;
|
|
4
|
+
// Export enums
|
|
5
|
+
var types_1 = require("./types");
|
|
6
|
+
Object.defineProperty(exports, "DduSetSymbol", { enumerable: true, get: function () { return types_1.DduSetSymbol; } });
|
|
7
|
+
// Export base classes
|
|
8
|
+
var base_1 = require("./base");
|
|
9
|
+
Object.defineProperty(exports, "BaseDdu", { enumerable: true, get: function () { return base_1.BaseDdu; } });
|
|
10
|
+
// Export encoders
|
|
11
|
+
var encoders_1 = require("./encoders");
|
|
12
|
+
Object.defineProperty(exports, "Ddu64", { enumerable: true, get: function () { return encoders_1.Ddu64; } });
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dduDefaultConstructorOptions = void 0;
|
|
4
|
+
const DduEnums_1 = require("./DduEnums");
|
|
5
|
+
const dduDefaultConstructorOptions = {
|
|
6
|
+
dduSetSymbol: DduEnums_1.DduSetSymbol.DDU,
|
|
7
|
+
usePowerOfTwo: true,
|
|
8
|
+
requiredLength: 8,
|
|
9
|
+
bitLength: 3,
|
|
10
|
+
useBuildErrorReturn: false,
|
|
11
|
+
};
|
|
12
|
+
exports.dduDefaultConstructorOptions = dduDefaultConstructorOptions;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DduSetSymbol = void 0;
|
|
4
|
+
var DduSetSymbol;
|
|
5
|
+
(function (DduSetSymbol) {
|
|
6
|
+
DduSetSymbol["DDU"] = "ddu";
|
|
7
|
+
DduSetSymbol["ONECHARSET"] = "oneCharSet";
|
|
8
|
+
DduSetSymbol["TWOCHARSET"] = "twoCharSet";
|
|
9
|
+
DduSetSymbol["THREECHARSET"] = "threeCharSet";
|
|
10
|
+
})(DduSetSymbol || (exports.DduSetSymbol = DduSetSymbol = {}));
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { DduSetSymbol } from "./DduEnums";
|
|
2
|
+
export interface CharSetConfig {
|
|
3
|
+
symbol: DduSetSymbol;
|
|
4
|
+
charSet: string[];
|
|
5
|
+
maxRequiredLength: number;
|
|
6
|
+
bitLength: number;
|
|
7
|
+
paddingChar: string;
|
|
8
|
+
}
|
|
9
|
+
export interface DduOptions {
|
|
10
|
+
}
|
|
11
|
+
export interface DduConstructorOptions {
|
|
12
|
+
dduSetSymbol?: DduSetSymbol;
|
|
13
|
+
dduChar?: string[] | string;
|
|
14
|
+
paddingChar?: string;
|
|
15
|
+
requiredLength?: number;
|
|
16
|
+
bitLength?: number;
|
|
17
|
+
usePowerOfTwo?: boolean;
|
|
18
|
+
useBuildErrorReturn?: boolean;
|
|
19
|
+
encoding?: BufferEncoding;
|
|
20
|
+
}
|
|
21
|
+
export interface BufferToDduBinaryResult {
|
|
22
|
+
dduBinary: string[];
|
|
23
|
+
padding: number;
|
|
24
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./DduEnums"), exports);
|
|
18
|
+
__exportStar(require("./DduInterface"), exports);
|
|
19
|
+
__exportStar(require("./DduDefaultTypes"), exports);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { DduOptions, BufferToDduBinaryResult } from "../types";
|
|
2
|
+
export declare abstract class BaseDdu {
|
|
3
|
+
protected readonly defaultEncoding: BufferEncoding;
|
|
4
|
+
/**
|
|
5
|
+
* 이진수 변환 룩업 테이블 (0-255 -> 8비트 이진 문자열)
|
|
6
|
+
*/
|
|
7
|
+
protected readonly binaryLookup: string[];
|
|
8
|
+
/**
|
|
9
|
+
* 정규표현식 특수문자 이스케이프
|
|
10
|
+
*/
|
|
11
|
+
protected escapeRegExp(str: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* 문자열을 지정된 길이로 분할하는 제너레이터
|
|
14
|
+
*/
|
|
15
|
+
protected splitString(s: string, length: number): Generator<string>;
|
|
16
|
+
/**
|
|
17
|
+
* 2의 거듭제곱 길이 계산
|
|
18
|
+
*/
|
|
19
|
+
protected getLargestPowerOfTwo(n: number): number;
|
|
20
|
+
/**
|
|
21
|
+
* 2의 거듭제곱 지수 계산
|
|
22
|
+
*/
|
|
23
|
+
protected getLargestPowerOfTwoExponent(n: number): number;
|
|
24
|
+
/**
|
|
25
|
+
* 비트 길이 계산
|
|
26
|
+
*/
|
|
27
|
+
protected getBitLength(setLength: number): number;
|
|
28
|
+
/**
|
|
29
|
+
* Buffer를 DDU Binary 배열로 변환
|
|
30
|
+
*/
|
|
31
|
+
protected bufferToDduBinary(input: Buffer, bitLength: number): BufferToDduBinaryResult;
|
|
32
|
+
/**
|
|
33
|
+
* DDU Binary를 Buffer로 변환
|
|
34
|
+
*/
|
|
35
|
+
protected dduBinaryToBuffer(decodedBin: string, paddingBits: number): Buffer;
|
|
36
|
+
abstract encode(input: Buffer | string, options?: DduOptions): string;
|
|
37
|
+
abstract decode(input: string, options?: DduOptions): string;
|
|
38
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export class BaseDdu {
|
|
2
|
+
defaultEncoding = "utf-8";
|
|
3
|
+
/**
|
|
4
|
+
* 이진수 변환 룩업 테이블 (0-255 -> 8비트 이진 문자열)
|
|
5
|
+
*/
|
|
6
|
+
binaryLookup = Array.from({ length: 256 }, (_, i) => i.toString(2).padStart(8, "0"));
|
|
7
|
+
/**
|
|
8
|
+
* 정규표현식 특수문자 이스케이프
|
|
9
|
+
*/
|
|
10
|
+
escapeRegExp(str) {
|
|
11
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 문자열을 지정된 길이로 분할하는 제너레이터
|
|
15
|
+
*/
|
|
16
|
+
*splitString(s, length) {
|
|
17
|
+
for (let i = 0; i < s.length; i += length) {
|
|
18
|
+
yield s.slice(i, Math.min(i + length, s.length));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 2의 거듭제곱 길이 계산
|
|
23
|
+
*/
|
|
24
|
+
getLargestPowerOfTwo(n) {
|
|
25
|
+
return 2 ** Math.floor(Math.log2(n));
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 2의 거듭제곱 지수 계산
|
|
29
|
+
*/
|
|
30
|
+
getLargestPowerOfTwoExponent(n) {
|
|
31
|
+
return Math.floor(Math.log2(n));
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 비트 길이 계산
|
|
35
|
+
*/
|
|
36
|
+
getBitLength(setLength) {
|
|
37
|
+
return Math.ceil(Math.log2(setLength));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Buffer를 DDU Binary 배열로 변환
|
|
41
|
+
*/
|
|
42
|
+
bufferToDduBinary(input, bitLength) {
|
|
43
|
+
// 성능 최적화: reduce 대신 for loop + join 사용
|
|
44
|
+
if (input.length === 0) {
|
|
45
|
+
return { dduBinary: [], padding: 0 };
|
|
46
|
+
}
|
|
47
|
+
const binaryParts = new Array(input.length);
|
|
48
|
+
for (let i = 0; i < input.length; i++) {
|
|
49
|
+
binaryParts[i] = this.binaryLookup[input[i]];
|
|
50
|
+
}
|
|
51
|
+
const encodedBin = binaryParts.join("");
|
|
52
|
+
const dduBinary = Array.from(this.splitString(encodedBin, bitLength));
|
|
53
|
+
const padding = bitLength - dduBinary[dduBinary.length - 1].length;
|
|
54
|
+
if (padding > 0) {
|
|
55
|
+
dduBinary[dduBinary.length - 1] += "0".repeat(padding);
|
|
56
|
+
}
|
|
57
|
+
return { dduBinary, padding };
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* DDU Binary를 Buffer로 변환
|
|
61
|
+
*/
|
|
62
|
+
dduBinaryToBuffer(decodedBin, paddingBits) {
|
|
63
|
+
if (paddingBits > 0) {
|
|
64
|
+
decodedBin = decodedBin.slice(0, -paddingBits);
|
|
65
|
+
}
|
|
66
|
+
const buffer = [];
|
|
67
|
+
for (let i = 0; i < decodedBin.length; i += 8) {
|
|
68
|
+
buffer.push(parseInt(decodedBin.slice(i, i + 8), 2));
|
|
69
|
+
}
|
|
70
|
+
return Buffer.from(buffer);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { BaseDdu } from "./BaseDdu";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { BaseDdu } from "./BaseDdu";
|