1 /** 2 * --------- 3 * |.##> <##.| Open Smart Card Development Platform (www.openscdp.org) 4 * |# #| 5 * |# #| Copyright (c) 1999-2018 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 Implementation of a ISO 7816-4 file system simulation 25 */ 26 27 var APDU = require('scsh/cardsim/APDU').APDU; 28 var FCP = require('scsh/cardsim/FCP').FCP; 29 var FSNode = require('scsh/cardsim/FSNode').FSNode; 30 31 32 33 /** 34 * Create a file system node that represents a transparent EF 35 * 36 * @class Class implementing a transparent EF 37 * @constructor 38 * @param {FCP} fcp the FCP for this EF 39 * @param {ByteString} contents the contents for this EF 40 */ 41 function TransparentEF(fcp, contents) { 42 if (!(fcp instanceof FCP)) { 43 throw new GPError("TransparentEF", GPError.INVALID_TYPE, APDU.SW_GENERALERROR, "Argument 1 must be of type FCP"); 44 } 45 46 if ((typeof(contents) != "undefined") && (contents != null) && !(contents instanceof ByteString)) { 47 throw new GPError("TransparentEF", GPError.INVALID_TYPE, APDU.SW_GENERALERROR, "Argument 2 must be of type ByteString"); 48 } 49 50 FSNode.call(this, fcp); 51 this.content = contents; 52 } 53 54 TransparentEF.prototype = new FSNode(); 55 TransparentEF.prototype.constructor = TransparentEF; 56 57 exports.TransparentEF = TransparentEF; 58 59 60 61 /** 62 * Reads data from a transparent EF 63 * 64 * @param {APDU} apdu the APDU used for reading 65 * @param {Number} offset the offset to read from 66 * @param {Number} length the length in bytes or 0 for all in short APDU or 65536 for all in extended APDUs 67 * @type ByteString 68 * @return the data read 69 */ 70 TransparentEF.prototype.readBinary = function(apdu, offset, length) { 71 if (typeof(offset) != "number") { 72 throw new GPError("TransparentEF", GPError.INVALID_TYPE, APDU.SW_GENERALERROR, "Offset must be type Number"); 73 } 74 if (typeof(length) != "number") { 75 throw new GPError("TransparentEF", GPError.INVALID_TYPE, APDU.SW_GENERALERROR, "Length must be type Number"); 76 } 77 78 if (offset >= this.content.length) { 79 throw new GPError("TransparentEF", GPError.INVALID_DATA, APDU.SW_INCP1P2, "Offset out of range"); 80 } 81 82 var rlen = length; 83 if ((length == 0) || (length == 65536)) { 84 rlen = this.content.length - offset; 85 if ((length == 0) && (rlen > 256)) { 86 rlen = 256; 87 } 88 } 89 90 if (offset + rlen > this.content.length) { 91 apdu.setSW(APDU.SW_EOF); 92 rlen = this.content.length - offset; 93 } else { 94 apdu.setSW(APDU.SW_OK); 95 } 96 97 return this.content.bytes(offset, rlen); 98 } 99 100 101 102 /** 103 * Update data in transparent EF 104 * 105 * @param {APDU} apdu the APDU used for updating 106 * @param {Number} offset the offset to update 107 * @param {ByteString} data the data to write into the EF 108 */ 109 TransparentEF.prototype.updateBinary = function(apdu, offset, data) { 110 if (typeof(offset) != "number") { 111 throw new GPError("TransparentEF", GPError.INVALID_TYPE, APDU.SW_GENERALERROR, "Offset must be type Number"); 112 } 113 if ((typeof(data) != "object") || !(data instanceof ByteString)) { 114 throw new GPError("TransparentEF", GPError.INVALID_TYPE, APDU.SW_GENERALERROR, "Data must be a ByteString"); 115 } 116 117 if (offset + data.length > this.fcp.size) { 118 throw new GPError("TransparentEF", GPError.INVALID_DATA, APDU.SW_WRONGLENGTH, "Writing beyond file limit"); 119 } 120 121 if (this.content) { 122 if (offset > this.content.length) { 123 throw new GPError("TransparentEF", GPError.INVALID_DATA, APDU.SW_INCP1P2, "Offset out of range"); 124 } 125 var newcontent = this.content.bytes(0, offset).concat(data); 126 if (this.content.length > newcontent.length) { 127 newcontent = newcontent.concat(this.content.bytes(newcontent.length)); 128 } 129 } else { 130 if (offset > 0) { 131 throw new GPError("TransparentEF", GPError.INVALID_DATA, APDU.SW_INCP1P2, "Offset out of range"); 132 } 133 var newcontent = data; 134 } 135 136 this.content = newcontent; 137 apdu.setSW(APDU.SW_OK); 138 } 139