1 /* Copyright 2007-2012 Fredrik Wikstrom. All rights reserved.
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
7 ** 1. Redistributions of source code must retain the above copyright
8 ** notice, this list of conditions and the following disclaimer.
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>
32 #define EAD_IS_FILE(ead) ((ead)->ed_Type < 0)
36 #define FIB_IS_FILE(fib) ((fib)->fib_DirEntryType < 0)
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
[] = {
52 static struct DiskImagePluginTable builtin_plugin_table
= {
54 USED_PLUGIN_API_VERSION
,
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 */
81 #define EA_BUFFER_SIZE 4096
83 struct ExAllControl
*eac
;
84 struct ExAllData
*eabuffer
;
85 struct ExAllData
*ead
;
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
) {
96 more
= ExAll(dir
, eabuffer
, EA_BUFFER_SIZE
, ED_TYPE
, eac
);
97 if (eac
->eac_Entries
== 0) {
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) {
110 CurrentDir(curr_dir
);
111 } while ((ead
= ead
->ed_Next
));
115 FreeDosObject(DOS_EXALLCONTROL
, eac
);
120 struct FileInfoBlock
*fib
;
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) {
137 CurrentDir(curr_dir
);
141 FreeDosObject(DOS_FIB
, fib
);
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
;
160 for (i
= 0; (plugin
= plugin_table
->Plugins
[i
]); i
++) {
161 if ((plugin
->Flags
& PLUGIN_UNUSED_FLAGS
) ||
162 !(plugin
->Flags
& PLUGIN_FLAG_M68K
))
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
;
172 plugin_table
->RefCount
++;
174 if (!(plugin
->Flags
& PLUGIN_FLAG_FOOTER
)) {
175 if (plugin
->TestSize
> libBase
->HeaderTestSize
) {
176 libBase
->HeaderTestSize
= plugin
->TestSize
;
179 if (plugin
->TestSize
> libBase
->FooterTestSize
) {
180 libBase
->FooterTestSize
= plugin
->TestSize
;
183 Enqueue(libBase
->Plugins
, &plugin
->Node
);
186 return plugin_table
->RefCount
;
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
;
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
;
224 file_size
= GetFileSize(file
);
226 case 0: SetIoErr(ERROR_OBJECT_WRONG_TYPE
);
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
);
235 SetIoErr(ERROR_NO_FREE_STORE
);
238 header_test_len
= Read(file
, header_test
, header_test_size
);
239 if (header_test_len
== -1) {
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
)) {
248 footer_test
= AllocVec(footer_test_size
, MEMF_ANY
);
250 SetIoErr(ERROR_NO_FREE_STORE
);
253 footer_test_len
= Read(file
, footer_test
, footer_test_size
);
254 if (footer_test_len
== -1) {
258 if (!ChangeFilePosition(file
, 0, OFFSET_BEGINNING
)) {
263 ptr
= (struct DiskImagePlugin
*)list
->lh_Head
;
264 while (ptr
->Node
.ln_Succ
) {
265 if (!(ptr
->Flags
& PLUGIN_FLAG_FOOTER
)) {
267 test_len
= header_test_len
;
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
);
277 ptr
= (struct DiskImagePlugin
*)ptr
->Node
.ln_Succ
;
281 FreeVec(header_test
);
282 FreeVec(footer_test
);
283 SetDiskImageError(NULL
, unit
, IoErr(), 0);
287 APTR
OpenImage (APTR Self
, struct DiskImageUnit
*unit
, BPTR file
, CONST_STRPTR name
) {
288 struct DiskImagePlugin
*ptr
;
290 ptr
= FindPlugin(unit
, file
, name
);
293 return Plugin_OpenImage(ptr
, unit
, file
, name
);