1/*
2 * Copyright 2010-2013, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Stefano Ceccherini, stefano.ceccherini@gmail.com
7 *		Siarzhuk Zharski, zharik@gmx.li
8 */
9
10
11#include "Colors.h"
12
13#include <ctype.h>
14#include <stdio.h>
15#include <strings.h>
16
17#include <Application.h>
18#include <Catalog.h>
19#include <Resources.h>
20
21
22#undef B_TRANSLATION_CONTEXT
23#define B_TRANSLATION_CONTEXT "Terminal colors scheme"
24
25
26struct color_scheme gCustomColorScheme = {
27	B_TRANSLATE("Custom")
28};
29
30
31BObjectList<const color_scheme>* gColorSchemes = NULL;
32
33
34bool
35ansi_color_scheme::operator==(const ansi_color_scheme& scheme)
36{
37	return black == scheme.black
38		&& red == scheme.red
39		&& green == scheme.green
40		&& yellow == scheme.yellow
41		&& blue == scheme.blue
42		&& magenta == scheme.magenta
43		&& cyan == scheme.cyan
44		&& white == scheme.white;
45}
46
47
48bool
49color_scheme::operator==(const color_scheme& scheme)
50{
51	return text_fore_color == scheme.text_fore_color
52		&& text_back_color == scheme.text_back_color
53		&& cursor_fore_color == scheme.cursor_fore_color
54		&& cursor_back_color == scheme.cursor_back_color
55		&& select_fore_color == scheme.select_fore_color
56		&& select_back_color == scheme.select_back_color
57		&& ansi_colors == scheme.ansi_colors
58		&& ansi_colors_h == scheme.ansi_colors_h;
59}
60
61// #pragma mark XColorsTable implementation
62
63XColorsTable gXColorsTable;
64
65
66XColorsTable::XColorsTable()
67		:
68		fTable(NULL),
69		fCount(0)
70{
71}
72
73
74XColorsTable::~XColorsTable()
75{
76	// fTable as result of LoadResource call and owned
77	// by BApplication so no need to free it explicitly
78	fTable = NULL;
79	fCount = 0;
80}
81
82
83status_t
84XColorsTable::LookUpColor(const char* name, rgb_color* color)
85{
86	if (name == NULL || color == NULL)
87		return B_BAD_DATA;
88
89	size_t length = strlen(name);
90
91	// first check for 'rgb:xx/xx/xx' or '#xxxxxx'-encoded color names
92	u_int r = 0, g = 0, b = 0;
93	float c = 0, m = 0, y = 0, k = 0;
94	if ((length == 12 && sscanf(name, "rgb:%02x/%02x/%02x", &r, &g, &b) == 3)
95		|| (length == 7 && sscanf(name, "#%02x%02x%02x", &r, &g, &b) == 3)) {
96		color->set_to(r, g, b);
97		return B_OK;
98	// then check for 'rgb:xxxx/xxxx/xxxx' or '#xxxxxxxxxxxx'-encoded color names
99	} else if ((length == 18 && sscanf(name, "rgb:%04x/%04x/%04x", &r, &g, &b) == 3)
100		|| (length == 13 && sscanf(name, "#%04x%04x%04x", &r, &g, &b) == 3)) {
101		color->set_to(r >> 8, g >> 8, b >> 8);
102		return B_OK;
103	// then check for 'cmyk:c.c/m.m/y.y/k.k' or 'cmy:c.c/m.m/y.y'-encoded color names
104	} else if (sscanf(name, "cmyk:%f/%f/%f/%f", &c, &m, &y, &k) == 4
105		|| sscanf(name, "cmy:%f/%f/%f", &c, &m, &y) == 3) {
106		if (c >= 0 && m >= 0 && y >= 0 && k >= 0
107			&& c <= 1 && m <= 1 && y <= 1 && k <= 1) {
108			color->set_to((1 - c) * (1 - k) * 255,
109				(1 - m) * (1 - k) * 255,
110				(1 - y) * (1 - k) * 255);
111			return B_OK;
112		}
113	}
114
115	// then search the X11 rgb table
116	if (fTable == NULL) {
117		status_t result = _LoadXColorsTable();
118		if (result != B_OK)
119			return result;
120	}
121
122	// use binary search to lookup color name hash in table
123	int left  = -1;
124	int right = fCount;
125	uint32 hash = _HashName(name);
126	while ((right - left) > 1) {
127		int i = (left + right) / 2;
128		((fTable[i].hash < hash) ? left : right) = i;
129	}
130
131	if (fTable[right].hash == hash) {
132		*color = fTable[right].color;
133		return B_OK;
134	}
135
136	return B_NAME_NOT_FOUND;
137}
138
139
140status_t
141XColorsTable::_LoadXColorsTable()
142{
143	BResources* res = BApplication::AppResources();
144	if (res == NULL)
145		return B_ERROR;
146
147	size_t size = 0;
148	fTable = (_XColorEntry*)res->LoadResource(B_RAW_TYPE, "XColorsTable", &size);
149	if (fTable == NULL || size < sizeof(_XColorEntry)) {
150		fTable = NULL;
151		return B_ENTRY_NOT_FOUND;
152	}
153
154	fCount = size / sizeof(_XColorEntry);
155	return B_OK;
156}
157
158
159uint32
160XColorsTable::_HashName(const char* name)
161{
162	uint32 hash = 0;
163	uint32 g = 0;
164
165	// Using modified P.J.Weinberger hash algorithm
166	// Spaces are purged out, characters are upper-cased
167	// 'E' replaced with 'A' (to join 'grey' and 'gray' variations)
168	for (const char* p = name; *p; p++) {
169		int ch = toupper(*p);
170		switch (ch) {
171		case ' ':
172			break;
173		case 'E':
174			ch = 'A';
175		default:
176			hash = (hash << 4) + (ch & 0xFF);
177			g = hash & 0xf0000000;
178			if (g != 0) {
179				hash ^= g >> 24;
180				hash ^= g;
181			}
182			break;
183		}
184	}
185
186	return hash;
187}
188