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		ioExtension->RemoveName(DOCUMENT_COUNT);
138		ioExtension->AddInt32(DOCUMENT_COUNT, documentCount);
139	}
140
141	info->type = ICNS_IMAGE_FORMAT;
142	info->group = B_TRANSLATOR_BITMAP;
143	info->quality = ICNS_IN_QUALITY;
144	info->capability = ICNS_IN_CAPABILITY;
145	BString iconName("Apple icon");
146	if (documentCount > 1)
147		iconName << " #" << documentIndex;
148	strlcpy(info->name, iconName.String(), sizeof(info->name));
149	strcpy(info->MIME, kICNSMimeType);
150
151	return B_OK;
152}
153
154
155status_t
156ICNSTranslator::DerivedTranslate(BPositionIO *source,
157	const translator_info *info, BMessage *ioExtension,
158	uint32 outType, BPositionIO *target, int32 baseType)
159{
160	if (!outType)
161		outType = B_TRANSLATOR_BITMAP;
162	if (outType != B_TRANSLATOR_BITMAP && outType != ICNS_IMAGE_FORMAT)
163		return B_NO_TRANSLATOR;
164
165	switch (baseType) {
166		case 1:
167		{
168			TranslatorBitmap bitsHeader;
169			status_t result;
170			result = identify_bits_header(source, NULL, &bitsHeader);
171			if (result != B_OK)
172				return B_NO_TRANSLATOR;
173
174			icns_type_t type = ICNSFormat(bitsHeader.bounds.Width() + 1,
175				bitsHeader.bounds.Height() + 1, bitsHeader.colors);
176			if (type == ICNS_NULL_TYPE)
177				return B_NO_TRANSLATOR;
178
179			if (outType == ICNS_IMAGE_FORMAT) {
180				ICNSSaver icnsFile(source, bitsHeader.rowBytes, type);
181				if (icnsFile.IsCreated())
182					return icnsFile.SaveData(target);
183			}
184
185			return B_NO_TRANSLATOR;
186		}
187
188		case 0:
189		{
190			if (outType != B_TRANSLATOR_BITMAP)
191				return B_NO_TRANSLATOR;
192
193			ICNSLoader icnsFile(source);
194			if (!icnsFile.IsLoaded() || icnsFile.IconsCount() <= 0)
195				return B_NO_TRANSLATOR;
196
197			int32 documentIndex = 1;
198
199			if (ioExtension) {
200				if (ioExtension->FindInt32(DOCUMENT_INDEX, &documentIndex) != B_OK)
201					documentIndex = 1;
202			}
203
204			return icnsFile.GetIcon(target, documentIndex);
205		}
206
207		default:
208			return B_NO_TRANSLATOR;
209	}
210}
211
212
213status_t
214ICNSTranslator::DerivedCanHandleImageSize(float width, float height) const
215{
216	if (ICNSFormat(width, height, B_RGBA32) == ICNS_NULL_TYPE)
217		return B_NO_TRANSLATOR;
218	return B_OK;
219}
220
221
222BView *
223ICNSTranslator::NewConfigView(TranslatorSettings *settings)
224{
225	return new ConfigView(settings);
226}
227
228
229//	#pragma mark -
230
231
232BTranslator *
233make_nth_translator(int32 n, image_id you, uint32 flags, ...)
234{
235	if (n != 0)
236		return NULL;
237
238	return new ICNSTranslator();
239}
240
241