Unify registration queue handling of commands and settings
[lsnes.git] / include / library / filesys.hpp
blob4eb9d77f7b3f9d2c262c39dcace43619ca0e675f
1 #ifndef _library__filesys__hpp__included
2 #define _library__filesys__hpp__included
4 #include <cstdint>
5 #include <map>
6 #include <string>
7 #include <fstream>
8 #include "library/workthread.hpp"
10 #define CLUSTER_SIZE 8192
11 #define CLUSTERS_PER_SUPER (CLUSTER_SIZE / 4)
12 #define SUPERCLUSTER_SIZE (static_cast<uint64_t>(CLUSTER_SIZE) * CLUSTERS_PER_SUPER)
13 #define FILESYSTEM_SUPERBLOCK 1
14 #define FILESYSTEM_ROOTDIR 2
16 class filesystem
18 public:
19 //Create a new or open existing filesystem backed by specified file.
20 filesystem(const std::string& backingfile);
21 //Allocate a new file.
22 uint32_t allocate_cluster();
23 //Delete specified file.
24 void free_cluster_chain(uint32_t cluster);
25 //Skip specfied amount of data. If skip goes to end of file, ptr will be left at CLUSTER_SIZE.
26 size_t skip_data(uint32_t& cluster, uint32_t& ptr, uint32_t length);
27 //Read specified amount of data. If read goes to end of file, ptr will be left at CLUSTER_SIZE.
28 //Returns the number of bytes read.
29 size_t read_data(uint32_t& cluster, uint32_t& ptr, void* data, uint32_t length);
30 //Write specified amount of data. real_cluster and real_ptr point to location data was written to.
31 //If write exactly fills the last cluster, ptr will be left at CLUSTER_SIZE.
32 void write_data(uint32_t& cluster, uint32_t& ptr, const void* data, uint32_t length,
33 uint32_t& real_cluster, uint32_t& real_ptr);
34 private:
35 filesystem(const filesystem&);
36 filesystem& operator=(const filesystem&);
37 void link_cluster(uint32_t cluster, uint32_t linkto);
38 struct supercluster
40 unsigned free_clusters;
41 uint32_t clusters[CLUSTERS_PER_SUPER];
42 void load(std::fstream& s, uint32_t index);
43 void save(std::fstream& s, uint32_t index);
45 uint32_t supercluster_count;
46 std::map<uint32_t, supercluster> superclusters;
47 std::fstream backing;
50 class filesystem_ref
52 public:
53 filesystem_ref()
55 refcnt = NULL;
56 mutex = NULL;
57 fs = NULL;
59 filesystem_ref(const std::string& backingfile)
61 refcnt = NULL;
62 mutex = NULL;
63 try {
64 refcnt = new unsigned;
65 mutex = new mutex_class;
66 fs = new filesystem(backingfile);
67 } catch(...) {
68 delete refcnt;
69 delete mutex;
70 throw;
72 *refcnt = 1;
74 ~filesystem_ref()
76 mutex_class* mtodelete = NULL;
77 if(!mutex)
78 return;
80 umutex_class m(*mutex);
81 --*refcnt;
82 if(!*refcnt) {
83 delete fs;
84 delete refcnt;
85 mtodelete = mutex;
88 if(mtodelete)
89 delete mtodelete;
91 filesystem_ref(const filesystem_ref& r)
93 umutex_class m(*r.mutex);
94 ++*(r.refcnt);
95 refcnt = r.refcnt;
96 mutex = r.mutex;
97 fs = r.fs;
99 filesystem_ref& operator=(const filesystem_ref& r)
101 if(this == &r)
102 return *this;
103 //This is tricky, due to having to lock two objects.
104 size_t A = (size_t)this;
105 size_t B = (size_t)&r;
106 mutex_class* mtodelete = NULL;
107 if(!refcnt) {
108 //We just have to grab a ref and copy.
109 umutex_class m(*r.mutex);
110 ++*(r.refcnt);
111 refcnt = r.refcnt;
112 mutex = r.mutex;
113 fs = r.fs;
114 } else if(A < B) {
115 //Two-object case.
116 umutex_class m1(*mutex);
117 umutex_class m2(*r.mutex);
118 --*refcnt;
119 if(!*refcnt) {
120 delete fs;
121 delete refcnt;
122 mtodelete = mutex;;
124 ++*(r.refcnt);
125 refcnt = r.refcnt;
126 mutex = r.mutex;
127 fs = r.fs;
128 } else {
129 //Two-object case.
130 umutex_class m1(*r.mutex);
131 umutex_class m2(*mutex);
132 --*refcnt;
133 if(!*refcnt) {
134 delete fs;
135 delete refcnt;
136 mtodelete = mutex;;
138 ++*(r.refcnt);
139 refcnt = r.refcnt;
140 mutex = r.mutex;
141 fs = r.fs;
143 if(mtodelete)
144 delete mtodelete;
145 return *this;
147 uint32_t allocate_cluster()
149 umutex_class m(*mutex);
150 return fs->allocate_cluster();
152 void free_cluster_chain(uint32_t cluster)
154 umutex_class m(*mutex);
155 fs->free_cluster_chain(cluster);
157 size_t skip_data(uint32_t& cluster, uint32_t& ptr, uint32_t length)
159 umutex_class m(*mutex);
160 return fs->skip_data(cluster, ptr, length);
162 size_t read_data(uint32_t& cluster, uint32_t& ptr, void* data, uint32_t length)
164 umutex_class m(*mutex);
165 return fs->read_data(cluster, ptr, data, length);
167 void write_data(uint32_t& cluster, uint32_t& ptr, const void* data, uint32_t length,
168 uint32_t& real_cluster, uint32_t& real_ptr)
170 umutex_class m(*mutex);
171 fs->write_data(cluster, ptr, data, length, real_cluster, real_ptr);
173 private:
174 filesystem* fs;
175 unsigned* refcnt;
176 mutex_class* mutex;
179 #endif