20130313
[gdash.git] / src / fileops / loadfile.cpp
blob4fdf1614bafa2ae623a4d0420267e13ee55f9464
1 /*
2 * Copyright (c) 2007-2013, Czirkos Zoltan http://code.google.com/p/gdash/
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include "fileops/loadfile.hpp"
19 #include <glib/gi18n.h>
20 #include <stdexcept>
21 #include <fstream>
22 #include "cave/caveset.hpp"
23 #include "fileops/binaryimport.hpp"
24 #include "fileops/brcimport.hpp"
25 #include "fileops/c64import.hpp"
26 #include "fileops/bdcffload.hpp"
27 #include "misc/logger.hpp"
28 #include "misc/util.hpp"
30 /** load some caveset from the binary data in the buffer.
31 * the length may be -1, if the caller is pretty sure of what he's doing. */
32 CaveSet create_from_buffer(const unsigned char *buffer, int length, char const *filename) {
33 /* set logging context to filename */
34 SetLoggerContextForFunction finally(gd_tostring_free(g_filename_display_basename(filename)));
36 /* try to load as a .GDS file */
37 if ((length >= 12 || length == -1) && C64Import::imported_get_format(buffer) != C64Import::GD_FORMAT_UNKNOWN) {
38 std::vector<CaveStored *> new_caveset = C64Import::caves_import_from_buffer(buffer, length);
39 /* if unable to load, exit here. error was reported by import_from_buffer() */
40 if (new_caveset.empty())
41 throw std::runtime_error(_("Error loading GDS file."));
42 /* no serious error :) */
43 CaveSet newcaves;
44 for (std::vector<CaveStored *>::iterator it=new_caveset.begin(); it!=new_caveset.end(); ++it)
45 newcaves.caves.push_back_adopt(*it);
46 newcaves.last_selected_cave=newcaves.first_selectable_cave_index();
47 newcaves.set_name_from_filename(filename);
48 return newcaves;
51 /* try to load as a BRC file (boulder remake) */
52 if (g_str_has_suffix(filename, ".brc") || g_str_has_suffix(filename, "*.BRC")) {
53 if (length != 96000) {
54 throw std::runtime_error(_("BRC files must be 96000 bytes long."));
56 CaveSet newcaves;
57 brc_import(newcaves, (guint8*) buffer);
58 newcaves.last_selected_cave = newcaves.first_selectable_cave_index();
59 newcaves.set_name_from_filename(filename);
60 return newcaves;
63 /* try to load as BDCFF */
64 if (g_str_has_suffix(filename, ".bd") || g_str_has_suffix(filename, ".BD")) {
65 CaveSet newcaves = load_from_bdcff((char const *) buffer);
66 newcaves.last_selected_cave = newcaves.first_selectable_cave_index();
67 /* remember filename, as the input is a bdcff file */
68 newcaves.filename = filename;
69 return newcaves;
72 /* if could not determine file format so far, try to load as a snapshot file */
73 if (g_str_has_suffix(filename, ".vsf") || g_str_has_suffix(filename, ".VSF")
74 || length == 65536 || length == 65538) {
75 std::vector<unsigned char> memory = load_memory_dump(buffer, length);
76 std::vector<unsigned char> imported = gdash_binary_import(memory);
77 return create_from_buffer(&imported[0], imported.size(), filename);
80 throw std::runtime_error(_("Cannot determine file format."));
84 /**
85 * Create a caveset by loading it from a file.
86 * @param filename The name of the file, which can be BDCFF or other binary formats.
87 * @return The caveset loaded. If impossible to load, throws an exception.
89 CaveSet create_from_file(const char *filename) throw (std::runtime_error) {
90 std::vector<unsigned char> contents = load_file_to_vector(filename);
91 /* -1 because the loader adds a terminating zero */
92 return create_from_buffer(&contents[0], contents.size()-1, filename);
96 /**
97 * Load a file to an array of bytes.
98 * @param filename The name of the file.
99 * @return The file loaded. If impossible to load, throws an exception.
101 std::vector<unsigned char> load_file_to_vector(char const *filename) {
102 /* open file */
103 std::ifstream is;
104 is.open(filename, std::ios::in | std::ios::binary);
105 if (!is)
106 throw std::runtime_error(_("Unable to open file."));
107 /* check size */
108 is.seekg(0, is.end);
109 int filesize = is.tellg();
110 is.seekg(0, is.beg);
111 if (filesize > (2 * 1<<20))
112 throw std::runtime_error(_("File bigger than 2MiB, refusing to load."));
113 /* read file. the vector will be one bytes bigger, so it can be added a terminating zero char. */
114 std::vector<unsigned char> contents(filesize+1);
115 if (!is.read((char *) &contents[0], filesize))
116 throw std::runtime_error(_("Unable to read file."));
117 is.close();
118 contents[filesize] = '\0';
120 return contents;