Line data Source code
1 : /******************************************************************************
2 : *
3 : * Purpose: Implementation of the CExternalChannel class.
4 : *
5 : * This class is used to implement band interleaved channels that are
6 : * references to an external image database that is not just a raw file.
7 : * It uses the application supplied EDB interface to access non-PCIDSK files.
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2010
11 : * PCI Geomatics, 90 Allstate Parkway, Markham, Ontario, Canada.
12 : *
13 : * SPDX-License-Identifier: MIT
14 : ****************************************************************************/
15 :
16 : #include "pcidsk_config.h"
17 : #include "pcidsk_types.h"
18 : #include "pcidsk_channel.h"
19 : #include "pcidsk_buffer.h"
20 : #include "pcidsk_exception.h"
21 : #include "pcidsk_file.h"
22 : #include "core/pcidsk_utils.h"
23 : #include "core/cpcidskfile.h"
24 : #include "channel/cexternalchannel.h"
25 : #include "core/clinksegment.h"
26 : #include <cassert>
27 : #include <cstring>
28 : #include <cstdio>
29 : #include <cstdlib>
30 : #include <climits>
31 :
32 : using namespace PCIDSK;
33 :
34 : /************************************************************************/
35 : /* CExternalChannel() */
36 : /************************************************************************/
37 :
38 0 : CExternalChannel::CExternalChannel( PCIDSKBuffer &image_headerIn,
39 : uint64 ih_offsetIn,
40 : CPL_UNUSED PCIDSKBuffer &file_headerIn,
41 : const std::string& filenameIn,
42 : int channelnumIn,
43 : CPCIDSKFile *fileIn,
44 0 : eChanType pixel_typeIn )
45 0 : : CPCIDSKChannel( image_headerIn, ih_offsetIn, fileIn, pixel_typeIn, channelnumIn)
46 :
47 : {
48 0 : db = nullptr;
49 0 : mutex = nullptr;
50 0 : writable = false;
51 0 : blocks_per_row = 0;
52 :
53 : /* -------------------------------------------------------------------- */
54 : /* Establish the data window. */
55 : /* -------------------------------------------------------------------- */
56 0 : exoff = atoi(image_headerIn.Get( 250, 8 ));
57 0 : eyoff = atoi(image_headerIn.Get( 258, 8 ));
58 0 : exsize = atoi(image_headerIn.Get( 266, 8 ));
59 0 : eysize = atoi(image_headerIn.Get( 274, 8 ));
60 :
61 0 : echannel = atoi(image_headerIn.Get( 282, 8 ));
62 :
63 0 : if (echannel == 0) {
64 0 : echannel = channelnumIn;
65 : }
66 :
67 0 : if( exoff < 0 || eyoff < 0 || exsize < 0 || eysize < 0 )
68 : {
69 0 : ThrowPCIDSKException("Invalid data window parameters for CExternalChannel");
70 : }
71 :
72 : /* -------------------------------------------------------------------- */
73 : /* Establish the file we will be accessing. */
74 : /* -------------------------------------------------------------------- */
75 0 : if( filenameIn != "" )
76 0 : this->filename = filenameIn;
77 : else
78 0 : image_headerIn.Get(64,64,this->filename);
79 0 : }
80 :
81 : /************************************************************************/
82 : /* ~CExternalChannel() */
83 : /************************************************************************/
84 :
85 0 : CExternalChannel::~CExternalChannel()
86 :
87 : {
88 : // no need to deaccess the EDBFile - the file is responsible for that.
89 0 : }
90 :
91 : /************************************************************************/
92 : /* AccessDB() */
93 : /************************************************************************/
94 :
95 0 : void CExternalChannel::AccessDB() const
96 :
97 : {
98 0 : if( db )
99 0 : return;
100 :
101 : /* -------------------------------------------------------------------- */
102 : /* open, or fetch an already open file handle. */
103 : /* -------------------------------------------------------------------- */
104 0 : writable = file->GetEDBFileDetails( &db, &mutex, filename );
105 :
106 0 : if( !db )
107 : {
108 0 : ThrowPCIDSKException("db == nullptr");
109 : }
110 : else
111 : {
112 0 : if( echannel < 0 || echannel > db->GetChannels() )
113 : {
114 0 : ThrowPCIDSKException( 0,
115 0 : "Invalid channel number: %d", echannel );
116 : }
117 :
118 0 : pixel_type = db->GetType(echannel);
119 :
120 : /* -------------------------------------------------------------------- */
121 : /* Capture the block size. */
122 : /* -------------------------------------------------------------------- */
123 0 : block_width = db->GetBlockWidth( echannel );
124 0 : if( block_width > width )
125 0 : block_width = width;
126 0 : block_height = db->GetBlockHeight( echannel );
127 0 : if( block_height > height )
128 0 : block_height = height;
129 :
130 0 : blocks_per_row = (GetWidth() + block_width - 1) / block_width;
131 : }
132 : }
133 :
134 : /************************************************************************/
135 : /* GetType() */
136 : /************************************************************************/
137 :
138 0 : eChanType CExternalChannel::GetType() const
139 : {
140 0 : AccessDB();
141 :
142 0 : return pixel_type;
143 : }
144 :
145 : /************************************************************************/
146 : /* GetBlockWidth() */
147 : /************************************************************************/
148 :
149 0 : int CExternalChannel::GetBlockWidth() const
150 :
151 : {
152 0 : AccessDB();
153 :
154 0 : return block_width;
155 : }
156 :
157 : /************************************************************************/
158 : /* GetBlockHeight() */
159 : /************************************************************************/
160 :
161 0 : int CExternalChannel::GetBlockHeight() const
162 :
163 : {
164 0 : AccessDB();
165 :
166 0 : return block_height;
167 : }
168 :
169 : /************************************************************************/
170 : /* ReadBlock() */
171 : /************************************************************************/
172 :
173 0 : int CExternalChannel::ReadBlock( int block_index, void *buffer,
174 : int xoff, int yoff,
175 : int xsize, int ysize )
176 :
177 : {
178 0 : AccessDB();
179 :
180 : /* -------------------------------------------------------------------- */
181 : /* Default window if needed. */
182 : /* -------------------------------------------------------------------- */
183 0 : if( xoff == -1 && yoff == -1 && xsize == -1 && ysize == -1 )
184 : {
185 0 : xoff = 0;
186 0 : yoff = 0;
187 0 : xsize = GetBlockWidth();
188 0 : ysize = GetBlockHeight();
189 : }
190 :
191 : /* -------------------------------------------------------------------- */
192 : /* Validate Window */
193 : /* -------------------------------------------------------------------- */
194 0 : if( xoff < 0 || xoff + xsize > GetBlockWidth()
195 0 : || yoff < 0 || yoff + ysize > GetBlockHeight() )
196 : {
197 0 : return ThrowPCIDSKException( 0,
198 : "Invalid window in ReadBlock(): xoff=%d,yoff=%d,xsize=%d,ysize=%d",
199 0 : xoff, yoff, xsize, ysize );
200 : }
201 :
202 : /* -------------------------------------------------------------------- */
203 : /* Do a direct call for the simplest case of 1:1 block mapping. */
204 : /* -------------------------------------------------------------------- */
205 0 : if( exoff == 0 && eyoff == 0
206 0 : && exsize == db->GetWidth()
207 0 : && eysize == db->GetHeight() )
208 : {
209 0 : MutexHolder oHolder( mutex );
210 0 : return db->ReadBlock( echannel, block_index, buffer,
211 0 : xoff, yoff, xsize, ysize );
212 : }
213 :
214 : /* ==================================================================== */
215 : /* Otherwise we need to break this down into potentially up to */
216 : /* four requests against the source file. */
217 : /* ==================================================================== */
218 0 : int src_block_width = db->GetBlockWidth( echannel );
219 0 : int src_block_height = db->GetBlockHeight( echannel );
220 0 : int src_blocks_per_row = (db->GetWidth() + src_block_width - 1)
221 0 : / src_block_width;
222 0 : int pixel_size = DataTypeSize(GetType());
223 0 : std::vector<uint8> temp_buffer_vec;
224 : try
225 : {
226 0 : temp_buffer_vec.resize(static_cast<size_t>(src_block_width)*src_block_height*pixel_size);
227 : }
228 0 : catch( const std::exception& )
229 : {
230 0 : return ThrowPCIDSKException(0, "Failed to allocate temporary block buffer." );
231 : }
232 0 : uint8 *temp_buffer = &temp_buffer_vec[0];
233 : int txoff, tyoff, txsize, tysize;
234 : int dst_blockx, dst_blocky;
235 :
236 0 : dst_blockx = block_index % blocks_per_row;
237 0 : dst_blocky = block_index / blocks_per_row;
238 :
239 : // what is the region of our desired data on the destination file?
240 :
241 0 : txoff = dst_blockx * block_width + exoff + xoff;
242 0 : tyoff = dst_blocky * block_height + eyoff + yoff;
243 0 : txsize = xsize;
244 0 : tysize = ysize;
245 :
246 : /* -------------------------------------------------------------------- */
247 : /* read external block for top left corner of target block. */
248 : /* -------------------------------------------------------------------- */
249 : int ablock_x, ablock_y, i_line;
250 : int axoff, ayoff, axsize, aysize;
251 0 : int block1_xsize=0, block1_ysize=0;
252 : int ttxoff, ttyoff, ttxsize, ttysize;
253 :
254 0 : ttxoff = txoff;
255 0 : ttyoff = tyoff;
256 0 : ttxsize = txsize;
257 0 : ttysize = tysize;
258 :
259 0 : ablock_x = ttxoff / src_block_width;
260 0 : ablock_y = ttyoff / src_block_height;
261 :
262 0 : axoff = ttxoff - ablock_x * src_block_width;
263 0 : ayoff = ttyoff - ablock_y * src_block_height;
264 :
265 0 : if( axoff + ttxsize > src_block_width )
266 0 : axsize = src_block_width - axoff;
267 : else
268 0 : axsize = ttxsize;
269 :
270 0 : if( ayoff + ttysize > src_block_height )
271 0 : aysize = src_block_height - ayoff;
272 : else
273 0 : aysize = ttysize;
274 :
275 0 : if( axsize > 0 )
276 0 : block1_xsize = axsize;
277 : else
278 0 : block1_xsize = 0;
279 :
280 0 : if( aysize > 0 )
281 0 : block1_ysize = aysize;
282 : else
283 0 : block1_ysize = 0;
284 :
285 0 : if( axsize > 0 && aysize > 0 )
286 : {
287 0 : MutexHolder oHolder( mutex );
288 0 : if( src_blocks_per_row > 0 &&
289 0 : (ablock_y > INT_MAX / src_blocks_per_row ||
290 0 : ablock_y * src_blocks_per_row > INT_MAX - ablock_x) )
291 : {
292 0 : ThrowPCIDSKException(0, "Integer overflow." );
293 : }
294 0 : db->ReadBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
295 0 : temp_buffer, axoff, ayoff, axsize, aysize );
296 :
297 0 : for( i_line = 0; i_line < aysize; i_line++ )
298 : {
299 0 : memcpy( ((uint8*) buffer) + i_line * xsize * pixel_size,
300 0 : temp_buffer + i_line * axsize * pixel_size,
301 0 : static_cast<size_t>(axsize) * pixel_size );
302 : }
303 : }
304 :
305 : /* -------------------------------------------------------------------- */
306 : /* read external block for top right corner of target block. */
307 : /* -------------------------------------------------------------------- */
308 0 : ttxoff = txoff + block1_xsize;
309 0 : ttyoff = tyoff;
310 0 : ttxsize = txsize - block1_xsize;
311 0 : ttysize = tysize;
312 :
313 0 : ablock_x = ttxoff / src_block_width;
314 0 : ablock_y = ttyoff / src_block_height;
315 :
316 0 : axoff = ttxoff - ablock_x * src_block_width;
317 0 : ayoff = ttyoff - ablock_y * src_block_height;
318 :
319 0 : if( axoff + ttxsize > src_block_width )
320 0 : axsize = src_block_width - axoff;
321 : else
322 0 : axsize = ttxsize;
323 :
324 0 : if( ayoff + ttysize > src_block_height )
325 0 : aysize = src_block_height - ayoff;
326 : else
327 0 : aysize = ttysize;
328 :
329 0 : if( axsize > 0 && aysize > 0 )
330 : {
331 0 : MutexHolder oHolder( mutex );
332 0 : db->ReadBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
333 0 : temp_buffer, axoff, ayoff, axsize, aysize );
334 :
335 0 : for( i_line = 0; i_line < aysize; i_line++ )
336 : {
337 0 : memcpy( ((uint8*) buffer)
338 0 : + (block1_xsize + i_line * xsize) * pixel_size,
339 0 : temp_buffer + i_line * axsize * pixel_size,
340 0 : static_cast<size_t>(axsize) * pixel_size );
341 : }
342 : }
343 :
344 : /* -------------------------------------------------------------------- */
345 : /* read external block for bottom left corner of target block. */
346 : /* -------------------------------------------------------------------- */
347 0 : ttxoff = txoff;
348 0 : ttyoff = tyoff + block1_ysize;
349 0 : ttxsize = txsize;
350 0 : ttysize = tysize - block1_ysize;
351 :
352 0 : ablock_x = ttxoff / src_block_width;
353 0 : ablock_y = ttyoff / src_block_height;
354 :
355 0 : axoff = ttxoff - ablock_x * src_block_width;
356 0 : ayoff = ttyoff - ablock_y * src_block_height;
357 :
358 0 : if( axoff + ttxsize > src_block_width )
359 0 : axsize = src_block_width - axoff;
360 : else
361 0 : axsize = ttxsize;
362 :
363 0 : if( ayoff + ttysize > src_block_height )
364 0 : aysize = src_block_height - ayoff;
365 : else
366 0 : aysize = ttysize;
367 :
368 0 : if( axsize > 0 && aysize > 0 )
369 : {
370 0 : MutexHolder oHolder( mutex );
371 0 : db->ReadBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
372 0 : temp_buffer, axoff, ayoff, axsize, aysize );
373 :
374 0 : for( i_line = 0; i_line < aysize; i_line++ )
375 : {
376 0 : memcpy( ((uint8*) buffer)
377 0 : + (i_line + block1_ysize) * xsize * pixel_size,
378 0 : temp_buffer + i_line * axsize * pixel_size,
379 0 : static_cast<size_t>(axsize) * pixel_size );
380 : }
381 : }
382 :
383 : /* -------------------------------------------------------------------- */
384 : /* read external block for bottom left corner of target block. */
385 : /* -------------------------------------------------------------------- */
386 0 : ttxoff = txoff + block1_xsize;
387 0 : ttyoff = tyoff + block1_ysize;
388 0 : ttxsize = txsize - block1_xsize;
389 0 : ttysize = tysize - block1_ysize;
390 :
391 0 : ablock_x = ttxoff / src_block_width;
392 0 : ablock_y = ttyoff / src_block_height;
393 :
394 0 : axoff = ttxoff - ablock_x * src_block_width;
395 0 : ayoff = ttyoff - ablock_y * src_block_height;
396 :
397 0 : if( axoff + ttxsize > src_block_width )
398 0 : axsize = src_block_width - axoff;
399 : else
400 0 : axsize = ttxsize;
401 :
402 0 : if( ayoff + ttysize > src_block_height )
403 0 : aysize = src_block_height - ayoff;
404 : else
405 0 : aysize = ttysize;
406 :
407 0 : if( axsize > 0 && aysize > 0 )
408 : {
409 0 : MutexHolder oHolder( mutex );
410 0 : db->ReadBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
411 0 : temp_buffer, axoff, ayoff, axsize, aysize );
412 :
413 0 : for( i_line = 0; i_line < aysize; i_line++ )
414 : {
415 0 : memcpy( ((uint8*) buffer)
416 0 : + (block1_xsize + (i_line + block1_ysize) * xsize) * pixel_size,
417 0 : temp_buffer + i_line * axsize * pixel_size,
418 0 : static_cast<size_t>(axsize) * pixel_size );
419 : }
420 : }
421 :
422 0 : return 1;
423 : }
424 :
425 : /************************************************************************/
426 : /* WriteBlock() */
427 : /************************************************************************/
428 :
429 0 : int CExternalChannel::WriteBlock( int block_index, void *buffer )
430 :
431 : {
432 0 : AccessDB();
433 :
434 0 : if( !file->GetUpdatable() || !writable )
435 0 : return ThrowPCIDSKException(0, "File not open for update in WriteBlock()" );
436 :
437 : /* -------------------------------------------------------------------- */
438 : /* Pass the request on directly in the simple case. */
439 : /* -------------------------------------------------------------------- */
440 0 : if( exoff == 0 && eyoff == 0
441 0 : && exsize == db->GetWidth()
442 0 : && eysize == db->GetHeight() )
443 : {
444 0 : MutexHolder oHolder( mutex );
445 0 : return db->WriteBlock( echannel, block_index, buffer );
446 : }
447 :
448 : /* ==================================================================== */
449 : /* Otherwise we need to break this down into potentially up to */
450 : /* four requests against the source file. */
451 : /* ==================================================================== */
452 0 : int src_block_width = db->GetBlockWidth( echannel );
453 0 : int src_block_height = db->GetBlockHeight( echannel );
454 0 : int src_blocks_per_row = (db->GetWidth() + src_block_width - 1)
455 0 : / src_block_width;
456 0 : int pixel_size = DataTypeSize(GetType());
457 0 : uint8 *temp_buffer = (uint8 *) calloc(static_cast<size_t>(src_block_width)*src_block_height,
458 : pixel_size);
459 : int txoff, tyoff, txsize, tysize;
460 : int dst_blockx, dst_blocky;
461 :
462 0 : if( temp_buffer == nullptr )
463 0 : return ThrowPCIDSKException(0, "Failed to allocate temporary block buffer." );
464 :
465 0 : dst_blockx = block_index % blocks_per_row;
466 0 : dst_blocky = block_index / blocks_per_row;
467 :
468 : // what is the region of our desired data on the destination file?
469 :
470 0 : txoff = dst_blockx * block_width + exoff;
471 0 : tyoff = dst_blocky * block_height + eyoff;
472 0 : txsize = block_width;
473 0 : tysize = block_height;
474 :
475 : /* -------------------------------------------------------------------- */
476 : /* process external block for top left corner of target block. */
477 : /* -------------------------------------------------------------------- */
478 : int ablock_x, ablock_y, i_line;
479 : int axoff, ayoff, axsize, aysize;
480 0 : int block1_xsize=0, block1_ysize=0;
481 : int ttxoff, ttyoff, ttxsize, ttysize;
482 :
483 0 : ttxoff = txoff;
484 0 : ttyoff = tyoff;
485 0 : ttxsize = txsize;
486 0 : ttysize = tysize;
487 :
488 0 : ablock_x = ttxoff / src_block_width;
489 0 : ablock_y = ttyoff / src_block_height;
490 :
491 0 : axoff = ttxoff - ablock_x * src_block_width;
492 0 : ayoff = ttyoff - ablock_y * src_block_height;
493 :
494 0 : if( axoff + ttxsize > src_block_width )
495 0 : axsize = src_block_width - axoff;
496 : else
497 0 : axsize = ttxsize;
498 :
499 0 : if( ayoff + ttysize > src_block_height )
500 0 : aysize = src_block_height - ayoff;
501 : else
502 0 : aysize = ttysize;
503 :
504 0 : if( axsize > 0 )
505 0 : block1_xsize = axsize;
506 : else
507 0 : block1_xsize = 0;
508 :
509 0 : if( aysize > 0 )
510 0 : block1_ysize = aysize;
511 : else
512 0 : block1_ysize = 0;
513 :
514 0 : if( axsize > 0 && aysize > 0 )
515 : {
516 0 : MutexHolder oHolder( mutex );
517 0 : db->ReadBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
518 0 : temp_buffer );
519 :
520 0 : for( i_line = 0; i_line < aysize; i_line++ )
521 : {
522 0 : memcpy( temp_buffer
523 0 : + (i_line+ayoff) * src_block_width * pixel_size
524 0 : + axoff * pixel_size,
525 0 : ((uint8*) buffer) + i_line * block_width * pixel_size,
526 0 : static_cast<size_t>(axsize) * pixel_size );
527 : }
528 :
529 0 : db->WriteBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
530 0 : temp_buffer );
531 : }
532 :
533 : /* -------------------------------------------------------------------- */
534 : /* read external block for top right corner of target block. */
535 : /* -------------------------------------------------------------------- */
536 0 : ttxoff = txoff + block1_xsize;
537 0 : ttyoff = tyoff;
538 0 : ttxsize = txsize - block1_xsize;
539 0 : ttysize = tysize;
540 :
541 0 : ablock_x = ttxoff / src_block_width;
542 0 : ablock_y = ttyoff / src_block_height;
543 :
544 0 : axoff = ttxoff - ablock_x * src_block_width;
545 0 : ayoff = ttyoff - ablock_y * src_block_height;
546 :
547 0 : if( axoff + ttxsize > src_block_width )
548 0 : axsize = src_block_width - axoff;
549 : else
550 0 : axsize = ttxsize;
551 :
552 0 : if( ayoff + ttysize > src_block_height )
553 0 : aysize = src_block_height - ayoff;
554 : else
555 0 : aysize = ttysize;
556 :
557 0 : if( axsize > 0 && aysize > 0 )
558 : {
559 0 : MutexHolder oHolder( mutex );
560 0 : db->ReadBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
561 0 : temp_buffer );
562 :
563 0 : for( i_line = 0; i_line < aysize; i_line++ )
564 : {
565 0 : memcpy( temp_buffer
566 0 : + (i_line+ayoff) * src_block_width * pixel_size
567 0 : + axoff * pixel_size,
568 0 : ((uint8*) buffer) + i_line * block_width * pixel_size
569 0 : + block1_xsize * pixel_size,
570 0 : static_cast<size_t>(axsize) * pixel_size );
571 : }
572 :
573 0 : db->WriteBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
574 0 : temp_buffer );
575 : }
576 :
577 : /* -------------------------------------------------------------------- */
578 : /* read external block for bottom left corner of target block. */
579 : /* -------------------------------------------------------------------- */
580 0 : ttxoff = txoff;
581 0 : ttyoff = tyoff + block1_ysize;
582 0 : ttxsize = txsize;
583 0 : ttysize = tysize - block1_ysize;
584 :
585 0 : ablock_x = ttxoff / src_block_width;
586 0 : ablock_y = ttyoff / src_block_height;
587 :
588 0 : axoff = ttxoff - ablock_x * src_block_width;
589 0 : ayoff = ttyoff - ablock_y * src_block_height;
590 :
591 0 : if( axoff + ttxsize > src_block_width )
592 0 : axsize = src_block_width - axoff;
593 : else
594 0 : axsize = ttxsize;
595 :
596 0 : if( ayoff + ttysize > src_block_height )
597 0 : aysize = src_block_height - ayoff;
598 : else
599 0 : aysize = ttysize;
600 :
601 0 : if( axsize > 0 && aysize > 0 )
602 : {
603 0 : MutexHolder oHolder( mutex );
604 0 : db->ReadBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
605 0 : temp_buffer );
606 :
607 0 : for( i_line = 0; i_line < aysize; i_line++ )
608 : {
609 0 : memcpy( temp_buffer
610 0 : + (i_line+ayoff) * src_block_width * pixel_size
611 0 : + axoff * pixel_size,
612 : ((uint8*) buffer)
613 0 : + (i_line+block1_ysize) * block_width * pixel_size,
614 0 : static_cast<size_t>(axsize) * pixel_size );
615 : }
616 :
617 0 : db->WriteBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
618 0 : temp_buffer );
619 : }
620 :
621 : /* -------------------------------------------------------------------- */
622 : /* read external block for bottom left corner of target block. */
623 : /* -------------------------------------------------------------------- */
624 0 : ttxoff = txoff + block1_xsize;
625 0 : ttyoff = tyoff + block1_ysize;
626 0 : ttxsize = txsize - block1_xsize;
627 0 : ttysize = tysize - block1_ysize;
628 :
629 0 : ablock_x = ttxoff / src_block_width;
630 0 : ablock_y = ttyoff / src_block_height;
631 :
632 0 : axoff = ttxoff - ablock_x * src_block_width;
633 0 : ayoff = ttyoff - ablock_y * src_block_height;
634 :
635 0 : if( axoff + ttxsize > src_block_width )
636 0 : axsize = src_block_width - axoff;
637 : else
638 0 : axsize = ttxsize;
639 :
640 0 : if( ayoff + ttysize > src_block_height )
641 0 : aysize = src_block_height - ayoff;
642 : else
643 0 : aysize = ttysize;
644 :
645 0 : if( axsize > 0 && aysize > 0 )
646 : {
647 0 : MutexHolder oHolder( mutex );
648 0 : db->ReadBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
649 0 : temp_buffer );
650 :
651 0 : for( i_line = 0; i_line < aysize; i_line++ )
652 : {
653 0 : memcpy( temp_buffer
654 0 : + (i_line+ayoff) * src_block_width * pixel_size
655 0 : + axoff * pixel_size,
656 : ((uint8*) buffer)
657 0 : + (i_line+block1_ysize) * block_width * pixel_size
658 0 : + block1_xsize * pixel_size,
659 0 : static_cast<size_t>(axsize) * pixel_size );
660 : }
661 :
662 0 : db->WriteBlock( echannel, ablock_x + ablock_y * src_blocks_per_row,
663 0 : temp_buffer );
664 : }
665 :
666 0 : free( temp_buffer );
667 :
668 0 : return 1;
669 : }
670 :
671 : /************************************************************************/
672 : /* GetEChanInfo() */
673 : /************************************************************************/
674 0 : void CExternalChannel::GetEChanInfo( std::string &filenameOut, int &echannelOut,
675 : int &exoffOut, int &eyoffOut,
676 : int &exsizeOut, int &eysizeOut ) const
677 :
678 : {
679 0 : echannelOut = this->echannel;
680 0 : exoffOut = this->exoff;
681 0 : eyoffOut = this->eyoff;
682 0 : exsizeOut = this->exsize;
683 0 : eysizeOut = this->eysize;
684 0 : filenameOut = this->filename;
685 0 : }
686 :
687 : /************************************************************************/
688 : /* SetEChanInfo() */
689 : /************************************************************************/
690 :
691 0 : void CExternalChannel::SetEChanInfo( std::string filenameIn, int echannelIn,
692 : int exoffIn, int eyoffIn,
693 : int exsizeIn, int eysizeIn )
694 :
695 : {
696 0 : if( ih_offset == 0 )
697 0 : return ThrowPCIDSKException( "No Image Header available for this channel." );
698 :
699 : /* -------------------------------------------------------------------- */
700 : /* Fetch the existing image header. */
701 : /* -------------------------------------------------------------------- */
702 0 : PCIDSKBuffer ih(1024);
703 :
704 0 : file->ReadFromFile( ih.buffer, ih_offset, 1024 );
705 :
706 : /* -------------------------------------------------------------------- */
707 : /* If the linked filename is too long to fit in the 64 */
708 : /* character IHi.2 field, then we need to use a link segment to */
709 : /* store the filename. */
710 : /* -------------------------------------------------------------------- */
711 0 : std::string IHi2_filename;
712 :
713 0 : if( filenameIn.size() > 64 )
714 : {
715 : int link_segment;
716 :
717 0 : ih.Get( 64, 64, IHi2_filename );
718 :
719 0 : if( IHi2_filename.substr(0,3) == "LNK" )
720 : {
721 0 : link_segment = std::atoi( IHi2_filename.c_str() + 4 );
722 : }
723 : else
724 : {
725 : char link_filename[64];
726 :
727 : link_segment =
728 0 : file->CreateSegment( "Link ",
729 : "Long external channel filename link.",
730 : SEG_SYS, 1 );
731 :
732 0 : snprintf( link_filename, sizeof(link_filename), "LNK %4d", link_segment );
733 0 : IHi2_filename = link_filename;
734 : }
735 :
736 : CLinkSegment *link =
737 0 : dynamic_cast<CLinkSegment*>( file->GetSegment( link_segment ) );
738 :
739 0 : if( link != nullptr )
740 : {
741 0 : link->SetPath( filenameIn );
742 0 : link->Synchronize();
743 : }
744 : }
745 :
746 : /* -------------------------------------------------------------------- */
747 : /* If we used to have a link segment but no longer need it, we */
748 : /* need to delete the link segment. */
749 : /* -------------------------------------------------------------------- */
750 : else
751 : {
752 0 : ih.Get( 64, 64, IHi2_filename );
753 :
754 0 : if( IHi2_filename.substr(0,3) == "LNK" )
755 : {
756 0 : int link_segment = std::atoi( IHi2_filename.c_str() + 4 );
757 :
758 0 : file->DeleteSegment( link_segment );
759 : }
760 :
761 0 : IHi2_filename = filenameIn;
762 : }
763 :
764 : /* -------------------------------------------------------------------- */
765 : /* Update the image header. */
766 : /* -------------------------------------------------------------------- */
767 : // IHi.2
768 0 : ih.Put( IHi2_filename.c_str(), 64, 64 );
769 :
770 : // IHi.6.1
771 0 : ih.Put( "", 168, 16 );
772 :
773 : // IHi.6.2
774 0 : ih.Put( "", 184, 8 );
775 :
776 : // IHi.6.3
777 0 : ih.Put( "", 192, 8 );
778 :
779 : // IHi.6.5
780 0 : ih.Put( "", 201, 1 );
781 :
782 : // IHi.6.7
783 0 : ih.Put( exoffIn, 250, 8 );
784 :
785 : // IHi.6.8
786 0 : ih.Put( eyoffIn, 258, 8 );
787 :
788 : // IHi.6.9
789 0 : ih.Put( exsizeIn, 266, 8 );
790 :
791 : // IHi.6.10
792 0 : ih.Put( eysizeIn, 274, 8 );
793 :
794 : // IHi.6.11
795 0 : ih.Put( echannelIn, 282, 8 );
796 :
797 0 : file->WriteToFile( ih.buffer, ih_offset, 1024 );
798 :
799 : /* -------------------------------------------------------------------- */
800 : /* Update local configuration. */
801 : /* -------------------------------------------------------------------- */
802 0 : this->filename = file->GetInterfaces()->MergeRelativePath( file->GetInterfaces()->io,
803 0 : file->GetFilename(),
804 0 : filenameIn );
805 :
806 0 : this->exoff = exoffIn;
807 0 : this->eyoff = eyoffIn;
808 0 : this->exsize = exsizeIn;
809 0 : this->eysize = eysizeIn;
810 0 : this->echannel = echannelIn;
811 : }
|