deBool Buffer_append (Buffer* buffer, const deUint8* data, size_t numBytes) { size_t offset = buffer->size; if (!Buffer_resize(buffer, buffer->size + numBytes)) return DE_FALSE; /* Append bytes. */ memcpy(&buffer->data[offset], data, numBytes); return DE_TRUE; }
void * Array_push_back(struct Array * array, void * data ){ struct Buffer *buffer = array -> buffer; if ( array -> used >= Array_capacity( array ) ){ size_t cursize = Buffer_size(buffer); size_t newsize = 0 ; if ( cursize== 0 ){ newsize = 64*array -> data_size; }else{ newsize = cursize *2; } Buffer_resize(buffer, newsize); void *pos = Buffer_at(buffer, array->used * array->data_size ); memmove( pos, data, array->data_size ); array->used ++; return pos; }else{ void *pos = Buffer_at(buffer, array->used * array->data_size ); memmove( pos, data, array->data_size ); array->used ++; return pos; } }
int Array_resize(struct Array * array, size_t size){ return Buffer_resize( array->buffer, size*array->data_size); }
/*--------------------------------------------------------------------*//*! * \brief Write base64 encoded raw image data into log * \param log qpTestLog instance * \param name Unique name (matching names can be compared across BatchResults). * \param description Textual description (shown in Candy). * \param compressionMode Compression mode * \param imageFormat Color format * \param width Width in pixels * \param height Height in pixels * \param stride Data stride (offset between rows) * \param data Pointer to pixel data * \return 0 if OK, otherwise <0 *//*--------------------------------------------------------------------*/ deBool qpTestLog_writeImage ( qpTestLog* log, const char* name, const char* description, qpImageCompressionMode compressionMode, qpImageFormat imageFormat, int width, int height, int stride, const void* data) { char widthStr[32]; char heightStr[32]; qpXmlAttribute attribs[8]; int numAttribs = 0; Buffer compressedBuffer; const void* writeDataPtr = DE_NULL; size_t writeDataBytes = ~(size_t)0; DE_ASSERT(log && name); DE_ASSERT(deInRange32(width, 1, 32768)); DE_ASSERT(deInRange32(height, 1, 32768)); DE_ASSERT(data); if (log->flags & QP_TEST_LOG_EXCLUDE_IMAGES) return DE_TRUE; /* Image not logged. */ Buffer_init(&compressedBuffer); /* BEST compression mode defaults to PNG. */ if (compressionMode == QP_IMAGE_COMPRESSION_MODE_BEST) { #if defined(QP_SUPPORT_PNG) compressionMode = QP_IMAGE_COMPRESSION_MODE_PNG; #else compressionMode = QP_IMAGE_COMPRESSION_MODE_NONE; #endif } #if defined(QP_SUPPORT_PNG) /* Try storing with PNG compression. */ if (compressionMode == QP_IMAGE_COMPRESSION_MODE_PNG) { deBool compressOk = compressImagePNG(&compressedBuffer, imageFormat, width, height, stride, data); if (compressOk) { writeDataPtr = compressedBuffer.data; writeDataBytes = compressedBuffer.size; } else { /* Fall-back to default compression. */ qpPrintf("WARNING: PNG compression failed -- storing image uncompressed.\n"); compressionMode = QP_IMAGE_COMPRESSION_MODE_NONE; } } #endif /* Handle image compression. */ switch (compressionMode) { case QP_IMAGE_COMPRESSION_MODE_NONE: { int pixelSize = imageFormat == QP_IMAGE_FORMAT_RGB888 ? 3 : 4; int packedStride = pixelSize*width; if (packedStride == stride) writeDataPtr = data; else { /* Need to re-pack pixels. */ if (Buffer_resize(&compressedBuffer, (size_t)(packedStride*height))) { int row; for (row = 0; row < height; row++) memcpy(&compressedBuffer.data[packedStride*row], &((const deUint8*)data)[row*stride], (size_t)(pixelSize*width)); } else { qpPrintf("ERROR: Failed to pack pixels for writing.\n"); Buffer_deinit(&compressedBuffer); return DE_FALSE; } } writeDataBytes = (size_t)(packedStride*height); break; } #if defined(QP_SUPPORT_PNG) case QP_IMAGE_COMPRESSION_MODE_PNG: DE_ASSERT(writeDataPtr); /* Already handled. */ break; #endif default: qpPrintf("qpTestLog_writeImage(): Unknown compression mode: %s\n", QP_LOOKUP_STRING(s_qpImageCompressionModeMap, compressionMode)); Buffer_deinit(&compressedBuffer); return DE_FALSE; } /* Fill in attributes. */ int32ToString(width, widthStr); int32ToString(height, heightStr); attribs[numAttribs++] = qpSetStringAttrib("Name", name); attribs[numAttribs++] = qpSetStringAttrib("Width", widthStr); attribs[numAttribs++] = qpSetStringAttrib("Height", heightStr); attribs[numAttribs++] = qpSetStringAttrib("Format", QP_LOOKUP_STRING(s_qpImageFormatMap, imageFormat)); attribs[numAttribs++] = qpSetStringAttrib("CompressionMode", QP_LOOKUP_STRING(s_qpImageCompressionModeMap, compressionMode)); if (description) attribs[numAttribs++] = qpSetStringAttrib("Description", description); /* \note Log lock is acquired after compression! */ deMutex_lock(log->lock); /* <Image ID="result" Name="Foobar" Width="640" Height="480" Format="RGB888" CompressionMode="None">base64 data</Image> */ if (!qpXmlWriter_startElement(log->writer, "Image", numAttribs, attribs) || !qpXmlWriter_writeBase64(log->writer, (const deUint8*)writeDataPtr, writeDataBytes) || !qpXmlWriter_endElement(log->writer, "Image")) { qpPrintf("qpTestLog_writeImage(): Writing XML failed\n"); deMutex_unlock(log->lock); Buffer_deinit(&compressedBuffer); return DE_FALSE; } deMutex_unlock(log->lock); /* Free compressed data if allocated. */ Buffer_deinit(&compressedBuffer); return DE_TRUE; }