while (buf->pending_bits >= 8) { if (buf->num_data >= buf->data_size) {
status = _lzw_buf_grow (buf); if (unlikely (status)) return;
}
buf->data[buf->num_data++] = buf->pending >> (buf->pending_bits - 8);
buf->pending_bits -= 8;
}
}
/* Store the last remaining pending bits into the buffer. * *Note:Thisfunctionmustbecalledafterthelastcallto *_lzw_buf_store_bits. * *Setsbuf->statustoeither%CAIRO_STATUS_SUCCESSor%CAIRO_STATUS_NO_MEMORY.
*/ staticvoid
_lzw_buf_store_pending (lzw_buf_t *buf)
{
cairo_status_t status;
if (buf->status) return;
if (buf->pending_bits == 0) return;
assert (buf->pending_bits < 8);
if (buf->num_data >= buf->data_size) {
status = _lzw_buf_grow (buf); if (unlikely (status)) return;
}
/* LZW defines a few magic code values */ #define LZW_CODE_CLEAR_TABLE 256 #define LZW_CODE_EOD 257 #define LZW_CODE_FIRST 258
/* We pack three separate values into a symbol as follows: * *12bits(31downto20):CODE:codevalueusedtorepresentthissymbol *12bits(19downto8):PREV:previouscodevalueinchain *8bits(7downto0):NEXT:nextbytevalueinchain
*/ typedef uint32_t lzw_symbol_t;
/* The PREV+NEXT fields can be seen as the key used to fetch values *fromthehashtable,whilethecodeisthevaluefetched.
*/ #define LZW_SYMBOL_KEY_MASK 0x000fffff
/* Since code values are only stored starting with 258 we can safely
* use a zero value to represent free slots in the hash table. */ #define LZW_SYMBOL_FREE 0x00000000
/* These really aren't very free for modifying. First, the PostScript *specificationsetsthe9-12bitrange.Second,theencodingof *lzw_symbol_tabovealsorelieson2ofLZW_BITS_MAXplusonebyte *fittingwithin32bits. * *Butotherthanthat,theLZWcompressionschemecouldfunctionwith *morebitspercode.
*/ #define LZW_BITS_MIN 9 #define LZW_BITS_MAX 12 #define LZW_BITS_BOUNDARY(bits) ((1<<(bits))-1) #define LZW_MAX_SYMBOLS (1<<LZW_BITS_MAX)
/* Lookup a symbol in the symbol table. The PREV and NEXT fields of *symbolformthekeyforthelookup. * *Ifsuccessful,thenthisfunctionreturns%TRUEandslot_retwillbe *leftpointingattheresultthatwillhavetheCODEfieldof *interest. * *Ifthelookupfails,thenthisfunctionreturns%FALSEandslot_ret *willbepointingatthelocationinthetabletowhichanewCODE *valueshouldbestoredalongwithPREVandNEXT.
*/ static cairo_bool_t
_lzw_symbol_table_lookup (lzw_symbol_table_t *table,
lzw_symbol_t symbol,
lzw_symbol_t **slot_ret)
{ /* The algorithm here is identical to that in cairo-hash.c. We *copyitheretoallowforarathermoreefficient *implementationduetoseveralcircumstancesthatdonotapply *tothemoregeneralcase: * *1)Wehaveaknownboundonthetotalnumberofsymbols,sowe *haveafixed-sizetablewithoutanycopyingwhengrowing * *2)Weneverdeleteanyentries,sowedon'tneedto *support/checkforDEADentriesduringlookup. * *3)Theobjectfitsin32bitssowestoreeachobjectinits *entiretywithinthetableratherthanstoringobjects *externallyandputtingpointersinthetable,(whichhere *wouldjustdoublethestoragerequirementsandhavenegative *impactsonmemorylocality).
*/ int i, idx, step, hash = symbol & LZW_SYMBOL_KEY_MASK;
lzw_symbol_t candidate;
idx = hash % LZW_SYMBOL_MOD1;
step = 0;
*slot_ret = NULL; for (i = 0; i < LZW_SYMBOL_TABLE_SIZE; i++)
{
candidate = table->table[idx]; if (candidate == LZW_SYMBOL_FREE)
{
*slot_ret = &table->table[idx]; returnFALSE;
} else/* candidate is LIVE */
{ if ((candidate & LZW_SYMBOL_KEY_MASK) ==
(symbol & LZW_SYMBOL_KEY_MASK))
{
*slot_ret = &table->table[idx]; return TRUE;
}
}
if (step == 0) {
step = hash % LZW_SYMBOL_MOD2; if (step == 0)
step = 1;
}
/* Compress a bytestream using the LZW algorithm. * *Thisisanoriginalimplementationbasedonreadingthe *specificationoftheLZWDecodefilterinthePostScriptLanguage *Reference.ThefreeparametersintheLZWalgorithmaresettothe *valuesmandatedbyPostScript,(symbolsencodedwithwidthsfrom9 *to12bits). * *Thisfunctionreturnsapointertoanewlyallocatedbufferholding *thecompresseddata,or%NULLifanout-of-memorysituation *occurs. * *Noticethatanyoneofthe_lzw_buffunctionscalledherecould *triggeranout-of-memorycondition.Butlzw_buf_tusescairo's *shutdown-on-erroridiom,soit'ssafetocontinuetocallinto *lzw_bufwithouthavingtocheckforerrors,(untilafinalcheckat *theend).
*/ unsignedchar *
_cairo_lzw_compress (unsignedchar *data, unsignedlong *size_in_out)
{ int bytes_remaining = *size_in_out;
lzw_buf_t buf;
lzw_symbol_table_t table;
lzw_symbol_t symbol, *slot = NULL; /* just to squelch a warning */ int code_next = LZW_CODE_FIRST; int code_bits = LZW_BITS_MIN; int prev, next = 0; /* just to squelch a warning */
if (*size_in_out == 0) return NULL;
_lzw_buf_init (&buf, *size_in_out);
_lzw_symbol_table_init (&table);
/* The LZW header is a clear table code. */
_lzw_buf_store_bits (&buf, LZW_CODE_CLEAR_TABLE, code_bits);
while (1) {
/* Find the longest existing code in the symbol table that
* matches the current input, if any. */
prev = *data++;
bytes_remaining--; if (bytes_remaining) { do
{
next = *data++;
bytes_remaining--;
LZW_SYMBOL_SET (symbol, prev, next); if (_lzw_symbol_table_lookup (&table, symbol, &slot))
prev = LZW_SYMBOL_GET_CODE (*slot);
} while (bytes_remaining && *slot != LZW_SYMBOL_FREE); if (*slot == LZW_SYMBOL_FREE) {
data--;
bytes_remaining++;
}
}
/* Write the code into the output. This is either a byte read *directlyfromtheinput,oracodefromthelastsuccessful
* lookup. */
_lzw_buf_store_bits (&buf, prev, code_bits);
if (likely (slot != NULL))
LZW_SYMBOL_SET_CODE (*slot, code_next, prev, next);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.