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 FSNode              = require('scsh/cardsim/FSNode').FSNode;
 29 var FileSystemIdObject  = require('scsh/cardsim/FileSystemIdObject').FileSystemIdObject;
 30 
 31 
 32 
 33 /**
 34  * Creates a Dedicated File (DF)
 35  *
 36  * <p>The constructor supports as argument a list of child elements</p>
 37  *
 38  * @class Class implementing dedicated files
 39  * @constructor
 40  * @param {FCP} the file control parameter
 41  */
 42 function DF(fcp) {
 43 	this.childs = new Array();
 44 	this.fidmap = new Array();
 45 	this.sfimap = new Array();
 46 	this.aidmap = new Array();
 47 	this.meta = new Array();
 48 
 49 	FSNode.call(this, fcp);
 50 
 51 	if (arguments.length > 1) {
 52 		for (var i = 1; i < arguments.length; i++) {
 53 			var arg = arguments[i];
 54 			this.add(arg);
 55 		}
 56 	}
 57 }
 58 
 59 DF.prototype = new FSNode();
 60 DF.prototype.constructor = DF;
 61 
 62 exports.DF = DF;
 63 
 64 
 65 /**
 66  * Adds a new child node to the DF
 67  *
 68  * @param {FSNode} node the node to add
 69  */
 70 DF.prototype.add = function(node) {
 71 	this.childs.push(node);
 72 	node.setParent(this);
 73 
 74 	var f = node.getFCP();
 75 
 76 	var fid = f.getFID();
 77 	if (fid) {
 78 		if (this.fidmap[fid]) {
 79 			throw new GPError("DF", GPError.INVALID_DATA, APDU.SW_FILEEXISTS, "Duplicate file identifier " + fid);
 80 		}
 81 		this.fidmap[fid] = node;
 82 	}
 83 
 84 	if (node.isDF()) {
 85 		var aid = f.getAID();
 86 		if (aid) {
 87 			if (this.aidmap[aid]) {
 88 				throw new GPError("DF", GPError.INVALID_DATA, APDU.SW_FILEEXISTS, "Duplicate application identifier " + aid);
 89 			}
 90 			this.aidmap[aid] = node;
 91 		}
 92 	} else {
 93 		var sfi = f.getSFI();
 94 //		print("Found SFI " + sfi);
 95 		if (typeof(sfi) != "undefined") {
 96 			if (this.sfimap[sfi]) {
 97 				throw new GPError("DF", GPError.INVALID_DATA, APDU.SW_FILEEXISTS, "Duplicate short file identifier " + sfi);
 98 			}
 99 			this.sfimap[sfi] = node;
100 		}
101 	}
102 
103 }
104 
105 
106 
107 /**
108  * Add meta information to DF
109  *
110  * @param {String} name name of meta information
111  * @param {Object} value value of meta information
112  */
113 DF.prototype.addMeta = function(name, value) {
114 	this.meta[name] = value;
115 }
116 
117 
118 
119 /**
120  * Add object to DF
121  *
122  * @param {Object} o object to be added. Must have property type and id.
123  */
124 DF.prototype.addObject = function(o) {
125 	assert((typeof(o) == "object") && (o instanceof FileSystemIdObject), "Argument must be instance of FileSystemIdObject");
126 	if (typeof(this.meta[o.getType()]) == "undefined") {
127 		this.meta[o.getType()] = [];
128 	}
129 	this.meta[o.getType()][o.getId()] = o;
130 }
131 
132 
133 
134 /**
135  * Select a file contained in the DF using the file identifier
136  *
137  * @param {ByteString} the file identifier
138  * @type FSNode
139  * @return the found node or undefined
140  */
141 DF.prototype.selectByFID = function(fid) {
142 	return this.fidmap[fid];
143 }
144 
145 
146 
147 /**
148  * Select a file contained in the DF using the short file identifier
149  *
150  * @param {Number} the short file identifier
151  * @type FSNode
152  * @return the found node or undefined
153  */
154 DF.prototype.selectBySFI = function(sfi) {
155 	return this.sfimap[sfi];
156 }
157 
158 
159 
160 /**
161  * Select a DF contained in the DF using the application identifier
162  *
163  * @param {ByteString} the application identifier
164  * @type FSNode
165  * @return the found node or undefined
166  */
167 DF.prototype.selectByAID = function(aid) {
168 	return this.aidmap[aid];
169 }
170 
171 
172 
173 /**
174  * Returns true as this is a DF
175  *
176  * @type boolean
177  * @return true this is a DF
178  */
179 DF.prototype.isDF = function() {
180 	return true;
181 }
182 
183 
184 
185 /**
186  * Dump the file system system recursively starting this this node
187  *
188  * @param {String} indent the string to prefix the output with
189  * @type String
190  * @return the dump
191  */
192 DF.prototype.dump = function(indent) {
193 	if (typeof(indent) == "undefined") {
194 		indent = "";
195 	}
196 	var str = indent + this.toString() + "\n";
197 
198 	if (this instanceof DF) {
199 		for (var i in this.meta) {
200 			str += indent + "  Meta:" + i + "\n";
201 			if (typeof(this.meta[i]) == "object") {
202 				for each (var e in this.meta[i]) {
203 					if (e instanceof FileSystemIdObject) {
204 						str += indent + "    " + e.toString() + "\n";
205 					}
206 				}
207 			}
208 		}
209 	}
210 
211 	for (var i = 0; i < this.childs.length; i++) {
212 		var c = this.childs[i];
213 
214 		if (c instanceof DF) {
215 			str += c.dump("  " + indent);
216 		} else {
217 			str += "  " + indent + c.toString() + "\n";
218 		}
219 	}
220 	return str;
221 }
222