fwupd/libfwupdplugin/fu-chunk.c
Richard Hughes 00f66f659d trivial: Do not include non-introspectable functions in the GIR
If we do need these for managed languages, we can of course create boxed types
when requried.
2019-11-27 12:45:35 +00:00

215 lines
5.2 KiB
C

/*
* Copyright (C) 2017-2018 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#define G_LOG_DOMAIN "FuChunk"
#include "config.h"
#include <string.h>
#include "fu-chunk.h"
/**
* SECTION:fu-chunk
* @short_description: A packet of chunked data
*
* An object that represents a packet of data.
*
*/
/**
* fu_chunk_new: (skip):
* @idx: the packet number
* @page: the hardware memory page
* @address: the address *within* the page
* @data: the data
* @data_sz: size of @data_sz
*
* Creates a new packet of chunked data.
*
* Return value: (transfer full): a #FuChunk
*
* Since: 1.1.2
**/
FuChunk *
fu_chunk_new (guint32 idx,
guint32 page,
guint32 address,
const guint8 *data,
guint32 data_sz)
{
FuChunk *item = g_new0 (FuChunk, 1);
item->idx = idx;
item->page = page;
item->address = address;
item->data = data;
item->data_sz = data_sz;
return item;
}
/**
* fu_chunk_to_string:
* @item: a #FuChunk
*
* Converts the chunked packet to a string representation.
*
* Return value: (transfer full): A string
*
* Since: 1.1.2
**/
gchar *
fu_chunk_to_string (FuChunk *item)
{
g_autoptr(GString) str = g_string_new (NULL);
if (item->data != NULL) {
for (guint32 i = 0; i < item->data_sz; i++) {
gchar tmp = (gchar) item->data[i];
if (tmp == 0x00)
break;
g_string_append_c (str, g_ascii_isalnum (tmp) ? tmp : '?');
}
}
return g_strdup_printf ("#%02" G_GUINT32_FORMAT ": page:%02x "
"addr:%04x len:%02" G_GUINT32_FORMAT " %s",
item->idx,
(guint) item->page,
(guint) item->address,
item->data_sz,
str->str);
}
/**
* fu_chunk_array_to_string:
* @chunks: (element-type FuChunk): array of packets
*
* Converts all the chunked packets in an array to a string representation.
*
* Return value: (transfer full): A string
*
* Since: 1.0.1
**/
gchar *
fu_chunk_array_to_string (GPtrArray *chunks)
{
GString *str = g_string_new (NULL);
for (guint i = 0; i < chunks->len; i++) {
FuChunk *item = g_ptr_array_index (chunks, i);
g_autofree gchar *tmp = fu_chunk_to_string (item);
g_string_append_printf (str, "%s\n", tmp);
}
return g_string_free (str, FALSE);
}
/**
* fu_chunk_array_new: (skip):
* @data: a linear blob of memory, or %NULL
* @data_sz: size of @data_sz
* @addr_start: the hardware address offset, or 0
* @page_sz: the hardware page size, or 0
* @packet_sz: the transfer size, or 0
*
* Chunks a linear blob of memory into packets, ensuring each packet does not
* cross a package boundary and is less that a specific transfer size.
*
* Return value: (transfer container) (element-type FuChunk): array of packets
*
* Since: 1.1.2
**/
GPtrArray *
fu_chunk_array_new (const guint8 *data,
guint32 data_sz,
guint32 addr_start,
guint32 page_sz,
guint32 packet_sz)
{
GPtrArray *segments = NULL;
guint32 page_old = G_MAXUINT32;
guint32 idx;
guint32 last_flush = 0;
g_return_val_if_fail (data_sz > 0, NULL);
segments = g_ptr_array_new_with_free_func (g_free);
for (idx = 1; idx < data_sz; idx++) {
guint32 page = 0;
if (page_sz > 0)
page = (addr_start + idx) / page_sz;
if (page_old == G_MAXUINT32) {
page_old = page;
} else if (page != page_old) {
const guint8 *data_offset = data != NULL ? data + last_flush : 0x0;
guint32 address_offset = addr_start + last_flush;
if (page_sz > 0)
address_offset %= page_sz;
g_ptr_array_add (segments,
fu_chunk_new (segments->len,
page_old,
address_offset,
data_offset,
idx - last_flush));
last_flush = idx;
page_old = page;
continue;
}
if (packet_sz > 0 && idx - last_flush >= packet_sz) {
const guint8 *data_offset = data != NULL ? data + last_flush : 0x0;
guint32 address_offset = addr_start + last_flush;
if (page_sz > 0)
address_offset %= page_sz;
g_ptr_array_add (segments,
fu_chunk_new (segments->len,
page,
address_offset,
data_offset,
idx - last_flush));
last_flush = idx;
continue;
}
}
if (last_flush != idx) {
const guint8 *data_offset = data != NULL ? data + last_flush : 0x0;
guint32 address_offset = addr_start + last_flush;
guint32 page = 0;
if (page_sz > 0) {
address_offset %= page_sz;
page = (addr_start + (idx - 1)) / page_sz;
}
g_ptr_array_add (segments,
fu_chunk_new (segments->len,
page,
address_offset,
data_offset,
data_sz - last_flush));
}
return segments;
}
/**
* fu_chunk_array_new_from_bytes: (skip):
* @blob: a #GBytes
* @addr_start: the hardware address offset, or 0
* @page_sz: the hardware page size, or 0
* @packet_sz: the transfer size, or 0
*
* Chunks a linear blob of memory into packets, ensuring each packet does not
* cross a package boundary and is less that a specific transfer size.
*
* Return value: (transfer container) (element-type FuChunk): array of packets
*
* Since: 1.1.2
**/
GPtrArray *
fu_chunk_array_new_from_bytes (GBytes *blob,
guint32 addr_start,
guint32 page_sz,
guint32 packet_sz)
{
gsize sz;
const guint8 *data = g_bytes_get_data (blob, &sz);
return fu_chunk_array_new (data, (guint32) sz,
addr_start, page_sz, packet_sz);
}