* ==========================================================================
* Demo: File system
* Caution: no error check for the sake of briefness and understandability
* Tips:
* The file system is the kernel of ROCKEY environment. ROCKEY files system like DOS file system 
* in some way, they both have directorys and files. But ROCKEY file system is defferent from 
* DOS FS. There are some  Basic Introduction.
*
* (1) Directory/File ID (2 bytes)
*     Both files and directories have the identical attributes of two bytes. The file IDs must be not same
*	   under same directory. It's unique for both directory and file.
*     
*     Caution: those ID are pre-defined:
*     3F00: ID of Root directory.
*     2F01: ATR file ID.
*     3FFF: ID for get current directory.(We not use it)
*     0000: reserved by system.
*     You can not use those ID when creating files and directorys.
*
* (2) Directory/File Class (1 byte)
*     a) All directories and files have a file class code (FCLA) that is defined by one 
*        byte (0x0-0xFF).Developers may use the file class code (FCLA) to define independent 
*        subsystems. Files in the same class are generally assumed to belong to the same product.         
*     b) Executable files are restricted by the FCLA - they can only read, write or create data 
*        files of the same class code.
*     c) (FCLA) that is defined by one byte (0x0-0xFF).
*     d) There is one byte for the system to keep the current file class, called "system current 
*        file class"(SYSFCLA).
*     e) There are specific FCLA rules: 0xFF means the file is a "none-class" file. Data files 
*        of this type can be accessed by any kind of executable file. Executable files of this 
*        type can only access 0xFF type data files.
*     f) When executing the "select file" command or calling a target file in dongle, the "system 
*        current file class" would change according to the following rules: SYSFCLA = FCLA¡£
*     g) If the target file is "none-class", the system current file class remains unchanged
*     h) The "system current security level" is reset to 0 when the "system current file" class 
*        is changed.
*     i) Resetting the dongle will put the system current file class to the default - 0xFF.
*     j) The class of root directory is 0xFF.(none-class).
*     k) In the ROCKEY system, "none-class" data files are public data and "none-class" 
*        executables are public processing programs.¡£
*     l) Executable files of class 0xFF can only access 0xFF type data files.
*     m) The more important application of the class code is the executable filter file. This is 
*        covered in chapter 12 of ROCKEY guide.
*
*     Suggest:
*     a) file class are generally used in product management. It's very convenient if develop have 
*        more than one products or many developers wokes at one product.        
*     b) You'd better set class of all files if ROCKEY is only for one product,one developer.
*     c) Fils and sub-directorys under same directory should have same class, then you can 
*        use "File privilige" to limit access.        
*
* (3) Dirctory/File Security Level (half byte)
*     a) In addition to "class", each file has a security level(FPRI) that may be used to 
*        enhance file management. 
*     b) FPRI only used for files with same FCLA. FPRI is lower level than FCLA.*        
*     c) The security level takes the lower four bits (0x00-0x0F) of one byte, while the four 
*        higher bits are taken by the file attribute. There are 16 levels of security privilege, 
*        rising from 0 to 15.        
*     d) The COS has its own security level (SYSFPRI). It consumes one byte for recording during
*        operation.*        
*     e) ts security level can only be advanced by a system call to an executable residing in the 
*        dongle. However, the COS security level set by the executable may not exceed that of the 
*        executable it's self¡£
*     f) Executable files can only execute (read, write, and create) data files with the same or 
*        lower security levels than them selves.
*     g) When an executable exits, the current system security level can be cleared to 0.
*     i) Executable files have FILEATTR_UPIGNORE attribute. when set it, it will not execute if SYSFPRI >= FPRI 
*        of exe file.			
*
*     Suggest:
*     a) The security level is a higher level of file management. File security levels may be set 
*		  to "0" if such complex management is unnecessary.        
*     b) You should set file class firstly, then file attribute.
*
* (4) Directory/File Attributes (half byte)
*     a) There are five kinds of file attributes: normal, executable, directory, up-ignore and 
*        internal. A directory or file may have more than attributes.
*        NORMAL	0x00	* Normal file
*        EXEC		0x10	* Executable file
*        DIR		0x20	* Directory
*        UPIGNORE	0x40	* Up-ignore
*        INTERNAL	0x80	* Internal
*     b) The "executable" attribute indicates that the file may be run by the COS. The COS will 
*        only run files under the root directory. "Executable" files can only be created or 
*        deleted after super password verification.¡£
*     c) The "directory" attribute indicates that the file is a sub directory. If the file is 
*        set to directory, other attribute bits can be ignored.
*     d) The "up-ignore" only applies to executable files. It means that the file can only be 
*        executed on the condition that the system security level is lower than that of the 
*        executable file its self. When the system security level is higher or equal to that of 
*        the executable file, this file will not be executed.
*     e) If the "internal" file is a data file, it is only accessible to the executable files in 
*        dongle. External operations can only delete "internal" files with prior super password 
*        verification. But external operations can never read or write to "internal" files. If the 
*        "internal" file is an executable, it will not be displayed without prior super password 
*        verification. The "internal" attribute is generally used to protect executables that have 
*        some hidden attributes. 
*
* (5) File name
*     Both files and directories have 16 bytes of long file name (optional). You can access file via 
*       file ID or file name if you set it.
* ==========================================================================
* Tips for program:
* (1) You must check supper password before format, and you can set ATR and VOLUME when format.
* (2) You must set directory ID, name, class&attribute when create. 
* (3) LIST_DIR use enumerate method. You can do it until get an error code.     
* (4) SET_CURRENT_DIR like DOS comman "cd xxxx". You need set file ID or file name when call it. 
*     Set file ID to 0 when call it via file name.
* (5) You must set File ID, name, size,class&attribute when create. Set file name buffer to zero if 
*     it have no file name.
* (6) File will be selected automatically after create, no need call SET_CURRENT_FILE.

#include "Dic32_Vfp.h"
clear 
DECLARE integer   DIC_Find IN Dic32u.dll
DECLARE integer   DIC_Open IN Dic32u.dll integer hic, string @  reader_name
DECLARE integer   DIC_Close  IN Dic32u.dll  integer   hic
DECLARE integer   DIC_Command  IN Dic32u.dll  integer  hic, integer cmd, string @  cmddata
DECLARE integer   DIC_Get  IN Dic32u.dll  string @  xdata, integer  p1, integer   p2, string @  buffer
DECLARE integer   DIC_Set  IN Dic32u.dll  string @  xdata, integer  p1, integer  p2, integer   p3, string @  buffer

store 0 to  errcode		   && error code
store 0 to  num		   && number of founded card reader(s)
store 0 to  hic		   && handle of ROCKEY device.
store 0 to  i
cmddata=space(256)
buffer=space(256)
store 0 to dirid,read_size

	num = DIC_Find()
	for i=0 to num-1
		hic = DIC_Open(i, NULL)
		if (hic >= 0) 
		  exit  	&& Stop searching once one is found.
  	  endif
	endfor
	if (i == num) 
	     return
    endif

	* a.Check supper password,it's required by format.
	* Super password is 8 FFs for demo ROCKEY
	for i=0 to 7
	    DIC_Set(@cmddata,i,1,0xff,NULL)
    endfor
	errcode = DIC_Command(hic, CHECK_SUPER_PASS, @cmddata) 

	* b. Format ROCKEY. it will clear all files and directorys.
	*    You can set ATR and VOLUME here.
	DIC_Set(@cmddata, VOLUME, BY_ARRAY, 0, "DICSYSTEM") 
	DIC_Set(@cmddata, ATR, BY_ARRAY, 0,"DIC Co.") 
	errcode = DIC_Command(hic, FORMAT_CARD, @cmddata) 

	* c. return to password not verified status
	errcode = DIC_Close(hic) 
	errcode = DIC_Open(hic, NULL) 

	* d. Create directory, id is 0x1000, name is "Dir1"
	cmddata=space(256)                                  &&Clear buffer
	DIC_Set(@cmddata, DIR_ID, BY_VALUE, 0x1000, NULL) 	 && dir ID
	DIC_Set(@cmddata, DIR_CLASS, BY_VALUE, 0xff, NULL) 	 && dir class
	DIC_Set(@cmddata, DIR_NAME, BY_ARRAY, 0,"Dir1" ) 	 && dir name
	errcode = DIC_Command(hic, CREATE_DIR, @cmddata) 

	* e. List all files in root dir.
	*    caution: the first is root dir ID, the second is ATR file.
	for i=0 to 254 
		DIC_Set(@cmddata, FILE_NO, BY_VALUE, i, NULL) 	 && set file index
		errcode = DIC_Command(hic, LIST_DIR, @cmddata) 
		if (errcode != SCARD_S_SUCCESS) 
		   exit
		endif
		dirid = DIC_Get(@cmddata, DIR_ID, BY_VALUE, NULL) 	 && Get file and directory in same way.
        buffer=space(256)
		DIC_Get(@cmddata, DIR_NAME, BY_ARRAY, @buffer) 
		? dirid, buffer 
	endfor

	* f. enter direcoty 0x1000
	DIC_Set(@cmddata, DIR_ID, BY_VALUE, 0x1000, NULL) 
	errcode = DIC_Command(hic, SET_CURRENT_DIR, @cmddata) 
	
	* g. create directory 0x2000 under 0x1000
	DIC_Set(@cmddata, DIR_ID, BY_VALUE, 0x2000, NULL) 	 && dir ID
	DIC_Set(@cmddata, DIR_CLASS, BY_VALUE, 0xff, NULL) 	 && dir class
	DIC_Set(@cmddata, DIR_NAME, BY_ARRAY, 0,"Dir2" ) 	 && dir name
	errcode = DIC_Command(hic, CREATE_DIR, @cmddata) 

	* h. create file 0x0033 in 0x1000
	DIC_Set(@cmddata, FILE_ID, BY_VALUE, 0x0033, NULL) 	 && file ID
	DIC_Set(@cmddata, FILE_CLASS, BY_VALUE, 0xff, NULL) 	 && file class
	DIC_Set(@cmddata, FILE_ATTRIBUTE, BY_VALUE, FILEATTR_NORMAL, NULL) 	 && file attr
	DIC_Set(@cmddata, FILE_SIZE, BY_VALUE, 20, NULL) 	 && file size
	DIC_Set(@cmddata, FILE_NAME, BY_ARRAY, 0,"File1" ) 	 && file name
	errcode = DIC_Command(hic, CREATE_FILE, @cmddata) 

	* i. write 20 bytes to file 0x0033
	*    File will be selected automatically after create, no need call SET_CURRENT_FILE.
	DIC_Set(@cmddata, WRITE_DATA, 20, 0, "abcdefghijklmnopqrst") 
	errcode = DIC_Command(hic, WRITE_FILE, @cmddata) 

	* j. Enter dir 0x2000 via dir-name.
	DIC_Set(@cmddata, DIR_ID, BY_ARRAY, 0, NULL) 	 && Must set file ID to 0
	DIC_Set(@cmddata, DIR_NAME, BY_ARRAY, 0x2000,"Dir2" ) 	 && dir name
	errcode = DIC_Command(hic, SET_CURRENT_DIR, @cmddata) 

	* k.Go to parent dir(0x1000)
	errcode = DIC_Command(hic, SET_PARENT_DIR, @cmddata) 

	* l. Select  file 0x0033
	DIC_Set(@cmddata, FILE_ID, BY_VALUE, 0x0033, NULL) 
	errcode = DIC_Command(hic, SET_CURRENT_FILE, @cmddata) 

	* m. Read it.
	DIC_Set(@cmddata, READ_DATA, 20, 0, NULL) 
	errcode = DIC_Command(hic, READ_FILE, @cmddata) 
    buffer=space(256)
	read_size = DIC_Get(@cmddata, READ_DATA, BY_VALUE, @buffer) 
	? read_size, buffer 

	errcode = DIC_Close(hic)  
clear dlls
return 	