1 /** 2 * --------- 3 * |.##> <##.| Open Smart Card Development Platform (www.openscdp.org) 4 * |# #| 5 * |# #| Copyright (c) 1999-2011 CardContact Software & System Consulting 6 * |'##> <##'| Andreas Schwier, 32429 Minden, Germany (www.cardcontact.de) 7 * --------- 8 * 9 * This file is part of OpenSCDP. 10 * 11 * OpenSCDP is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License version 2 as 13 * published by the Free Software Foundation. 14 * 15 * OpenSCDP is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with OpenSCDP; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 * 24 * @fileoverview Create or decode NDEF messages 25 */ 26 27 function Ndef(encoded) { 28 if (typeof(encoded) != "undefined") { 29 this.decode(encoded); 30 } else { 31 this.typeLength = 0; 32 this.flags = Ndef.messageBegin | Ndef.messageEnd | Ndef.shortRecord | 1; 33 this.id = null; 34 } 35 } 36 37 //Flag Byte Constants 38 Ndef.messageBegin = 0x80; 39 Ndef.messageEnd = 0x40; 40 Ndef.chunkFlag = 0x20; 41 Ndef.shortRecord = 0x10; 42 Ndef.idLengthFlag = 0x08; //IL 43 Ndef.tnf = 0x07; 44 45 46 //Uri Identifier Abbrevations 47 Ndef.uriIdentifier = new Array(null, "http://www.", "https://www.", "http://", "https://", "tel:", "mailto:", "ftp://anonymous:anonymous@", "ftp://ftp.", "ftps://", "sftp://", "smb://", "nfs://", "ftp://", "dav://", "news:", "telnet://", "imap:", "rtsp://", "urn:", "pop", "sip:", "sips:", "tftp:", "btspp://", "btl2cap://", "btgoep://", "tcpobex://", "irdaobex://", "file://", "urn:epc:id:", "urn:epc:tag:", "urn:epc:pat:", "urn:epc:raw:", "urn:epc:", "urn:nfc:"); 48 49 /** 50 * Create Ndef object 51 * @param {ByteString} encoded the encoded Ndef ByteString 52 */ 53 Ndef.prototype.decode = function(encoded) { 54 this.flags = encoded.byteAt(0); 55 this.typeLength = encoded.byteAt(1); 56 var ofs = 2; 57 58 if (this.isShortRecord()) { 59 this.payloadLength = encoded.byteAt(ofs++); 60 } else { 61 this.payloadLength = encoded.bytes(ofs, 4).toUnsigned(); 62 ofs += 4; 63 } 64 65 if (this.isIdLengthFlag()) { 66 this.idLength = encoded.byteAt(ofs++); 67 } 68 69 this.type = encoded.bytes(ofs, this.typeLength); 70 ofs += this.typeLength; 71 72 if (this.isIdLengthFlag()) { 73 this.id = encoded.bytes(ofs, this.idLength); 74 ofs += this.idLength; 75 } 76 77 this.payload = encoded.bytes(ofs, this.payloadLength); 78 ofs += this.payloadLength; 79 80 if (this.isChunked()) { 81 var nextRecord = new Ndef(encoded.bytes(ofs)); 82 this.payload += nextRecord.getPayload(); 83 } 84 85 this.setMessageBegin(true); 86 this.setMessageEnd(true); 87 this.setChunked(false); 88 this.payloadLength == this.payload.length; 89 } 90 91 92 /** 93 * Return the payload of the NDEF object. 94 * @return {ByteString} the payload 95 */ 96 Ndef.prototype.getPayload = function() { 97 return new ByteString(this.payload, HEX); 98 } 99 100 101 /** 102 * Return the decoded URI in readable form. 103 * @return {String} the UTF-8 decoded URI 104 */ 105 Ndef.prototype.getUri = function() { 106 //type must be "U" 107 var payload = new ByteString(this.payload, HEX); 108 109 if (this.type == 55) { 110 var i = payload.byteAt(0); 111 var str = ""; 112 if (i > 0) { 113 str += Ndef.uriIdentifier[i]; 114 } 115 str += payload.bytes(1).toString(UTF8); 116 117 return str; 118 } 119 } 120 121 122 /** 123 * Check if the Message Begin flag is set. The flag indicates the start of an NDEF message. 124 * @return {Boolean} 125 */ 126 Ndef.prototype.isMessageBegin = function() { 127 return (this.flags & Ndef.messageBegin) == 0x80; 128 } 129 130 131 /** 132 * Set the Message Begin flag. The flag indicates the start of an NDEF message. 133 * @param {Boolean} state 134 */ 135 Ndef.prototype.setMessageBegin = function(state) { 136 this.flags = this.flags & ~Ndef.messageBegin | (state ? Ndef.messageBegin : 0); 137 return this.flags & Ndef.messageBegin; 138 } 139 140 141 /** 142 * Check if the Message End flag is set. The flag indicates the end of an NDEF message. 143 * @return {Boolean} 144 */ 145 Ndef.prototype.isMessageEnd = function(state) { 146 return (this.flags & Ndef.messageBegin) == 0x40; 147 } 148 149 150 /** 151 * Set the Message End flag. The flag indicates the end of an NDEF message. 152 * @param {Boolean} state 153 */ 154 Ndef.prototype.setMessageEnd = function(state) { 155 this.flags = this.flags & ~Ndef.messageEnd | (state ? Ndef.messageEnd : 0); 156 return this.flags & Ndef.messageBegin; 157 } 158 159 160 /** 161 * Check if the Chunk flag is set. 162 * The flag indicates that this is either the first or the middle record chunk of a chunked payload. 163 * @return {Boolean} 164 */ 165 Ndef.prototype.isChunked = function() { 166 return (this.flags & Ndef.chunkFlag) == 0x20; 167 } 168 169 170 /** 171 * Set the Chunk flag. 172 * The flag indicates that this is either the first or the middle record chunk of a chunked payload. 173 * @param {Boolean} state 174 */ 175 Ndef.prototype.setChunked = function(state) { 176 this.flags = this.flags & ~Ndef.chunkFlag | (state ? Ndef.chunkFlag : 0); 177 return this.flags & Ndef.chunkFlag; 178 } 179 180 181 /** 182 * Check if the Short Record flag is set. 183 * The flag indicates that the payload size will range between 0 to 255 octets. 184 * @return {Boolean} 185 */ 186 Ndef.prototype.isShortRecord = function() { 187 return (this.flags & Ndef.shortRecord) == 0x10; 188 } 189 190 191 /** 192 * Set the Short Record flag. 193 * The flag indicates that the payload size will range between 0 to 255 octets. 194 * @param {Boolean} state 195 */ 196 Ndef.prototype.setShortRecord = function(state) { 197 this.flags = this.flags & ~Ndef.shortRecord | (state ? Ndef.shortRecord : 0); 198 return this.flags & Ndef.shortRecord; 199 } 200 201 202 /** 203 * Check if the ID Length flag is set. 204 * The flag indicates that the ID Length field and the ID field are present. Otherwise the both are omitted from the record. 205 * @return {Boolean} 206 */ 207 Ndef.prototype.isIdLengthFlag = function() { 208 return (this.flags & Ndef.idLengthFlag) == 0x08; 209 } 210 211 212 /** 213 * Set the ID Length flag. 214 * The flag indicates that the ID Length field and the ID field are present. Otherwise the both are omitted from the record. 215 * @param {Boolean} state 216 */ 217 Ndef.prototype.setIdLengthFlag = function(state) { 218 this.flags = this.flags & ~Ndef.idLengthFlag | (state ? Ndef.idLengthFlag : 0); 219 return this.flags & Ndef.idLengthFlag; 220 } 221 222 223 /** 224 * Set the TNF (Type Name Format) flag. 225 * The flag indicates the structure of the type value. 226 * 227 * 0x00 = Empty 228 * 0x01 = NFC Forum well-known type 229 * 0x02 = Media-type as defined in RFC 2046 230 * 0x03 = Absolute URI as defined in RFC 3986 231 * 0x04 = NFC Forum external type 232 * 0x05 = Unknown 233 * 0x06 = Unchanged 234 * 0x07 = Reserved 235 * 236 * @param {Boolean} state 237 */ 238 Ndef.prototype.setTNF = function(tnf) { 239 if (tnf <= 7 && tnf >= 0) { 240 this.flags = this.flags & ~Ndef.tnf | tnf; 241 } 242 } 243 244 245 /** 246 * Return the TNF flag 247 * The flag indicates the structure of the type value. 248 * 249 * 0x00 = Empty 250 * 0x01 = NFC Forum well-known type 251 * 0x02 = Media-type as defined in RFC 2046 252 * 0x03 = Absolute URI as defined in RFC 3986 253 * 0x04 = NFC Forum external type 254 * 0x05 = Unknown 255 * 0x06 = Unchanged 256 * 0x07 = Reserved 257 * 258 259 * @return {ByteString} the TNF 260 */ 261 Ndef.prototype.getTNF = function() { 262 return this.flags & Ndef.tnf; 263 } 264 265 266 267 268 /** 269 * Search for possible abbrevation in String and return the corresponding Uri Identifier 270 * @param {String} str the message coded in UTF-8 271 * @return {ByteString} the payload consisting of the Uri Identifier and the shortened string 272 */ 273 Ndef.shortenString = function(str) { 274 for(var i = 1; i <= Ndef.uriIdentifier.length; i++) { 275 276 var containsUriID = str.indexOf(Ndef.uriIdentifier[i]) 277 if(containsUriID != -1) { 278 str = new ByteString(str.substring(Ndef.uriIdentifier[i].length), UTF8); 279 var payload = ByteString.valueOf(i); 280 return payload.concat(str); 281 } 282 } 283 var payload = new ByteString("0x00", HEX).concat(new ByteString(str, UTF8)); 284 return payload; 285 } 286 287 288 /** 289 * Create a new Uri from string 290 * @param {String} str 291 * @return {NDEF} the NDEF object 292 */ 293 Ndef.newUri = function(str) { 294 var n = new Ndef(); 295 var payload = Ndef.shortenString(str); 296 297 n.typeLength = ByteString.valueOf(1); 298 n.payloadLength = new ByteString(payload.length, HEX); 299 n.type = new ByteString("U", UTF8); 300 n.payload = payload; 301 302 if (n.payloadLength > 255) { 303 n.setShortRecord(false); 304 } 305 306 307 return n; 308 } 309 310 311 /** 312 * Create a new NDEF Message 313 * @param {String} type The type of the NDEF Message coded in US-ASCII. 314 * @param {ByteString} payload 315 */ 316 Ndef.newMessage = function(type, payload) { 317 var n = new Ndef(); 318 n.typeLength = new ByteString(type.length, HEX); 319 n.payloadLength = payload.length; 320 n.type = type; 321 n.payload = payload; 322 323 //TODO... 324 //n.setTNF(); 325 326 if (n.payloadLength > 255) { 327 n.setShortRecord(false); 328 } 329 330 331 return n; 332 } 333 334 335 /** 336 * Return the Ndef in encoded format 337 * @return {ByteString} encoded Ndef 338 */ 339 Ndef.prototype.getEncoded = function() { 340 var buffer = new ByteBuffer(); 341 var flagByte = new ByteString(ByteString.valueOf(this.flags), HEX); 342 343 this.flags = (this.flags & ~Ndef.idLengthFlag) | (this.id ? Ndef.idLengthFlag : 0); 344 345 buffer.append(flagByte); 346 buffer.append(this.type.length); 347 buffer.append(this.payload.length); 348 if (this.id) { 349 buffer.append(this.id.length); 350 } 351 buffer.append(this.type); 352 if (this.id) { 353 buffer.append(this.id); 354 } 355 buffer.append(this.payload); 356 357 //print(buffer.toByteString()); 358 return buffer.toByteString(); 359 } 360 361 362 /** 363 * @return {String} str A String containing the flag byte and the uri payload. 364 */ 365 Ndef.prototype.toString = function() { 366 var str = "flag=" + this.flags.toString(HEX); 367 str += ",uri="; 368 var payload = new ByteString(this.payload, HEX); 369 var i = payload.byteAt(0); 370 if (i > 0) { 371 str += Ndef.uriIdentifier[i]; 372 } 373 str += payload.bytes(1).toString(UTF8); 374 375 return str; 376 } 377