-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathAAMVAtoJSON.js
66 lines (66 loc) · 2.8 KB
/
AAMVAtoJSON.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
function AAMVAtoJSON(data, options = { format: "string" } ) {
// Detect AAMVA header:
// 1. The first character must be: "@"
// 2. The next character should be "\n"
// 3. The third character should be 0x1e but we ignore it because of South Carolina 0x1c edge condition
// 4. The next character should be "\r"
// 5. Next 5 characters either "ANSI " or "AAMVA"
// 6. Next 12 characters: IIN, AAMVAVersion, JurisdictionVersion, numberOfEntries
// N.B. Because of the South Carolina 0x1c edge conditions, we relax rules 2-4 with a generic `[^\w]+` to handle non-alphabetic sequences
let [ header, AAMVAType, IIN, AAMVAVersion, jurisdictionVersion, numberOfEntries ]
= data.match(/^@[^\w]+(A....)(\d{6})(\d{2})(\d{2})(\d{2})?/) || [ ];
AAMVAVersion = +AAMVAVersion;
jurisdictionVersion = +jurisdictionVersion;
let obj = {
header: {
AAMVAType: AAMVAType,
IIN: IIN,
AAMVAVersion: AAMVAVersion,
jurisdictionVersion: jurisdictionVersion
}
};
for (let i = 0; !numberOfEntries || i < numberOfEntries; i++) {
const entryOffset = header.length + i * 10;
let [ , subfileType, offset, length ]
= data.substring(entryOffset, entryOffset + 10).match(/(.{2})(\d{4})(\d{4})/) || [ ];
if (!subfileType) break;
offset = +offset;
length = +length;
if (i === 0) obj.files = [ ];
obj.files.push(subfileType);
obj[subfileType] = data.substring(offset + 2, offset + length).trim().split(/\n\r?/).reduce((p, c) => {
p[c.substring(0,3)] = c.substring(3);
return p;
}, { } );
}
// Convert date string (in local timezone) into Javascript UTC time
function convertAAMVADate(str, country) {
function convertMMDDCCYY(str) {
const [ __str, month, day, year ] = str.match(/(\d{2})(\d{2})(\d{4})/) || [ ];
if (!__str) return null;
return new Date(year, month-1, day).getTime();
}
function convertCCYYMMDD(str) {
const [ __str, year, month, day ] = str.match(/(\d{4})(\d{2})(\d{2})/) || [ ];
if (!__str) return null;
return new Date(year, month-1, day).getTime();
}
switch (country) {
case "USA": return convertMMDDCCYY(str);
case "CAN": return convertCCYYMMDD(str);
default: return convertCCYYMMDD(str);
}
}
if (obj.DL) {
for (let k of ["DBA", "DBB", "DBD", "DDB", "DDC", "DDH", "DDI", "DDJ"]) {
if (!obj.DL[k]) continue;
const t = convertAAMVADate(obj.DL[k], obj.DL.DCG);
if (!t) continue;
obj.DL[k] = t;
}
}
if (options && options.format === "string") {
return JSON.stringify(obj);
}
return obj;
}