1/*
2 * Copyright 2006-2007, Haiku. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Stephan A��mus <superstippi@gmx.de>
7 */
8
9
10#include "FlatIconFormat.h"
11
12#include "LittleEndianBuffer.h"
13
14
15_BEGIN_ICON_NAMESPACE
16
17
18const uint32 FLAT_ICON_MAGIC = 'ficn';
19
20const char* kVectorAttrNodeName = "BEOS:ICON";
21const char* kVectorAttrMimeName = "META:ICON";
22
23
24// read_coord
25bool
26read_coord(LittleEndianBuffer& buffer, float& coord)
27{
28	uint8 value;
29	if (!buffer.Read(value))
30		return false;
31
32	if (value & 128) {
33		// high bit set, the next byte is part of the coord
34		uint8 lowValue;
35		if (!buffer.Read(lowValue))
36			return false;
37		value &= 127;
38		uint16 coordValue = (value << 8) | lowValue;
39		coord = (float)coordValue / 102.0 - 128.0;
40	} else {
41		// simple coord
42		coord = (float)value - 32.0;
43	}
44	return true;
45}
46
47// write_coord
48bool
49write_coord(LittleEndianBuffer& buffer, float coord)
50{
51	// clamp coord
52	if (coord < -128.0)
53		coord = -128.0;
54	if (coord > 192.0)
55		coord = 192.0;
56
57	if (int(coord * 100.0) == (int)coord * 100
58		&& coord >= - 32.0 && coord <= 95.0) {
59		// saving coord in 7 bit is sufficient
60		uint8 value = (uint8)(coord + 32.0);
61		return buffer.Write(value);
62	} else {
63		// needing to save coord in 15 bits
64		uint16 value = (uint16)((coord + 128.0) * 102.0);
65		// set high bit to indicate there is only one byte
66		value |= 32768;
67		uint8 highValue = value >> 8;
68		uint8 lowValue = value & 255;
69		return buffer.Write(highValue) && buffer.Write(lowValue);
70	}
71}
72
73// read_float_24
74bool
75read_float_24(LittleEndianBuffer& buffer, float& _value)
76{
77	uint8 bufferValue[3];
78	if (!buffer.Read(bufferValue[0]) || !buffer.Read(bufferValue[1])
79		|| !buffer.Read(bufferValue[2]))
80		return false;
81
82	int shortValue = (bufferValue[0] << 16)
83		| (bufferValue[1] << 8) | bufferValue[2];
84
85	int sign = (shortValue & 0x800000) >> 23;
86	int exponent = ((shortValue & 0x7e0000) >> 17) - 32;
87	int mantissa = (shortValue & 0x01ffff) << 6;
88
89	if (shortValue == 0)
90		_value = 0.0;
91	else {
92		union {
93			uint32 intValue;
94			float floatValue;
95		} i2f;
96		i2f.intValue = (sign << 31) | ((exponent + 127) << 23) | mantissa;
97		_value = i2f.floatValue;
98	}
99
100	return true;
101}
102
103// write_float_24
104bool
105write_float_24(LittleEndianBuffer& buffer, float _value)
106{
107	// 1 bit sign
108	// 6 bit exponent
109	// 17 bit mantissa
110	// TODO: fixme for non-IEEE 754 architectures
111	union {
112		float floatValue;
113		uint32 intValue;
114	} f2i;
115	f2i.floatValue = _value;
116
117	int sign = (f2i.intValue & 0x80000000) >> 31;
118	int exponent = ((f2i.intValue & 0x7f800000) >> 23) - 127;
119	int mantissa = f2i.intValue & 0x007fffff;
120
121	if (exponent >= 32 || exponent < -32) {
122		uint8 zero = 0;
123		return buffer.Write(zero) && buffer.Write(zero)
124			&& buffer.Write(zero);
125	}
126
127	int shortValue = (sign << 23)
128					 | ((exponent + 32) << 17)
129					 | (mantissa >> 6);
130
131	return buffer.Write((uint8)(shortValue >> 16))
132		&& buffer.Write((uint8)((shortValue >> 8) & 0xff))
133		&& buffer.Write((uint8)(shortValue & 0xff));
134}
135
136
137_END_ICON_NAMESPACE
138