mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-29 13:03:36 +01:00
bfile: clean up header, add BFile_Seek and BFile_GetPos
This commit is contained in:
parent
2e5e56f82e
commit
71de4dcb95
2 changed files with 245 additions and 86 deletions
|
@ -1,9 +1,60 @@
|
||||||
//---
|
//---
|
||||||
// gint:bfile - BFile interface
|
// gint:bfile - BFile interface
|
||||||
//
|
//
|
||||||
// The system's file system is a nightmare and the risk of corrupting it
|
// BFile is the OS's native interface to the filesystem. It has quite a bit of
|
||||||
// or the flash by driving it manually is too great to risk. This module
|
// legacy, so it's not very easy to use. Please note that BFile cannot be used
|
||||||
// interfaces with the BFile syscalls for file management.
|
// from within gint, so do a gint_world_switch() (<gint/gint.h>) to call BFile
|
||||||
|
// functions; otherwise the add-in is likely to crash.
|
||||||
|
//
|
||||||
|
// There are two different filesystems:
|
||||||
|
// * An older, in-house one made by CASIO and informally called CASIOWIN (which
|
||||||
|
// is the name of the OS itself), which is incomplete, hard to use, and very
|
||||||
|
// limiting, but also very fast.
|
||||||
|
// * A newer one, designed by Kyoto Software Research and called Fugue, which
|
||||||
|
// is mostly complete and behaves as a regular filesystem, though very slow.
|
||||||
|
//
|
||||||
|
// You can detect which one is used by querying gint[HWFS] (<gint/hardware.h>):
|
||||||
|
// * HWFS_FUGUE is the newer one; it is found in:
|
||||||
|
// - The fx-CG series (in France: Prizm and Graph 90+E)
|
||||||
|
// - The fx G-III series (in France: Graph 35+E II)
|
||||||
|
// * HWFS_CASIOWIN is the older one; it is found in all older black-and-white
|
||||||
|
// model that have a storage memory.
|
||||||
|
//
|
||||||
|
// Wherever Fugue is used, gint supports the Unix file API (open, read, write,
|
||||||
|
// etc) and the C99 standard file API (fopen, fread, fwrite, etc), so there is
|
||||||
|
// no need to call into BFile directly (you should still do a world switch
|
||||||
|
// before using these functions).
|
||||||
|
//
|
||||||
|
// You should only have to use BFile if you're dealing with the CASIOWIN
|
||||||
|
// filesystem. With Fugue, not only are the Unix/C99 APIs easier to use, but
|
||||||
|
// the meanings of arguments and return values in BFile calls also change
|
||||||
|
// compared to the CASIOWIN filesystem, so there's little to gain anyway.
|
||||||
|
//
|
||||||
|
// If you're here for the CASIOWIN filesystem, be aware of its limitations. In
|
||||||
|
// general reading files will work fine; expect no issues with that. Modifying
|
||||||
|
// files is where things get difficult. Keep the following in mind:
|
||||||
|
//
|
||||||
|
// * Non-standard meanings of arguments and return values (eg. BFile_Read()
|
||||||
|
// returns the number of readable bytes between the new position and EOF).
|
||||||
|
// * Files must be created with a fixed size indicated in BFile_Create() and
|
||||||
|
// are initialized with 0xff.
|
||||||
|
// * A write to a file can only replace 1's with 0's, meaning in practice a
|
||||||
|
// file can only be written to once. (That's why it's created with 0xff.)
|
||||||
|
// * All writes must be of even size; writing an odd number of bytes can mess
|
||||||
|
// up the file and confuse the filesystem.
|
||||||
|
// * Only one level of folders is supported; attempting to create second-level
|
||||||
|
// subfolders results in weird recursive directories (don't do that).
|
||||||
|
//
|
||||||
|
// File paths in the OS use the non-standard FONTCHARACTER encoding, which is a
|
||||||
|
// 16-bit fixed-width encoding. Most users don't care about special characters;
|
||||||
|
// in GCC, you can get a 16-bit literal string with the u"" prefix, eg.
|
||||||
|
// u"\\\\fls0\\data.bin"
|
||||||
|
// which is what you usually supply as the [uint16_t const *path] argument.
|
||||||
|
//
|
||||||
|
// All functions return nonnegative values on success. If no return value is
|
||||||
|
// described then a successful call returns 0. Unless specified otherwise, all
|
||||||
|
// functions can also return a negative error code as documented near the end
|
||||||
|
// of this header.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#ifndef GINT_BFILE
|
#ifndef GINT_BFILE
|
||||||
|
@ -15,88 +66,162 @@ extern "C" {
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/* BFile_Remove(): Remove a file
|
//---
|
||||||
Also works if the file does not exist.
|
// Common file access functions
|
||||||
|
//---
|
||||||
|
|
||||||
@file FONTCHARACTER file path
|
/* Remove a file or folder (also works if the entry does not exist). */
|
||||||
Returns a BFile error code. */
|
int BFile_Remove(uint16_t const *path);
|
||||||
int BFile_Remove(uint16_t const *file);
|
|
||||||
|
#define BFile_File 1
|
||||||
|
#define BFile_Folder 5
|
||||||
|
|
||||||
|
/* BFile_Create(): Create a new file or folder
|
||||||
|
|
||||||
/* BFile_Create(): Create a new entry
|
|
||||||
The file or directory must not exist. For a file the size pointer must point
|
The file or directory must not exist. For a file the size pointer must point
|
||||||
to the desired file size (which is fixed), for a folder it is ignored.
|
to the desired file size (which is fixed), for a folder it is ignored. With
|
||||||
|
CASIOWIN this is the final size of the file. With Fugue the file can be
|
||||||
|
resized dynamically and is usually created with initial size 0.
|
||||||
|
|
||||||
@file FONTCHARACTER file path
|
@path FONTCHARACTER file path
|
||||||
@type Entry type
|
@type Entry type (BFile_File or BFile_Folder)
|
||||||
@size Pointer to file size if [type = BFile_File], use NULL otherwise
|
@size Pointer to file size if type is BFile_File, use NULL otherwise */
|
||||||
Returns a BFile error code. */
|
int BFile_Create(uint16_t const *path, int type, int *size);
|
||||||
enum BFile_EntryType
|
|
||||||
{
|
|
||||||
BFile_File = 1,
|
|
||||||
BFile_Folder = 5,
|
|
||||||
};
|
|
||||||
int BFile_Create(uint16_t const *file, enum BFile_EntryType type, int *size);
|
|
||||||
|
|
||||||
/* BFile_Open(): Open an existing file
|
#define BFile_ReadOnly 0x01
|
||||||
The file must exist.
|
#define BFile_WriteOnly 0x02
|
||||||
|
#define BFile_ReadWrite (BFile_ReadOnly | BFile_WriteOnly)
|
||||||
|
#define BFile_Share 0x80
|
||||||
|
#define BFile_ReadShare (BFile_ReadOnly | BFile_Share)
|
||||||
|
#define BFile_ReadWriteShare (BFile_ReadWrite | BFile_Share)
|
||||||
|
|
||||||
@file FONTCHARACTER file path
|
/* BFile_Open(): Open a file for reading or writing
|
||||||
|
|
||||||
|
The file must exist, even when opening in writing mode. The meaning of the
|
||||||
|
[Share] flag isn't clear; I believe it's simply ignored in the CASIOWIN
|
||||||
|
filesystem.
|
||||||
|
|
||||||
|
@path FONTCHARACTER file path
|
||||||
@mode Desired access mode
|
@mode Desired access mode
|
||||||
Returns a file descriptor on success, or a negative BFile error code. */
|
Returns a file descriptor (or a negative error code). */
|
||||||
enum BFile_OpenMode
|
int BFile_Open(uint16_t const *path, int mode);
|
||||||
{
|
|
||||||
BFile_ReadOnly = 0x01,
|
|
||||||
BFile_WriteOnly = 0x02,
|
|
||||||
BFile_ReadWrite = BFile_ReadOnly | BFile_WriteOnly,
|
|
||||||
};
|
|
||||||
int BFile_Open(uint16_t const *file, enum BFile_OpenMode mode);
|
|
||||||
|
|
||||||
/* BFile_Close(): Close a file descriptor
|
/* Close an open file descriptor. */
|
||||||
@fd Open file descriptor
|
|
||||||
Returns a BFile error code. */
|
|
||||||
int BFile_Close(int fd);
|
int BFile_Close(int fd);
|
||||||
|
|
||||||
/* BFile_Size(): Retrieve size of an open file
|
/* Get the size of an open file. */
|
||||||
@fd Open file descriptor
|
|
||||||
Returns the file size in bytes, or a negative BFile error code*/
|
|
||||||
int BFile_Size(int fd);
|
int BFile_Size(int fd);
|
||||||
|
|
||||||
/* BFile_Write(): Write data to an open file
|
/* BFile_Write(): Write data to an open file
|
||||||
Second and third argument specify the data and length to write.
|
|
||||||
|
|
||||||
WARNING: The file systems has shown to become inconsistent if an odd number
|
WARNING: The CASIOWIN fs is known to become inconsistent if an odd number of
|
||||||
of bytes is written with BFile_Write(). Keep it even!
|
bytes is written with BFile_Write(). Always keep it even!
|
||||||
|
|
||||||
@fd File descriptor open for writing
|
With CASIOWIN, returns the new file offset after writing (or an error code).
|
||||||
@data Data to write
|
With Fugue, returns the amount of data written (or an error code). */
|
||||||
@even_size Size to write (must be even, yes)
|
|
||||||
Returns a BFile error code. */
|
|
||||||
int BFile_Write(int fd, void const *data, int even_size);
|
int BFile_Write(int fd, void const *data, int even_size);
|
||||||
|
|
||||||
/* BFile_Read(): Read data from an open file
|
/* BFile_Read(): Read data from an open file
|
||||||
The second and third argument specify where to store and how much to read.
|
|
||||||
The location from where the data is read depends on [whence]:
|
The extra argument [whence] specifies where data is read from in the style
|
||||||
|
of pread(2), and is supported with both filesystems.
|
||||||
|
|
||||||
* If [whence >= 0], it is taken as an absolute location within the file;
|
* If [whence >= 0], it is taken as an absolute location within the file;
|
||||||
* If [whence == -1], BFile_Read() reads from the current position.
|
* If [whence == -1], BFile_Read() reads from the current position.
|
||||||
|
|
||||||
@fd File descriptor open for reading
|
With CASIOWIN, returns how much data can be read from the updated file
|
||||||
@data Buffer of at least [size] bytes to store data to
|
offset (ie. how many bytes until end of file), or an error code.
|
||||||
@size Number of bytes to read
|
With Fugue, returns the amount of data read (or an error code). */
|
||||||
@whence Starting position of the data to read in the file
|
|
||||||
Returns a BFile error code. */
|
|
||||||
int BFile_Read(int handle, void *data, int size, int whence);
|
int BFile_Read(int handle, void *data, int size, int whence);
|
||||||
|
|
||||||
/* BFile_FindFirst(): Search a directory for file with matching name
|
/* BFile_Seek(): Seek to a relative or absolute position within an open file
|
||||||
Doesn't work on Main memory. Only four search handle can be opened, you need
|
|
||||||
to close them to be able to reuse them. Search is NOT case sensitive and *
|
With CASIOWIN, moves [offset] bytes relative to the current position, and
|
||||||
can be used as a wildcard.
|
returns how much data can be read from the new position. BFile_Seek(fd, 0)
|
||||||
|
combined with BFile_Size(fd) can be used to determine the current position.
|
||||||
|
|
||||||
|
With Fugue, moves to the absolute position [offset] within the file, and
|
||||||
|
returns the amount of allocated space following the new position (usually
|
||||||
|
larger than the amount of data until end-of-file because files are allocated
|
||||||
|
in units of 4096 bytes). There is no way to seek relative to the current
|
||||||
|
position unless the target is precomputed with BFile_GetPos(). */
|
||||||
|
int BFile_Seek(int fd, int offset);
|
||||||
|
|
||||||
|
/* BFile_GetPos(): Get the current position in an open file
|
||||||
|
|
||||||
|
This call does not exist in the CASIOWIN interface, so this function always
|
||||||
|
returns -1 on models with a CASIOWIN filesystem.
|
||||||
|
|
||||||
|
This call exists in Fugue, however some Fugue models have their syscall list
|
||||||
|
inherited from the CASIOWIN era and don't have an entry point for it (or if
|
||||||
|
there's one it's escape scrutiny so far).
|
||||||
|
|
||||||
|
* Prizm / Graph 90+E / fx-CG series: this function works as intended.
|
||||||
|
* Graph 35+E II / G-III series: the call is missing, returns -1.
|
||||||
|
|
||||||
|
For the latter models there is no easily reliable way of knowing the current
|
||||||
|
position within an open file! */
|
||||||
|
int BFile_GetPos(int fd);
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Error codes
|
||||||
|
//---
|
||||||
|
|
||||||
|
#define BFile_EntryNotFound -1
|
||||||
|
#define BFile_IllegalParam -2
|
||||||
|
#define BFile_IllegalPath -3
|
||||||
|
#define BFile_DeviceFull -4
|
||||||
|
#define BFile_IllegalDevice -5
|
||||||
|
#define BFile_IllegalFilesystem -6
|
||||||
|
#define BFile_IllegalSystem -7
|
||||||
|
#define BFile_AccessDenied -8
|
||||||
|
#define BFile_AlreadyLocked -9
|
||||||
|
#define BFile_IllegalTaskID -10
|
||||||
|
#define BFile_PermissionError -11
|
||||||
|
#define BFile_EntryFull -12
|
||||||
|
#define BFile_AlreadyExists -13
|
||||||
|
#define BFile_ReadOnlyFile -14
|
||||||
|
#define BFile_IllegalFilter -15
|
||||||
|
#define BFile_EnumerateEnd -16
|
||||||
|
#define BFile_DeviceChanged -17
|
||||||
|
//#define BFile_NotRecordFile -18 // Not used
|
||||||
|
#define BFile_IllegalSeekPos -19
|
||||||
|
#define BFile_IllegalBlockFile -20
|
||||||
|
//#define BFile_NoSuchDevice -21 // Not used
|
||||||
|
//#define BFile_EndOfFile -22 // Not used
|
||||||
|
#define BFile_NotMountDevice -23
|
||||||
|
#define BFile_NotUnmountDevice -24
|
||||||
|
#define BFile_CannotLockSystem -25
|
||||||
|
#define BFile_RecordNotFound -26
|
||||||
|
//#define BFile_NotDualRecordFile -27 // Not used
|
||||||
|
#define BFile_NoAlarmSupport -28
|
||||||
|
#define BFile_CannotAddAlarm -29
|
||||||
|
#define BFile_FileFindUsed -30
|
||||||
|
#define BFile_DeviceError -31
|
||||||
|
#define BFile_SystemNotLocked -32
|
||||||
|
#define BFile_DeviceNotFound -33
|
||||||
|
#define BFile_FileTypeMismatch -34
|
||||||
|
#define BFile_NotEmpty -35
|
||||||
|
#define BFile_BrokenSystemData -36
|
||||||
|
#define BFile_MediaNotReady -37
|
||||||
|
#define BFile_TooManyAlarms -38
|
||||||
|
#define BFile_SameAlarmExists -39
|
||||||
|
#define BFile_AccessSwapArea -40
|
||||||
|
#define BFile_MultimediaCard -41
|
||||||
|
#define BFile_CopyProtection -42
|
||||||
|
#define BFile_IllegalFileData -43
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Search API
|
||||||
|
//
|
||||||
|
// The search API is described below. It's somewhat unreliable, with unclear
|
||||||
|
// semantics and a history of breaking in seemingly reasonable programs. One
|
||||||
|
// day probably we'll know how to use it properly and reliably.
|
||||||
|
//
|
||||||
|
// Note: always close search handles or trouble will ensue (eg. add-in
|
||||||
|
// discovery failing).
|
||||||
|
//---
|
||||||
|
|
||||||
@search FONTCHARACTER file path to match
|
|
||||||
@shandle Search handle to pass to BFile_FindNext or BFile_FindClose
|
|
||||||
@founfile FONTCHARACTER found file path
|
|
||||||
@fileinfo Structure containing a lot of information on the found file
|
|
||||||
Returns 0 on success, -1 if no file found, or negative value on error. */
|
|
||||||
struct BFile_FileInfo
|
struct BFile_FileInfo
|
||||||
{
|
{
|
||||||
uint16_t index;
|
uint16_t index;
|
||||||
|
@ -109,36 +234,59 @@ struct BFile_FileInfo
|
||||||
/* Address of first fragment (do not use directly) */
|
/* Address of first fragment (do not use directly) */
|
||||||
void *address;
|
void *address;
|
||||||
};
|
};
|
||||||
enum BFile_FileType
|
|
||||||
{
|
#define BFile_Type_Directory 0x0000
|
||||||
BFile_Type_Directory = 0x0000,
|
#define BFile_Type_File 0x0001
|
||||||
BFile_Type_File = 0x0001,
|
#define BFile_Type_Addin 0x0002
|
||||||
BFile_Type_Addin = 0x0002,
|
#define BFile_Type_Eact 0x0003
|
||||||
BFile_Type_Eact = 0x0003,
|
#define BFile_Type_Language 0x0004
|
||||||
BFile_Type_Language = 0x0004,
|
#define BFile_Type_Bitmap 0x0005
|
||||||
BFile_Type_Bitmap = 0x0005,
|
#define BFile_Type_MainMem 0x0006
|
||||||
BFile_Type_MainMem = 0x0006,
|
#define BFile_Type_Temp 0x0007
|
||||||
BFile_Type_Temp = 0x0007,
|
#define BFile_Type_Dot 0x0008
|
||||||
BFile_Type_Dot = 0x0008,
|
#define BFile_Type_DotDot 0x0009
|
||||||
BFile_Type_DotDot = 0x0009,
|
#define BFile_Type_Volume 0x000a
|
||||||
BFile_Type_Volume = 0x000a,
|
#define BFile_Type_Archived 0x0041
|
||||||
BFile_Type_Archived = 0x0041,
|
|
||||||
};
|
/* BFile_FindFirst(): Search the storage memory for paths matching a pattern
|
||||||
int BFile_FindFirst(uint16_t const *search, int *shandle, uint16_t *foundfile,
|
|
||||||
|
This if for the storage memory only. There are only four search handles;
|
||||||
|
make sure to close them, there is no automatic device to close them for you
|
||||||
|
even after the add-in exists.
|
||||||
|
|
||||||
|
Search is NOT case sensitive. '*' can be used as a wildcard, although it's
|
||||||
|
unclear whether more than one '*' is supported, whether '*' can match in a
|
||||||
|
directory name, whether multiple folders can be searched simultaneously, and
|
||||||
|
whether directories can be matched.
|
||||||
|
|
||||||
|
@pattern FONTCHARACTER glob pattern
|
||||||
|
@shandle Will receive search handle (to use in BFile_FindNext/FindClose)
|
||||||
|
@foundfile Will receive FONTCHARACTER path of matching entry
|
||||||
|
@fileinfo Will receive metadata of matching entry
|
||||||
|
|
||||||
|
On success, returns 0, stores the search handle in *shandle, and stores
|
||||||
|
information about the first match in foundfile and fileinfo. The negative
|
||||||
|
error code BFile_EntryNotFound should be interpreted as an empty result (ie.
|
||||||
|
no entry matched) rather than an error.
|
||||||
|
|
||||||
|
Returns 0 on success or a negative error code. BFile_EntryNotFound should be
|
||||||
|
interpreted as an empty result (ie. no file matched). */
|
||||||
|
int BFile_FindFirst(uint16_t const *pattern, int *shandle, uint16_t *foundfile,
|
||||||
struct BFile_FileInfo *fileinfo);
|
struct BFile_FileInfo *fileinfo);
|
||||||
|
|
||||||
/* BFile_FindNext(): Continue a search a directory for file with matching name
|
/* BFile_FindNext(): Continue a search
|
||||||
|
|
||||||
@shandle Search handle from BFile_FindFirst
|
Continues the search for matches. The search handle is the value set in
|
||||||
@founfile FONTCHARACTER found file path
|
*shandle in BFile_FindFirst(). As before, *foundfile receives the matching
|
||||||
@fileinfo Structure containing a lot of information on the found file
|
entry's path and *fileinfo its metadata.
|
||||||
Returns 0 on success, -1 if end is reached, or negative value on error. */
|
|
||||||
|
Returns 0 on success. The negative error code BFile_EnumerateEnd should be
|
||||||
|
interpreted as the end of the search (ie. all matching files have been
|
||||||
|
returned) rather than an error. */
|
||||||
int BFile_FindNext(int shandle, uint16_t *foundfile,
|
int BFile_FindNext(int shandle, uint16_t *foundfile,
|
||||||
struct BFile_FileInfo *fileinfo);
|
struct BFile_FileInfo *fileinfo);
|
||||||
|
|
||||||
/* BFile_FindClose(): Close the specified search handle
|
/* Close a search handle (with or without exhausting the matches). */
|
||||||
@shandle Search handle from BFile_FindFirst
|
|
||||||
Return 0 on success or negative value on error. */
|
|
||||||
int BFile_FindClose(int shandle);
|
int BFile_FindClose(int shandle);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
.global _BFile_Open
|
.global _BFile_Open
|
||||||
.global _BFile_Close
|
.global _BFile_Close
|
||||||
.global _BFile_Size
|
.global _BFile_Size
|
||||||
|
.global _BFile_Seek
|
||||||
|
.global _BFile_GetPos
|
||||||
.global _BFile_Write
|
.global _BFile_Write
|
||||||
.global _BFile_Read
|
.global _BFile_Read
|
||||||
.global _BFile_FindFirst
|
.global _BFile_FindFirst
|
||||||
|
@ -64,6 +66,7 @@ ___realloc:
|
||||||
/* BFile driver */
|
/* BFile driver */
|
||||||
|
|
||||||
_BFile_Remove:
|
_BFile_Remove:
|
||||||
|
mov #0, r5
|
||||||
syscall(0x0439)
|
syscall(0x0439)
|
||||||
_BFile_Create:
|
_BFile_Create:
|
||||||
syscall(0x0434)
|
syscall(0x0434)
|
||||||
|
@ -73,6 +76,11 @@ _BFile_Close:
|
||||||
syscall(0x042d)
|
syscall(0x042d)
|
||||||
_BFile_Size:
|
_BFile_Size:
|
||||||
syscall(0x042f)
|
syscall(0x042f)
|
||||||
|
_BFile_Seek:
|
||||||
|
syscall(0x0431)
|
||||||
|
_BFile_GetPos:
|
||||||
|
rts
|
||||||
|
mov #-1, r0
|
||||||
_BFile_Write:
|
_BFile_Write:
|
||||||
syscall(0x0435)
|
syscall(0x0435)
|
||||||
_BFile_Read:
|
_BFile_Read:
|
||||||
|
@ -122,7 +130,6 @@ ___realloc:
|
||||||
/* BFile driver */
|
/* BFile driver */
|
||||||
|
|
||||||
_BFile_Remove:
|
_BFile_Remove:
|
||||||
mov #0, r5
|
|
||||||
syscall(0x1db4)
|
syscall(0x1db4)
|
||||||
_BFile_Create:
|
_BFile_Create:
|
||||||
syscall(0x1dae)
|
syscall(0x1dae)
|
||||||
|
@ -133,6 +140,10 @@ _BFile_Close:
|
||||||
syscall(0x1da4)
|
syscall(0x1da4)
|
||||||
_BFile_Size:
|
_BFile_Size:
|
||||||
syscall(0x1da6)
|
syscall(0x1da6)
|
||||||
|
_BFile_Seek:
|
||||||
|
syscall(0x1da9)
|
||||||
|
_BFile_GetPos:
|
||||||
|
syscall(0x1dab)
|
||||||
_BFile_Write:
|
_BFile_Write:
|
||||||
syscall(0x1daf)
|
syscall(0x1daf)
|
||||||
_BFile_Read:
|
_BFile_Read:
|
||||||
|
|
Loading…
Reference in a new issue