revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / diskimage / device / plugins.c
blob468044ff26c3a9f48b1079c1ce7bcb4a74f8eda7
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 -1L,
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;
71 #ifdef __AROS__
72 plugin_data.StdCBase = libBase->StdCBase;
73 #endif
75 libBase->HeaderTestSize = 0;
76 libBase->FooterTestSize = 0;
78 /* Built-in plugins */
79 InitPlugins(libBase, &builtin_plugin_table, libBase->SegList, &plugin_data);
81 /* Dynamically loaded plugins */
83 #ifdef __AROS__
84 #define EA_BUFFER_SIZE 4096
85 BPTR dir, curr_dir;
86 struct ExAllControl *eac;
87 struct ExAllData *eabuffer;
88 struct ExAllData *ead;
89 BOOL more;
90 BPTR seglist;
91 struct DiskImagePluginTable *plugin_table;
93 dir = Lock("DEVS:DiskImage", ACCESS_READ);
94 eac = AllocDosObject(DOS_EXALLCONTROL, NULL);
95 eabuffer = AllocVec(EA_BUFFER_SIZE, MEMF_ANY);
97 if (dir && eac && eabuffer) {
98 do {
99 more = ExAll(dir, eabuffer, EA_BUFFER_SIZE, ED_TYPE, eac);
100 if (eac->eac_Entries == 0) {
101 continue;
103 ead = eabuffer;
104 do {
105 curr_dir = CurrentDir(dir);
106 if (EAD_IS_FILE(ead) && (seglist = LoadSeg(ead->ed_Name))) {
107 APTR (*entry)(void) = (APTR)((BPTR *)BADDR(seglist) + 1);
108 plugin_table = (struct DiskImagePluginTable *)entry();
109 if (InitPlugins(libBase, plugin_table, seglist, &plugin_data) == 0) {
110 UnLoadSeg(seglist);
113 CurrentDir(curr_dir);
114 } while ((ead = ead->ed_Next));
115 } while (more);
118 FreeDosObject(DOS_EXALLCONTROL, eac);
119 FreeVec(eabuffer);
120 UnLock(dir);
121 #else
122 BPTR dir, curr_dir;
123 struct FileInfoBlock *fib;
124 BPTR seglist;
125 struct DiskImagePluginTable *plugin_table;
127 dir = Lock("DEVS:DiskImage", ACCESS_READ);
128 fib = AllocDosObject(DOS_FIB, NULL);
130 if (dir && fib && Examine(dir, fib)) {
131 while (ExNext(dir, fib)) {
132 curr_dir = CurrentDir(dir);
133 if (FIB_IS_FILE(fib) && (seglist = LoadSeg(fib->fib_FileName))) {
134 APTR (*entry)(void) = (APTR)((BPTR *)BADDR(seglist) + 1);
135 plugin_table = (struct DiskImagePluginTable *)entry();
136 if (InitPlugins(libBase, plugin_table, seglist, &plugin_data) == 0) {
137 UnLoadSeg(seglist);
140 CurrentDir(curr_dir);
144 FreeDosObject(DOS_FIB, fib);
145 UnLock(dir);
146 #endif
150 static ULONG InitPlugins (struct DiskImageBase *libBase, struct DiskImagePluginTable *plugin_table,
151 BPTR seglist, const struct PluginData *plugin_data)
153 struct Library *SysBase = libBase->SysBase;
155 if (plugin_table && TypeOfMem(plugin_table) &&
156 plugin_table->Magic == PLUGIN_MAGIC &&
157 plugin_table->API_Version >= MIN_PLUGIN_API_VERSION &&
158 plugin_table->API_Version <= MAX_PLUGIN_API_VERSION)
160 struct DiskImagePlugin *plugin;
161 ULONG i;
163 for (i = 0; (plugin = plugin_table->Plugins[i]); i++) {
164 if ((plugin->Flags & PLUGIN_UNUSED_FLAGS) ||
165 !(plugin->Flags & PLUGIN_FLAG_M68K))
167 continue;
169 plugin->SegList = seglist;
170 plugin->RefCount = &plugin_table->RefCount;
171 if (!plugin->plugin_Init || Plugin_Init(plugin, plugin_data)) {
172 if (plugin_table->RefCount == (ULONG)-1) {
173 plugin->Flags |= PLUGIN_FLAG_BUILTIN;
174 } else {
175 plugin_table->RefCount++;
177 if (!(plugin->Flags & PLUGIN_FLAG_FOOTER)) {
178 if (plugin->TestSize > libBase->HeaderTestSize) {
179 libBase->HeaderTestSize = plugin->TestSize;
181 } else {
182 if (plugin->TestSize > libBase->FooterTestSize) {
183 libBase->FooterTestSize = plugin->TestSize;
186 Enqueue(libBase->Plugins, &plugin->Node);
189 return plugin_table->RefCount;
191 return 0;
194 void FreePlugins (struct DiskImageBase *libBase) {
195 struct Library *SysBase = libBase->SysBase;
196 struct Library *DOSBase = libBase->DOSBase;
197 struct DiskImagePlugin *plugin;
199 if (libBase->Plugins) {
200 while ((plugin = (struct DiskImagePlugin *)RemHead(libBase->Plugins))) {
201 if (plugin->plugin_Exit) Plugin_Exit(plugin);
202 if (!(plugin->Flags & PLUGIN_FLAG_BUILTIN) && --plugin->RefCount[0] == 0) {
203 UnLoadSeg(plugin->SegList);
208 libBase->HeaderTestSize = 0;
209 libBase->FooterTestSize = 0;
212 struct DiskImagePlugin *FindPlugin (struct DiskImageUnit *unit, BPTR file, CONST_STRPTR name) {
213 struct DiskImageBase *libBase = unit->LibBase;
214 struct Library *DOSBase = libBase->DOSBase;
215 struct List *list = libBase->Plugins;
216 QUAD file_size;
217 UBYTE *header_test = NULL;
218 LONG header_test_size = libBase->HeaderTestSize;
219 LONG header_test_len = 0;
220 UBYTE *footer_test = NULL;
221 LONG footer_test_size = libBase->FooterTestSize;
222 LONG footer_test_len = 0;
223 struct DiskImagePlugin *ptr;
224 UBYTE *test;
225 LONG test_len;
227 file_size = GetFileSize(file);
228 switch (file_size) {
229 case 0: SetIoErr(ERROR_OBJECT_WRONG_TYPE);
230 case -1: goto error;
233 if (header_test_size > 0 || footer_test_size > 0) {
234 if (header_test_size > 0) {
235 if ((QUAD)header_test_size > file_size) header_test_size = file_size;
236 header_test = AllocVec(header_test_size, MEMF_ANY);
237 if (!header_test) {
238 SetIoErr(ERROR_NO_FREE_STORE);
239 goto error;
241 header_test_len = Read(file, header_test, header_test_size);
242 if (header_test_len == -1) {
243 goto error;
246 if (footer_test_size > 0) {
247 if ((QUAD)footer_test_size > file_size) footer_test_size = file_size;
248 if (!ChangeFilePosition(file, -footer_test_size, OFFSET_END)) {
249 goto error;
251 footer_test = AllocVec(footer_test_size, MEMF_ANY);
252 if (!footer_test) {
253 SetIoErr(ERROR_NO_FREE_STORE);
254 goto error;
256 footer_test_len = Read(file, footer_test, footer_test_size);
257 if (footer_test_len == -1) {
258 goto error;
261 if (!ChangeFilePosition(file, 0, OFFSET_BEGINNING)) {
262 goto error;
266 ptr = (struct DiskImagePlugin *)list->lh_Head;
267 while (ptr->Node.ln_Succ) {
268 if (!(ptr->Flags & PLUGIN_FLAG_FOOTER)) {
269 test = header_test;
270 test_len = header_test_len;
271 } else {
272 test = footer_test;
273 test_len = footer_test_len;
275 if (ptr->plugin_CheckImage && Plugin_CheckImage(ptr, file, name, file_size, test, test_len)) {
276 FreeVec(header_test);
277 FreeVec(footer_test);
278 return ptr;
280 ptr = (struct DiskImagePlugin *)ptr->Node.ln_Succ;
283 error:
284 FreeVec(header_test);
285 FreeVec(footer_test);
286 SetDiskImageError(NULL, unit, IoErr(), 0);
287 return NULL;
290 APTR OpenImage (APTR Self, struct DiskImageUnit *unit, BPTR file, CONST_STRPTR name) {
291 struct DiskImagePlugin *ptr;
293 ptr = FindPlugin(unit, file, name);
294 if (ptr) {
295 unit->Plugin = ptr;
296 return Plugin_OpenImage(ptr, unit, file, name);
298 return NULL;