Publish Vulpes Preview 15 sources for desktop, Android and Tundra

Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,671 @@
/* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright © 2013, Deutsche Telekom, Inc. */
/* globals MozNDEFRecord, TextEncoder, TextDecoder, StringHelper */
/* exported NDEF, NfcBuffer, NfcUtils */
'use strict';
(function(exports) {
/**
* NDEF (NFC Data Exchange Format) contants and common values.
*/
const NDEF = {
MB: 1 << 7,
ME: 1 << 6,
CF: 1 << 5,
SR: 1 << 4,
IL: 1 << 3,
TNF: 0x07,
TNF_EMPTY: 'empty',
TNF_WELL_KNOWN: 'well-known',
TNF_MIME_MEDIA: 'media-type',
TNF_ABSOLUTE_URI: 'absolute-uri',
TNF_EXTERNAL_TYPE: 'external',
TNF_UNKNOWN: 'unknown',
TNF_UNCHANGED: 'unchanged',
RTD_TEXT: 0,
RTD_URI: 0,
RTD_SMART_POSTER: 0,
RTD_ALTERNATIVE_CARRIER: 0,
RTD_COLLISION_RESOLUTION: 0,
RTD_HANDOVER_CARRIER: 0,
RTD_HANDOVER_REQUEST: 0,
RTD_HANDOVER_SELECT: 0,
RTD_TEXT_IANA_LENGTH: 0x3F,
RTD_TEXT_ENCODING: 0x80,
RTD_TEXT_UTF8: 0,
RTD_TEXT_UTF16: 1,
CPS_INACTIVE: 0,
CPS_ACTIVE: 1,
CPS_ACTIVATING: 2,
CPS_UNKNOWN: 3,
MIME_BLUETOOTH_OOB: 0,
SMARTPOSTER_ACTION: 0,
// Action Record Values:
DO_ACTION: 0x00,
SAVE_FOR_LATER_ACTION: 0x01,
OPEN_FOR_EDITING_ACTION: 0x02,
RFU_ACTION: 0x03, // Reserved from 0x03 to 0xFF
URIS: [],
init: function ndef_init() {
var nfcUtils = new NfcUtils();
this.RTD_TEXT = nfcUtils.fromUTF8('T');
this.RTD_URI = nfcUtils.fromUTF8('U');
this.RTD_SMART_POSTER = nfcUtils.fromUTF8('Sp');
this.RTD_ALTERNATIVE_CARRIER = nfcUtils.fromUTF8('ac');
this.RTD_COLLISION_RESOLUTION = nfcUtils.fromUTF8('cr');
this.RTD_HANDOVER_CARRIER = nfcUtils.fromUTF8('Hc');
this.RTD_HANDOVER_REQUEST = nfcUtils.fromUTF8('Hr');
this.RTD_HANDOVER_SELECT = nfcUtils.fromUTF8('Hs');
this.MIME_BLUETOOTH_OOB =
nfcUtils.fromUTF8('application/vnd.bluetooth.ep.oob');
this.MIME_VCARD_STR_ARR =
['text/vcard', 'text/x-vCard', 'text/x-vcard'];
this.SMARTPOSTER_ACTION = nfcUtils.fromUTF8('act');
this.URIS[0x00] = '';
this.URIS[0x01] = 'http://www.';
this.URIS[0x02] = 'https://www.';
this.URIS[0x03] = 'http://';
this.URIS[0x04] = 'https://';
this.URIS[0x05] = 'tel:';
this.URIS[0x06] = 'mailto:';
this.URIS[0x07] = 'ftp://anonymous:anonymous@';
this.URIS[0x08] = 'ftp://ftp.';
this.URIS[0x09] = 'ftps://';
this.URIS[0x0A] = 'sftp://';
this.URIS[0x0B] = 'smb://';
this.URIS[0x0C] = 'nfs://';
this.URIS[0x0D] = 'ftp://';
this.URIS[0x0E] = 'dav://';
this.URIS[0x0F] = 'news:';
this.URIS[0x10] = 'telnet://';
this.URIS[0x11] = 'imap:';
this.URIS[0x12] = 'rtsp://';
this.URIS[0x13] = 'urn:';
this.URIS[0x14] = 'pop:';
this.URIS[0x15] = 'sip:';
this.URIS[0x16] = 'sips:';
this.URIS[0x17] = 'tftp:';
this.URIS[0x18] = 'btspp://';
this.URIS[0x19] = 'btl2cap://';
this.URIS[0x1A] = 'btgoep://';
this.URIS[0x1B] = 'tcpobex://';
this.URIS[0x1C] = 'irdaobex://';
this.URIS[0x1D] = 'file://';
this.URIS[0x1E] = 'urn:epc:id:';
this.URIS[0x1F] = 'urn:epc:tag:';
this.URIS[0x20] = 'urn:epc:pat:';
this.URIS[0x21] = 'urn:epc:raw:';
this.URIS[0x22] = 'urn:epc:';
this.URIS[0x23] = 'urn:nfc:';
},
payload: {
/**
* Decodes NDEF record payload
* @see NFCForum-TS-NDEF_1.0
* @param String tnf - record TNF
* @param {Uint8Array} type - record type
* @param {Uint8Array} payload - record payload
* @returns {Object} data - decoded payload or null if invalid
*/
decode: function decode(tnf, type, payload) {
var nfcUtils = new NfcUtils();
var decodedPayload = { type: 'empty' };
switch (tnf) {
case NDEF.TNF_WELL_KNOWN:
decodedPayload = this.decodeWellKnown(type, payload);
break;
case NDEF.TNF_MIME_MEDIA:
decodedPayload = this.decodeMIME(type, payload);
break;
case NDEF.TNF_ABSOLUTE_URI:
case NDEF.TNF_EXTERNAL_TYPE:
decodedPayload = { type: nfcUtils.toUTF8(type) };
break;
case NDEF.TNF_UNKNOWN:
decodedPayload = {};
break;
case NDEF.TNF_UNCHANGED:
decodedPayload = null;
break;
}
return decodedPayload;
},
/**
* Decodes TNF Well Know NDEF record payload
* @see NFCForum-TS-NDEF_1.0
* @param {Uint8Array} type - record type
* @param {Uint8Array} payload - record payload
* @returns {Object} data - decoded payload or null if invalid
*/
decodeWellKnown: function decodeWellKnown(type, payload) {
var nfcUtils = new NfcUtils();
if (nfcUtils.equalArrays(type, NDEF.RTD_TEXT)) {
return this.decodeText(payload);
} else if (nfcUtils.equalArrays(type, NDEF.RTD_URI)) {
return this.decodeURI(payload);
} else if (nfcUtils.equalArrays(type, NDEF.RTD_SMART_POSTER)) {
return this.decodeSmartPoster(payload);
}
return null;
},
/**
* Decodes TNF Well Known RTD Text NDEF record payload
* @see NFCForum-TS-RTD_Text_1.0
* @param {Uint8Array} payload - record payload
* @returns {Object} data - decoded payload
*/
decodeText: function decodeText(payload) {
var nfcUtils = new NfcUtils();
var decoded = { type: 'text' };
var langLen = payload[0] & NDEF.RTD_TEXT_IANA_LENGTH;
decoded.language = nfcUtils.toUTF8(payload.subarray(1, langLen + 1));
var encoding = (payload[0] & NDEF.RTD_TEXT_ENCODING) !== 0 ? 1 : 0;
if (encoding === NDEF.RTD_TEXT_UTF8) {
decoded.text = nfcUtils.toUTF8(payload.subarray(langLen + 1));
decoded.encoding = 'UTF-8';
} else if (encoding === NDEF.RTD_TEXT_UTF16) {
decoded.text = nfcUtils.UTF16BytesToStr(payload.subarray(langLen +
1));
decoded.encoding = 'UTF-16';
}
return decoded;
},
/**
* Decodes TNF Well Known RTD URI NDEF record payload
* @see NFCForum-TS-RTD_URI_1.0
* @param {Uint8Array} payload - record payload
* @returns {Object} data - decoded payload or null if invalid
*/
decodeURI: function decodeURI(payload) {
var nfcUtils = new NfcUtils();
var prefix = NDEF.URIS[payload[0]];
if (prefix === undefined) {
return null;
}
var suffix = nfcUtils.toUTF8(payload.subarray(1));
return { type: 'uri', uri: prefix + suffix };
},
/**
* Decodes TNF Well Known RTD Smart Poster NDEF record payload
* @see NFCForum-SmartPoster_RTD_1.0
* @param {Uint8Array} payload - record payload
* @returns {Object} data - decoded payload
*/
decodeSmartPoster: function decodeSmartPoster(payload) {
var nfcUtils = new NfcUtils();
var buffer = new NfcBuffer(payload);
var records = nfcUtils.parseNDEF(buffer);
// First, decode URI. It's treated specially, because it's the only
// mandatory record in a smart poster.
var URIRecords = records.filter(function(record) {
return nfcUtils.equalArrays(record.type, NDEF.RTD_URI);
});
if (URIRecords.length !== 1) {
return null;
}
var uriPoster = {
type: 'smartposter',
uri: NDEF.payload.decodeURI(URIRecords[0].payload).uri
};
// Now decode all other records and attach their data to poster.
return records.reduce((poster, record) => {
var typeStr = nfcUtils.toUTF8(record.type);
if (nfcUtils.equalArrays(record.type, NDEF.RTD_TEXT)) {
poster.text = poster.text || {};
var textData = NDEF.payload.decodeText(record.payload);
if (poster.text[textData.language]) {
// According to NFCForum-SmartPoster_RTD_1.0 3.3.2,
// there MUST NOT be two or more records with
// the same language identifier.
return null;
}
poster.text[textData.language] = textData.text;
} else if ('act' === typeStr) {
poster.action = record.payload[0];
} else if (NDEF.TNF_MIME_MEDIA === record.tnf) {
poster.icons = poster.icons || [];
poster.icons.push({
type: nfcUtils.toUTF8(record.type),
bytes: record.payload
});
}
return poster;
}, uriPoster);
},
/**
* Decodes TNF MIME Media NDEF Record payload
* @see NFCForum-TS-NDEF_1.0
* @param {Uint8Array} type - record mime-type
* @returns {Object} data - decoded payload
*/
decodeMIME: function docodeMIME(type, payload) {
var nfcUtils = new NfcUtils();
var typeStr = (typeof type === 'string') ? type : nfcUtils.toUTF8(type);
if (NDEF.MIME_VCARD_STR_ARR.indexOf(typeStr) !== -1) {
return {
type: 'text/vcard',
blob: new Blob([nfcUtils.toUTF8(payload)], {type: 'text/vcard'})
};
}
return { type: typeStr };
}
}
};
/**
* NfcBuffer wraps Uint8Array providing helper methods for accessing
* its elements.
*
* @param {Array} array Either a plain Array or an Uint8Array instance.
* @constructor
*/
function NfcBuffer(array) {
this.uint8array = new Uint8Array(array);
this.offset = 0;
}
NfcBuffer.prototype = {
uint8array: null,
offset: 0,
/**
* Returns a single octet from the buffer advancing position
* by one.
*
* @returns {Number} Single element from the buffer.
* @memberof NfcBuffer
*/
getOctet: function getOctet() {
if (this.offset == this.uint8array.length) {
throw Error('NfcBuffer too small');
}
return this.uint8array[this.offset++];
},
/**
* Returns an Uint8Array containing first len elements from the
* buffer.
*
* @param {Number} len Number of elements to return.
* @returns {Uint8Array} Array of len first elements from the buffer.
* @memberof NfcBuffer
*/
getOctetArray: function getOctetArray(len) {
if (typeof len !== 'number' || len < 0 ||
this.offset + len > this.uint8array.length) {
throw Error('NfcBuffer too small');
}
return this.uint8array.subarray(this.offset, this.offset += len);
},
/**
* Discards len elements from the buffer.
*
* @param {Number} len Number of elements to skip over.
* @memberof NfcBuffer
*/
skip: function skip(len) {
if (typeof len !== 'number' || len < 0 ||
this.offset + len > this.uint8array.length) {
throw Error('NfcBuffer too small');
}
this.offset += len;
},
/**
* Returns a single octet from the buffer, but will not
* advance a position.
*
* @returns {Number} Single element from the buffer.
* @memberof NfcBuffer
*/
peek: function peek() {
if (this.offset === this.uint8array.length) {
throw Error('NfcBuffer too small');
}
return this.uint8array[this.offset];
}
};
/**
* NfcUtils offers a set of utility function to handle NDEF messages according
* to NFCForum-TS-NDEF_1.0.
*
* @class NfcUtils
*/
function NfcUtils() { }
NfcUtils.prototype = {
/**
* Returns an Uint8Array representation of a string.
*
* @param {String} str String to convert.
* @return {Uint8Array}
* @memberof NfcUtils
*/
fromUTF8: function fromUTF8(str) {
if (!str) {
return null;
}
var enc = new TextEncoder('utf-8');
return enc.encode(str);
},
/**
* Returns a string representation of an Uint8Array.
*
* @param {Uint8Array} a Uint8Array instance.
* @return {String}
* @memberof NfcUtils
*/
toUTF8: function toUTF8(a) {
if (!a) {
return null;
}
// BOM removal
if (this.equalArrays(a.subarray(0, 3), [0xEF, 0xBB, 0xBF])) {
a = a.subarray(3);
}
var dec = new TextDecoder('utf-8');
return dec.decode(a);
},
/**
* Decodes UTF-16 bytes array into a String
*
* @param {Uint8Array} array containing UTF-16 encoded bytes
* @return {string}
* @memberof NfcUtils
*/
UTF16BytesToStr: function UTF16BytesToStr(array) {
if (!array) {
return null;
}
// if BOM not present Big-endian should be used
// NFCForum-TS-RTD_Text_1.0
var le = false;
var possibleBom = array.subarray(0, 2);
if (this.equalArrays(possibleBom, [0xFF, 0xFE])) {
array = array.subarray(2);
le = true;
} else if (this.equalArrays(possibleBom, [0xFE, 0xFF])) {
array = array.subarray(2);
}
var encoding = (le) ? 'utf-16le' : 'utf-16be';
var dec = new TextDecoder(encoding);
return dec.decode(array);
},
/**
* Ecodes string into Uint8Array conating UTF-16 BE bytes without BOM.
* @param {string}
* @return {Uint8Array}
* @memberof NfcUtils
*/
strToUTF16Bytes: function strToUTF16Bytes(str) {
if (!str) {
return null;
}
var enc = new TextEncoder('utf-16be');
return enc.encode(str);
},
/**
* Compares arrays, array-like objects and typed arrays for equality.
*
* @param {Array} a1 First array
* @param {Array} a2 Second array
* @return {Boolean} True if arrays are equal, false otherwise.
* @memberof NfcUtils
*/
equalArrays: function equalArrays(a1, a2) {
if (!a1 || !a2) {
return false;
}
if (a1.length !== a2.length) {
return false;
}
for (var i = 0; i < a1.length; i++) {
if (a1[i] !== a2[i]) {
return false;
}
}
return true;
},
/**
* Takes an array of NDEFRecords and returns an Array of octets
* representing the binary encoding of the NDEF message according
* to the NFC Forum.
* Note: support for message chunking is not implemented.
*
* @param {Array} ndefRecords Array of NDEF records to encode.
* @return {Array} Byte array containing encoded NDEF message.
* @memberof NfcUtils
*/
encodeNDEF: function encodeNDEF(records) {
var result = [];
function getTnfNum(tnfString) {
var tnf = [
NDEF.TNF_EMPTY, NDEF.TNF_WELL_KNOWN, NDEF.TNF_MIME_MEDIA,
NDEF.TNF_ABSOLUTE_URI, NDEF.TNF_EXTERNAL_TYPE, NDEF.TNF_UNKNOWN,
NDEF.TNF_UNCHANGED, NDEF.TNF_RESERVED];
return tnf.indexOf(tnfString);
}
records.forEach((record, recordIndex) => {
record.payload = record.payload || [];
record.id = record.id || [];
record.type = record.type || [];
var payloadLen = record.payload.length;
var idLen = record.id.length;
var typeLen = record.type.length;
var firstOctet = getTnfNum(record.tnf) & 0x07;
firstOctet |= (recordIndex === 0) ? NDEF.MB : 0;
firstOctet |= (recordIndex === records.length - 1) ? NDEF.ME : 0;
firstOctet |= (idLen > 0) ? NDEF.IL : 0;
firstOctet |= (payloadLen <= 0xFF) ? NDEF.SR : 0;
result.push(firstOctet);
result.push(typeLen);
for (var p = (payloadLen > 0xFF ? 3 : 0); p >= 0; p -= 1) {
result.push((payloadLen >>> (8 * p)) & 0xFF);
}
if (idLen > 0) {
result.push(idLen);
}
result.push.apply(result, record.type);
result.push.apply(result, record.id);
result.push.apply(result, record.payload);
});
return result;
},
/**
* Parses a NDEF message contained in a NfcBuffer instance according to
* NFCForum-TS-NDEF_1.0.
*
* Usage:
* var buf = new NfcBuffer(<Uint8Array that contains the raw NDEF
* message>);
* var ndefMessage = NdefCodec.parse(buf);
*
* @param {NfcBuffer} Buffer containing the NDEF message.
* @return {Array} Array of MozNDEFRecord instances or null if message
* couldn't be parsed.
* @memberof NfcUtils
*/
parseNDEF: function parseNDEF(buffer) {
try {
return this._doParseNDEF(buffer);
} catch (err) {
console.error('[NfcUtils]: ' + err);
return null;
}
},
_doParseNDEF: function doParseNDEF(buffer) {
var records = [];
var isFirstRecord = true;
var firstOctet;
do {
firstOctet = buffer.peek();
if (isFirstRecord && !(firstOctet & NDEF.MB)) {
throw Error('MB bit not set in first NDEF record');
}
if (!isFirstRecord && (firstOctet & NDEF.MB)) {
throw Error('MB can only be set for the first record');
}
if (firstOctet & NDEF.CF) {
throw Error('Chunked payloads are not supported');
}
records.push(this._parseNDEFRecord(buffer));
isFirstRecord = false;
} while (!(firstOctet & NDEF.ME));
if (buffer.offset < buffer.uint8array.length) {
throw Error('ME bit set on non-last record');
}
return records;
},
_parseNDEFRecord: function parseNDEFRecord(buffer) {
var tnfArray = [
NDEF.TNF_EMPTY, NDEF.TNF_WELL_KNOWN, NDEF.TNF_MIME_MEDIA,
NDEF.TNF_ABSOLUTE_URI, NDEF.TNF_EXTERNAL_TYPE, NDEF.TNF_UNKNOWN,
NDEF.TNF_UNCHANGED, NDEF.TNF_RESERVED];
var firstOctet = buffer.getOctet();
var typeLen = buffer.getOctet();
var payloadLen = buffer.getOctet();
if (!(firstOctet & NDEF.SR)) {
for (var i = 0; i < 3; i++) {
payloadLen <<= 8;
payloadLen |= buffer.getOctet();
}
}
var idLen = 0;
if (firstOctet & NDEF.IL) {
idLen = buffer.getOctet();
}
var tnf = firstOctet & NDEF.TNF;
var type = buffer.getOctetArray(typeLen);
var id = buffer.getOctetArray(idLen);
var payload = buffer.getOctetArray(payloadLen);
return new MozNDEFRecord({tnf: tnfArray[tnf],
type: type || undefined,
id: id || undefined,
payload: payload || undefined});
},
/**
* Parses a URL string to MozNDEFRecord format.
*
* @param {String} url url string.
* @return {Array} Array of MozNDEFRecord instances.
* @memberof NfcUtils
*/
parseURIString: function parseURIString(url) {
if (!url) {
return;
}
var content = url;
for (var i = 1; i < NDEF.URIS.length; i++) {
var len = NDEF.URIS[i].length;
if (url.substring(0, len) == NDEF.URIS[i]) {
var uriPayload = url.substring(len);
content = String.fromCharCode(i) + uriPayload;
break;
}
}
var payload = StringHelper.fromUTF8(content);
var record = new MozNDEFRecord({tnf: NDEF.TNF_WELL_KNOWN,
type: NDEF.RTD_URI,
payload: payload});
if (!record) {
return null;
}
return [record];
}
};
NDEF.init();
exports.NfcBuffer = NfcBuffer;
exports.NfcUtils = NfcUtils;
exports.NDEF = NDEF;
})(window);