1 /*
2  *    Copyright 2013-2016, 2018 Kai Pastor
3  *
4  *    Some parts taken from file_format_oc*d8{.h,_p.h,cpp} which are
5  *    Copyright 2012 Pete Curtis
6  *
7  *    This file is part of OpenOrienteering.
8  *
9  *    OpenOrienteering is free software: you can redistribute it and/or modify
10  *    it under the terms of the GNU General Public License as published by
11  *    the Free Software Foundation, either version 3 of the License, or
12  *    (at your option) any later version.
13  *
14  *    OpenOrienteering is distributed in the hope that it will be useful,
15  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *    GNU General Public License for more details.
18  *
19  *    You should have received a copy of the GNU General Public License
20  *    along with OpenOrienteering.  If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include "ocd_file_format.h"
24 
25 // IWYU pragma: no_include <algorithm>
26 #include <memory>
27 
28 #include <QtGlobal>
29 #include <QFlags>
30 #include <QString>
31 
32 #include "fileformats/file_import_export.h"
33 #include "fileformats/ocad8_file_format_p.h"
34 #include "fileformats/ocd_file_export.h"
35 #include "fileformats/ocd_file_import.h"
36 
37 
38 namespace OpenOrienteering {
39 
40 namespace {
41 
labelForVersion(quint16 version)42 QString labelForVersion(quint16 version)
43 {
44 	switch (version)
45 	{
46 	case OcdFileFormat::autoDeterminedVersion():
47 		return ::OpenOrienteering::ImportExport::tr("OCAD");
48 	case OcdFileFormat::legacyVersion():
49 		return ::OpenOrienteering::ImportExport::tr("OCAD version 8, old implementation");
50 	default:
51 		return ::OpenOrienteering::ImportExport::tr("OCAD version %1").arg(version);
52 	}
53 }
54 
featuresForVersion(quint16 version)55 FileFormat::Features featuresForVersion(quint16 version)
56 {
57 	switch (version)
58 	{
59 	case OcdFileFormat::legacyVersion():
60 		return FileFormat::Feature::FileOpen | FileFormat::Feature::FileImport | FileFormat::Feature::ReadingLossy |
61 		       FileFormat::Feature::FileSave | FileFormat::Feature::FileSaveAs | FileFormat::Feature::WritingLossy;
62 
63 	case OcdFileFormat::autoDeterminedVersion():
64 		// Intentionally no FileFormat::ExportSupported. This prevents this
65 		// format from being shown in the Save-as dialog. However, it is legal
66 		// to create an exporter for the autoDeterminedVersion(). The actual
67 		// export version will be determined from the Map's versionProperty()
68 		// if possible, or from OcdFileExport::default_version.
69 		return FileFormat::Feature::FileOpen | FileFormat::Feature::FileImport | FileFormat::Feature::ReadingLossy |
70 		       FileFormat::Feature::FileSave | FileFormat::Feature::WritingLossy;
71 
72 	default:
73 		// Intentionally no FileFormat::ImportSupported. Import is handled
74 		// by the autoDeterminedVersion().
75 		return FileFormat::Feature::FileSave | FileFormat::Feature::FileSaveAs | FileFormat::Feature::WritingLossy;
76 	}
77 }
78 
79 }  // namespace
80 
81 
82 
83 // ### OcdFileFormat ###
84 
85 // static
idForVersion(quint16 version)86 const char* OcdFileFormat::idForVersion(quint16 version)
87 {
88 	switch (version)
89 	{
90 	case OcdFileFormat::autoDeterminedVersion():
91 		return "OCD";
92 	case 8:
93 		return "OCD8";
94 	case 9:
95 		return "OCD9";
96 	case 10:
97 		return "OCD10";
98 	case 11:
99 		return "OCD11";
100 	case 12:
101 		return "OCD12";
102 	case OcdFileFormat::legacyVersion():
103 		return "OCD-legacy";
104 	default:
105 		qFatal("Unsupported OCD version");
106 	}
107 }
108 
109 
110 // static
makeAll()111 std::vector<std::unique_ptr<OcdFileFormat>> OcdFileFormat::makeAll()
112 {
113 	std::vector<std::unique_ptr<OcdFileFormat>> result;
114 	result.reserve(7);
115 	result.push_back(std::make_unique<OcdFileFormat>(autoDeterminedVersion()));
116 	result.push_back(std::make_unique<OcdFileFormat>(12));
117 	result.push_back(std::make_unique<OcdFileFormat>(11));
118 	result.push_back(std::make_unique<OcdFileFormat>(10));
119 	result.push_back(std::make_unique<OcdFileFormat>(9));
120 	result.push_back(std::make_unique<OcdFileFormat>(8));
121 	result.push_back(std::make_unique<OcdFileFormat>(legacyVersion()));
122 	return result;
123 }
124 
125 
126 
OcdFileFormat(quint16 version)127 OcdFileFormat::OcdFileFormat(quint16 version)
128 : FileFormat { MapFile, idForVersion(version), labelForVersion(version), QStringLiteral("ocd"), featuresForVersion(version) }
129 , version { version }
130 {
131 	// Nothing
132 }
133 
134 
135 
understands(const char * buffer,int size) const136 FileFormat::ImportSupportAssumption OcdFileFormat::understands(const char* buffer, int size) const
137 {
138 	// The first two bytes of the file must be AD 0C.
139 	if (size < 2)
140 		return Unknown;
141 	else if (quint8(buffer[0]) == 0xAD && buffer[1] == 0x0C)
142 		return FullySupported;
143 	else
144 		return NotSupported;
145 }
146 
147 
makeImporter(const QString & path,Map * map,MapView * view) const148 std::unique_ptr<Importer> OcdFileFormat::makeImporter(const QString& path, Map *map, MapView *view) const
149 {
150 	if (version == legacyVersion())
151 		return std::make_unique<OCAD8FileImport>(path, map, view);
152 	return std::make_unique<OcdFileImport>(path, map, view);
153 }
154 
makeExporter(const QString & path,const Map * map,const MapView * view) const155 std::unique_ptr<Exporter> OcdFileFormat::makeExporter(const QString& path, const Map* map, const MapView* view) const
156 {
157 	if (version == legacyVersion())
158 		return std::make_unique<OCAD8FileExport>(path, map, view);
159 	return std::make_unique<OcdFileExport>(path, map, view, version);
160 }
161 
162 
163 }  // namespace OpenOrienteering
164