├── .editorconfig ├── package.json ├── LICENSE ├── dev ├── header-constants.js ├── location-report.html └── test.html ├── README.md └── dist └── vmf-parser.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | indent_size = 4 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vmf-parser", 3 | "version": "0.1.0", 4 | "description": "A library for reading and writing to Variable Message Format", 5 | "license" : "MIT", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/spatialillusions/vmf-parser.git" 9 | }, 10 | "dependencies": {} 11 | } 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Måns Beckman - www.spatialillusions.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dev/header-constants.js: -------------------------------------------------------------------------------- 1 | var VERSION_CODES = [ 2 | 'MIL-STD-2045-47001', 3 | 'MIL-STD-2045-47001B', 4 | 'MIL-STD-2045-47001C', 5 | 'MIL-STD-2045-47001D', 6 | undefined, 7 | undefined, 8 | undefined, 9 | undefined, 10 | undefined, 11 | undefined, 12 | undefined, 13 | undefined, 14 | undefined, 15 | undefined, 16 | undefined, 17 | 'Version Sent Not Implemented' 18 | ]; 19 | 20 | var DATA_COMPRESSION_TYPE_CODES = [ 21 | 'Unix compress/uncompress', 22 | 'GZIP', 23 | undefined, 24 | undefined 25 | ]; 26 | 27 | var UMF_CODES = [ 28 | 'Link 16', 29 | 'Binary File', 30 | 'Variable Message Format (VMF)', 31 | 'National Imagery Transmission Format System (NITFS)', 32 | 'Redistributed Message (RDM)', 33 | 'United States Message Text Format (USMTF)', 34 | '(DOI-103)', 35 | 'eXtensible Markup Language (XML) - Message Text Format (MTF)', 36 | 'eXtensible Markup Language (XML) - Variable Message Format (VMF)', 37 | undefined, 38 | undefined, 39 | undefined, 40 | undefined, 41 | undefined, 42 | undefined, 43 | undefined 44 | ]; 45 | 46 | var OPERATION_INDICATOR_CODES = [ 47 | 'Operation', 48 | 'Exercise', 49 | 'Simulation', 50 | 'Test' 51 | ]; 52 | 53 | var MESSAGE_PRECEDENCE_CODES = [ 54 | 'Routine', 55 | 'Priority', 56 | 'Immediate', 57 | 'Flash', 58 | 'Flash Override', 59 | 'CRITIC/ECP', 60 | 'Reserved', 61 | 'Reserved' 62 | ]; 63 | 64 | var SECURITY_CLASSIFICATION_CODES = [ 65 | 'Unclassified', 66 | 'Confidential', 67 | 'Secret', 68 | 'Top secret' 69 | ]; 70 | 71 | var RC_CODES = [ 72 | undefined, 73 | 'Machine Receipt', 74 | 'Cannot Process', 75 | 'Operator Acknowledge', 76 | 'Will Comply', 77 | 'Have Complied', 78 | 'Cannot Comply', 79 | undefined 80 | ]; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vmf-parser 2 | Library for parsing and writing Variable Message Format (VMF) in JavaScript. 3 | 4 | ## Introduction 5 | 6 | This library is able to read and write to Variable Message Format using pure javascript. Header information according to **MIL-STD-2045 47001D** can be read using built in functionality and messages according to **MIL-STD-6017** can be read if message type objects are provided. 7 | 8 | To read and write coordinates in messages, you can use my library [latlng-uint](https://github.com/spatialillusions/latlng-uint). 9 | 10 | ### Limitations 11 | 12 | Since **MIL-STD-6017** currently is under limited distribution message type objects for messages described in this standard cannot be provided with the library, they are however quite easy to create using the header message type as a template. 13 | 14 | - 15 | 16 | ## Main Class VMF 17 | 18 | Create a new message object by calling the main class with or without a byte array. 19 | 20 | `var message = new VMF([binary])` 21 | 22 | ### readHeader() 23 | Reads the header from the object binary and returns a header object containing the information. 24 | 25 | ### readMessage(message type) 26 | Reads a message from the object binary using the provided message type object and returns a message object containing the information. 27 | 28 | ### setBinary(binary) 29 | Sets the binary for the VMF object. 30 | 31 | ### setHeader(header object) 32 | Sets the header of the VMF object to the provided message object. 33 | 34 | ### setMessage(message object) 35 | Sets the message of the VMF object to the provided message object. 36 | 37 | ### writeHeaderToBinary() 38 | Writes the current header object to binary and returns a Uint8Array containing the information. 39 | 40 | ### writeMessageToBinary(message type) 41 | Writes the current message object to binary using the provided message type object and returns a Uint8Array containing the information. 42 | 43 | ## License and Contact 44 | The library is developed by Måns Beckman, www.spatialillusions.com, and is provided under a MIT License. 45 | -------------------------------------------------------------------------------- /dev/location-report.html: -------------------------------------------------------------------------------- 1 | . 2 | 3 | 4 | 5 | VMF Parser – Location Report 6 | 8 | 9 | 10 |

Loction Report

11 | 129 | 130 | -------------------------------------------------------------------------------- /dev/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tests of VMF parser 6 | 8 | 9 | 10 |

Tests

11 | 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /dist/vmf-parser.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var VMF = class { 3 | constructor(binary) { 4 | this.binary = new Uint8Array(binary); 5 | this.header, this.headerLength,this.message, this.messageLength; 6 | this._headermessage = {name:'header', type:'group', items:[ 7 | {name:'Version', length:4 , type:'number'}, 8 | {name:'DataCompressionType', length: 2, type:'number', fpi:true}, 9 | {name:'OriginatorAddressGroup', type:'group', gpi:true, items: [ 10 | {name:'Urn', length: 24, type:'number', fpi:true}, 11 | {name:'UnitName', length:448, type:'string', fpi:true}, 12 | ]}, 13 | {name:'RecipientAddressGroup', type:'group', gpi:true, gri:true, items: [ 14 | {name:'Urn', length: 24, type:'number', fpi:true}, 15 | {name:'UnitName', length: 448, type:'string', fpi:true} 16 | ]}, 17 | {name:'InformationAddressGroup', type:'group', gpi:true, gri:true, items: [ 18 | {name:'Urn', length: 24, type:'number', fpi:true}, 19 | {name:'UnitName', length: 448, type:'string', fpi:true} 20 | ]}, 21 | {name:'HeaderSize', length: 16, type:'number', fpi:true}, 22 | {name:'FutureUse1', type:'group', gpi:true, items:[ 23 | {name:'size', length: 12, type:'number'} 24 | ]}, 25 | {name:'FutureUse2', type:'group', gpi:true, items:[ 26 | {name:'size', length: 12, type:'number'} 27 | ]}, 28 | {name:'FutureUse3', type:'group', gpi:true, items:[ 29 | {name:'size', length: 12, type:'number'} 30 | ]}, 31 | {name:'FutureUse4', type:'group', gpi:true, items:[ 32 | {name:'size', length: 12, type:'number'} 33 | ]}, 34 | {name:'FutureUse5', type:'group', gpi:true, items:[ 35 | {name:'size', length: 12, type:'number'} 36 | ]}, 37 | {name:'MessageHandlingGroup', type:'group', gri:true, items: [ 38 | {name:'Umf', length: 4, type:'number'}, 39 | {name:'MessageStandardVersion', length: 4, type:'number', fpi:true}, 40 | {name:'VmfMessageIdentificationGroup', type:'group', gpi:true, items: [ 41 | {name:'Fad', length: 4, type:'number'}, 42 | {name:'MessageNumber', length: 7, type:'number'}, 43 | {name:'MessageSubtype', length: 7, type:'number', fpi:true} 44 | ]}, 45 | {name:'FileName', length: 448, type:'string', fpi:true}, 46 | {name:'MessageSize', length: 20, type:'number', fpi:true}, 47 | {name:'OperationIndicator', length: 2, type:'number'}, 48 | {name:'RetransmitIndicator', length: 1, type:'number'}, 49 | {name:'MessagePrecedenceCode', length: 3, type:'number'}, 50 | {name:'SecurityClassification', length: 2, type:'number'}, 51 | {name:'ControlReleaseMarking', length: 9, type:'number', fpi:true, fri:true}, 52 | {name:'OriginatorDtg', type:'group', gpi:true, items: [ 53 | {name:'Year', length: 7, type:'number'}, 54 | {name:'Month', length: 4, type:'number'}, 55 | {name:'Day', length: 5, type:'number'}, 56 | {name:'Hour', length: 5, type:'number'}, 57 | {name:'Minute', length: 6, type:'number'}, 58 | {name:'Second', length:6 , type:'number'}, 59 | {name:'DtgExtension', length: 12, type:'number', fpi:true} 60 | ]}, 61 | {name:'PerishabilityDtg', type:'group', gpi:true, items:[ 62 | {name:'Year', length: 7, type:'number'}, 63 | {name:'Month', length: 4, type:'number'}, 64 | {name:'Day', length: 5, type:'number'}, 65 | {name:'Hour', length: 5, type:'number'}, 66 | {name:'Minute', length: 6, type:'number'}, 67 | {name:'Second', length: 6, type:'number'} 68 | ]}, 69 | {name:'AcknowledgmentRequestGroup', type:'group', gpi:true, items: [ 70 | {name:'MachineAcknowledgeRequestIndicator', length: 1, type:'number'}, 71 | {name:'OperatorAcknowledgeRequestIndicator', length: 1, type:'number'}, 72 | {name:'OperatorReplyRequestIndicator', length: 1, type:'number'} 73 | ]}, 74 | {name:'ResponseDataGroup', type:'group', gpi:true, items: [ 75 | {name:'Year', length: 7, type:'number'}, 76 | {name:'Month', length: 4, type:'number'}, 77 | {name:'Day', length: 5, type:'number'}, 78 | {name:'Hour', length: 5, type:'number'}, 79 | {name:'Minute', length: 6, type:'number'}, 80 | {name:'Second', length: 6, type:'number'}, 81 | {name:'DtgExtension', length: 12, type:'number', fpi:true}, 82 | {name:'ResponseToAcknowledgeRequest', length: 3, type:'number'}, 83 | {name:'CantcoReasonCode', length: 3, type:'number', fpi:true}, 84 | {name:'CantproReasonCode', length: 6, type:'number', fpi:true}, 85 | {name:'ReplyAmplification', length: 350, type:'number', fpi:true} 86 | ]}, 87 | {name:'ReferenceMessageDataGroup', type:'group', gpi:true, gri:true, items: [ 88 | {name:'Urn', length: 24, type:'number', fpi:true}, 89 | {name:'UnitName', length: 448, type:'string', fpi:true}, 90 | {name:'Year', length: 7, type:'number'}, 91 | {name:'Month', length: 4, type:'number'}, 92 | {name:'Day', length: 5, type:'number'}, 93 | {name:'Hour', length: 5, type:'number'}, 94 | {name:'Minute', length: 6, type:'number'}, 95 | {name:'Second', length: 6, type:'number'}, 96 | {name:'DtgExtension', length: 12, type:'number', fpi:true} 97 | ]}, 98 | {name:'FutureUse6', type:'group', gpi:true, items:[ 99 | {name:'size', length: 12, type:'number'} 100 | ]}, 101 | {name:'FutureUse7', type:'group', gpi:true, items:[ 102 | {name:'size', length: 12, type:'number'} 103 | ]}, 104 | {name:'FutureUse8', type:'group', gpi:true, items:[ 105 | {name:'size', length: 12, type:'number'} 106 | ]}, 107 | {name:'FutureUse9', type:'group', gpi:true, items:[ 108 | {name:'size', length: 12, type:'number'} 109 | ]}, 110 | {name:'FutureUse10', type:'group', gpi:true, items:[ 111 | {name:'size', length: 12, type:'number'} 112 | ]}, 113 | {name:'MessageSecurityGroup', type:'group', gpi:true, items: [ 114 | {name:'SecurityParametersInformation', length: 4, type:'number'}, 115 | {name:'KeyingMaterialGroup', type:'group', gpi:true, items: [ 116 | {name:'Length', length: 3, type:'number'}, 117 | {name:'KeyingMaterialId', length: 64, type:'number'} 118 | ]}, 119 | {name:'CryptographicInitializationGroup', type:'group', gpi:true, items: [ 120 | {name:'Length', length: 4, type:'number'}, 121 | {name:'CryptographicInitialization', length: 1024, type:'number'} 122 | ]}, 123 | {name:'KeyTokenGroup', type:'group', gpi:true, items: [ 124 | {name:'Length', length: 8, type:'number'}, 125 | {name:'KeyToken', length: [16384], type:'number', fri:true} 126 | ]}, 127 | {name:'AuthenticationAGroup', type:'group', gpi:true, items: [ 128 | {name:'Length', length: 7, type:'number'}, 129 | {name:'DigitalSignature', length: 8192, type:'number'} 130 | ]}, 131 | {name:'AuthenticationBGroup', type:'group', gpi:true, items: [ 132 | {name:'Length', length: 7, type:'number'}, 133 | {name:'DigitalSignature', length: 8192, type:'number'} 134 | ]}, 135 | {name:'SignedAcknowledgeRequestIndicator', length: 1, type:'number'}, 136 | {name:'MessageSecurityPaddingGroup', type:'group', gpi:true, items: [ 137 | {name:'Length', length: 8, type:'number'}, 138 | {name:'MessageSecurityPadding', length: 2040, type:'number', fpi:true} 139 | ]} 140 | ]} 141 | ]}, 142 | {name:'FutureUse11', type:'group', gpi:true, items:[ 143 | {name:'size', length: 12, type:'number'} 144 | ]}, 145 | {name:'FutureUse12', type:'group', gpi:true, items:[ 146 | {name:'size', length: 12, type:'number'} 147 | ]}, 148 | {name:'FutureUse13', type:'group', gpi:true, items:[ 149 | {name:'size', length: 12, type:'number'} 150 | ]}, 151 | {name:'FutureUse14', type:'group', gpi:true, items:[ 152 | {name:'size', length: 12, type:'number'} 153 | ]}, 154 | {name:'FutureUse15', type:'group', gpi:true, items:[ 155 | {name:'size', length: 12, type:'number'} 156 | ]} 157 | ]}; 158 | } 159 | readHeader(){ 160 | this.headerLength = 0; 161 | var message = this.readMessage(this._headermessage); 162 | this.header = message; 163 | this.headerLength = this.messageLength; 164 | return message; 165 | } 166 | readMessage(messagetype){ 167 | var readByte = this.headerLength || 0; 168 | var bitString = ''; 169 | function fpiCheck(field){ 170 | if(field.fpi){ 171 | if(parseInt(readBits(1)))return friCheck(field); 172 | }else{ 173 | return friCheck(field); 174 | } 175 | } 176 | function friCheck(field){ 177 | if(field.fri){ 178 | var data = []; 179 | var fri = 1; 180 | while(fri){ 181 | fri = parseInt(readBits(1)); 182 | data.push(getField(field)); 183 | } 184 | return data; 185 | }else{ 186 | return getField(field); 187 | } 188 | } 189 | function readBits(bitsToRead){ 190 | while(bitString.length < bitsToRead){ 191 | readData(); 192 | } 193 | var bits = bitString.slice(-bitsToRead); 194 | bitString = bitString.slice(0,-bitsToRead); 195 | return bits; 196 | } 197 | function readData(){ 198 | var octet = selfBinary[readByte].toString(2); 199 | bitString = Array(8 - octet.length + 1).join(0) + octet + bitString; 200 | readByte++; 201 | } 202 | function getField(field){ 203 | var data; 204 | if(field.type == 'string'){ 205 | var bitsRead = 0; 206 | data = ''; 207 | while (bitsRead < field.length){ 208 | var bits = readBits(7); 209 | if(bits == '1111111')break; 210 | data += String.fromCharCode(parseInt(bits,2)); 211 | bitsRead += 7; 212 | } 213 | }else{ 214 | data = parseInt(readBits(field.length),2); 215 | } 216 | //console.log(field.name + ' - ' + field.length + 'bits - ' + field.type + ' Value: '+ data); 217 | return data; 218 | } 219 | function gpiCheck(group){ 220 | if(group.gpi){ 221 | if(parseInt(readBits(1)))return griCheck(group); 222 | }else{ 223 | return griCheck(group); 224 | } 225 | } 226 | function griCheck(group){ 227 | if(group.gri){ 228 | var data = []; 229 | var gri = 1; 230 | while(gri){ 231 | gri = parseInt(readBits(1)); 232 | data.push(read(group.items)); 233 | } 234 | return data; 235 | }else{ 236 | return read(group.items); 237 | } 238 | } 239 | 240 | function read(messagetype){ 241 | var obj = {}; 242 | for( var i = 0; i