1/*
2 * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 * Copyright 2012, Gerasim Troeglazov, 3dEyes@gmail.com. All rights reserved.
4 * Distributed under the terms of the MIT License.
5 */
6
7#include "ICNSTranslator.h"
8
9#include <stdlib.h>
10#include <stdio.h>
11#include <string.h>
12
13#include "ConfigView.h"
14#include "ICNSLoader.h"
15
16#include <Catalog.h>
17
18#undef B_TRANSLATION_CONTEXT
19#define B_TRANSLATION_CONTEXT "ICNSTranslator"
20
21extern "C" {
22#include "icns.h"
23}
24
25const char *kDocumentCount = "/documentCount";
26const char *kDocumentIndex = "/documentIndex";
27
28#define kICNSMimeType "image/icns"
29#define kICNSName "Apple Icon"
30
31// The input formats that this translator supports.
32static const translation_format sInputFormats[] = {
33	{
34		ICNS_IMAGE_FORMAT,
35		B_TRANSLATOR_BITMAP,
36		ICNS_IN_QUALITY,
37		ICNS_IN_CAPABILITY,
38		kICNSMimeType,
39		kICNSName
40	},
41	{
42		B_TRANSLATOR_BITMAP,
43		B_TRANSLATOR_BITMAP,
44		BITS_IN_QUALITY,
45		BITS_IN_CAPABILITY,
46		"image/x-be-bitmap",
47		"Be Bitmap Format (ICNSTranslator)"
48	},
49};
50
51// The output formats that this translator supports.
52static const translation_format sOutputFormats[] = {
53	{
54		ICNS_IMAGE_FORMAT,
55		B_TRANSLATOR_BITMAP,
56		ICNS_OUT_QUALITY,
57		ICNS_OUT_CAPABILITY,
58		kICNSMimeType,
59		kICNSName
60	},
61	{
62		B_TRANSLATOR_BITMAP,
63		B_TRANSLATOR_BITMAP,
64		BITS_OUT_QUALITY,
65		BITS_OUT_CAPABILITY,
66		"image/x-be-bitmap",
67		"Be Bitmap Format (ICNSTranslator)"
68	},
69};
70
71// Default settings for the Translator
72static const TranSetting sDefaultSettings[] = {
73	{B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false},
74	{B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false}
75};
76
77const uint32 kNumInputFormats = sizeof(sInputFormats)
78	/ sizeof(translation_format);
79const uint32 kNumOutputFormats = sizeof(sOutputFormats)
80	/ sizeof(translation_format);
81const uint32 kNumDefaultSettings = sizeof(sDefaultSettings)
82	/ sizeof(TranSetting);
83
84
85ICNSTranslator::ICNSTranslator()
86	: BaseTranslator(B_TRANSLATE("Apple icons"),
87		B_TRANSLATE("Apple icon translator"),
88		ICNS_TRANSLATOR_VERSION,
89		sInputFormats, kNumInputFormats,
90		sOutputFormats, kNumOutputFormats,
91		"ICNSTranslator",
92		sDefaultSettings, kNumDefaultSettings,
93		B_TRANSLATOR_BITMAP, ICNS_IMAGE_FORMAT)
94{
95}
96
97
98ICNSTranslator::~ICNSTranslator()
99{
100}
101
102
103status_t
104ICNSTranslator::DerivedIdentify(BPositionIO *stream,
105	const translation_format *format, BMessage *ioExtension,
106	translator_info *info, uint32 outType)
107{
108	if (!outType)
109		outType = B_TRANSLATOR_BITMAP;
110	if (outType != B_TRANSLATOR_BITMAP && outType != ICNS_IMAGE_FORMAT)
111		return B_NO_TRANSLATOR;
112
113	uint32 signatureData;
114	ssize_t signatureSize = 4;
115	if (stream->Read(&signatureData, signatureSize) != signatureSize)
116		return B_IO_ERROR;
117
118	const uint32 kICNSMagic = B_HOST_TO_BENDIAN_INT32('icns');
119
120	if (signatureData != kICNSMagic)
121		return B_ILLEGAL_DATA;
122
123
124	ICNSLoader icnsFile(stream);
125	if(!icnsFile.IsLoaded() || icnsFile.IconsCount() <= 0)
126		return B_ILLEGAL_DATA;
127
128	int32 documentCount = icnsFile.IconsCount();
129	int32 documentIndex = 1;
130
131	if (ioExtension) {
132		if (ioExtension->FindInt32(DOCUMENT_INDEX, &documentIndex) != B_OK)
133			documentIndex = 1;
134		if (documentIndex < 1 || documentIndex > documentCount)
135			return B_NO_TRANSLATOR;
136	}
137
138	if (ioExtension) {
139		ioExtension->RemoveName(DOCUMENT_COUNT);
140		ioExtension->AddInt32(DOCUMENT_COUNT, documentCount);
141	}
142
143	info->type = ICNS_IMAGE_FORMAT;
144	info->group = B_TRANSLATOR_BITMAP;
145	info->quality = ICNS_IN_QUALITY;
146	info->capability = ICNS_IN_CAPABILITY;
147	BString iconName("Apple icon");
148	if (documentCount > 1)
149		iconName << " #" << documentIndex;
150	snprintf(info->name, sizeof(info->name), iconName.String());
151	strcpy(info->MIME, kICNSMimeType);
152
153	return B_OK;
154}
155
156
157status_t
158ICNSTranslator::DerivedTranslate(BPositionIO *source,
159	const translator_info *info, BMessage *ioExtension,
160	uint32 outType, BPositionIO *target, int32 baseType)
161{
162	if (!outType)
163		outType = B_TRANSLATOR_BITMAP;
164	if (outType != B_TRANSLATOR_BITMAP && outType != ICNS_IMAGE_FORMAT)
165		return B_NO_TRANSLATOR;
166
167	switch (baseType) {
168		case 1:
169		{
170			TranslatorBitmap bitsHeader;
171			status_t result;
172			result = identify_bits_header(source, NULL, &bitsHeader);
173			if (result != B_OK)
174				return B_NO_TRANSLATOR;
175
176			icns_type_t type = ICNSFormat(bitsHeader.bounds.Width() + 1,
177				bitsHeader.bounds.Height() + 1, bitsHeader.colors);
178			if (type == ICNS_NULL_TYPE)
179				return B_NO_TRANSLATOR;
180
181			if (outType == ICNS_IMAGE_FORMAT) {
182				ICNSSaver icnsFile(source, bitsHeader.rowBytes, type);
183				if (icnsFile.IsCreated())
184					return icnsFile.SaveData(target);
185			}
186
187			return B_NO_TRANSLATOR;
188		}
189
190		case 0:
191		{
192			if (outType != B_TRANSLATOR_BITMAP)
193				return B_NO_TRANSLATOR;
194
195			ICNSLoader icnsFile(source);
196			if (!icnsFile.IsLoaded() || icnsFile.IconsCount() <= 0)
197				return B_NO_TRANSLATOR;
198
199			int32 documentIndex = 1;
200
201			if (ioExtension) {
202				if (ioExtension->FindInt32(DOCUMENT_INDEX, &documentIndex) != B_OK)
203					documentIndex = 1;
204			}
205
206			return icnsFile.GetIcon(target, documentIndex);
207		}
208
209		default:
210			return B_NO_TRANSLATOR;
211	}
212}
213
214
215status_t
216ICNSTranslator::DerivedCanHandleImageSize(float width, float height) const
217{
218	if (ICNSFormat(width, height, B_RGBA32) == ICNS_NULL_TYPE)
219		return B_NO_TRANSLATOR;
220	return B_OK;
221}
222
223
224BView *
225ICNSTranslator::NewConfigView(TranslatorSettings *settings)
226{
227	return new ConfigView(settings);
228}
229
230
231//	#pragma mark -
232
233
234BTranslator *
235make_nth_translator(int32 n, image_id you, uint32 flags, ...)
236{
237	if (n != 0)
238		return NULL;
239
240	return new ICNSTranslator();
241}
242
243