WIP build diskimage device with %build_module.
[AROS.git] / workbench / devs / diskimage / device / plugins.c
blob2e8e2fcd52d9d8c020744f83048c0de64439f400
1 /* Copyright 2007-2012 Fredrik Wikstrom. All rights reserved.
2 **
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
5 ** are met:
6 **
7 ** 1. Redistributions of source code must retain the above copyright
8 ** notice, this list of conditions and the following disclaimer.
9 **
10 ** 2. Redistributions in binary form must reproduce the above copyright
11 ** notice, this list of conditions and the following disclaimer in the
12 ** documentation and/or other materials provided with the distribution.
14 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
15 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 ** POSSIBILITY OF SUCH DAMAGE.
27 #include "diskimage_device.h"
28 #include "device_locale.h"
29 #include <dos/exall.h>
31 #ifndef EAD_IS_FILE
32 #define EAD_IS_FILE(ead) ((ead)->ed_Type < 0)
33 #endif
35 #ifndef FIB_IS_FILE
36 #define FIB_IS_FILE(fib) ((fib)->fib_DirEntryType < 0)
37 #endif
39 extern struct DiskImagePlugin generic_plugin;
40 extern struct DiskImagePlugin adf_plugin;
41 extern struct DiskImagePlugin d64_plugin;
42 extern struct DiskImagePlugin iso_plugin;
44 static struct DiskImagePlugin * const builtin_plugin_array[] = {
45 &generic_plugin,
46 &adf_plugin,
47 &d64_plugin,
48 &iso_plugin,
49 NULL
52 static struct DiskImagePluginTable builtin_plugin_table = {
53 PLUGIN_MAGIC,
54 USED_PLUGIN_API_VERSION,
55 -1UL,
56 builtin_plugin_array
59 static ULONG InitPlugins (struct DiskImageBase *libBase, struct DiskImagePluginTable *plugin_table,
60 BPTR seglist, const struct PluginData *plugin_data);
62 void LoadPlugins (struct DiskImageBase *libBase) {
63 struct Library *DOSBase = libBase->DOSBase;
64 struct PluginData plugin_data;
66 IPluginIFace.Data.LibBase = &libBase->LibNode;
67 plugin_data.SysBase = libBase->SysBase;
68 plugin_data.DOSBase = libBase->DOSBase;
69 plugin_data.UtilityBase = libBase->UtilityBase;
70 plugin_data.IPlugin = &IPluginIFace;
72 libBase->HeaderTestSize = 0;
73 libBase->FooterTestSize = 0;
75 /* Built-in plugins */
76 InitPlugins(libBase, &builtin_plugin_table, libBase->SegList, &plugin_data);
78 /* Dynamically loaded plugins */
80 #ifdef __AROS__
81 #define EA_BUFFER_SIZE 4096
82 BPTR dir, curr_dir;
83 struct ExAllControl *eac;
84 struct ExAllData *eabuffer;
85 struct ExAllData *ead;
86 BOOL more;
87 BPTR seglist;
88 struct DiskImagePluginTable *plugin_table;
90 dir = Lock("DEVS:DiskImage", ACCESS_READ);
91 eac = AllocDosObject(DOS_EXALLCONTROL, NULL);
92 eabuffer = AllocVec(EA_BUFFER_SIZE, MEMF_ANY);
94 if (dir && eac && eabuffer) {
95 do {
96 more = ExAll(dir, eabuffer, EA_BUFFER_SIZE, ED_TYPE, eac);
97 if (eac->eac_Entries == 0) {
98 continue;
100 ead = eabuffer;
101 do {
102 curr_dir = CurrentDir(dir);
103 if (EAD_IS_FILE(ead) && (seglist = LoadSeg(ead->ed_Name))) {
104 APTR (*entry)(void) = (APTR)((BPTR *)BADDR(seglist) + 1);
105 plugin_table = (struct DiskImagePluginTable *)entry();
106 if (InitPlugins(libBase, plugin_table, seglist, &plugin_data) == 0) {
107 UnLoadSeg(seglist);
110 CurrentDir(curr_dir);
111 } while ((ead = ead->ed_Next));
112 } while (more);
115 FreeDosObject(DOS_EXALLCONTROL, eac);
116 FreeVec(eabuffer);
117 UnLock(dir);
118 #else
119 BPTR dir, curr_dir;
120 struct FileInfoBlock *fib;
121 BPTR seglist;
122 struct DiskImagePluginTable *plugin_table;
124 dir = Lock("DEVS:DiskImage", ACCESS_READ);
125 fib = AllocDosObject(DOS_FIB, NULL);
127 if (dir && fib && Examine(dir, fib)) {
128 while (ExNext(dir, fib)) {
129 curr_dir = CurrentDir(dir);
130 if (FIB_IS_FILE(fib) && (seglist = LoadSeg(fib->fib_FileName))) {
131 APTR (*entry)(void) = (APTR)((BPTR *)BADDR(seglist) + 1);
132 plugin_table = (struct DiskImagePluginTable *)entry();
133 if (InitPlugins(libBase, plugin_table, seglist, &plugin_data) == 0) {
134 UnLoadSeg(seglist);
137 CurrentDir(curr_dir);
141 FreeDosObject(DOS_FIB, fib);
142 UnLock(dir);
143 #endif
147 static ULONG InitPlugins (struct DiskImageBase *libBase, struct DiskImagePluginTable *plugin_table,
148 BPTR seglist, const struct PluginData *plugin_data)
150 struct Library *SysBase = libBase->SysBase;
152 if (plugin_table && TypeOfMem(plugin_table) &&
153 plugin_table->Magic == PLUGIN_MAGIC &&
154 plugin_table->API_Version >= MIN_PLUGIN_API_VERSION &&
155 plugin_table->API_Version <= MAX_PLUGIN_API_VERSION)
157 struct DiskImagePlugin *plugin;
158 ULONG i;
160 for (i = 0; (plugin = plugin_table->Plugins[i]); i++) {
161 if ((plugin->Flags & PLUGIN_UNUSED_FLAGS) ||
162 !(plugin->Flags & PLUGIN_FLAG_M68K))
164 continue;
166 plugin->SegList = seglist;
167 plugin->RefCount = &plugin_table->RefCount;
168 if (!plugin->plugin_Init || Plugin_Init(plugin, plugin_data)) {
169 if (plugin_table->RefCount == -1UL) {
170 plugin->Flags |= PLUGIN_FLAG_BUILTIN;
171 } else {
172 plugin_table->RefCount++;
174 if (!(plugin->Flags & PLUGIN_FLAG_FOOTER)) {
175 if (plugin->TestSize > libBase->HeaderTestSize) {
176 libBase->HeaderTestSize = plugin->TestSize;
178 } else {
179 if (plugin->TestSize > libBase->FooterTestSize) {
180 libBase->FooterTestSize = plugin->TestSize;
183 Enqueue(libBase->Plugins, &plugin->Node);
186 return plugin_table->RefCount;
188 return 0;
191 void FreePlugins (struct DiskImageBase *libBase) {
192 struct Library *SysBase = libBase->SysBase;
193 struct Library *DOSBase = libBase->DOSBase;
194 struct DiskImagePlugin *plugin;
196 if (libBase->Plugins) {
197 while ((plugin = (struct DiskImagePlugin *)RemHead(libBase->Plugins))) {
198 if (plugin->plugin_Exit) Plugin_Exit(plugin);
199 if (!(plugin->Flags & PLUGIN_FLAG_BUILTIN) && --plugin->RefCount[0] == 0) {
200 UnLoadSeg(plugin->SegList);
205 libBase->HeaderTestSize = 0;
206 libBase->FooterTestSize = 0;
209 struct DiskImagePlugin *FindPlugin (struct DiskImageUnit *unit, BPTR file, CONST_STRPTR name) {
210 struct DiskImageBase *libBase = unit->LibBase;
211 struct Library *DOSBase = libBase->DOSBase;
212 struct List *list = libBase->Plugins;
213 QUAD file_size;
214 UBYTE *header_test = NULL;
215 LONG header_test_size = libBase->HeaderTestSize;
216 LONG header_test_len = 0;
217 UBYTE *footer_test = NULL;
218 LONG footer_test_size = libBase->FooterTestSize;
219 LONG footer_test_len = 0;
220 struct DiskImagePlugin *ptr;
221 UBYTE *test;
222 LONG test_len;
224 file_size = GetFileSize(file);
225 switch (file_size) {
226 case 0: SetIoErr(ERROR_OBJECT_WRONG_TYPE);
227 case -1: goto error;
230 if (header_test_size > 0 || footer_test_size > 0) {
231 if (header_test_size > 0) {
232 if ((QUAD)header_test_size > file_size) header_test_size = file_size;
233 header_test = AllocVec(header_test_size, MEMF_ANY);
234 if (!header_test) {
235 SetIoErr(ERROR_NO_FREE_STORE);
236 goto error;
238 header_test_len = Read(file, header_test, header_test_size);
239 if (header_test_len == -1) {
240 goto error;
243 if (footer_test_size > 0) {
244 if ((QUAD)footer_test_size > file_size) footer_test_size = file_size;
245 if (!ChangeFilePosition(file, -footer_test_size, OFFSET_END)) {
246 goto error;
248 footer_test = AllocVec(footer_test_size, MEMF_ANY);
249 if (!footer_test) {
250 SetIoErr(ERROR_NO_FREE_STORE);
251 goto error;
253 footer_test_len = Read(file, footer_test, footer_test_size);
254 if (footer_test_len == -1) {
255 goto error;
258 if (!ChangeFilePosition(file, 0, OFFSET_BEGINNING)) {
259 goto error;
263 ptr = (struct DiskImagePlugin *)list->lh_Head;
264 while (ptr->Node.ln_Succ) {
265 if (!(ptr->Flags & PLUGIN_FLAG_FOOTER)) {
266 test = header_test;
267 test_len = header_test_len;
268 } else {
269 test = footer_test;
270 test_len = footer_test_len;
272 if (ptr->plugin_CheckImage && Plugin_CheckImage(ptr, file, name, file_size, test, test_len)) {
273 FreeVec(header_test);
274 FreeVec(footer_test);
275 return ptr;
277 ptr = (struct DiskImagePlugin *)ptr->Node.ln_Succ;
280 error:
281 FreeVec(header_test);
282 FreeVec(footer_test);
283 SetDiskImageError(NULL, unit, IoErr(), 0);
284 return NULL;
287 APTR OpenImage (APTR Self, struct DiskImageUnit *unit, BPTR file, CONST_STRPTR name) {
288 struct DiskImagePlugin *ptr;
290 ptr = FindPlugin(unit, file, name);
291 if (ptr) {
292 unit->Plugin = ptr;
293 return Plugin_OpenImage(ptr, unit, file, name);
295 return NULL;