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 plugin_data
.StdCBase
= libBase
->StdCBase
;
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 */
84 #define EA_BUFFER_SIZE 4096
86 struct ExAllControl
*eac
;
87 struct ExAllData
*eabuffer
;
88 struct ExAllData
*ead
;
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
) {
99 more
= ExAll(dir
, eabuffer
, EA_BUFFER_SIZE
, ED_TYPE
, eac
);
100 if (eac
->eac_Entries
== 0) {
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) {
113 CurrentDir(curr_dir
);
114 } while ((ead
= ead
->ed_Next
));
118 FreeDosObject(DOS_EXALLCONTROL
, eac
);
123 struct FileInfoBlock
*fib
;
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) {
140 CurrentDir(curr_dir
);
144 FreeDosObject(DOS_FIB
, fib
);
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
;
163 for (i
= 0; (plugin
= plugin_table
->Plugins
[i
]); i
++) {
164 if ((plugin
->Flags
& PLUGIN_UNUSED_FLAGS
) ||
165 !(plugin
->Flags
& PLUGIN_FLAG_M68K
))
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
;
175 plugin_table
->RefCount
++;
177 if (!(plugin
->Flags
& PLUGIN_FLAG_FOOTER
)) {
178 if (plugin
->TestSize
> libBase
->HeaderTestSize
) {
179 libBase
->HeaderTestSize
= plugin
->TestSize
;
182 if (plugin
->TestSize
> libBase
->FooterTestSize
) {
183 libBase
->FooterTestSize
= plugin
->TestSize
;
186 Enqueue(libBase
->Plugins
, &plugin
->Node
);
189 return plugin_table
->RefCount
;
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
;
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
;
227 file_size
= GetFileSize(file
);
229 case 0: SetIoErr(ERROR_OBJECT_WRONG_TYPE
);
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
);
238 SetIoErr(ERROR_NO_FREE_STORE
);
241 header_test_len
= Read(file
, header_test
, header_test_size
);
242 if (header_test_len
== -1) {
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
)) {
251 footer_test
= AllocVec(footer_test_size
, MEMF_ANY
);
253 SetIoErr(ERROR_NO_FREE_STORE
);
256 footer_test_len
= Read(file
, footer_test
, footer_test_size
);
257 if (footer_test_len
== -1) {
261 if (!ChangeFilePosition(file
, 0, OFFSET_BEGINNING
)) {
266 ptr
= (struct DiskImagePlugin
*)list
->lh_Head
;
267 while (ptr
->Node
.ln_Succ
) {
268 if (!(ptr
->Flags
& PLUGIN_FLAG_FOOTER
)) {
270 test_len
= header_test_len
;
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
);
280 ptr
= (struct DiskImagePlugin
*)ptr
->Node
.ln_Succ
;
284 FreeVec(header_test
);
285 FreeVec(footer_test
);
286 SetDiskImageError(NULL
, unit
, IoErr(), 0);
290 APTR
OpenImage (APTR Self
, struct DiskImageUnit
*unit
, BPTR file
, CONST_STRPTR name
) {
291 struct DiskImagePlugin
*ptr
;
293 ptr
= FindPlugin(unit
, file
, name
);
296 return Plugin_OpenImage(ptr
, unit
, file
, name
);