예제 #1
0
void
scanSegStack(segstack *stack, void (*func)(void *cell))
{ segchunk *chunk;

  if ( (chunk=stack->last) )		/* something there */
  { if ( stack->base == CHUNK_DATA(chunk) )
      chunk->top = stack->top;		/* close last chunk */
    for(; chunk; chunk=chunk->previous)
      scan_chunk(stack, chunk->top, CHUNK_DATA(chunk), func);
  }
}
예제 #2
0
void
popTopOfSegStack_(segstack *stack)
{ again:

  if ( stack->top >= stack->base + stack->unit_size )
  { stack->top -= stack->unit_size;
  } else
  { segchunk *chunk = stack->last;

    if ( chunk )
    { if ( chunk->previous )
      { segchunk *del = chunk;

	stack->last = chunk->previous;
	stack->last->next = NULL;
	chunk = stack->last;
	stack->top  = chunk->top;
	MemoryBarrier();		/* Sync with scanSegStack() */
	stack->base = CHUNK_DATA(chunk);
	stack->max  = addPointer(chunk, chunk->size);

	if ( del->allocated )
	  PL_free(del);

	goto again;
      }
    }

    assert(0);
  }
}
예제 #3
0
int
popSegStack_(segstack *stack, void *data)
{ again:

  if ( stack->top >= stack->base + stack->unit_size )
  { stack->top -= stack->unit_size;
    memcpy(data, stack->top, stack->unit_size);

    return TRUE;
  } else
  { segchunk *chunk = stack->last;

    if ( chunk )
    { if ( chunk->previous )
      { stack->last = chunk->previous;
	stack->last->next = NULL;
	if ( chunk->allocated )
	  PL_free(chunk);

	chunk = stack->last;
	stack->base = CHUNK_DATA(chunk);
	stack->max  = addPointer(chunk, chunk->size);
	stack->top  = chunk->top;
	goto again;
      }
    }

    return FALSE;
  }
}
예제 #4
0
void *
topOfSegStack(segstack *stack)
{ segchunk *chunk;

  if ( stack->top >= stack->base + stack->unit_size )
  { return stack->top - stack->unit_size;
  } else if ( stack->last && (chunk=stack->last->previous) )
  { assert(chunk->top - stack->unit_size >= CHUNK_DATA(chunk));
    return chunk->top - stack->unit_size;
  }

  return NULL;
}
예제 #5
0
int
pushSegStack_(segstack *stack, void *data)
{ if ( stack->top + stack->unit_size <= stack->max )
  { memcpy(stack->top, data, stack->unit_size);
    stack->top += stack->unit_size;

    return TRUE;
  } else
  { segchunk *chunk = PL_malloc(SEGSTACK_CHUNKSIZE);

    if ( !chunk )
      return FALSE;			/* out of memory */

    chunk->allocated = TRUE;
    chunk->size = SEGSTACK_CHUNKSIZE;
    chunk->next = NULL;
    chunk->previous = stack->last;
    chunk->top = CHUNK_DATA(chunk);	/* async scanning */
    if ( stack->last )
    { stack->last->next = chunk;
      stack->last->top = stack->top;
      stack->top = chunk->top;		/* async scanning */
      stack->last = chunk;
    } else
    { stack->top = chunk->top;		/* async scanning */
      stack->last = stack->first = chunk;
    }

    stack->base = CHUNK_DATA(chunk);
    stack->max  = addPointer(chunk, chunk->size);
    memcpy(CHUNK_DATA(chunk), data, stack->unit_size);
    stack->top  = CHUNK_DATA(chunk) + stack->unit_size;

    return TRUE;
  }
}
예제 #6
0
bool KPngPlugin::readInfo( KFileMetaInfo& info, uint what)
{
    if ( info.path().isEmpty() ) // remote file
        return false;
    QFile f(info.path());
    if ( !f.open(IO_ReadOnly) )
        return false;

    QIODevice::Offset fileSize = f.size();

    if (fileSize < 29) return false;
    // the technical group will be read from the first 29 bytes. If the file
    // is smaller, we can't even read this.

    bool readComments = false;
    if (what & (KFileMetaInfo::Fastest |
                KFileMetaInfo::DontCare |
                KFileMetaInfo::ContentInfo)) readComments = true;
    else
	fileSize = 29; // No need to read more

    uchar *data = new uchar[fileSize+1];
    f.readBlock(reinterpret_cast<char*>(data), fileSize);
    data[fileSize]='\n';

    // find the start
    if (data[0] == 137 && data[1] == 80 && data[2] == 78 && data[3] == 71 &&
        data[4] ==  13 && data[5] == 10 && data[6] == 26 && data[7] == 10 )
    {
        // ok
        // the IHDR chunk should be the first
        if (!strncmp((char*)&data[12], "IHDR", 4))
        {
            // we found it, get the dimensions
            ulong x,y;
            x = (data[16]<<24) + (data[17]<<16) + (data[18]<<8) + data[19];
            y = (data[20]<<24) + (data[21]<<16) + (data[22]<<8) + data[23];

            uint type = data[25];
            uint bpp =  data[24];
            kdDebug(7034) << "dimensions " << x << "*" << y << endl;

            // the bpp are only per channel, so we need to multiply the with
            // the channel count
            switch (type)
            {
                case 0: break;           // Grayscale
                case 2: bpp *= 3; break; // RGB
                case 3: break;           // palette
                case 4: bpp *= 2; break; // grayscale w. alpha
                case 6: bpp *= 4; break; // RGBA

                default: // we don't get any sensible value here
                    bpp = 0;
            }

            KFileMetaInfoGroup techgroup = appendGroup(info, "Technical");

            appendItem(techgroup, "Dimensions", QSize(x, y));
            appendItem(techgroup, "BitDepth", bpp);
            appendItem(techgroup, "ColorMode",
                       (type < sizeof(colors)/sizeof(colors[0]))
                       ? i18n(colors[data[25]]) : i18n("Unknown"));

            appendItem(techgroup, "Compression",
                       (data[26] < sizeof(compressions)/sizeof(compressions[0]))
                       ? i18n(compressions[data[26]]) : i18n("Unknown"));

            appendItem(techgroup, "InterlaceMode",
                       (data[28] < sizeof(interlaceModes)/sizeof(interlaceModes[0]))
                       ? i18n(interlaceModes[data[28]]) : i18n("Unknown"));
        }

        // look for a tEXt chunk
        if (readComments)
        {
            uint index = 8;
            index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE;
            KFileMetaInfoGroup commentGroup = appendGroup(info, "Comment");

            while(index<fileSize-12)
            {
                while (index < fileSize - 12 &&
                       strncmp((char*)CHUNK_TYPE(data,index), "tEXt", 4) &&
                       strncmp((char*)CHUNK_TYPE(data,index), "zTXt", 4))

                {
                    if (!strncmp((char*)CHUNK_TYPE(data,index), "IEND", 4))
                        goto end;

                    index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE;
                }

                if (index < fileSize - 12)
                {
                    // we found a tEXt or zTXt field

                    // get the key, it's a null terminated string at the
                    //  chunk start

                    uchar* key = &CHUNK_DATA(data,index,0);

                    int keysize=0;
                    for (;key[keysize]!=0; keysize++)
                        // look if we reached the end of the file
                        // (it might be corrupted)
                        if (8+index+keysize>=fileSize)
                            goto end;

		    QByteArray arr;
		    if(!strncmp((char*)CHUNK_TYPE(data,index), "zTXt", 4)) {
			kdDebug(7034) << "We found a zTXt field\n";
			// we get the compression method after the key
			uchar* compressionMethod = &CHUNK_DATA(data,index,keysize+1);
			if ( *compressionMethod != 0x00 ) {
			    // then it isn't zlib compressed and we are sunk
			    kdDebug(7034) << "Non-standard compression method." << endl;
			    goto end;
			}
			// compressed string after the compression technique spec
			uchar* compressedText = &CHUNK_DATA(data, index, keysize+2);
			uint compressedTextSize = CHUNK_SIZE(data, index)-keysize-2;

			// security check, also considering overflow wraparound from the addition --
			// we may endup with a /smaller/ index if we wrap all the way around
			uint firstIndex       = (uint)(compressedText - data);
			uint onePastLastIndex = firstIndex + compressedTextSize;
			if ( onePastLastIndex > fileSize || onePastLastIndex <= firstIndex)
			    goto end;

			uLongf uncompressedLen = compressedTextSize * 2; // just a starting point
			int zlibResult;
			do {
			    arr.resize(uncompressedLen);
			    zlibResult = uncompress((Bytef*)arr.data(), &uncompressedLen,
						    compressedText, compressedTextSize);
			    if (Z_OK == zlibResult) {
				// then it is all OK
				arr.resize(uncompressedLen);
			    } else if (Z_BUF_ERROR == zlibResult) {
				// the uncompressedArray needs to be larger
				// kdDebug(7034) << "doubling size for decompression" << endl;
				uncompressedLen *= 2;

                                // DoS protection. can't be bigger than 64k
                                if ( uncompressedLen > 131072 )
                                    break;
			    } else {
				// something bad happened
				goto end;
			    }
			} while (Z_BUF_ERROR == zlibResult);

			if (Z_OK != zlibResult)
			    goto end;
		    } else if (!strncmp((char*)CHUNK_TYPE(data,index), "tEXt", 4)) {
			kdDebug(7034) << "We found a tEXt field\n";
			// the text comes after the key, but isn't null terminated
			uchar* text = &CHUNK_DATA(data,index, keysize+1);
			uint textsize = CHUNK_SIZE(data, index)-keysize-1;

			// security check, also considering overflow wraparound from the addition --
			// we may endup with a /smaller/ index if we wrap all the way around
			uint firstIndex       = (uint)(text - data);
			uint onePastLastIndex = firstIndex + textsize;

			if ( onePastLastIndex > fileSize || onePastLastIndex <= firstIndex)
			    goto end;

			arr.resize(textsize);
			arr = QByteArray(textsize).duplicate((const char*)text,
							     textsize);
			
		    } else {
			kdDebug(7034) << "We found a field, not expected though\n";
			goto end;
		    }
		    appendItem(commentGroup,
			       QString(reinterpret_cast<char*>(key)),
			       QString(arr));
		    
		    kdDebug(7034) << "adding " << key << " / "
				  << QString(arr) << endl;

		    index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE;
                }
            }
        }
    }
end:
    delete[] data;
    return true;
}