Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_unix/sys/src/cmd/gs/src/sdcparam.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1998, 1999 Aladdin Enterprises.  All rights reserved.
2
 
3
  This software is provided AS-IS with no warranty, either express or
4
  implied.
5
 
6
  This software is distributed under license and may not be copied,
7
  modified or distributed except as expressly authorized under the terms
8
  of the license contained in the file LICENSE in this distribution.
9
 
10
  For more information about licensing, please refer to
11
  http://www.ghostscript.com/licensing/. For information on
12
  commercial licensing, go to http://www.artifex.com/licensing/ or
13
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
*/
16
 
17
/* $Id: sdcparam.c,v 1.6 2003/08/26 15:38:50 igor Exp $ */
18
/* DCT filter parameter setting and reading */
19
#include "memory_.h"
20
#include "jpeglib_.h"
21
#include "gserror.h"
22
#include "gserrors.h"
23
#include "gstypes.h"
24
#include "gsmemory.h"
25
#include "gsparam.h"
26
#include "strimpl.h"		/* sdct.h requires this */
27
#include "sdct.h"
28
#include "sdcparam.h"
29
#include "sjpeg.h"
30
 
31
/* Define the DCT parameters. */
32
#define dctp(key, type, stype, memb) { key, type, offset_of(stype, memb) }
33
private const gs_param_item_t s_DCT_param_items[] =
34
{
35
dctp("ColorTransform", gs_param_type_int, stream_DCT_state, ColorTransform),
36
    dctp("QFactor", gs_param_type_float, stream_DCT_state, QFactor),
37
    gs_param_item_end
38
};
39
private const gs_param_item_t jsd_param_items[] =
40
{
41
    dctp("Picky", gs_param_type_int, jpeg_stream_data, Picky),
42
    dctp("Relax", gs_param_type_int, jpeg_stream_data, Relax),
43
    gs_param_item_end
44
};
45
 
46
#undef dctp
47
 
48
/*
49
 * Adobe specifies the values to be supplied in zigzag order.
50
 * For IJG versions newer than v6, we need to convert this order
51
 * to natural array order.  Older IJG versions want zigzag order.
52
 */
53
#if JPEG_LIB_VERSION >= 61
54
	/* natural array position of n'th element of JPEG zigzag order */
55
static const byte natural_order[DCTSIZE2] =
56
{
57
    0, 1, 8, 16, 9, 2, 3, 10,
58
    17, 24, 32, 25, 18, 11, 4, 5,
59
    12, 19, 26, 33, 40, 48, 41, 34,
60
    27, 20, 13, 6, 7, 14, 21, 28,
61
    35, 42, 49, 56, 57, 50, 43, 36,
62
    29, 22, 15, 23, 30, 37, 44, 51,
63
    58, 59, 52, 45, 38, 31, 39, 46,
64
    53, 60, 61, 54, 47, 55, 62, 63
65
};
66
 
67
#define jpeg_order(x)  natural_order[x]
68
	/* invert natural_order for getting parameters */
69
static const byte inverse_natural_order[DCTSIZE2] =
70
{
71
    0, 1, 5, 6, 14, 15, 27, 28,
72
    2, 4, 7, 13, 16, 26, 29, 42,
73
    3, 8, 12, 17, 25, 30, 41, 43,
74
    9, 11, 18, 24, 31, 40, 44, 53,
75
    10, 19, 23, 32, 39, 45, 52, 54,
76
    20, 22, 33, 38, 46, 51, 55, 60,
77
    21, 34, 37, 47, 50, 56, 59, 61,
78
    35, 36, 48, 49, 57, 58, 62, 63
79
};
80
 
81
#define jpeg_inverse_order(x)  inverse_natural_order[x]
82
#else
83
#define jpeg_order(x)  (x)
84
#define jpeg_inverse_order(x) (x)
85
#endif
86
 
87
/* ================ Get parameters ================ */
88
 
89
private int
90
quant_param_string(gs_param_string * pstr, int count, const UINT16 * pvals,
91
		   floatp QFactor, gs_memory_t * mem)
92
{
93
    byte *data;
94
    int code = 0;
95
    int i;
96
 
97
    data = gs_alloc_string(mem, count, "quant_param_string");
98
    if (data == 0)
99
	return_error(gs_error_VMerror);
100
    for (i = 0; i < count; ++i) {
101
	floatp val = pvals[jpeg_inverse_order(i)] / QFactor;
102
 
103
	data[i] =
104
	    (val < 1 ? (code = 1) : val > 255 ? (code = 255) : (byte) val);
105
    }
106
    pstr->data = data;
107
    pstr->size = count;
108
    pstr->persistent = true;
109
    return code & 1;
110
}
111
 
112
private int
113
quant_param_array(gs_param_float_array * pfa, int count, const UINT16 * pvals,
114
		  floatp QFactor, gs_memory_t * mem)
115
{
116
    float *data;
117
    int i;
118
 
119
    data = (float *)gs_alloc_byte_array(mem, count, sizeof(float),
120
					"quant_param_array");
121
 
122
    if (data == 0)
123
	return_error(gs_error_VMerror);
124
    for (i = 0; i < count; ++i)
125
	data[i] = pvals[jpeg_inverse_order(i)] / QFactor;
126
    pfa->data = data;
127
    pfa->size = count;
128
    pfa->persistent = true;
129
    return 0;
130
}
131
 
132
int
133
s_DCT_get_quantization_tables(gs_param_list * plist,
134
	   const stream_DCT_state * pdct, const stream_DCT_state * defaults,
135
			      bool is_encode)
136
{
137
    gs_memory_t *mem = pdct->memory;
138
    jpeg_component_info d_comp_info[4];
139
    int num_in_tables;
140
    const jpeg_component_info *comp_info;
141
    const jpeg_component_info *default_comp_info;
142
    JQUANT_TBL **table_ptrs;
143
    JQUANT_TBL **default_table_ptrs;
144
    gs_param_array quant_tables;
145
    floatp QFactor = pdct->QFactor;
146
    int i;
147
    int code;
148
 
149
    if (is_encode) {
150
	num_in_tables = pdct->data.compress->cinfo.num_components;
151
	comp_info = pdct->data.compress->cinfo.comp_info;
152
	table_ptrs = pdct->data.compress->cinfo.quant_tbl_ptrs;
153
	if (defaults) {
154
	    default_comp_info = defaults->data.compress->cinfo.comp_info;
155
	    default_table_ptrs = defaults->data.compress->cinfo.quant_tbl_ptrs;
156
	}
157
    } else {
158
	quant_tables.size = count_of(d_comp_info);
159
	num_in_tables = quant_tables.size;
160
	for (i = 0; i < num_in_tables; ++i)
161
	    d_comp_info[i].quant_tbl_no = i;
162
	comp_info = d_comp_info;
163
	table_ptrs = pdct->data.decompress->dinfo.quant_tbl_ptrs;
164
	if (defaults) {
165
	    default_comp_info = d_comp_info;
166
	    default_table_ptrs =
167
		defaults->data.decompress->dinfo.quant_tbl_ptrs;
168
	}
169
    }
170
 
171
    /* Check whether all tables match defaults. */
172
    if (defaults) {
173
	bool match = true;
174
 
175
	for (i = 0; i < num_in_tables; ++i) {
176
	    JQUANT_TBL *tbl = table_ptrs[comp_info[i].quant_tbl_no];
177
	    JQUANT_TBL *default_tbl =
178
	    (default_comp_info == 0 || default_table_ptrs == 0 ? 0 :
179
	     default_table_ptrs[default_comp_info[i].quant_tbl_no]);
180
 
181
	    if (tbl == default_tbl)
182
		continue;
183
	    if (tbl == 0 || default_tbl == 0 ||
184
		memcmp(tbl->quantval, default_tbl->quantval,
185
		       DCTSIZE2 * sizeof(UINT16))
186
		) {
187
		match = false;
188
		break;
189
	    }
190
	}
191
	if (match)
192
	    return 0;
193
    }
194
    quant_tables.size = num_in_tables;
195
    code = param_begin_write_collection(plist, "QuantTables",
196
					&quant_tables,
197
					gs_param_collection_array);
198
    if (code < 0)
199
	return code;
200
    for (i = 0; i < num_in_tables; ++i) {
201
	char key[3];
202
	gs_param_string str;
203
	gs_param_float_array fa;
204
 
205
	sprintf(key, "%d", i);
206
	if (QFactor == 1.0) {
207
	    code = quant_param_string(&str, DCTSIZE2,
208
			    table_ptrs[comp_info[i].quant_tbl_no]->quantval,
209
				      QFactor, mem);
210
	    switch (code) {
211
		case 0:
212
		    code = param_write_string(quant_tables.list, key, &str);
213
		    if (code < 0)
214
			return code;	/* should dealloc */
215
		    continue;
216
		default:
217
		    return code;	/* should dealloc */
218
		case 1:
219
		    break;
220
	    }
221
	    /* break const to free the string */
222
	    gs_free_string(mem, (byte *) str.data, str.size,
223
			   "quant_param_string");
224
	}
225
	code = quant_param_array(&fa, DCTSIZE2,
226
			    table_ptrs[comp_info[i].quant_tbl_no]->quantval,
227
				 QFactor, mem);
228
	if (code < 0)
229
	    return code;	/* should dealloc */
230
	code = param_write_float_array(quant_tables.list, key, &fa);
231
	if (code < 0)
232
	    return code;	/* should dealloc */
233
    }
234
    return param_end_write_dict(plist, "QuantTables", &quant_tables);
235
}
236
 
237
private int
238
pack_huff_table(gs_param_string * pstr, const JHUFF_TBL * table,
239
		gs_memory_t * mem)
240
{
241
    int total;
242
    int i;
243
    byte *data;
244
 
245
    for (i = 1, total = 0; i <= 16; ++i)
246
	total += table->bits[i];
247
    data = gs_alloc_string(mem, 16 + total, "pack_huff_table");
248
    if (data == 0)
249
	return_error(gs_error_VMerror);
250
    memcpy(data, table->bits + 1, 16);
251
    memcpy(data + 16, table->huffval, total);
252
    pstr->data = data;
253
    pstr->size = 16 + total;
254
    pstr->persistent = true;
255
    return 0;
256
}
257
 
258
int
259
s_DCT_get_huffman_tables(gs_param_list * plist,
260
	   const stream_DCT_state * pdct, const stream_DCT_state * defaults,
261
			 bool is_encode)
262
{
263
    gs_memory_t *mem = pdct->memory;
264
    gs_param_string *huff_data;
265
    gs_param_string_array hta;
266
    int num_in_tables;
267
    jpeg_component_info *comp_info;
268
    JHUFF_TBL **dc_table_ptrs;
269
    JHUFF_TBL **ac_table_ptrs;
270
    int i;
271
    int code = 0;
272
 
273
    if (is_encode) {
274
	dc_table_ptrs = pdct->data.compress->cinfo.dc_huff_tbl_ptrs;
275
	ac_table_ptrs = pdct->data.compress->cinfo.ac_huff_tbl_ptrs;
276
	num_in_tables = pdct->data.compress->cinfo.input_components * 2;
277
	comp_info = pdct->data.compress->cinfo.comp_info;
278
    } else {
279
	dc_table_ptrs = pdct->data.decompress->dinfo.dc_huff_tbl_ptrs;
280
	ac_table_ptrs = pdct->data.decompress->dinfo.ac_huff_tbl_ptrs;
281
	for (i = 2; i > 0; --i)
282
	    if (dc_table_ptrs[i - 1] || ac_table_ptrs[i - 1])
283
		break;
284
	num_in_tables = i * 2;
285
	comp_info = NULL;	/* do not set for decompress case */
286
    }
287
/****** byte_array IS WRONG ******/
288
    huff_data = (gs_param_string *)
289
	gs_alloc_byte_array(mem, num_in_tables, sizeof(gs_param_string),
290
			    "get huffman tables");
291
    if (huff_data == 0)
292
	return_error(gs_error_VMerror);
293
    for (i = 0; i < num_in_tables; i += 2) {
294
	if ((code = pack_huff_table(huff_data + i, ac_table_ptrs[i >> 1], mem)) < 0 ||
295
	    (code = pack_huff_table(huff_data + i + 1, dc_table_ptrs[i >> 1], mem))
296
	    )
297
	    break;
298
    }
299
    if (code < 0)
300
	return code;
301
    hta.data = huff_data;
302
    hta.size = num_in_tables;
303
    hta.persistent = true;
304
    return param_write_string_array(plist, "HuffTables", &hta);
305
}
306
 
307
int
308
s_DCT_get_params(gs_param_list * plist, const stream_DCT_state * ss,
309
		 const stream_DCT_state * defaults)
310
{
311
    int code =
312
    gs_param_write_items(plist, ss, defaults, s_DCT_param_items);
313
 
314
    if (code >= 0)
315
	code = gs_param_write_items(plist, ss->data.common,
316
				    (defaults ? defaults->data.common :
317
				     NULL),
318
				    jsd_param_items);
319
    return code;
320
}
321
 
322
/* ================ Put parameters ================ */
323
 
324
stream_state_proc_put_params(s_DCT_put_params, stream_DCT_state);	/* check */
325
 
326
/* ---------------- Utilities ---------------- */
327
 
328
/*
329
 * Get N byte-size values from an array or a string.
330
 * Used for HuffTables, HSamples, VSamples.
331
 */
332
int
333
s_DCT_byte_params(gs_param_list * plist, gs_param_name key, int start,
334
		  int count, UINT8 * pvals)
335
{
336
    int i;
337
    gs_param_string bytes;
338
    gs_param_float_array floats;
339
    int code = param_read_string(plist, key, &bytes);
340
 
341
    switch (code) {
342
	case 0:
343
	    if (bytes.size < start + count) {
344
		code = gs_note_error(gs_error_rangecheck);
345
		break;
346
	    }
347
	    for (i = 0; i < count; ++i)
348
		pvals[i] = (UINT8) bytes.data[start + i];
349
	    return 0;
350
	default:		/* might be a float array */
351
	    code = param_read_float_array(plist, key, &floats);
352
	    if (!code) {
353
		if (floats.size < start + count) {
354
		    code = gs_note_error(gs_error_rangecheck);
355
		    break;
356
		}
357
		for (i = 0; i < count; ++i) {
358
		    float v = floats.data[start + i];
359
 
360
		    if (v < 0 || v > 255) {
361
			code = gs_note_error(gs_error_rangecheck);
362
			break;
363
		    }
364
		    pvals[i] = (UINT8) (v + 0.5);
365
		}
366
	    }
367
    }
368
    if (code < 0)
369
	param_signal_error(plist, key, code);
370
    return code;
371
}
372
 
373
/* Get N quantization values from an array or a string. */
374
private int
375
quant_params(gs_param_list * plist, gs_param_name key, int count,
376
	     UINT16 * pvals, floatp QFactor)
377
{
378
    int i;
379
    gs_param_string bytes;
380
    gs_param_float_array floats;
381
    int code = param_read_string(plist, key, &bytes);
382
 
383
    switch (code) {
384
	case 0:
385
	    if (bytes.size != count) {
386
		code = gs_note_error(gs_error_rangecheck);
387
		break;
388
	    }
389
	    for (i = 0; i < count; ++i) {
390
		double v = bytes.data[i] * QFactor;
391
 
392
		pvals[jpeg_order(i)] =
393
		    (UINT16) (v < 1 ? 1 : v > 255 ? 255 : v + 0.5);
394
	    }
395
	    return 0;
396
	default:		/* might be a float array */
397
	    code = param_read_float_array(plist, key, &floats);
398
	    if (!code) {
399
		if (floats.size != count) {
400
		    code = gs_note_error(gs_error_rangecheck);
401
		    break;
402
		}
403
		for (i = 0; i < count; ++i) {
404
		    double v = floats.data[i] * QFactor;
405
 
406
		    pvals[jpeg_order(i)] =
407
			(UINT16) (v < 1 ? 1 : v > 255 ? 255 : v + 0.5);
408
		}
409
	    }
410
    }
411
    if (code < 0)
412
	param_signal_error(plist, key, code);
413
    return code;
414
#undef jpeg_order
415
}
416
 
417
/* ---------------- Main procedures ---------------- */
418
 
419
/* Put common scalars. */
420
int
421
s_DCT_put_params(gs_param_list * plist, stream_DCT_state * pdct)
422
{
423
    int code =
424
    gs_param_read_items(plist, pdct, s_DCT_param_items);
425
 
426
    if (code < 0)
427
	return code;
428
    code = gs_param_read_items(plist, pdct->data.common, jsd_param_items);
429
    if (code < 0)
430
	return code;
431
    if (pdct->data.common->Picky < 0 || pdct->data.common->Picky > 1 ||
432
	pdct->data.common->Relax < 0 || pdct->data.common->Relax > 1 ||
433
	pdct->ColorTransform < -1 || pdct->ColorTransform > 2 ||
434
	pdct->QFactor < 0.0 || pdct->QFactor > 1000000.0
435
	)
436
	return_error(gs_error_rangecheck);
437
    return 0;
438
}
439
 
440
/* Put quantization tables. */
441
int
442
s_DCT_put_quantization_tables(gs_param_list * plist, stream_DCT_state * pdct,
443
			      bool is_encode)
444
{
445
    int code;
446
    int i, j;
447
    gs_param_array quant_tables;	/* array of strings/arrays */
448
    int num_in_tables;
449
    int num_out_tables;
450
    jpeg_component_info *comp_info;
451
    JQUANT_TBL **table_ptrs;
452
    JQUANT_TBL *this_table;
453
 
454
    switch ((code = param_begin_read_dict(plist, "QuantTables",
455
					  &quant_tables, true))
456
	) {
457
	case 1:
458
	    return 1;
459
	default:
460
	    return param_signal_error(plist, "QuantTables", code);
461
	case 0:
462
	    ;
463
    }
464
    if (is_encode) {
465
	num_in_tables = pdct->data.compress->cinfo.num_components;
466
	if (quant_tables.size < num_in_tables)
467
	    return_error(gs_error_rangecheck);
468
	comp_info = pdct->data.compress->cinfo.comp_info;
469
	table_ptrs = pdct->data.compress->cinfo.quant_tbl_ptrs;
470
    } else {
471
	num_in_tables = quant_tables.size;
472
	comp_info = NULL;	/* do not set for decompress case */
473
	table_ptrs = pdct->data.decompress->dinfo.quant_tbl_ptrs;
474
    }
475
    num_out_tables = 0;
476
    for (i = 0; i < num_in_tables; ++i) {
477
	char istr[5];		/* i converted to string key */
478
	UINT16 values[DCTSIZE2];
479
 
480
	sprintf(istr, "%d", i);
481
	code = quant_params(quant_tables.list, istr, DCTSIZE2, values,
482
			    pdct->QFactor);
483
	if (code < 0)
484
	    return code;
485
	/* Check for duplicate tables. */
486
	for (j = 0; j < num_out_tables; j++) {
487
	    if (!memcmp(table_ptrs[j]->quantval, values, sizeof(values)))
488
		break;
489
	}
490
	if (comp_info != NULL)
491
	    comp_info[i].quant_tbl_no = j;
492
	if (j < num_out_tables)	/* found a duplicate */
493
	    continue;
494
	if (++num_out_tables > NUM_QUANT_TBLS)
495
	    return_error(gs_error_rangecheck);
496
	this_table = table_ptrs[j];
497
	if (this_table == NULL) {
498
	    this_table = gs_jpeg_alloc_quant_table(pdct);
499
	    if (this_table == NULL)
500
		return_error(gs_error_VMerror);
501
	    table_ptrs[j] = this_table;
502
	}
503
	memcpy(this_table->quantval, values, sizeof(values));
504
    }
505
    return 0;
506
}
507
 
508
/* Put Huffman tables. */
509
private int
510
find_huff_values(JHUFF_TBL ** table_ptrs, int num_tables,
511
	       const UINT8 counts[16], const UINT8 * values, int codes_size)
512
{
513
    int j;
514
 
515
    for (j = 0; j < num_tables; ++j)
516
	if (!memcmp(table_ptrs[j]->bits, counts, sizeof(counts)) &&
517
	    !memcmp(table_ptrs[j]->huffval, values,
518
		    codes_size * sizeof(values[0])))
519
	    break;
520
    return j;
521
}
522
int
523
s_DCT_put_huffman_tables(gs_param_list * plist, stream_DCT_state * pdct,
524
			 bool is_encode)
525
{
526
    int code;
527
    int i, j;
528
    gs_param_array huff_tables;
529
    int num_in_tables;
530
    int ndc, nac;
531
    int codes_size;
532
    jpeg_component_info *comp_info;
533
    JHUFF_TBL **dc_table_ptrs;
534
    JHUFF_TBL **ac_table_ptrs;
535
    JHUFF_TBL **this_table_ptr;
536
    JHUFF_TBL *this_table;
537
    int max_tables = 2;		/* baseline limit */
538
 
539
    switch ((code = param_begin_read_dict(plist, "HuffTables",
540
					  &huff_tables, true))
541
	) {
542
	case 1:
543
	    return 0;
544
	default:
545
	    return param_signal_error(plist, "HuffTables", code);
546
	case 0:
547
	    ;
548
    }
549
    if (is_encode) {
550
	num_in_tables = pdct->data.compress->cinfo.input_components * 2;
551
	if (huff_tables.size < num_in_tables)
552
	    return_error(gs_error_rangecheck);
553
	comp_info = pdct->data.compress->cinfo.comp_info;
554
	dc_table_ptrs = pdct->data.compress->cinfo.dc_huff_tbl_ptrs;
555
	ac_table_ptrs = pdct->data.compress->cinfo.ac_huff_tbl_ptrs;
556
	if (pdct->data.common->Relax)
557
	    max_tables = max(pdct->data.compress->cinfo.input_components, 2);
558
    } else {
559
	num_in_tables = huff_tables.size;
560
	comp_info = NULL;	/* do not set for decompress case */
561
	dc_table_ptrs = pdct->data.decompress->dinfo.dc_huff_tbl_ptrs;
562
	ac_table_ptrs = pdct->data.decompress->dinfo.ac_huff_tbl_ptrs;
563
	if (pdct->data.common->Relax)
564
	    max_tables = NUM_HUFF_TBLS;
565
    }
566
    ndc = nac = 0;
567
    for (i = 0; i < num_in_tables; ++i) {
568
	char istr[5];		/* i converted to string key */
569
	UINT8 counts[16], values[256];
570
 
571
	/* Collect the Huffman parameters. */
572
	sprintf(istr, "%d", i);
573
	code = s_DCT_byte_params(huff_tables.list, istr, 0, 16, counts);
574
	if (code < 0)
575
	    return code;
576
	for (codes_size = 0, j = 0; j < 16; j++)
577
	    codes_size += counts[j];
578
	if (codes_size > 256 /*|| r_size(pa) != codes_size+16 */ )
579
	    return_error(gs_error_rangecheck);
580
	code = s_DCT_byte_params(huff_tables.list, istr, 16, codes_size,
581
				 values);
582
	if (code < 0)
583
	    return code;
584
	if (i & 1) {
585
	    j = find_huff_values(ac_table_ptrs, nac, counts, values,
586
				 codes_size);
587
	    if (comp_info != NULL)
588
		comp_info[i >> 1].ac_tbl_no = j;
589
	    if (j < nac)
590
		continue;
591
	    if (++nac > NUM_HUFF_TBLS)
592
		return_error(gs_error_rangecheck);
593
	    this_table_ptr = ac_table_ptrs + j;
594
	} else {
595
	    j = find_huff_values(dc_table_ptrs, ndc, counts, values,
596
				 codes_size);
597
	    if (comp_info != NULL)
598
		comp_info[i >> 1].dc_tbl_no = j;
599
	    if (j < ndc)
600
		continue;
601
	    if (++ndc > NUM_HUFF_TBLS)
602
		return_error(gs_error_rangecheck);
603
	    this_table_ptr = dc_table_ptrs + j;
604
	}
605
	this_table = *this_table_ptr;
606
	if (this_table == NULL) {
607
	    this_table = gs_jpeg_alloc_huff_table(pdct);
608
	    if (this_table == NULL)
609
		return_error(gs_error_VMerror);
610
	    *this_table_ptr = this_table;
611
	}
612
	memcpy(this_table->bits, counts, sizeof(counts));
613
	memcpy(this_table->huffval, values, codes_size * sizeof(values[0]));
614
    }
615
    if (nac > max_tables || ndc > max_tables)
616
	return_error(gs_error_rangecheck);
617
    return 0;
618
}