Reading png using dart ffi and libpng - dart

I am trying to use libpng1.6 to load a png from file, but the execution fails with a segmentation fault.
I load the library and libpng function called png_image_begin_read_from_file as shown:
final dylib = ffi.DynamicLibrary.open(
"/opt/homebrew/Cellar/libpng/1.6.37/lib/libpng.dylib");
final dart_function_t png_image_begin_read_from_file = dylib
.lookup<ffi.NativeFunction<native_function_t>>(
'png_image_begin_read_from_file')
.asFunction();
Here is the full snippet to reproduce the problem.
import 'dart:ffi' as ffi;
import 'package:ffi/ffi.dart';
class png_controlp extends ffi.Opaque {}
// Fields taken from "png.h"
class PngImage extends ffi.Struct {
#ffi.Uint32()
external int version,
width,
height,
flags,
format,
colormap_entries,
warning_or_error;
#ffi.Array(64)
external ffi.Array<ffi.Char> message;
external ffi.Pointer<png_controlp> opaque;
}
// native type
typedef native_function_t = ffi.Int32 Function(
ffi.Pointer<PngImage> image, ffi.Pointer<Utf8> file_name);
// dart type
typedef dart_function_t = int Function(
ffi.Pointer<PngImage> image, ffi.Pointer<Utf8> file_name);
void main() {
final dylib = ffi.DynamicLibrary.open(
"/opt/homebrew/Cellar/libpng/1.6.37/lib/libpng.dylib");
final dart_function_t png_image_begin_read_from_file = dylib
.lookup<ffi.NativeFunction<native_function_t>>(
'png_image_begin_read_from_file')
.asFunction();
final path = "my_image.png";
ffi.Pointer<PngImage> p_pngImage = calloc<PngImage>();
p_pngImage.ref.version = 1;
final res = png_image_begin_read_from_file(p_pngImage, path.toNativeUtf8());
}
===== CRASH =====
si_signo=Segmentation fault: 11(11), si_code=2, si_addr=0x11
version=2.17.0-266.7.beta (beta) (Mon Apr 25 14:54:53 2022 +0000) on "macos_arm64"
pid=42862, thread=20995, isolate_group=main(0x123810200), isolate=main(0x122034200)
isolate_instructions=10263d8c0, vm_instructions=10263d8c0
pc 0x00000001051b6604 fp 0x000000016e1be830 png_image_free+0x24
pc 0x00000001051b66c8 fp 0x000000016e1be850 png_image_error+0x38

It looks like the Dart struct is in the wrong order - check the C header:
2672 typedef struct
2673 {
2674 png_controlp opaque; /* Initialize to NULL, free with png_image_free */
2675 png_uint_32 version; /* Set to PNG_IMAGE_VERSION */
2676 png_uint_32 width; /* Image width in pixels (columns) */
2677 png_uint_32 height; /* Image height in pixels (rows) */
2678 png_uint_32 format; /* Image format as defined below */
2679 png_uint_32 flags; /* A bit mask containing informational flags */
2680 png_uint_32 colormap_entries;
2681 /* Number of entries in the color-map */
....
2704
2705 png_uint_32 warning_or_error;
2706
2707 char message[64];
2708 } png_image, *png_imagep;
So, the Dart struct should be:
class PngImage extends ffi.Struct {
external ffi.Pointer<png_controlp> opaque;
#ffi.Uint32()
external int version,
width,
height,
flags,
format,
colormap_entries,
warning_or_error;
#ffi.Array(64)
external ffi.Array<ffi.Char> message;
}
Also note the comment in the header:
2976 * The png_image passed to the read APIs must have been initialized by setting
2977 * the png_controlp field 'opaque' to NULL (or, safer, memset the whole thing.)
Be sure to set the opaque pointer to nullPtr - though this is probably unnecessary as you are using calloc to create it - which will zero it for you. (Also remember that you may need to make another C call to free stuff allocated by the read_from_file method, and also free anything that you calloc.)

Related

GRUB memory map gives me weird values

I am trying to use grub in order to get the memory map, instead of going through the bios route. The problem is that grub seems to be giving me very weird values for some reason. Can anyone help with this?
Relevant code:
This is how I parse the mmap
void mm_init(mmap_entry_t *mmap_addr, uint32_t length)
{
mmap = mmap_addr;
/* Loop through mmap */
printk("-- Scanning memory map --");
for (size_t i = 0; mmap < (mmap_addr + length); i++) {
/* RAM is available! */
if (mmap->type == 1) {
uint64_t starting_addr = (((uint64_t) mmap->base_addr_high) << 32) | ((uint64_t) mmap->base_addr_low);
uint64_t length = (((uint64_t) mmap->length_high) << 32) | ((uint64_t) mmap->length_low);
printk("Found segment starting from 0x%x, with a length of %i", starting_addr, length);
}
/* Next entry */
mmap = (mmap_entry_t *) ((uint32_t) mmap + mmap->size + sizeof(mmap->size));
}
}
This is my mmap_entry_t struct (not the one in multiboot.h):
struct mmap_entry {
uint32_t size;
uint32_t base_addr_low, base_addr_high;
uint32_t length_low, length_high;
uint8_t type;
} __attribute__((packed));
typedef struct mmap_entry mmap_entry_t;
And this is how I call mm_init()
/* Kernel main function */
void kmain(multiboot_info_t *info)
{
/* Check if grub can give us a memory map */
/* TODO: Detect manually */
if (!(info->flags & (1<<6))) {
panic("couldn't get memory map!");
}
/* Init mm */
mm_init((mmap_entry_t *) info->mmap_addr, info->mmap_length);
for(;;);
}
This is the output I get on qemu:
-- Scanning memory map --
Found segment starting from 0x0, with a length of 0
Found segment starting from 0x100000, with a length of 0
And yes, I am pushing eax and ebx before calling kmain. Any ideas on what is going wrong here?
It turns out that the bit masking stuff was the problem. If we drop that, we can still have 32-bit addresses and the memory map works just fine.

Play a Video from MemoryStream, Using FFMpeg

I'm having a hard time, searching how to play a video file from a TMemoryStream (or a similar buffer in memory) using FFMpeg. I've seen many things, including UltraStarDX, expensive FFMpeg components for Delphi and so on.
One component called FFMpeg Vcl Player claims to play video formats from a memory stream. I downloaded the trial version and I guess it uses CircularBuffer.pas for that matter (maybe).
Does any one know how to do this?
Edit:
Now the better question is how to play an encrypted video file, using FFMpeg or similar libraries.
To play video from memory stream, you can use custom AVIOContext.
static const int kBufferSize = 4 * 1024;
class my_iocontext_private
{
private:
my_iocontext_private(my_iocontext_private const &);
my_iocontext_private& operator = (my_iocontext_private const &);
public:
my_iocontext_private(IInputStreamPtr inputStream)
: inputStream_(inputStream)
, buffer_size_(kBufferSize)
, buffer_(static_cast<unsigned char*>(::av_malloc(buffer_size_))) {
ctx_ = ::avio_alloc_context(buffer_, buffer_size_, 0, this,
&my_iocontext_private::read, NULL, &my_iocontext_private::seek);
}
~my_iocontext_private() {
::av_free(ctx_);
::av_free(buffer_);
}
void reset_inner_context() { ctx_ = NULL; buffer_ = NULL; }
static int read(void *opaque, unsigned char *buf, int buf_size) {
my_iocontext_private* h = static_cast<my_iocontext_private*>(opaque);
return h->inputStream_->Read(buf, buf_size);
}
static int64_t seek(void *opaque, int64_t offset, int whence) {
my_iocontext_private* h = static_cast<my_iocontext_private*>(opaque);
if (0x10000 == whence)
return h->inputStream_->Size();
return h->inputStream_->Seek(offset, whence);
}
::AVIOContext *get_avio() { return ctx_; }
private:
IInputStreamPtr inputStream_; // abstract stream interface, You can adapt it to TMemoryStream
int buffer_size_;
unsigned char * buffer_;
::AVIOContext * ctx_;
};
//// ..........
/// prepare input stream:
IInputStreamPtr inputStream = MyCustomCreateInputStreamFromMemory();
my_iocontext_private priv_ctx(inputStream);
AVFormatContext * ctx = ::avformat_alloc_context();
ctx->pb = priv_ctx.get_avio();
int err = avformat_open_input(&ctx, "arbitrarytext", NULL, NULL);
if (err < 0)
return -1;
//// normal usage of ctx
//// avformat_find_stream_info(ctx, NULL);
//// av_read_frame(ctx, &pkt);
//// etc..
You can waste your time rewriting FFMPEG from C++ to Delphi, or mess with wrapper libraries.
Or if you're just interested in playing a video in Delphi, then check out Mitov's VideoLab components.
http://www.mitov.com/products/videolab#components
If you want play Stream from memory you can make a virtual memory. I suggest BoxedAppSdk.
This will help you to make a virtual drive with virtual files that you can write on it and then give the virtual path to the player component that you have.
BoxedApp is not free but it is really awesome and very simple in use!

Changing DCT coefficients

I decided to use libjpeg as the main library working with jpeg files.
I've read libjpg.txt file. And I was pleased that library allows DCT coefficients reading/writing in a convenient way. Since writing an own decoder will take a long time.
My work is related to the lossless embedding. Currently I need to read DCT coefficients from a file then modify some of them and write changed coefficients in the same file.
Well, I found jpeg_write_coefficients() function. And I naively thought that I could apply it to a decompression object (struct jpeg_decompress_struct). But it does not work and requires a compression object.
I can't believe that such the powerful library is not able to do this.
I think that most likely I'm missing something. Although I tried to be attentive.
Perhaps the writing coefficients can be done more sophisticated way.
But I don't know how to.
I will be very glad if you propose your ideas.
You can ue jpeg_write_coefficients to write your changed DCT.
The following information is avaliable in libjpeg.txt
To write the contents of a JPEG file as DCT coefficients, you must provide
the DCT coefficients stored in virtual block arrays. You can either pass
block arrays read from an input JPEG file by jpeg_read_coefficients(), or
allocate virtual arrays from the JPEG compression object and fill them
yourself. In either case, jpeg_write_coefficients() is substituted for
jpeg_start_compress() and jpeg_write_scanlines(). Thus the sequence is
* Create compression object
* Set all compression parameters as necessary
* Request virtual arrays if needed
* jpeg_write_coefficients()
* jpeg_finish_compress()
* Destroy or re-use compression object
jpeg_write_coefficients() is passed a pointer to an array of virtual block
array descriptors; the number of arrays is equal to cinfo.num_components.
The virtual arrays need only have been requested, not realized, before
jpeg_write_coefficients() is called. A side-effect of
jpeg_write_coefficients() is to realize any virtual arrays that have been
requested from the compression object's memory manager. Thus, when obtaining
the virtual arrays from the compression object, you should fill the arrays
after calling jpeg_write_coefficients(). The data is actually written out
when you call jpeg_finish_compress(); jpeg_write_coefficients() only writes
the file header.
When writing raw DCT coefficients, it is crucial that the JPEG quantization
tables and sampling factors match the way the data was encoded, or the
resulting file will be invalid. For transcoding from an existing JPEG file,
we recommend using jpeg_copy_critical_parameters(). This routine initializes
all the compression parameters to default values (like jpeg_set_defaults()),
then copies the critical information from a source decompression object.
The decompression object should have just been used to read the entire
JPEG input file --- that is, it should be awaiting jpeg_finish_decompress().
jpeg_write_coefficients() marks all tables stored in the compression object
as needing to be written to the output file (thus, it acts like
jpeg_start_compress(cinfo, TRUE)). This is for safety's sake, to avoid
emitting abbreviated JPEG files by accident. If you really want to emit an
abbreviated JPEG file, call jpeg_suppress_tables(), or set the tables'
individual sent_table flags, between calling jpeg_write_coefficients() and
jpeg_finish_compress().
So to change a single dct, you can use the following simple code:
To access any dct coeff, you need to change four index, cx, bx, by, bi.
In my code, I used blockptr_one[bi]++; to increase one dct Coeff
#include <stdio.h>
#include <jpeglib.h>
#include <stdlib.h>
#include <iostream>
#include <string>
int write_jpeg_file(std::string outname,jpeg_decompress_struct in_cinfo, jvirt_barray_ptr *coeffs_array ){
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE * infile;
if ((infile = fopen(outname.c_str(), "wb")) == NULL) {
fprintf(stderr, "can't open %s\n", outname.c_str());
return 0;
}
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, infile);
j_compress_ptr cinfo_ptr = &cinfo;
jpeg_copy_critical_parameters((j_decompress_ptr)&in_cinfo,cinfo_ptr);
jpeg_write_coefficients(cinfo_ptr, coeffs_array);
jpeg_finish_compress( &cinfo );
jpeg_destroy_compress( &cinfo );
fclose( infile );
return 1;
}
int read_jpeg_file( std::string filename, std::string outname )
{
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE * infile;
if ((infile = fopen(filename.c_str(), "rb")) == NULL) {
fprintf(stderr, "can't open %s\n", filename.c_str());
return 0;
}
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, infile);
(void) jpeg_read_header(&cinfo, TRUE);
jvirt_barray_ptr *coeffs_array = jpeg_read_coefficients(&cinfo);
//change one dct:
int ci = 0; // between 0 and number of image component
int by = 0; // between 0 and compptr_one->height_in_blocks
int bx = 0; // between 0 and compptr_one->width_in_blocks
int bi = 0; // between 0 and 64 (8x8)
JBLOCKARRAY buffer_one;
JCOEFPTR blockptr_one;
jpeg_component_info* compptr_one;
compptr_one = cinfo.comp_info + ci;
buffer_one = (cinfo.mem->access_virt_barray)((j_common_ptr)&cinfo, coeffs_array[ci], by, (JDIMENSION)1, FALSE);
blockptr_one = buffer_one[0][bx];
blockptr_one[bi]++;
write_jpeg_file(outname, cinfo, coeffs_array);
jpeg_finish_decompress( &cinfo );
jpeg_destroy_decompress( &cinfo );
fclose( infile );
return 1;
}
int main()
{
std::string infilename = "you_image.jpg", outfilename = "out_image.jpg";
/* Try opening a jpeg*/
if( read_jpeg_file( infilename, outfilename ) > 0 )
{
std::cout << "It's Okay..." << std::endl;
}
else return -1;
return 0;
}
You should really take a look at transupp.h and sources for jpegtran that comes with the library.
Anyway, here is my dirty code with comments, assembled partially from jpegtran. It lets you manipulate DCT coefficients one by one.
#include "jpeglib.h" /* Common decls for cjpeg/djpeg applications */
#include "transupp.h" /* Support routines for jpegtran */
struct jpeg_decompress_struct srcinfo;
struct jpeg_compress_struct dstinfo;
struct jpeg_error_mgr jsrcerr, jdsterr;
static jpeg_transform_info transformoption; /* image transformation options */
transformoption.transform = JXFORM_NONE;
transformoption.trim = FALSE;
transformoption.force_grayscale = FALSE;
jvirt_barray_ptr * src_coef_arrays;
jvirt_barray_ptr * dst_coef_arrays;
/* Initialize the JPEG decompression object with default error handling. */
srcinfo.err = jpeg_std_error(&jsrcerr);
jpeg_create_decompress(&srcinfo);
/* Initialize the JPEG compression object with default error handling. */
dstinfo.err = jpeg_std_error(&jdsterr);
jpeg_create_compress(&dstinfo);
FILE *fp;
if((fp = fopen(filePath], "rb")) == NULL) {
//Throw an error
} else {
//Continue
}
/* Specify data source for decompression */
jpeg_stdio_src(&srcinfo, fp);
/* Enable saving of extra markers that we want to copy */
jcopy_markers_setup(&srcinfo, JCOPYOPT_ALL);
/* Read file header */
(void) jpeg_read_header(&srcinfo, TRUE);
jtransform_request_workspace(&srcinfo, &transformoption);
src_coef_arrays = jpeg_read_coefficients(&srcinfo);
jpeg_copy_critical_parameters(&srcinfo, &dstinfo);
/* Do your DCT shenanigans here on src_coef_arrays like this (I've moved it into a separate function): */
moveDCTAround(&srcinfo, &dstinfo, 0, src_coef_arrays);
/* ..when done with DCT, do this: */
dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, src_coef_arrays, &transformoption);
fclose(fp);
//And write everything back
fp = fopen(filePath, "wb");
/* Specify data destination for compression */
jpeg_stdio_dest(&dstinfo, fp);
/* Start compressor (note no image data is actually written here) */
jpeg_write_coefficients(&dstinfo, dst_coef_arrays);
/* Copy to the output file any extra markers that we want to preserve */
jcopy_markers_execute(&srcinfo, &dstinfo, JCOPYOPT_ALL);
jpeg_finish_compress(&dstinfo);
jpeg_destroy_compress(&dstinfo);
(void) jpeg_finish_decompress(&srcinfo);
jpeg_destroy_decompress(&srcinfo);
fclose(fp);
And the function itself:
void moveDCTAround (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, jvirt_barray_ptr *src_coef_arrays)
{
size_t block_row_size;
JBLOCKARRAY coef_buffers[MAX_COMPONENTS];
JBLOCKARRAY row_ptrs[MAX_COMPONENTS];
//Allocate DCT array buffers
for (JDIMENSION compnum=0; compnum<srcinfo->num_components; compnum++)
{
coef_buffers[compnum] = (dstinfo->mem->alloc_barray)((j_common_ptr) dstinfo, JPOOL_IMAGE, srcinfo->comp_info[compnum].width_in_blocks,
srcinfo->comp_info[compnum].height_in_blocks);
}
//For each component,
for (JDIMENSION compnum=0; compnum<srcinfo->num_components; compnum++)
{
block_row_size = (size_t) sizeof(JCOEF)*DCTSIZE2*srcinfo->comp_info[compnum].width_in_blocks;
//...iterate over rows,
for (JDIMENSION rownum=0; rownum<srcinfo->comp_info[compnum].height_in_blocks; rownum++)
{
row_ptrs[compnum] = ((dstinfo)->mem->access_virt_barray)((j_common_ptr) &dstinfo, src_coef_arrays[compnum], rownum, (JDIMENSION) 1, FALSE);
//...and for each block in a row,
for (JDIMENSION blocknum=0; blocknum<srcinfo->comp_info[compnum].width_in_blocks; blocknum++)
//...iterate over DCT coefficients
for (JDIMENSION i=0; i<DCTSIZE2; i++)
{
//Manipulate your DCT coefficients here. For instance, the code here inverts the image.
coef_buffers[compnum][rownum][blocknum][i] = -row_ptrs[compnum][0][blocknum][i];
}
}
}
//Save the changes
//For each component,
for (JDIMENSION compnum=0; compnum<srcinfo->num_components; compnum++)
{
block_row_size = (size_t) sizeof(JCOEF)*DCTSIZE2 * srcinfo->comp_info[compnum].width_in_blocks;
//...iterate over rows
for (JDIMENSION rownum=0; rownum < srcinfo->comp_info[compnum].height_in_blocks; rownum++)
{
//Copy the whole rows
row_ptrs[compnum] = (dstinfo->mem->access_virt_barray)((j_common_ptr) dstinfo, src_coef_arrays[compnum], rownum, (JDIMENSION) 1, TRUE);
memcpy(row_ptrs[compnum][0][0], coef_buffers[compnum][rownum][0], block_row_size);
}
}

Using dynamic library loaded by LC_LOAD_DYLIB to interpose C functions

Firstly, what I want to do is to intercept an arbitrary standard C function (like fopen, read, write, malloc, ...) of an iOS application.
I have a libtest.dylib with this code:
typedef struct interpose_s {
void *new_func;
void *orig_func;
} interpose_t;
FILE *vg_fopen(const char * __restrict, const char * __restrict);
static const interpose_t interposing_functions[] \
__attribute__ ((section("__DATA, __interpose"))) = {
{ (void *)vg_fopen, (void *)fopen },
};
FILE *vg_fopen(const char * __restrict path, const char * __restrict mode) {
printf("vg_fopen");
return fopen(path, mode);
}
After compiled the dylib, I go to the binary of the host iOS app and add an LC_LOAD_DYLIB to the end of the LC_LOAD_COMMANDS list and point it to #executable_path/libtest.dylib
What I expect is that it will override the implementation of fopen, and print "vg_fopen" whenever fopen is called. However, I do not get it, so the interposition might have been failed.
I'd like to know what might be the reason. This is for in-house development for learning purpose only, so please don't mention about the impact or warn me about inappropriate use.
Thanks in advance.
From the dyld source:
// link any inserted libraries
// do this after linking main executable so that any dylibs pulled in by inserted
// dylibs (e.g. libSystem) will not be in front of dylibs the program uses
if ( sInsertedDylibCount > 0 ) {
for(unsigned int i=0; i < sInsertedDylibCount; ++i) {
ImageLoader* image = sAllImages[i+1];
link(image, sEnv.DYLD_BIND_AT_LAUNCH, ImageLoader::RPathChain(NULL, NULL));
// only INSERTED libraries can interpose
image->registerInterposing();
}
}
So no, only libraries inserted via DYLD_INSERT_LIBRARIES have their interposing applied.

Network stats gatherer (loadable kernel module) isn't working?

I'm kinda new to linux kernel modules and I'm trying to write my own module that gives me some statistics about a device ( the NIC here).
although I'm using kernel 2.6.35 and I've included linux/netdevices, compiling keeps saying that the function ndo_get_stats is implicitly declared. can anyone tell me what's going on ?
here's the module, simple I know,
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/netdevice.h> /* Needed for netdevice*/
static int __init hello_start(void)
{
struct net_device *dev;
struct net_device_stats *devstats;
printk(KERN_INFO "Loading Stats module...\n");
printk(KERN_ALERT "Hello world\n");
dev = first_net_device(&init_net);
while (dev)
{
printk(KERN_INFO "found [%s] and it's [%d]\n", dev->name, dev->flags & IFF_UP);
printk(KERN_INFO "End of dev struct ... now starts the get_stats struct\n");
devstats = ndo_get_stats(dev);
printk(KERN_INFO "recive errors: [%li]\n transmission errors: [%li]\n number of collisions: [%li]", devstats->rx_errors , devstats->tx_errors, devstats->collisions);
dev = next_net_device(dev);
}
return 0;
}
static void __exit hello_end(void)
{
printk(KERN_ALERT "Goodbye.\n");
}
module_init(hello_start);
module_exit(hello_end);

Resources