00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126 #include <string.h>
00127
00128 #include <sys/types.h>
00129 #include <sys/stat.h>
00130 #include <unistd.h>
00131 #include <fcntl.h>
00132
00133 #include <grass/config.h>
00134
00135 #include "G.h"
00136 #include <grass/glocale.h>
00137
00138 static int _zeros_r_nulls = 1;
00139
00140 static int put_raster_data(int,void *,int,int,int,int,RASTER_MAP_TYPE);
00141 static int put_data(int,CELL *,int, int,int,int);
00142 static int check_open(const char *,int,int);
00143 static int adjust(int, int *, int *);
00144 static void write_error(int,int);
00145 static int same(const unsigned char *, const unsigned char *, int);
00146 static int seek_random(int, int, int);
00147 static void set_file_pointer(int,int);
00148 static int put_fp_data(int,void *,int,int,int,RASTER_MAP_TYPE);
00149 static int put_null_data(int,char *, int);
00150 static int convert_and_write_if(int, CELL *);
00151 static int convert_and_write_id(int, CELL *);
00152 static int convert_and_write_df(int, DCELL *);
00153 static int convert_and_write_fd(int, FCELL *);
00154 static int put_raster_row(int fd, void *buf, RASTER_MAP_TYPE data_type, int zeros_r_nulls);
00155
00156
00157
00158
00159
00160 int G_zeros_r_nulls(int zeros_r_nulls)
00161 {
00162 if (zeros_r_nulls >= 0)
00163 _zeros_r_nulls = zeros_r_nulls > 0;
00164
00165 return _zeros_r_nulls;
00166 }
00167
00168 int G_put_map_row_random(int fd, CELL *buf, int row, int col, int n)
00169 {
00170 struct fileinfo *fcb = &G__.fileinfo[fd];
00171
00172 if (!check_open("G_put_map_row_random", fd, 1))
00173 return -1;
00174
00175 buf += adjust(fd, &col, &n);
00176 switch (put_data(fd, buf, row, col, n, _zeros_r_nulls))
00177 {
00178 case -1: return -1;
00179 case 0: return 1;
00180 }
00181
00182
00183 if (fcb->want_histogram)
00184 G_update_cell_stats (buf, n, &fcb->statf);
00185
00186 G_row_update_range (buf, n, &fcb->range);
00187
00188 return 1;
00189 }
00190
00191 int G__put_null_value_row(int fd, char *buf)
00192 {
00193 struct fileinfo *fcb = &G__.fileinfo[fd];
00194
00195 switch (put_null_data(fd, buf, fcb->null_cur_row))
00196 {
00197 case -1: return -1;
00198 case 0: return 1;
00199 }
00200
00201 fcb->null_cur_row++;
00202
00203 return 1;
00204 }
00205
00206 int G_put_map_row(int fd, CELL *buf)
00207 {
00208 struct fileinfo *fcb = &G__.fileinfo[fd];
00209
00210 if (fcb->map_type != CELL_TYPE)
00211 {
00212 G_fatal_error(_("G_put_map_row: %s is not integer! Use G_put_[f/d]_raster_row()!"),
00213 fcb->name);
00214 return -1;
00215 }
00216
00217 return put_raster_row(fd, buf, CELL_TYPE, _zeros_r_nulls);
00218 }
00219
00220 int G_put_raster_row(int fd, void *buf, RASTER_MAP_TYPE data_type)
00221 {
00222 return put_raster_row(fd, buf, data_type, 0);
00223 }
00224
00225 int G_put_c_raster_row(int fd, CELL *buf)
00226 {
00227 return G_put_raster_row(fd, buf, CELL_TYPE);
00228 }
00229
00230 int G_put_f_raster_row(int fd, FCELL *buf)
00231 {
00232 return G_put_raster_row(fd, buf, FCELL_TYPE);
00233 }
00234
00235 int G_put_d_raster_row(int fd, DCELL *buf)
00236 {
00237 return G_put_raster_row(fd, buf, DCELL_TYPE);
00238 }
00239
00240
00241
00242 static int check_open(const char *me, int fd, int random)
00243 {
00244 struct fileinfo *fcb = &G__.fileinfo[fd];
00245
00246 switch (fcb->open_mode)
00247 {
00248 case OPEN_OLD:
00249 G_warning(_("%s: map [%s] not open for write - request ignored"), me, fcb->name);
00250 break;
00251 case OPEN_NEW_COMPRESSED:
00252 case OPEN_NEW_UNCOMPRESSED:
00253 if (!random)
00254 return 1;
00255
00256 G_warning(_("%s: map [%s] not open for random write - request ignored"),
00257 me, fcb->name);
00258 break;
00259 case OPEN_NEW_RANDOM:
00260 if (random)
00261 return 1;
00262
00263 G_warning(_("%s: map [%s] not open for sequential write - request ignored"),
00264 me, fcb->name);
00265 break;
00266 default:
00267 G_warning(_("%s: unopened file descriptor - request ignored"), me);
00268 break;
00269 }
00270
00271 return 0;
00272 }
00273
00274
00275
00276
00277
00278
00279
00280
00281 static int adjust(int fd, int *col, int *n)
00282 {
00283 struct fileinfo *fcb = &G__.fileinfo[fd];
00284 int adj = 0;
00285 int last = *col + *n;
00286
00287 if (*col < 0)
00288 {
00289 adj = -(*col);
00290 *col = 0;
00291 }
00292
00293 if (last > fcb->cellhd.cols)
00294 last = fcb->cellhd.cols;
00295
00296 *n = last - *col;
00297
00298 return adj;
00299 }
00300
00301 static void write_error(int fd,int row)
00302 {
00303 struct fileinfo *fcb = &G__.fileinfo[fd];
00304
00305 if (fcb->io_error)
00306 return;
00307
00308 G_warning(_("map [%s] - unable to write row %d"), fcb->name, row);
00309
00310 fcb->io_error = 1;
00311
00312 return;
00313 }
00314
00315
00316
00317 int G__write_data(int fd, int row, int n)
00318
00319 {
00320 struct fileinfo *fcb = &G__.fileinfo[fd];
00321 ssize_t nwrite = fcb->nbytes * n;
00322
00323 if (write(fd, G__.work_buf, nwrite) != nwrite)
00324 {
00325 write_error(fd, row);
00326 return -1;
00327 }
00328
00329 return 0;
00330 }
00331
00332 int G__write_data_compressed(int fd, int row, int n)
00333 {
00334 struct fileinfo *fcb = &G__.fileinfo[fd];
00335 int nwrite = fcb->nbytes * n;
00336
00337 if (G_zlib_write(fd, G__.work_buf, nwrite) < 0)
00338 {
00339 write_error(fd, row);
00340 return -1;
00341 }
00342
00343 return 0;
00344 }
00345
00346
00347
00348 static int seek_random(int fd, int row, int col)
00349 {
00350 struct fileinfo *fcb = &G__.fileinfo[fd];
00351 off_t offset = ((off_t) fcb->cellhd.cols * row + col) * fcb->nbytes;
00352
00353 if (lseek(fd, offset, SEEK_SET) < 0)
00354 {
00355 write_error(fd, row);
00356 return -1;
00357 }
00358
00359 return 0;
00360 }
00361
00362
00363
00364 static void set_file_pointer(int fd, int row)
00365 {
00366 struct fileinfo *fcb = &G__.fileinfo[fd];
00367
00368 fcb->row_ptr[row] = lseek(fd, 0L, SEEK_CUR);
00369 }
00370
00371
00372
00373
00374
00375 static int convert_float(
00376 XDR *xdrs, const FCELL *rast, int row, int col, int n, int random)
00377 {
00378 int i;
00379
00380 for (i = 0; i < n; i++)
00381 {
00382 FCELL f;
00383
00384
00385 if (G_is_f_null_value(&rast[i]))
00386 {
00387 f = 0.;
00388 if (!random)
00389 G__.null_buf[col + i] = 1;
00390 }
00391 else
00392 f = rast[i];
00393
00394 if (!xdr_float(xdrs, &f))
00395 {
00396 G_warning(_("xdr_float failed for index %d of row %d"), i, row);
00397 return -1;
00398 }
00399 }
00400
00401 return 0;
00402 }
00403
00404 static int convert_double(
00405 XDR *xdrs, const DCELL *rast, int row, int col, int n, int random)
00406 {
00407 int i;
00408
00409 for (i = 0; i < n; i++)
00410 {
00411 DCELL d;
00412
00413
00414 if (G_is_d_null_value(&rast[i]))
00415 {
00416 d = 0.;
00417 if (!random)
00418 G__.null_buf[col + i] = 1;
00419 }
00420 else
00421 d = rast[i];
00422
00423 if (!xdr_double(xdrs, &d))
00424 {
00425 G_warning(_("xdr_double failed for index %d of row %d"), i, row);
00426 return -1;
00427 }
00428 }
00429
00430 return 0;
00431 }
00432
00433
00434
00435
00436
00437 static int put_fp_data(int fd, void *rast, int row, int col, int n, RASTER_MAP_TYPE data_type)
00438 {
00439 struct fileinfo *fcb = &G__.fileinfo[fd];
00440 int random = (fcb->open_mode == OPEN_NEW_RANDOM);
00441 int compressed = (fcb->open_mode == OPEN_NEW_COMPRESSED);
00442 XDR *xdrs = &fcb->xdrstream;
00443
00444 if (row < 0 || row >= fcb->cellhd.rows)
00445 return 0;
00446
00447 if (n <= 0)
00448 return 0;
00449
00450 if (random)
00451 {
00452 if (seek_random(fd, row, col) == -1)
00453 return -1;
00454 }
00455 else if (compressed)
00456 set_file_pointer(fd, row);
00457
00458 xdrmem_create(xdrs, (caddr_t) G__.work_buf,
00459 (u_int) (fcb->nbytes * fcb->cellhd.cols), XDR_ENCODE);
00460 xdr_setpos (xdrs, 0);
00461
00462 if (data_type == FCELL_TYPE)
00463 {
00464 if (convert_float(xdrs, rast, row, col, n, random) < 0)
00465 return -1;
00466 }
00467 else
00468 {
00469 if (convert_double(xdrs, rast, row, col, n, random) < 0)
00470 return -1;
00471 }
00472
00473 xdr_destroy(&fcb->xdrstream);
00474
00475 if (compressed)
00476 {
00477 if (G__write_data_compressed(fd, row, n) == -1)
00478 return -1;
00479 }
00480 else
00481 if (G__write_data(fd, row, n) == -1)
00482 return -1;
00483
00484 return 1;
00485 }
00486
00487
00488
00489
00490
00491 static void convert_int(
00492 unsigned char *wk, const CELL *rast, int col, int n,
00493 int random, int len, int zeros_r_nulls)
00494 {
00495 int i;
00496
00497
00498
00499 for (i = 0; i < n; i++)
00500 {
00501 CELL v = rast[i];
00502 int neg;
00503 int k;
00504
00505
00506 if (G_is_c_null_value(&v))
00507 {
00508 v = 0;
00509 if (!random)
00510 G__.null_buf[col + i] = 1;
00511 }
00512 else if (!random && zeros_r_nulls && !v)
00513 G__.null_buf[col + i] = 1;
00514
00515
00516 if (v < 0)
00517 {
00518 neg = 1;
00519 v = -v;
00520 }
00521 else
00522 neg = 0;
00523
00524
00525 for (k = len - 1; k >= 0; k--)
00526 {
00527 wk[k] = v & 0xff;
00528 v >>= 8;
00529 }
00530
00531
00532 if (neg)
00533 wk[0] |= 0x80 ;
00534
00535 wk += len;
00536 }
00537 }
00538
00539 static int count_bytes(const unsigned char *wk, int n, int len)
00540 {
00541 int i, j;
00542
00543 for (i = 0; i < len - 1; i++)
00544 for (j = 0; j < n; j++)
00545 if (wk[j * len + i] != 0)
00546 return len - i;
00547
00548 return 1;
00549 }
00550
00551 static void trim_bytes(unsigned char *wk, int n, int slen, int trim)
00552 {
00553 unsigned char *wk2 = wk;
00554 int i, j;
00555
00556 for (i = 0; i < n; i++)
00557 {
00558 for (j = 0; j < trim; j++)
00559 wk++;
00560 for ( ; j < slen; j++)
00561 *wk2++ = *wk++;
00562 }
00563 }
00564
00565 static int same(const unsigned char *x, const unsigned char *y, int n)
00566 {
00567 return (memcmp(x, y, n) == 0);
00568 }
00569
00570 static int count_run(const unsigned char *src, int n, int nbytes)
00571 {
00572 const unsigned char *cur = src + nbytes;
00573 int i;
00574
00575 for (i = 1; i < n; i++)
00576 {
00577 if (i == 255 || !same(cur, src, nbytes))
00578 return i;
00579
00580 cur += nbytes;
00581 }
00582
00583 return n;
00584 }
00585
00586 static int rle_compress(unsigned char *dst, unsigned char *src, int n, int nbytes)
00587 {
00588 int nwrite = 0;
00589 int total = nbytes * n;
00590
00591 while (n > 0)
00592 {
00593 int count;
00594
00595 nwrite += nbytes + 1;
00596 if (nwrite >= total)
00597 return 0;
00598
00599 count = count_run(src, n, nbytes);
00600
00601 *dst++ = count;
00602 memcpy(dst, src, nbytes);
00603 dst += nbytes;
00604
00605 src += count * nbytes;
00606 n -= count;
00607 }
00608
00609 return nwrite;
00610 }
00611
00612 static int zlib_compress(unsigned char *dst, unsigned char *src, int n, int nbytes)
00613 {
00614 int total = nbytes * n;
00615 int nwrite = G_zlib_compress(G__.work_buf + 1, total,
00616 G__.compressed_buf + 1, G__.compressed_buf_size - 1);
00617
00618 return (nwrite >= total) ? 0 : nwrite;
00619 }
00620
00621
00622
00623 static int put_data(int fd, CELL *cell, int row, int col, int n, int zeros_r_nulls)
00624 {
00625 struct fileinfo *fcb = &G__.fileinfo[fd];
00626 int random = (fcb->open_mode == OPEN_NEW_RANDOM);
00627 int compressed = fcb->cellhd.compressed;
00628 int len = compressed ? sizeof(CELL) : fcb->nbytes;
00629 unsigned char *wk = G__.work_buf;
00630 ssize_t nwrite;
00631
00632 if (row < 0 || row >= fcb->cellhd.rows)
00633 return 0;
00634
00635 if (n <= 0)
00636 return 0;
00637
00638 if (random)
00639 {
00640 if (seek_random(fd, row, col) == -1)
00641 return -1;
00642 }
00643 else if (compressed)
00644 set_file_pointer(fd, row);
00645
00646 if (compressed)
00647 wk++;
00648
00649 convert_int(wk, cell, col, n, random, len, zeros_r_nulls);
00650
00651 if (compressed)
00652 {
00653 unsigned char *wk = G__.work_buf + 1;
00654 int nbytes = count_bytes(wk, n, len);
00655
00656 if (fcb->nbytes < nbytes)
00657 fcb->nbytes = nbytes;
00658
00659
00660 if (nbytes < len)
00661 trim_bytes(wk, n, len, len - nbytes);
00662
00663 G__.compressed_buf[0] = G__.work_buf[0] = nbytes;
00664
00665
00666 nwrite = compressed == 1
00667 ? rle_compress(G__.compressed_buf + 1, G__.work_buf + 1, n, nbytes)
00668 : zlib_compress(G__.compressed_buf + 1, G__.work_buf + 1, n, nbytes);
00669
00670 if (nwrite > 0)
00671 {
00672 nwrite++;
00673
00674 if (write(fd, G__.compressed_buf, nwrite) != nwrite)
00675 {
00676 write_error(fd, row);
00677 return -1;
00678 }
00679 }
00680 else
00681 {
00682 nwrite = nbytes * n + 1;
00683 if (write(fd, G__.work_buf, nwrite) != nwrite)
00684 {
00685 write_error(fd, row);
00686 return -1;
00687 }
00688 }
00689 }
00690 else
00691 {
00692 nwrite = fcb->nbytes * n;
00693
00694 if (write(fd, G__.work_buf, nwrite) != nwrite)
00695 {
00696 write_error(fd, row);
00697 return -1;
00698 }
00699 }
00700
00701 return 1;
00702 }
00703
00704
00705
00706
00707
00708 static int put_raster_data(int fd, void *rast, int row, int col, int n, int zeros_r_nulls, RASTER_MAP_TYPE map_type)
00709 {
00710 return (map_type == CELL_TYPE)
00711 ? put_data(fd, rast, row, col, n, zeros_r_nulls)
00712 : put_fp_data(fd, rast, row, col, n, map_type);
00713 }
00714
00715
00716
00717
00718
00719 static int put_null_data(int fd, char *flags, int row)
00720 {
00721 struct fileinfo *fcb = &G__.fileinfo[fd];
00722 int null_fd, i;
00723
00724 if (fcb->min_null_row + NULL_ROWS_INMEM <= row)
00725 {
00726
00727
00728
00729
00730 if (fcb->min_null_row >= 0)
00731 {
00732 null_fd = G__open_null_write(fd);
00733 if (null_fd < 0)
00734 return -1;
00735
00736 for (i = 0; i < NULL_ROWS_INMEM; i++)
00737 {
00738
00739 if (i + fcb->min_null_row >= fcb->cellhd.rows)
00740 break;
00741
00742 if (G__write_null_bits(null_fd, fcb->NULL_ROWS[i],
00743 i+fcb->min_null_row, fcb->cellhd.cols, fd) < 0)
00744 return -1;
00745
00746 }
00747 if (null_fd >= 0)
00748 close(null_fd);
00749 }
00750
00751
00752 fcb->min_null_row = fcb->min_null_row + NULL_ROWS_INMEM;
00753
00754 }
00755
00756
00757 G__convert_01_flags(flags, fcb->NULL_ROWS[row - fcb->min_null_row], fcb->cellhd.cols);
00758
00759 return 1;
00760 }
00761
00762 int G__open_null_write(int fd)
00763 {
00764 struct fileinfo *fcb = &G__.fileinfo[fd];
00765 int null_fd;
00766
00767 if (access(fcb->null_temp_name, 0) != 0)
00768 {
00769 G_warning(_("unable to find a temporary null file %s"), fcb->null_temp_name);
00770 return -1;
00771 }
00772
00773 null_fd = open(fcb->null_temp_name, O_WRONLY);
00774 if (null_fd < 0)
00775 return -1;
00776
00777 return null_fd;
00778 }
00779
00780 int G__write_null_bits(int null_fd, unsigned char *flags, int row, int cols, int fd)
00781 {
00782 off_t offset;
00783 size_t size;
00784
00785 size = G__null_bitstream_size(cols);
00786 offset = (off_t) size * row;
00787
00788 if (lseek(null_fd, offset, SEEK_SET) < 0)
00789 {
00790 G_warning(_("error writing null row %d"), row);
00791 return -1;
00792 }
00793
00794 if (write(null_fd, flags, size) != size)
00795 {
00796 G_warning(_("error writing null row %d"), row);
00797 return -1;
00798 }
00799
00800 return 1;
00801 }
00802
00803
00804
00805
00806
00807 static int convert_and_write_if(int fd, CELL *buf)
00808 {
00809 struct fileinfo *fcb = &G__.fileinfo[fd];
00810 FCELL *p = (FCELL *) fcb->data;
00811 int i;
00812
00813 for (i = 0; i < fcb->cellhd.cols; i++)
00814 if (G_is_c_null_value(&buf[i]))
00815 G_set_f_null_value(&p[i], 1);
00816 else
00817 p[i] = (FCELL) buf[i];
00818
00819 return G_put_f_raster_row(fd, p);
00820 }
00821
00822 static int convert_and_write_df(int fd, DCELL *buf)
00823 {
00824 struct fileinfo *fcb = &G__.fileinfo[fd];
00825 FCELL *p = (FCELL *) fcb->data;
00826 int i;
00827
00828 for (i = 0; i < fcb->cellhd.cols; i++)
00829 if (G_is_d_null_value(&buf[i]))
00830 G_set_f_null_value(&p[i], 1);
00831 else
00832 p[i] = (FCELL) buf[i];
00833
00834 return G_put_f_raster_row(fd, p);
00835 }
00836
00837 static int convert_and_write_id(int fd, CELL *buf)
00838 {
00839 struct fileinfo *fcb = &G__.fileinfo[fd];
00840 DCELL *p = (DCELL *) fcb->data;
00841 int i;
00842
00843 for (i = 0; i < fcb->cellhd.cols; i++)
00844 if (G_is_c_null_value(&buf[i]))
00845 G_set_d_null_value(&p[i], 1);
00846 else
00847 p[i] = (DCELL) buf[i];
00848
00849 return G_put_d_raster_row(fd, p);
00850 }
00851
00852 static int convert_and_write_fd(int fd, FCELL *buf)
00853 {
00854 struct fileinfo *fcb = &G__.fileinfo[fd];
00855 DCELL *p = (DCELL *) fcb->data;
00856 int i;
00857
00858 for (i = 0; i < fcb->cellhd.cols; i++)
00859 if (G_is_f_null_value(&buf[i]))
00860 G_set_d_null_value(&p[i], 1);
00861 else
00862 p[i] = (DCELL) buf[i];
00863
00864 return G_put_d_raster_row(fd, p);
00865 }
00866
00867 static int convert_and_write_fi(int fd, FCELL *buf)
00868 {
00869 struct fileinfo *fcb = &G__.fileinfo[fd];
00870 CELL *p = (CELL *) fcb->data;
00871 int i;
00872
00873 for (i = 0; i < fcb->cellhd.cols; i++)
00874 if (G_is_f_null_value(&buf[i]))
00875 G_set_c_null_value(&p[i], 1);
00876 else
00877 p[i] = (CELL) buf[i];
00878
00879 return G_put_c_raster_row(fd, p);
00880 }
00881
00882 static int convert_and_write_di(int fd, DCELL *buf)
00883 {
00884 struct fileinfo *fcb = &G__.fileinfo[fd];
00885 CELL *p = (CELL *) fcb->data;
00886 int i;
00887
00888 for (i = 0; i < fcb->cellhd.cols; i++)
00889 if (G_is_d_null_value(&buf[i]))
00890 G_set_c_null_value(&p[i], 1);
00891 else
00892 p[i] = (CELL) buf[i];
00893
00894 return G_put_c_raster_row(fd, p);
00895 }
00896
00897
00898
00899 static int put_raster_row(
00900 int fd, void *buf, RASTER_MAP_TYPE data_type, int zeros_r_nulls)
00901 {
00902 struct fileinfo *fcb = &G__.fileinfo[fd];
00903
00904 static int (*convert_and_write_FtypeOtype[3][3])() = {
00905 {NULL , convert_and_write_if, convert_and_write_id},
00906 {convert_and_write_fi, NULL , convert_and_write_fd},
00907 {convert_and_write_di, convert_and_write_df, NULL }
00908 };
00909
00910 if (!check_open("put_raster_row", fd, 0))
00911 return -1;
00912
00913 if (fcb->map_type != data_type)
00914 return convert_and_write_FtypeOtype[data_type][fcb->map_type](fd, buf);
00915
00916 G_zero(G__.null_buf, fcb->cellhd.cols * sizeof(char));
00917
00918 switch (put_raster_data(fd, buf, fcb->cur_row, 0, fcb->cellhd.cols, zeros_r_nulls, data_type))
00919 {
00920 case -1: return -1;
00921 case 0: return 1;
00922 }
00923
00924
00925 if (data_type == CELL_TYPE)
00926 {
00927 if (fcb->want_histogram)
00928 G_update_cell_stats(buf, fcb->cellhd.cols, &fcb->statf);
00929 G__row_update_range(buf, fcb->cellhd.cols, &fcb->range, zeros_r_nulls);
00930 }
00931 else
00932 G_row_update_fp_range (buf, fcb->cellhd.cols, &fcb->fp_range, data_type);
00933
00934 fcb->cur_row++;
00935
00936
00937 return G__put_null_value_row(fd, G__.null_buf);
00938 }