mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-06-19 14:15:21 -06:00
278 lines
9.6 KiB
C++
278 lines
9.6 KiB
C++
/******************************************************************************
|
|
* $Id: rmflzw.cpp 11865 2007-08-09 11:53:57Z warmerdam $
|
|
*
|
|
* Project: Raster Matrix Format
|
|
* Purpose: Implementation of the ad-hoc compression algorithm used in
|
|
* GIS "Panorama"/"Integratsia".
|
|
* Author: Andrey Kiselev, dron@ak4719.spb.edu
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 2009, Andrey Kiselev <dron@ak4719.spb.edu>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
****************************************************************************/
|
|
|
|
#include "cpl_conv.h"
|
|
|
|
#include "rmfdataset.h"
|
|
|
|
/*
|
|
* The encoded data stream is a series of records.
|
|
*
|
|
* Encoded record consist from the 1-byte record header followed by the
|
|
* encoded data block. Header specifies the number of elements in the data
|
|
* block and encoding type. Header format
|
|
*
|
|
* +---+---+---+---+---+---+---+---+
|
|
* | type | count |
|
|
* +---+---+---+---+---+---+---+---+
|
|
* 7 6 5 4 3 2 1 0
|
|
*
|
|
* If count is zero then it means that there are more than 31 elements in this
|
|
* record. Read the next byte in the stream and increase its value with 32 to
|
|
* get the count. In this case maximum number of elements is 287.
|
|
*
|
|
* The "type" field specifies encoding type. It can be either difference
|
|
* between the previous and the next data value (for the first element the
|
|
* previous value is zero) or out-of-range codes.
|
|
*
|
|
* In case of "out of range" or "zero difference" values there are no more
|
|
* elements in record after the header. Otherwise read as much encoded
|
|
* elements as count specifies.
|
|
*/
|
|
|
|
// Encoding types
|
|
#define TYPE_OUT 0x00 // Value is out of range
|
|
#define TYPE_ZERO 0x20 // Zero difference
|
|
#define TYPE_INT4 0x40 // Difference is 4-bit wide
|
|
#define TYPE_INT8 0x60 // Difference is 8-bit wide
|
|
#define TYPE_INT12 0x80 // Difference is 12-bit wide
|
|
#define TYPE_INT16 0xA0 // Difference is 16-bit wide
|
|
#define TYPE_INT24 0xC0 // Difference is 24-bit wide
|
|
#define TYPE_INT32 0xE0 // Difference is 32-bit wide
|
|
|
|
// Encoding ranges
|
|
#define RANGE_INT4 0x00000007L // 4-bit
|
|
#define RANGE_INT12 0x000007FFL // 12-bit
|
|
#define RANGE_INT24 0x007FFFFFL // 24-bit
|
|
|
|
// Out of range codes
|
|
#define OUT_INT4 ((GInt32)0xFFFFFFF8)
|
|
#define OUT_INT8 ((GInt32)0xFFFFFF80)
|
|
#define OUT_INT12 ((GInt32)0xFFFFF800)
|
|
#define OUT_INT16 ((GInt32)0xFFFF8000)
|
|
#define OUT_INT24 ((GInt32)0xFF800000)
|
|
#define OUT_INT32 ((GInt32)0x80000000)
|
|
|
|
// Inversion masks
|
|
#define INV_INT4 0xFFFFFFF0L
|
|
#define INV_INT12 0xFFFFF000L
|
|
#define INV_INT24 0xFF000000L
|
|
|
|
|
|
/************************************************************************/
|
|
/* DEMDecompress() */
|
|
/************************************************************************/
|
|
|
|
int RMFDataset::DEMDecompress( const GByte* pabyIn, GUInt32 nSizeIn,
|
|
GByte* pabyOut, GUInt32 nSizeOut )
|
|
{
|
|
GUInt32 nCount; // Number of encoded data elements to read
|
|
char* pabyTempIn;
|
|
GInt32* paiOut;
|
|
GInt32 nType; // The encoding type
|
|
GInt32 iPrev = 0; // The last data value decoded
|
|
GInt32 nCode;
|
|
|
|
if ( pabyIn == 0 ||
|
|
pabyOut == 0 ||
|
|
nSizeOut < nSizeIn ||
|
|
nSizeIn < 2 )
|
|
return 0;
|
|
|
|
pabyTempIn = (char*)pabyIn;
|
|
paiOut = (GInt32*)pabyOut;
|
|
nSizeOut /= sizeof(GInt32);
|
|
|
|
while ( nSizeIn > 0 )
|
|
{
|
|
// Read number of codes in the record and encoding type
|
|
nCount = *pabyTempIn & 0x1F;
|
|
nType = *pabyTempIn++ & 0xE0;
|
|
nSizeIn--;
|
|
if ( nCount == 0 )
|
|
{
|
|
if ( nSizeIn == 0 )
|
|
break;
|
|
nCount = 32 + *((unsigned char*)pabyTempIn++);
|
|
nSizeIn--;
|
|
}
|
|
|
|
switch (nType)
|
|
{
|
|
case TYPE_ZERO:
|
|
if ( nSizeOut < nCount )
|
|
break;
|
|
nSizeOut -= nCount;
|
|
while ( nCount-- > 0 )
|
|
*paiOut++ = iPrev;
|
|
break;
|
|
|
|
case TYPE_OUT:
|
|
if ( nSizeOut < nCount )
|
|
break;
|
|
nSizeOut -= nCount;
|
|
while ( nCount-- > 0 )
|
|
*paiOut++ = OUT_INT32;
|
|
break;
|
|
|
|
case TYPE_INT4:
|
|
if ( nSizeIn < nCount / 2 )
|
|
break;
|
|
if ( nSizeOut < nCount )
|
|
break;
|
|
nSizeIn -= nCount / 2;
|
|
nSizeOut -= nCount;
|
|
while ( nCount-- > 0 )
|
|
{
|
|
nCode = (*pabyTempIn) & 0x0F;
|
|
if ( nCode > RANGE_INT4 )
|
|
nCode |= INV_INT4;
|
|
*paiOut++ = ( nCode == OUT_INT4 ) ?
|
|
OUT_INT32 : iPrev += nCode;
|
|
|
|
if ( nCount-- == 0 )
|
|
{
|
|
pabyTempIn++;
|
|
nSizeIn--;
|
|
break;
|
|
}
|
|
|
|
nCode = ((*pabyTempIn++)>>4) & 0x0F;
|
|
if ( nCode > RANGE_INT4 )
|
|
nCode |= INV_INT4;
|
|
*paiOut++ = ( nCode == OUT_INT4 ) ?
|
|
OUT_INT32 : iPrev += nCode;
|
|
}
|
|
break;
|
|
|
|
case TYPE_INT8:
|
|
if ( nSizeIn < nCount )
|
|
break;
|
|
if ( nSizeOut < nCount )
|
|
break;
|
|
nSizeIn -= nCount;
|
|
nSizeOut -= nCount;
|
|
while ( nCount-- > 0 )
|
|
{
|
|
*paiOut++ = ( (nCode = *pabyTempIn++) == OUT_INT8 ) ?
|
|
OUT_INT32 : iPrev += nCode;
|
|
}
|
|
break;
|
|
|
|
case TYPE_INT12:
|
|
if ( nSizeIn < 3 * nCount / 2 )
|
|
break;
|
|
if ( nSizeOut < nCount )
|
|
break;
|
|
nSizeIn -= 3 * nCount / 2;
|
|
nSizeOut -= nCount;
|
|
|
|
while ( nCount-- > 0 )
|
|
{
|
|
nCode = *((GInt16*)pabyTempIn++) & 0x0FFF;
|
|
if ( nCode > RANGE_INT12 )
|
|
nCode |= INV_INT12;
|
|
*paiOut++ = ( nCode == OUT_INT12 ) ?
|
|
OUT_INT32 : iPrev += nCode;
|
|
|
|
if ( nCount-- == 0 )
|
|
{
|
|
pabyTempIn++;
|
|
nSizeIn--;
|
|
break;
|
|
}
|
|
|
|
nCode = ( (*(GInt16*)pabyTempIn) >> 4 ) & 0x0FFF;
|
|
pabyTempIn += 2;
|
|
if ( nCode > RANGE_INT12 )
|
|
nCode |= INV_INT12;
|
|
*paiOut++ = ( nCode == OUT_INT12 ) ?
|
|
OUT_INT32 : iPrev += nCode;
|
|
}
|
|
break;
|
|
|
|
case TYPE_INT16:
|
|
if ( nSizeIn < 2 * nCount )
|
|
break;
|
|
if ( nSizeOut < nCount )
|
|
break;
|
|
nSizeIn -= 2 * nCount;
|
|
nSizeOut -= nCount;
|
|
|
|
while ( nCount-- > 0 )
|
|
{
|
|
nCode = *((GInt16*)pabyTempIn);
|
|
pabyTempIn += 2;
|
|
*paiOut++ = ( nCode == OUT_INT16 ) ?
|
|
OUT_INT32 : iPrev += nCode;
|
|
}
|
|
break;
|
|
|
|
case TYPE_INT24:
|
|
if ( nSizeIn < 3 * nCount )
|
|
break;
|
|
if ( nSizeOut < nCount )
|
|
break;
|
|
nSizeIn -= 3 * nCount;
|
|
nSizeOut -= nCount;
|
|
|
|
while ( nCount-- > 0 )
|
|
{
|
|
nCode =*((GInt32 *)pabyTempIn) & 0x00FFFFFF;
|
|
pabyTempIn += 3;
|
|
if ( nCode > RANGE_INT24 )
|
|
nCode |= INV_INT24;
|
|
*paiOut++ = ( nCode == OUT_INT24 ) ?
|
|
OUT_INT32 : iPrev += nCode;
|
|
}
|
|
break;
|
|
|
|
case TYPE_INT32:
|
|
if ( nSizeIn < 4 * nCount )
|
|
break;
|
|
if ( nSizeOut < nCount )
|
|
break;
|
|
nSizeIn -= 4 * nCount;
|
|
nSizeOut -= nCount;
|
|
|
|
while ( nCount-- > 0 )
|
|
{
|
|
nCode = *(GInt32 *)pabyTempIn;
|
|
pabyTempIn += 4;
|
|
*paiOut++ = ( nCode == OUT_INT32 ) ?
|
|
OUT_INT32 : iPrev += nCode;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ((GByte*)paiOut - pabyOut);
|
|
}
|
|
|