1 /*
2  * libInstPatch
3  * Copyright (C) 1999-2014 Element Green <element@elementsofsound.org>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public License
7  * as published by the Free Software Foundation; version 2.1
8  * of the License only.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  * 02110-1301, USA or on the web at http://www.gnu.org.
19  */
20 #ifndef __IPATCH_FILE_H__
21 #define __IPATCH_FILE_H__
22 
23 #include <glib.h>
24 #include <glib-object.h>
25 #include <libinstpatch/compat.h>
26 
27 /* forward type declarations */
28 
29 typedef struct _IpatchFile IpatchFile;
30 typedef struct _IpatchFileClass IpatchFileClass;
31 typedef struct _IpatchFileIOFuncs IpatchFileIOFuncs;
32 typedef struct _IpatchFileHandle IpatchFileHandle;
33 
34 #include <libinstpatch/IpatchItem.h>
35 
36 #define IPATCH_TYPE_FILE (ipatch_file_get_type ())
37 #define IPATCH_FILE(obj) \
38   (G_TYPE_CHECK_INSTANCE_CAST ((obj), IPATCH_TYPE_FILE, IpatchFile))
39 #define IPATCH_FILE_CLASS(klass) \
40   (G_TYPE_CHECK_CLASS_CAST ((klass), IPATCH_TYPE_FILE, IpatchFileClass))
41 #define IPATCH_IS_FILE(obj) \
42   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IPATCH_TYPE_FILE))
43 #define IPATCH_IS_FILE_CLASS(klass) \
44   (G_TYPE_CHECK_CLASS_TYPE ((klass), IPATCH_TYPE_FILE))
45 #define IPATCH_FILE_GET_CLASS(obj) \
46   (G_TYPE_INSTANCE_GET_CLASS ((obj), IPATCH_TYPE_FILE, IpatchFileClass))
47 
48 /* IO function table for IpatchFile instances */
49 struct _IpatchFileIOFuncs
50 {
51     gboolean(*open)(IpatchFileHandle *handle, const char *mode, GError **err);
52     void (*close)(IpatchFileHandle *handle);
53     GIOStatus(*read)(IpatchFileHandle *handle, gpointer buf, guint size,
54                      guint *bytes_read, GError **err);
55     GIOStatus(*write)(IpatchFileHandle *handle, gconstpointer buf, guint size,
56                       GError **err);
57     GIOStatus(*seek)(IpatchFileHandle *handle, int offset, GSeekType type, GError **err);
58     int (*getfd)(IpatchFileHandle *handle); /* optional get file descriptor method */
59     int (*get_size)(IpatchFile *file, GError **err);  /* optional get size method */
60 };
61 
62 /* File object */
63 struct _IpatchFile
64 {
65     IpatchItem parent_instance;
66 
67     /*< private >*/
68 
69     IpatchFileIOFuncs *iofuncs;	/* per instance I/O methods */
70     char *file_name;		/* not always set */
71     GIOChannel *iochan;           /* assigned directly with ipatch_file_set_(fd/iochan) */
72     GHashTable *ref_hash;         /* registered objects referencing this file: objectPtr -> GWeakRef */
73     guint open_count;             /* count of open file handles */
74 };
75 
76 /* File object class */
77 struct _IpatchFileClass
78 {
79     IpatchItemClass parent_class;
80 
81     /* File identify method */
82     gboolean(*identify)(IpatchFile *file, IpatchFileHandle *handle, GError **err);
83     int identify_order;   /* Identify execution order (see #IpatchFileIdentifyOrder, 0 = default) */
84 };
85 
86 /**
87  * IpatchFileFlags:
88  * @IPATCH_FILE_FLAG_SWAP: Swap multi-byte numbers?
89  * @IPATCH_FILE_FLAG_BIG_ENDIAN: Big endian file?
90  * @IPATCH_FILE_FLAG_FREE_IOFUNCS: Should ->iofuncs be freed?
91  */
92 typedef enum
93 {
94     IPATCH_FILE_FLAG_SWAP = 1 << (IPATCH_ITEM_UNUSED_FLAG_SHIFT),
95     IPATCH_FILE_FLAG_BIG_ENDIAN = 1 << (IPATCH_ITEM_UNUSED_FLAG_SHIFT + 1),
96     IPATCH_FILE_FLAG_FREE_IOFUNCS = 1 << (IPATCH_ITEM_UNUSED_FLAG_SHIFT + 2)
97 } IpatchFileFlags;
98 
99 /**
100  * IpatchFileIdentifyOrder:
101  * @IPATCH_FILE_IDENTIFY_ORDER_LAST: Execute last (toward the end of the list)
102  * @IPATCH_FILE_IDENTIFY_ORDER_DEFAULT: Default execution order (no preference)
103  * @IPATCH_FILE_IDENTIFY_ORDER_FIRST: Execute first (toward the start of the list)
104  *
105  * Some helpful constants for the identify_order #IpatchFileClass field.  Note
106  * that any value can be used and this enum just provides some helpful values.
107  * This value determines in what order file identification methods are called.
108  * Higher values are executed first.
109  */
110 typedef enum
111 {
112     IPATCH_FILE_IDENTIFY_ORDER_LAST = -10,
113     IPATCH_FILE_IDENTIFY_ORDER_DEFAULT = 0,
114     IPATCH_FILE_IDENTIFY_ORDER_FIRST = 10
115 } IpatchFileIdentifyOrder;
116 
117 /**
118  * IPATCH_FILE_UNUSED_FLAG_SHIFT: (skip)
119  */
120 /* reserve 6 flags (3 for expansion) */
121 #define IPATCH_FILE_UNUSED_FLAG_SHIFT  (IPATCH_ITEM_UNUSED_FLAG_SHIFT + 6)
122 
123 /* macro to check if multi-byte numbers in file require swapping */
124 #define IPATCH_FILE_NEED_SWAP(file) \
125   (ipatch_item_get_flags(file) & IPATCH_FILE_FLAG_SWAP)
126 /* macro to check if file is big endian */
127 #define IPATCH_FILE_BIG_ENDIAN(file) \
128   (ipatch_item_get_flags(file) & IPATCH_FILE_FLAG_BIG_ENDIAN)
129 
130 /* runtime byte swapping macros for convenient loading of cross endian
131    files, takes a pointer to the value to swap (like in a buffer) */
132 #define IPATCH_FILE_SWAP16(file, p16) \
133  (IPATCH_FILE_NEED_SWAP (file) ? \
134   GUINT16_SWAP_LE_BE (*(guint16 *)(p16)) : *(guint16 *)(p16))
135 #define IPATCH_FILE_SWAP32(file, p32) \
136  (IPATCH_FILE_NEED_SWAP (file) ? \
137   GUINT32_SWAP_LE_BE (*(guint32 *)(p32)) : *(guint32 *)(p32))
138 #define IPATCH_FILE_SWAP64(file, p64) \
139  (IPATCH_FILE_NEED_SWAP (file) ? \
140   GUINT64_SWAP_LE_BE (*(guint64 *)(p64)) : *(guint64 *)(p64))
141 
142 #define IPATCH_IS_FILE_HANDLE(handle) \
143   ((handle) && IPATCH_IS_FILE ((handle)->file))
144 
145 /**
146  * IpatchFileHandle:
147  *
148  * #IpatchFile handle for opening a file and reading/writing from/to it.
149  */
150 struct _IpatchFileHandle
151 {
152     IpatchFile *file;		/* Parent file object */
153     guint position;               /* Current file position */
154     GByteArray *buf;              /* For buffered reads/writes */
155     guint buf_position;           /* Current position in buffer */
156     GIOChannel *iochan;		/* glib IO channel (default methods) */
157     gpointer data;                /* iofuncs defined data */
158 };
159 
160 
161 GType ipatch_file_get_type(void);
162 GType ipatch_file_handle_get_type(void);
163 IpatchFile *ipatch_file_new(void);
164 IpatchFile *ipatch_file_pool_new(const char *file_name, gboolean *created);
165 IpatchFile *ipatch_file_pool_lookup(const char *file_name);
166 
167 void ipatch_file_ref_from_object(IpatchFile *file, GObject *object);
168 void ipatch_file_unref_from_object(IpatchFile *file, GObject *object);
169 gboolean ipatch_file_test_ref_object(IpatchFile *file, GObject *object);
170 IpatchList *ipatch_file_get_refs(IpatchFile *file);
171 IpatchList *ipatch_file_get_refs_by_type(IpatchFile *file, GType type);
172 
173 void ipatch_file_set_name(IpatchFile *file, const char *file_name);
174 char *ipatch_file_get_name(IpatchFile *file);
175 gboolean ipatch_file_rename(IpatchFile *file, const char *new_name, GError **err);
176 gboolean ipatch_file_unlink(IpatchFile *file, GError **err);
177 gboolean ipatch_file_replace(IpatchFile *newfile, IpatchFile *oldfile, GError **err);
178 IpatchFileHandle *ipatch_file_open(IpatchFile *file, const char *file_name,
179                                    const char *mode, GError **err);
180 void ipatch_file_assign_fd(IpatchFile *file, int fd, gboolean close_on_finalize);
181 void ipatch_file_assign_io_channel(IpatchFile *file, GIOChannel *iochan);
182 GIOChannel *ipatch_file_get_io_channel(IpatchFileHandle *handle);
183 int ipatch_file_get_fd(IpatchFileHandle *handle);
184 void ipatch_file_close(IpatchFileHandle *handle);
185 
186 guint ipatch_file_get_position(IpatchFileHandle *handle);
187 void ipatch_file_update_position(IpatchFileHandle *handle, guint offset);
188 
189 gboolean ipatch_file_read(IpatchFileHandle *handle, gpointer buf, guint size,
190                           GError **err);
191 GIOStatus ipatch_file_read_eof(IpatchFileHandle *handle, gpointer buf, guint size,
192                                guint *bytes_read, GError **err);
193 gboolean ipatch_file_write(IpatchFileHandle *handle, gconstpointer buf,
194                            guint size, GError **err);
195 #define ipatch_file_skip(handle, offset, err) \
196   ipatch_file_seek (handle, offset, G_SEEK_CUR, err)
197 gboolean ipatch_file_seek(IpatchFileHandle *handle, int offset, GSeekType type,
198                           GError **err);
199 GIOStatus ipatch_file_seek_eof(IpatchFileHandle *handle, int offset,
200                                GSeekType type, GError **err);
201 int ipatch_file_get_size(IpatchFile *file, GError **err);
202 GType ipatch_file_identify(IpatchFile *file, GError **err);
203 GType ipatch_file_identify_name(const char *filename, GError **err);
204 GType ipatch_file_identify_by_ext(IpatchFile *file);
205 IpatchFileHandle *ipatch_file_identify_open(const char *file_name, GError **err);
206 IpatchFile *ipatch_file_identify_new(const char *file_name, GError **err);
207 
208 void ipatch_file_set_little_endian(IpatchFile *file);
209 void ipatch_file_set_big_endian(IpatchFile *file);
210 
211 gboolean ipatch_file_read_u8(IpatchFileHandle *handle, guint8 *val, GError **err);
212 gboolean ipatch_file_read_u16(IpatchFileHandle *handle, guint16 *val, GError **err);
213 gboolean ipatch_file_read_u32(IpatchFileHandle *handle, guint32 *val, GError **err);
214 gboolean ipatch_file_read_u64(IpatchFileHandle *handle, guint64 *val, GError **err);
215 gboolean ipatch_file_read_s8(IpatchFileHandle *handle, gint8 *val, GError **err);
216 gboolean ipatch_file_read_s16(IpatchFileHandle *handle, gint16 *val, GError **err);
217 gboolean ipatch_file_read_s32(IpatchFileHandle *handle, gint32 *val, GError **err);
218 gboolean ipatch_file_read_s64(IpatchFileHandle *handle, gint64 *val, GError **err);
219 
220 gboolean ipatch_file_write_u8(IpatchFileHandle *handle, guint8 val, GError **err);
221 gboolean ipatch_file_write_u16(IpatchFileHandle *handle, guint16 val, GError **err);
222 gboolean ipatch_file_write_u32(IpatchFileHandle *handle, guint32 val, GError **err);
223 gboolean ipatch_file_write_u64(IpatchFileHandle *handle, guint64 val, GError **err);
224 gboolean ipatch_file_write_s8(IpatchFileHandle *handle, gint8 val, GError **err);
225 gboolean ipatch_file_write_s16(IpatchFileHandle *handle, gint16 val, GError **err);
226 gboolean ipatch_file_write_s32(IpatchFileHandle *handle, gint32 val, GError **err);
227 gboolean ipatch_file_write_s64(IpatchFileHandle *handle, gint64 val, GError **err);
228 
229 gboolean ipatch_file_buf_load(IpatchFileHandle *handle, guint size, GError **err);
230 void ipatch_file_buf_read(IpatchFileHandle *handle, gpointer buf, guint size);
231 void ipatch_file_buf_write(IpatchFileHandle *handle, gconstpointer buf,
232                            guint size);
233 #define ipatch_file_buf_zero(filebuf, size) \
234   ipatch_file_buf_memset(filebuf, 0, size)
235 void ipatch_file_buf_memset(IpatchFileHandle *handle, unsigned char c, guint size);
236 void ipatch_file_buf_set_size(IpatchFileHandle *handle, guint size);
237 gboolean ipatch_file_buf_commit(IpatchFileHandle *handle, GError **err);
238 #define ipatch_file_buf_skip(filebuf, offset) \
239   ipatch_file_buf_seek (filebuf, offset, G_SEEK_CUR)
240 void ipatch_file_buf_seek(IpatchFileHandle *handle, int offset, GSeekType type);
241 
242 guint8 ipatch_file_buf_read_u8(IpatchFileHandle *handle);
243 guint16 ipatch_file_buf_read_u16(IpatchFileHandle *handle);
244 guint32 ipatch_file_buf_read_u32(IpatchFileHandle *handle);
245 guint64 ipatch_file_buf_read_u64(IpatchFileHandle *handle);
246 gint8 ipatch_file_buf_read_s8(IpatchFileHandle *handle);
247 gint16 ipatch_file_buf_read_s16(IpatchFileHandle *handle);
248 gint32 ipatch_file_buf_read_s32(IpatchFileHandle *handle);
249 gint64 ipatch_file_buf_read_s64(IpatchFileHandle *handle);
250 
251 void ipatch_file_buf_write_u8(IpatchFileHandle *handle, guint8 val);
252 void ipatch_file_buf_write_u16(IpatchFileHandle *handle, guint16 val);
253 void ipatch_file_buf_write_u32(IpatchFileHandle *handle, guint32 val);
254 void ipatch_file_buf_write_u64(IpatchFileHandle *handle, guint64 val);
255 void ipatch_file_buf_write_s8(IpatchFileHandle *handle, gint8 val);
256 void ipatch_file_buf_write_s16(IpatchFileHandle *handle, gint16 val);
257 void ipatch_file_buf_write_s32(IpatchFileHandle *handle, gint32 val);
258 void ipatch_file_buf_write_s64(IpatchFileHandle *handle, gint64 val);
259 
260 void ipatch_file_set_iofuncs_static(IpatchFile *file,
261                                     IpatchFileIOFuncs *funcs);
262 void ipatch_file_set_iofuncs(IpatchFile *file,
263                              const IpatchFileIOFuncs *funcs);
264 void ipatch_file_get_iofuncs(IpatchFile *file, IpatchFileIOFuncs *out_funcs);
265 void ipatch_file_set_iofuncs_null(IpatchFile *file);
266 
267 gboolean ipatch_file_default_open_method(IpatchFileHandle *handle, const char *mode,
268         GError **err);
269 void ipatch_file_default_close_method(IpatchFileHandle *handle);
270 GIOStatus ipatch_file_default_read_method(IpatchFileHandle *handle, gpointer buf,
271         guint size, guint *bytes_read,
272         GError **err);
273 GIOStatus ipatch_file_default_write_method(IpatchFileHandle *handle,
274         gconstpointer buf,
275         guint size, GError **err);
276 GIOStatus ipatch_file_default_seek_method(IpatchFileHandle *handle, int offset,
277         GSeekType type, GError **err);
278 int ipatch_file_default_getfd_method(IpatchFileHandle *handle);
279 int ipatch_file_default_get_size_method(IpatchFile *file, GError **err);
280 
281 #endif
282