Coverage Report

Created: 2026-09-26 08:22

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