xref: /haiku/src/preferences/keymap/Keymap.cpp (revision 91054f1d38dd7827c0f0ba9490c213775ec7b471)
1 /*
2  * Copyright 2004-2009 Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Sandor Vroemisse
7  *		Jérôme Duval
8  *		Axel Dörfler, axeld@pinc-software.de.
9  */
10 
11 #include "Keymap.h"
12 
13 #include <new>
14 #include <stdio.h>
15 #include <string.h>
16 
17 #include <ByteOrder.h>
18 #include <File.h>
19 
20 #include <input_globals.h>
21 
22 
23 static const uint32 kModifierKeys = B_SHIFT_KEY | B_COMMAND_KEY | B_CONTROL_KEY
24 	| B_CAPS_LOCK | B_OPTION_KEY | B_MENU_KEY;
25 
26 
27 static void
28 print_key(char *chars, int32 offset)
29 {
30 	int size = chars[offset++];
31 
32 	switch (size) {
33 		case 0:
34 			// Not mapped
35 			printf("N/A");
36 			break;
37 
38 		case 1:
39 			// 1-byte UTF-8/ASCII character
40 			printf("%c", chars[offset]);
41 			break;
42 
43 		default:
44 		{
45 			// 2-, 3-, or 4-byte UTF-8 character
46 			char *str = new char[size + 1];
47 			strncpy(str, &chars[offset], size);
48 			str[size] = 0;
49 			printf("%s", str);
50 			delete[] str;
51 			break;
52 		}
53 	}
54 
55 	printf("\t");
56 }
57 
58 
59 //	#pragma mark -
60 
61 
62 Keymap::Keymap()
63 	:
64 	fChars(NULL),
65 	fCharsSize(0),
66 	fModificationMessage(NULL)
67 {
68 }
69 
70 
71 Keymap::~Keymap()
72 {
73 	delete fModificationMessage;
74 }
75 
76 
77 void
78 Keymap::SetTarget(BMessenger target, BMessage* modificationMessage)
79 {
80 	delete fModificationMessage;
81 
82 	fTarget = target;
83 	fModificationMessage = modificationMessage;
84 }
85 
86 
87 void
88 Keymap::DumpKeymap()
89 {
90 	// Print a chart of the normal, shift, option, and option+shift
91 	// keys.
92 	printf("Key #\tNormal\tShift\tCaps\tC+S\tOption\tO+S\tO+C\tO+C+S\tControl\n");
93 	for (int i = 0; i < 128; i++) {
94 		printf(" 0x%x\t", i);
95 		print_key(fChars, fKeys.normal_map[i]);
96 		print_key(fChars, fKeys.shift_map[i]);
97 		print_key(fChars, fKeys.caps_map[i]);
98 		print_key(fChars, fKeys.caps_shift_map[i]);
99 		print_key(fChars, fKeys.option_map[i]);
100 		print_key(fChars, fKeys.option_shift_map[i]);
101 		print_key(fChars, fKeys.option_caps_map[i]);
102 		print_key(fChars, fKeys.option_caps_shift_map[i]);
103 		print_key(fChars, fKeys.control_map[i]);
104 		printf("\n");
105 	}
106 }
107 
108 
109 /*
110 	file format in big endian :
111 	struct key_map
112 	uint32 size of following charset
113 	charset (offsets go into this with size of character followed by character)
114 */
115 // we load a map from a file
116 status_t
117 Keymap::Load(entry_ref &ref)
118 {
119 	status_t err;
120 	BEntry entry(&ref, true);
121 	if ((err = entry.InitCheck()) != B_OK) {
122 		fprintf(stderr, "error loading keymap: %s\n", strerror(err));
123 		return err;
124 	}
125 
126 	BFile file(&entry, B_READ_ONLY);
127 	if ((err = file.InitCheck()) != B_OK) {
128 		fprintf(stderr, "error loading keymap: %s\n", strerror(err));
129 		return err;
130 	}
131 
132 	if ((err = file.Read(&fKeys, sizeof(fKeys))) < (ssize_t)sizeof(fKeys)) {
133 		fprintf(stderr, "error reading keymap keys: %s\n", strerror(err));
134 		return B_BAD_VALUE;
135 	}
136 
137 	for (uint32 i=0; i<sizeof(fKeys)/4; i++)
138 		((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]);
139 
140 	if ((err = file.Read(&fCharsSize, sizeof(uint32))) < (ssize_t)sizeof(uint32)) {
141 		fprintf(stderr, "error reading keymap size: %s\n", strerror(err));
142 		return B_BAD_VALUE;
143 	}
144 
145 	fCharsSize = B_BENDIAN_TO_HOST_INT32(fCharsSize);
146 	delete[] fChars;
147 
148 	fChars = new char[fCharsSize];
149 
150 	err = file.Read(fChars, fCharsSize);
151 	if (err < B_OK) {
152 		fprintf(stderr, "error reading keymap chars: %s\n", strerror(err));
153 	}
154 	strlcpy(fName, ref.name, sizeof(fName));
155 	return err;
156 }
157 
158 
159 //!	We save a map to a file
160 status_t
161 Keymap::Save(entry_ref& ref)
162 {
163 	BFile file;
164 	status_t status = file.SetTo(&ref,
165 		B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
166 	if (status != B_OK) {
167 		printf("error %s\n", strerror(status));
168 		return status;
169 	}
170 
171 	for (uint32 i = 0; i < sizeof(fKeys) / 4; i++) {
172 		((uint32*)&fKeys)[i] = B_HOST_TO_BENDIAN_INT32(((uint32*)&fKeys)[i]);
173 	}
174 
175 	ssize_t bytesWritten = file.Write(&fKeys, sizeof(fKeys));
176 	if (bytesWritten < (ssize_t)sizeof(fKeys)) {
177 		if (bytesWritten < 0)
178 			return bytesWritten;
179 		return B_IO_ERROR;
180 	}
181 
182 	for (uint32 i = 0; i < sizeof(fKeys) / 4; i++) {
183 		((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]);
184 	}
185 
186 	fCharsSize = B_HOST_TO_BENDIAN_INT32(fCharsSize);
187 
188 	bytesWritten = file.Write(&fCharsSize, sizeof(uint32));
189 	if (bytesWritten < (ssize_t)sizeof(uint32)) {
190 		if (bytesWritten < 0)
191 			return bytesWritten;
192 		return B_IO_ERROR;
193 	}
194 
195 	fCharsSize = B_BENDIAN_TO_HOST_INT32(fCharsSize);
196 
197 	bytesWritten = file.Write(fChars, fCharsSize);
198 	if (bytesWritten < (ssize_t)fCharsSize) {
199 		if (bytesWritten < 0)
200 			return bytesWritten;
201 		return B_IO_ERROR;
202 	}
203 
204 	file.WriteAttr("keymap:name", B_STRING_TYPE, 0, fName, strlen(fName));
205 		// Failing would be non-fatal
206 
207 	return B_OK;
208 }
209 
210 
211 bool
212 Keymap::Equals(const Keymap& other) const
213 {
214 	// not really efficient but this is the only way i found
215 	// to reliably compare keymaps (used only for apply and revert)
216 	return fCharsSize == other.fCharsSize
217 		&& !memcmp(&other.fKeys, &fKeys, sizeof(key_map))
218 		&& !memcmp(other.fChars, fChars, fCharsSize);
219 }
220 
221 
222 /*!	We need to know if a key is a modifier key to choose
223 	a valid key when several are pressed together.
224 */
225 bool
226 Keymap::IsModifierKey(uint32 keyCode)
227 {
228 	return keyCode == fKeys.caps_key
229 		|| keyCode == fKeys.num_key
230 		|| keyCode == fKeys.scroll_key
231 		|| keyCode == fKeys.left_shift_key
232 		|| keyCode == fKeys.right_shift_key
233 		|| keyCode == fKeys.left_command_key
234 		|| keyCode == fKeys.right_command_key
235 		|| keyCode == fKeys.left_control_key
236 		|| keyCode == fKeys.right_control_key
237 		|| keyCode == fKeys.left_option_key
238 		|| keyCode == fKeys.right_option_key
239 		|| keyCode == fKeys.menu_key;
240 }
241 
242 
243 //! We need to know a modifier for a key
244 uint32
245 Keymap::Modifier(uint32 keyCode)
246 {
247 	if (keyCode == fKeys.caps_key)
248 		return B_CAPS_LOCK;
249 	if (keyCode == fKeys.num_key)
250 		return B_NUM_LOCK;
251 	if (keyCode == fKeys.scroll_key)
252 		return B_SCROLL_LOCK;
253 	if (keyCode == fKeys.left_shift_key)
254 		return B_LEFT_SHIFT_KEY | B_SHIFT_KEY;
255 	if (keyCode == fKeys.right_shift_key)
256 		return B_RIGHT_SHIFT_KEY | B_SHIFT_KEY;
257 	if (keyCode == fKeys.left_command_key)
258 		return B_LEFT_COMMAND_KEY | B_COMMAND_KEY;
259 	if (keyCode == fKeys.right_command_key)
260 		return B_RIGHT_COMMAND_KEY | B_COMMAND_KEY;
261 	if (keyCode == fKeys.left_control_key)
262 		return B_LEFT_CONTROL_KEY | B_CONTROL_KEY;
263 	if (keyCode == fKeys.right_control_key)
264 		return B_RIGHT_CONTROL_KEY | B_CONTROL_KEY;
265 	if (keyCode == fKeys.left_option_key)
266 		return B_LEFT_OPTION_KEY | B_OPTION_KEY;
267 	if (keyCode == fKeys.right_option_key)
268 		return B_RIGHT_OPTION_KEY | B_OPTION_KEY;
269 	if (keyCode == fKeys.menu_key)
270 		return B_MENU_KEY;
271 
272 	return 0;
273 }
274 
275 
276 uint32
277 Keymap::KeyForModifier(uint32 modifier)
278 {
279 	if (modifier == B_CAPS_LOCK)
280 		return fKeys.caps_key;
281 	if (modifier == B_NUM_LOCK)
282 		return fKeys.num_key;
283 	if (modifier == B_SCROLL_LOCK)
284 		return fKeys.scroll_key;
285 	if (modifier == B_LEFT_SHIFT_KEY || modifier == B_SHIFT_KEY)
286 		return fKeys.left_shift_key;
287 	if (modifier == B_RIGHT_SHIFT_KEY)
288 		return fKeys.right_shift_key;
289 	if (modifier == B_LEFT_COMMAND_KEY || modifier == B_COMMAND_KEY)
290 		return fKeys.left_command_key;
291 	if (modifier == B_RIGHT_COMMAND_KEY)
292 		return fKeys.right_command_key;
293 	if (modifier == B_LEFT_CONTROL_KEY || modifier == B_CONTROL_KEY)
294 		return fKeys.left_control_key;
295 	if (modifier == B_RIGHT_CONTROL_KEY)
296 		return fKeys.right_control_key;
297 	if (modifier == B_LEFT_OPTION_KEY || modifier == B_OPTION_KEY)
298 		return fKeys.left_option_key;
299 	if (modifier == B_RIGHT_OPTION_KEY)
300 		return fKeys.right_option_key;
301 	if (modifier == B_MENU_KEY)
302 		return fKeys.menu_key;
303 
304 	return 0;
305 }
306 
307 
308 status_t
309 Keymap::SetModifier(uint32 keyCode, uint32 modifier)
310 {
311 	const uint32 kSingleKeys = B_LEFT_SHIFT_KEY | B_RIGHT_SHIFT_KEY
312 		| B_LEFT_COMMAND_KEY | B_RIGHT_COMMAND_KEY | B_LEFT_CONTROL_KEY
313 		| B_RIGHT_CONTROL_KEY | B_LEFT_OPTION_KEY | B_RIGHT_OPTION_KEY;
314 
315 	if ((modifier & kSingleKeys) != 0)
316 		modifier &= kSingleKeys;
317 	else if ((modifier & kModifierKeys) != 0)
318 		modifier &= kModifierKeys;
319 
320 	if (modifier == B_CAPS_LOCK)
321 		fKeys.caps_key = keyCode;
322 	else if (modifier == B_NUM_LOCK)
323 		fKeys.num_key = keyCode;
324 	else if (modifier == B_SCROLL_LOCK)
325 		fKeys.scroll_key = keyCode;
326 	else if (modifier == B_LEFT_SHIFT_KEY)
327 		fKeys.left_shift_key = keyCode;
328 	else if (modifier == B_RIGHT_SHIFT_KEY)
329 		fKeys.right_shift_key = keyCode;
330 	else if (modifier == B_LEFT_COMMAND_KEY)
331 		fKeys.left_command_key = keyCode;
332 	else if (modifier == B_RIGHT_COMMAND_KEY)
333 		fKeys.right_command_key = keyCode;
334 	else if (modifier == B_LEFT_CONTROL_KEY)
335 		fKeys.left_control_key = keyCode;
336 	else if (modifier == B_RIGHT_CONTROL_KEY)
337 		fKeys.right_control_key = keyCode;
338 	else if (modifier == B_LEFT_OPTION_KEY)
339 		fKeys.left_option_key = keyCode;
340 	else if (modifier == B_RIGHT_OPTION_KEY)
341 		fKeys.right_option_key = keyCode;
342 	else if (modifier == B_MENU_KEY)
343 		fKeys.menu_key = keyCode;
344 	else
345 		return B_BAD_VALUE;
346 
347 	if (fModificationMessage != NULL)
348 		fTarget.SendMessage(fModificationMessage);
349 
350 	return B_OK;
351 }
352 
353 
354 //! Checks whether a key is a dead key.
355 uint8
356 Keymap::IsDeadKey(uint32 keyCode, uint32 modifiers)
357 {
358 	if (fChars == NULL)
359 		return 0;
360 
361 	uint32 tableMask = 0;
362 	int32 offset = _Offset(keyCode, modifiers, &tableMask);
363 	if (offset <= 0)
364 		return 0;
365 
366 	uint32 numBytes = fChars[offset];
367 	if (!numBytes)
368 		return 0;
369 
370 	char chars[4];
371 	strncpy(chars, &fChars[offset + 1], numBytes);
372 	chars[numBytes] = 0;
373 
374 	int32 deadOffsets[] = {
375 		fKeys.acute_dead_key[1],
376 		fKeys.grave_dead_key[1],
377 		fKeys.circumflex_dead_key[1],
378 		fKeys.dieresis_dead_key[1],
379 		fKeys.tilde_dead_key[1]
380 	};
381 
382 	uint32 deadTables[] = {
383 		fKeys.acute_tables,
384 		fKeys.grave_tables,
385 		fKeys.circumflex_tables,
386 		fKeys.dieresis_tables,
387 		fKeys.tilde_tables
388 	};
389 
390 	for (int32 i = 0; i < 5; i++) {
391 		if ((deadTables[i] & tableMask) == 0)
392 			continue;
393 
394 		if (offset == deadOffsets[i])
395 			return i + 1;
396 
397 		uint32 deadNumBytes = fChars[deadOffsets[i]];
398 		if (!deadNumBytes)
399 			continue;
400 
401 		if (strncmp(chars, &fChars[deadOffsets[i] + 1], deadNumBytes) == 0)
402 			return i + 1;
403 	}
404 	return 0;
405 }
406 
407 
408 //! Tell if a key is a dead second key, needed for draw a dead second key.
409 bool
410 Keymap::IsDeadSecondKey(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey)
411 {
412 	if (!activeDeadKey)
413 		return false;
414 
415 	int32 offset = _Offset(keyCode, modifiers);
416 	if (offset < 0)
417 		return false;
418 
419 	uint32 numBytes = fChars[offset];
420 	if (!numBytes)
421 		return false;
422 
423 	int32* deadOffsets[] = {
424 		fKeys.acute_dead_key,
425 		fKeys.grave_dead_key,
426 		fKeys.circumflex_dead_key,
427 		fKeys.dieresis_dead_key,
428 		fKeys.tilde_dead_key
429 	};
430 
431 	int32 *deadOffset = deadOffsets[activeDeadKey - 1];
432 
433 	for (int32 i=0; i<32; i++) {
434 		if (offset == deadOffset[i])
435 			return true;
436 
437 		uint32 deadNumBytes = fChars[deadOffset[i]];
438 
439 		if (!deadNumBytes)
440 			continue;
441 
442 		if (strncmp(&fChars[offset + 1], &fChars[deadOffset[i] + 1],
443 				deadNumBytes) == 0)
444 			return true;
445 		i++;
446 	}
447 	return false;
448 }
449 
450 
451 //! Get the char for a key given modifiers and active dead key
452 void
453 Keymap::GetChars(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey,
454 	char** chars, int32* numBytes)
455 {
456 	*numBytes = 0;
457 	*chars = NULL;
458 
459 	if (keyCode > 128 || fChars == NULL)
460 		return;
461 
462 	// here we take NUMLOCK into account
463 	if ((modifiers & B_NUM_LOCK) != 0) {
464 		switch (keyCode) {
465 			case 0x37:
466 			case 0x38:
467 			case 0x39:
468 			case 0x48:
469 			case 0x49:
470 			case 0x4a:
471 			case 0x58:
472 			case 0x59:
473 			case 0x5a:
474 			case 0x64:
475 			case 0x65:
476 				modifiers ^= B_SHIFT_KEY;
477 		}
478 	}
479 
480 	int32 offset = _Offset(keyCode, modifiers);
481 	if (offset < 0)
482 		return;
483 
484 	// here we get the char size
485 	*numBytes = fChars[offset];
486 	if (!*numBytes)
487 		return;
488 
489 	// here we take an potential active dead key
490 	int32 *deadKey;
491 	switch (activeDeadKey) {
492 		case 1: deadKey = fKeys.acute_dead_key; break;
493 		case 2: deadKey = fKeys.grave_dead_key; break;
494 		case 3: deadKey = fKeys.circumflex_dead_key; break;
495 		case 4: deadKey = fKeys.dieresis_dead_key; break;
496 		case 5: deadKey = fKeys.tilde_dead_key; break;
497 		default:
498 		{
499 			// if not dead, we copy and return the char
500 			char *str = *chars = new char[*numBytes + 1];
501 			strncpy(str, &fChars[offset + 1], *numBytes);
502 			str[*numBytes] = 0;
503 			return;
504 		}
505 	}
506 
507 	// if dead key, we search for our current offset char in the dead key
508 	// offset table string comparison is needed
509 	for (int32 i = 0; i < 32; i++) {
510 		if (strncmp(&fChars[offset + 1], &fChars[deadKey[i] + 1], *numBytes)
511 				== 0) {
512 			*numBytes = fChars[deadKey[i + 1]];
513 
514 			switch (*numBytes) {
515 				case 0:
516 					// Not mapped
517 					*chars = NULL;
518 					break;
519 				default:
520 				{
521 					// 1-, 2-, 3-, or 4-byte UTF-8 character
522 					char *str = *chars = new char[*numBytes + 1];
523 					strncpy(str, &fChars[deadKey[i + 1] + 1], *numBytes);
524 					str[*numBytes] = 0;
525 					break;
526 				}
527 			}
528 			return;
529 		}
530 		i++;
531 	}
532 
533 	// if not found we return the current char mapped
534 	*chars = new char[*numBytes + 1];
535 	strncpy(*chars, &fChars[offset + 1], *numBytes);
536 	(*chars)[*numBytes] = 0;
537 }
538 
539 
540 //! We make our input server use the map in /boot/home/config/settings/Keymap
541 status_t
542 Keymap::Use()
543 {
544 	return _restore_key_map_();
545 }
546 
547 
548 void
549 Keymap::SetKey(uint32 keyCode, uint32 modifiers, int8 deadKey,
550 	const char* bytes, int32 numBytes)
551 {
552 	int32 offset = _Offset(keyCode, modifiers);
553 	if (offset < 0)
554 		return;
555 
556 	if (numBytes == -1)
557 		numBytes = strlen(bytes);
558 	if (numBytes > 6)
559 		return;
560 
561 	int32 oldNumBytes = fChars[offset];
562 
563 	if (oldNumBytes == numBytes
564 		&& !memcmp(&fChars[offset + 1], bytes, numBytes)) {
565 		// nothing to do
566 		return;
567 	}
568 
569 	// TODO: handle dead keys!
570 
571 	int32 diff = numBytes - oldNumBytes;
572 	if (diff != 0) {
573 		fCharsSize += diff;
574 
575 		if (diff > 0) {
576 			// make space for the new data
577 			char* chars = new(std::nothrow) char[fCharsSize];
578 			if (chars != NULL) {
579 				memcpy(chars, fChars, offset + oldNumBytes + 1);
580 				memcpy(&chars[offset + 1 + numBytes],
581 					&fChars[offset + 1 + oldNumBytes],
582 					fCharsSize - 2 - offset - diff);
583 				delete[] fChars;
584 				fChars = chars;
585 			} else
586 				return;
587 		} else if (diff < 0) {
588 			// shrink table
589 			memmove(&fChars[offset + numBytes], &fChars[offset + oldNumBytes],
590 				fCharsSize - offset - 2 - diff);
591 		}
592 
593 		// update offsets
594 
595 		int32* data = fKeys.control_map;
596 		int32 size = sizeof(fKeys.control_map) / 4 * 9
597 			+ sizeof(fKeys.acute_dead_key) / 4 * 5;
598 		for (int32 i = 0; i < size; i++) {
599 			if (data[i] > offset)
600 				data[i] += diff;
601 		}
602 	}
603 
604 	memcpy(&fChars[offset + 1], bytes, numBytes);
605 	fChars[offset] = numBytes;
606 
607 	if (fModificationMessage != NULL)
608 		fTarget.SendMessage(fModificationMessage);
609 }
610 
611 
612 Keymap&
613 Keymap::operator=(const Keymap& other)
614 {
615 	if (this == &other)
616 		return *this;
617 
618 	delete[] fChars;
619 	delete fModificationMessage;
620 
621 	fChars = new(std::nothrow) char[other.fCharsSize];
622 	if (fChars != NULL) {
623 		memcpy(fChars, other.fChars, other.fCharsSize);
624 		fCharsSize = other.fCharsSize;
625 	} else
626 		fCharsSize = 0;
627 
628 	memcpy(&fKeys, &other.fKeys, sizeof(key_map));
629 	strlcpy(fName, other.fName, sizeof(fName));
630 
631 	fTarget = other.fTarget;
632 
633 	if (other.fModificationMessage != NULL)
634 		fModificationMessage = new BMessage(*other.fModificationMessage);
635 
636 	return *this;
637 }
638 
639 
640 int32
641 Keymap::_Offset(uint32 keyCode, uint32 modifiers, uint32* _table)
642 {
643 	int32 offset;
644 	uint32 table;
645 
646 	if (keyCode >= 128)
647 		return -1;
648 
649 	switch (modifiers & kModifierKeys) {
650 		case B_SHIFT_KEY:
651 			offset = fKeys.shift_map[keyCode];
652 			table = B_SHIFT_TABLE;
653 			break;
654 		case B_CAPS_LOCK:
655 			offset = fKeys.caps_map[keyCode];
656 			table = B_CAPS_TABLE;
657 			break;
658 		case B_CAPS_LOCK | B_SHIFT_KEY:
659 			offset = fKeys.caps_shift_map[keyCode];
660 			table = B_CAPS_SHIFT_TABLE;
661 			break;
662 		case B_OPTION_KEY:
663 			offset = fKeys.option_map[keyCode];
664 			table = B_OPTION_TABLE;
665 			break;
666 		case B_OPTION_KEY | B_SHIFT_KEY:
667 			offset = fKeys.option_shift_map[keyCode];
668 			table = B_OPTION_SHIFT_TABLE;
669 			break;
670 		case B_OPTION_KEY | B_CAPS_LOCK:
671 			offset = fKeys.option_caps_map[keyCode];
672 			table = B_OPTION_CAPS_TABLE;
673 			break;
674 		case B_OPTION_KEY | B_SHIFT_KEY | B_CAPS_LOCK:
675 			offset = fKeys.option_caps_shift_map[keyCode];
676 			table = B_OPTION_CAPS_SHIFT_TABLE;
677 			break;
678 		case B_CONTROL_KEY:
679 			offset = fKeys.control_map[keyCode];
680 			table = B_CONTROL_TABLE;
681 			break;
682 		default:
683 			offset = fKeys.normal_map[keyCode];
684 			table = B_NORMAL_TABLE;
685 			break;
686 	}
687 
688 	if (_table != NULL)
689 		*_table = table;
690 
691 	if (offset >= (int32)fCharsSize)
692 		return -1;
693 
694 	return offset;
695 }
696