summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2022-10-02 18:02:27 +0100
committerAidan MacDonald <amachronic@protonmail.com>2022-10-17 14:29:12 +0100
commitc6ee9dc8833814bf628ea5ce53e91c60067c5a06 (patch)
tree9a4680c1e1eca4763e98c215acc39a99200fbed7
parent4bd97c653558bde62237f095a6b9810fb5d16491 (diff)
downloadrockbox-c6ee9dc8833814bf628ea5ce53e91c60067c5a06.tar.gz
rockbox-c6ee9dc8833814bf628ea5ce53e91c60067c5a06.zip
Limit exposure of skin engine internals
Drop wps_internals.h from skin_engine.h. The WPS and to a lesser extent the radio screen are too tightly integrated to drop their dependency on wps_internals.h, unfortunately. Skinned lists, for obvious reasons, also need access to the internals. Change-Id: I00a55aa423900f9ad22edccbe2fc1910af380e38
-rw-r--r--apps/debug_menu.c53
-rw-r--r--apps/gui/list.h11
-rw-r--r--apps/gui/skin_engine/skin_display.c71
-rw-r--r--apps/gui/skin_engine/skin_display.h4
-rw-r--r--apps/gui/skin_engine/skin_engine.c55
-rw-r--r--apps/gui/skin_engine/skin_engine.h10
-rw-r--r--apps/gui/skin_engine/skin_render.c2
-rw-r--r--apps/gui/skin_engine/wps_internals.h11
-rw-r--r--apps/gui/statusbar-skinned.c2
-rw-r--r--apps/gui/statusbar-skinned.h1
-rw-r--r--apps/gui/wps.c1
-rw-r--r--apps/radio/radio.c1
-rw-r--r--apps/radio/radio_skin.c1
-rw-r--r--apps/recorder/albumart.c70
-rw-r--r--apps/recorder/albumart.h6
15 files changed, 157 insertions, 142 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index d17668ade5..87a41920b9 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -2509,59 +2509,6 @@ static bool dbg_pic(void)
2509} 2509}
2510#endif 2510#endif
2511 2511
2512static bool dbg_skin_engine(void)
2513{
2514 struct simplelist_info info;
2515 int i, total = 0;
2516#if defined(HAVE_BACKDROP_IMAGE)
2517 int ref_count;
2518 char *path;
2519 size_t bytes;
2520 int path_prefix_len = strlen(ROCKBOX_DIR "/wps/");
2521#endif
2522 simplelist_info_init(&info, "Skin engine usage", 0, NULL);
2523 simplelist_set_line_count(0);
2524 FOR_NB_SCREENS(j) {
2525#if NB_SCREENS > 1
2526 simplelist_addline("%s display:",
2527 j == 0 ? "Main" : "Remote");
2528#endif
2529 for (i = 0; i < skin_get_num_skins(); i++) {
2530 struct skin_stats *stats = skin_get_stats(i, j);
2531 if (stats->buflib_handles)
2532 {
2533 simplelist_addline("Skin ID: %d, %d allocations",
2534 i, stats->buflib_handles);
2535 simplelist_addline("\tskin: %d bytes",
2536 stats->tree_size);
2537 simplelist_addline("\tImages: %d bytes",
2538 stats->images_size);
2539 simplelist_addline("\tTotal: %d bytes",
2540 stats->tree_size + stats->images_size);
2541 total += stats->tree_size + stats->images_size;
2542 }
2543 }
2544 }
2545 simplelist_addline("Skin total usage: %d bytes", total);
2546#if defined(HAVE_BACKDROP_IMAGE)
2547 simplelist_addline("Backdrop Images:");
2548 i = 0;
2549 while (skin_backdrop_get_debug(i++, &path, &ref_count, &bytes)) {
2550 if (ref_count > 0) {
2551
2552 if (!strncasecmp(path, ROCKBOX_DIR "/wps/", path_prefix_len))
2553 path += path_prefix_len;
2554 simplelist_addline("%s", path);
2555 simplelist_addline("\tref_count: %d", ref_count);
2556 simplelist_addline("\tsize: %d", bytes);
2557 total += bytes;
2558 }
2559 }
2560 simplelist_addline("Total usage: %d bytes", total);
2561#endif
2562 return simplelist_show_list(&info);
2563}
2564
2565#if defined(HAVE_BOOTDATA) && !defined(SIMULATOR) 2512#if defined(HAVE_BOOTDATA) && !defined(SIMULATOR)
2566static bool dbg_boot_data(void) 2513static bool dbg_boot_data(void)
2567{ 2514{
diff --git a/apps/gui/list.h b/apps/gui/list.h
index ede62d7b0a..15ee1df736 100644
--- a/apps/gui/list.h
+++ b/apps/gui/list.h
@@ -229,16 +229,7 @@ extern bool gui_synclist_keyclick_callback(int action, void* data);
229 */ 229 */
230extern bool gui_synclist_do_button(struct gui_synclist * lists, int *action); 230extern bool gui_synclist_do_button(struct gui_synclist * lists, int *action);
231#if !defined(PLUGIN) 231#if !defined(PLUGIN)
232struct listitem_viewport_cfg { 232struct listitem_viewport_cfg;
233 struct wps_data *data;
234 OFFSETTYPE(char *) label;
235 int width;
236 int height;
237 int xmargin;
238 int ymargin;
239 bool tile;
240 struct skin_viewport selected_item_vp;
241};
242 233
243bool skinlist_get_item(struct screen *display, struct gui_synclist *list, int x, int y, int *item); 234bool skinlist_get_item(struct screen *display, struct gui_synclist *list, int x, int y, int *item);
244bool skinlist_draw(struct screen *display, struct gui_synclist *list); 235bool skinlist_draw(struct screen *display, struct gui_synclist *list);
diff --git a/apps/gui/skin_engine/skin_display.c b/apps/gui/skin_engine/skin_display.c
index 2285a20b59..cef38892ff 100644
--- a/apps/gui/skin_engine/skin_display.c
+++ b/apps/gui/skin_engine/skin_display.c
@@ -46,6 +46,7 @@
46#include "tagcache.h" 46#include "tagcache.h"
47#include "list.h" 47#include "list.h"
48#include "option_select.h" 48#include "option_select.h"
49#include "buffering.h"
49 50
50#include "peakmeter.h" 51#include "peakmeter.h"
51/* Image stuff */ 52/* Image stuff */
@@ -636,6 +637,76 @@ void draw_peakmeters(struct gui_wps *gwps, int line_number,
636 } 637 }
637} 638}
638 639
640/* Draw the album art bitmap from the given handle ID onto the given WPS.
641 Call with clear = true to clear the bitmap instead of drawing it. */
642void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear)
643{
644 if (!gwps || !gwps->data || !gwps->display || handle_id < 0)
645 return;
646
647 struct wps_data *data = gwps->data;
648 struct skin_albumart *aa = SKINOFFSETTOPTR(get_skin_buffer(data), data->albumart);
649
650 if (!aa)
651 return;
652
653 struct bitmap *bmp;
654 if (bufgetdata(handle_id, 0, (void *)&bmp) <= 0)
655 return;
656
657 short x = aa->x;
658 short y = aa->y;
659 short width = bmp->width;
660 short height = bmp->height;
661
662 if (aa->width > 0)
663 {
664 /* Crop if the bitmap is too wide */
665 width = MIN(bmp->width, aa->width);
666
667 /* Align */
668 if (aa->xalign & WPS_ALBUMART_ALIGN_RIGHT)
669 x += aa->width - width;
670 else if (aa->xalign & WPS_ALBUMART_ALIGN_CENTER)
671 x += (aa->width - width) / 2;
672 }
673
674 if (aa->height > 0)
675 {
676 /* Crop if the bitmap is too high */
677 height = MIN(bmp->height, aa->height);
678
679 /* Align */
680 if (aa->yalign & WPS_ALBUMART_ALIGN_BOTTOM)
681 y += aa->height - height;
682 else if (aa->yalign & WPS_ALBUMART_ALIGN_CENTER)
683 y += (aa->height - height) / 2;
684 }
685
686 if (!clear)
687 {
688 /* Draw the bitmap */
689 gwps->display->bitmap_part((fb_data*)bmp->data, 0, 0,
690 STRIDE(gwps->display->screen_type,
691 bmp->width, bmp->height),
692 x, y, width, height);
693#ifdef HAVE_LCD_INVERT
694 if (global_settings.invert) {
695 gwps->display->set_drawmode(DRMODE_COMPLEMENT);
696 gwps->display->fillrect(x, y, width, height);
697 gwps->display->set_drawmode(DRMODE_SOLID);
698 }
699#endif
700 }
701 else
702 {
703 /* Clear the bitmap */
704 gwps->display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
705 gwps->display->fillrect(x, y, width, height);
706 gwps->display->set_drawmode(DRMODE_SOLID);
707 }
708}
709
639bool skin_has_sbs(enum screen_type screen, struct wps_data *data) 710bool skin_has_sbs(enum screen_type screen, struct wps_data *data)
640{ 711{
641 (void)screen; 712 (void)screen;
diff --git a/apps/gui/skin_engine/skin_display.h b/apps/gui/skin_engine/skin_display.h
index de1b0b20b5..6226da3eec 100644
--- a/apps/gui/skin_engine/skin_display.h
+++ b/apps/gui/skin_engine/skin_display.h
@@ -54,4 +54,8 @@ void write_line(struct screen *display, struct align_pos *format_align,
54 int line, bool scroll, struct line_desc *line_desc); 54 int line, bool scroll, struct line_desc *line_desc);
55void draw_peakmeters(struct gui_wps *gwps, int line_number, 55void draw_peakmeters(struct gui_wps *gwps, int line_number,
56 struct viewport *viewport); 56 struct viewport *viewport);
57/* Draw the album art bitmap from the given handle ID onto the given Skin.
58 Call with clear = true to clear the bitmap instead of drawing it. */
59void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear);
60
57#endif 61#endif
diff --git a/apps/gui/skin_engine/skin_engine.c b/apps/gui/skin_engine/skin_engine.c
index 8ba76e5739..a3ad85fd6e 100644
--- a/apps/gui/skin_engine/skin_engine.c
+++ b/apps/gui/skin_engine/skin_engine.c
@@ -34,9 +34,11 @@
34#if CONFIG_TUNER 34#if CONFIG_TUNER
35#include "radio.h" 35#include "radio.h"
36#endif 36#endif
37#include "gui/list.h"
37#include "skin_engine.h" 38#include "skin_engine.h"
38#include "skin_buffer.h" 39#include "skin_buffer.h"
39#include "statusbar-skinned.h" 40#include "statusbar-skinned.h"
41#include "wps_internals.h"
40 42
41#define FAILSAFENAME "rockbox_failsafe" 43#define FAILSAFENAME "rockbox_failsafe"
42 44
@@ -334,3 +336,56 @@ void skin_request_full_update(enum skinnable_screens skin)
334 FOR_NB_SCREENS(i) 336 FOR_NB_SCREENS(i)
335 skins[skin][i].needs_full_update = true; 337 skins[skin][i].needs_full_update = true;
336} 338}
339
340bool dbg_skin_engine(void)
341{
342 struct simplelist_info info;
343 int i, total = 0;
344#if defined(HAVE_BACKDROP_IMAGE)
345 int ref_count;
346 char *path;
347 size_t bytes;
348 int path_prefix_len = strlen(ROCKBOX_DIR "/wps/");
349#endif
350 simplelist_info_init(&info, "Skin engine usage", 0, NULL);
351 simplelist_set_line_count(0);
352 FOR_NB_SCREENS(j) {
353#if NB_SCREENS > 1
354 simplelist_addline("%s display:",
355 j == 0 ? "Main" : "Remote");
356#endif
357 for (i = 0; i < skin_get_num_skins(); i++) {
358 struct skin_stats *stats = skin_get_stats(i, j);
359 if (stats->buflib_handles)
360 {
361 simplelist_addline("Skin ID: %d, %d allocations",
362 i, stats->buflib_handles);
363 simplelist_addline("\tskin: %d bytes",
364 stats->tree_size);
365 simplelist_addline("\tImages: %d bytes",
366 stats->images_size);
367 simplelist_addline("\tTotal: %d bytes",
368 stats->tree_size + stats->images_size);
369 total += stats->tree_size + stats->images_size;
370 }
371 }
372 }
373 simplelist_addline("Skin total usage: %d bytes", total);
374#if defined(HAVE_BACKDROP_IMAGE)
375 simplelist_addline("Backdrop Images:");
376 i = 0;
377 while (skin_backdrop_get_debug(i++, &path, &ref_count, &bytes)) {
378 if (ref_count > 0) {
379
380 if (!strncasecmp(path, ROCKBOX_DIR "/wps/", path_prefix_len))
381 path += path_prefix_len;
382 simplelist_addline("%s", path);
383 simplelist_addline("\tref_count: %d", ref_count);
384 simplelist_addline("\tsize: %d", bytes);
385 total += bytes;
386 }
387 }
388 simplelist_addline("Total usage: %d bytes", total);
389#endif
390 return simplelist_show_list(&info);
391}
diff --git a/apps/gui/skin_engine/skin_engine.h b/apps/gui/skin_engine/skin_engine.h
index e26ec34d1f..d7efb5b888 100644
--- a/apps/gui/skin_engine/skin_engine.h
+++ b/apps/gui/skin_engine/skin_engine.h
@@ -26,8 +26,7 @@
26#ifndef PLUGIN 26#ifndef PLUGIN
27 27
28#include "tag_table.h" 28#include "tag_table.h"
29 29#include "screen_access.h"
30#include "wps_internals.h" /* TODO: remove this line.. shoudlnt be needed */
31 30
32enum skinnable_screens { 31enum skinnable_screens {
33 CUSTOM_STATUSBAR, 32 CUSTOM_STATUSBAR,
@@ -39,6 +38,11 @@ enum skinnable_screens {
39 SKINNABLE_SCREENS_COUNT 38 SKINNABLE_SCREENS_COUNT
40}; 39};
41 40
41struct skin_stats;
42struct skin_viewport;
43struct touchregion;
44struct wps_data;
45
42#ifdef HAVE_TOUCHSCREEN 46#ifdef HAVE_TOUCHSCREEN
43int skin_get_touchaction(struct wps_data *data, int* edge_offset, 47int skin_get_touchaction(struct wps_data *data, int* edge_offset,
44 struct touchregion **retregion); 48 struct touchregion **retregion);
@@ -89,5 +93,7 @@ void skin_unload_all(void);
89bool skin_do_full_update(enum skinnable_screens skin, enum screen_type screen); 93bool skin_do_full_update(enum skinnable_screens skin, enum screen_type screen);
90void skin_request_full_update(enum skinnable_screens skin); 94void skin_request_full_update(enum skinnable_screens skin);
91 95
96bool dbg_skin_engine(void);
97
92#endif /* !PLUGIN */ 98#endif /* !PLUGIN */
93#endif 99#endif
diff --git a/apps/gui/skin_engine/skin_render.c b/apps/gui/skin_engine/skin_render.c
index 1f777b6672..2238bd9bec 100644
--- a/apps/gui/skin_engine/skin_render.c
+++ b/apps/gui/skin_engine/skin_render.c
@@ -74,6 +74,8 @@ struct skin_draw_info {
74 int offset; /* used by the playlist viewer */ 74 int offset; /* used by the playlist viewer */
75}; 75};
76 76
77extern void sb_set_info_vp(enum screen_type screen, OFFSETTYPE(char*) label);
78
77typedef bool (*skin_render_func)(struct skin_element* alternator, struct skin_draw_info *info); 79typedef bool (*skin_render_func)(struct skin_element* alternator, struct skin_draw_info *info);
78bool skin_render_alternator(struct skin_element* alternator, struct skin_draw_info *info); 80bool skin_render_alternator(struct skin_element* alternator, struct skin_draw_info *info);
79 81
diff --git a/apps/gui/skin_engine/wps_internals.h b/apps/gui/skin_engine/wps_internals.h
index c220480f13..35d7b979fc 100644
--- a/apps/gui/skin_engine/wps_internals.h
+++ b/apps/gui/skin_engine/wps_internals.h
@@ -313,6 +313,17 @@ struct listitem {
313 short offset; 313 short offset;
314}; 314};
315 315
316struct listitem_viewport_cfg {
317 struct wps_data *data;
318 OFFSETTYPE(char *) label;
319 int width;
320 int height;
321 int xmargin;
322 int ymargin;
323 bool tile;
324 struct skin_viewport selected_item_vp;
325};
326
316#ifdef HAVE_SKIN_VARIABLES 327#ifdef HAVE_SKIN_VARIABLES
317struct skin_var { 328struct skin_var {
318 OFFSETTYPE(const char *) label; 329 OFFSETTYPE(const char *) label;
diff --git a/apps/gui/statusbar-skinned.c b/apps/gui/statusbar-skinned.c
index cda3ec29c9..f1b8af015e 100644
--- a/apps/gui/statusbar-skinned.c
+++ b/apps/gui/statusbar-skinned.c
@@ -53,6 +53,8 @@ static const char* sbs_title[NB_SCREENS];
53static enum themable_icons sbs_icon[NB_SCREENS]; 53static enum themable_icons sbs_icon[NB_SCREENS];
54static bool sbs_loaded[NB_SCREENS] = { false }; 54static bool sbs_loaded[NB_SCREENS] = { false };
55 55
56void sb_set_info_vp(enum screen_type screen, OFFSETTYPE(char*) label);
57
56bool sb_set_title_text(const char* title, enum themable_icons icon, enum screen_type screen) 58bool sb_set_title_text(const char* title, enum themable_icons icon, enum screen_type screen)
57{ 59{
58 sbs_title[screen] = title; 60 sbs_title[screen] = title;
diff --git a/apps/gui/statusbar-skinned.h b/apps/gui/statusbar-skinned.h
index 7f4d93e67e..c7b33d5908 100644
--- a/apps/gui/statusbar-skinned.h
+++ b/apps/gui/statusbar-skinned.h
@@ -34,7 +34,6 @@ void sb_skin_data_load(enum screen_type screen, const char *buf, bool isfile);
34 34
35char* sb_create_from_settings(enum screen_type screen); 35char* sb_create_from_settings(enum screen_type screen);
36void sb_skin_init(void) INIT_ATTR; 36void sb_skin_init(void) INIT_ATTR;
37void sb_set_info_vp(enum screen_type screen, OFFSETTYPE(char*) label);
38struct viewport *sb_skin_get_info_vp(enum screen_type screen); 37struct viewport *sb_skin_get_info_vp(enum screen_type screen);
39void sb_skin_update(enum screen_type screen, bool force); 38void sb_skin_update(enum screen_type screen, bool force);
40 39
diff --git a/apps/gui/wps.c b/apps/gui/wps.c
index 7554892451..01f6e5c77c 100644
--- a/apps/gui/wps.c
+++ b/apps/gui/wps.c
@@ -61,6 +61,7 @@
61#include "playlist_viewer.h" 61#include "playlist_viewer.h"
62#include "wps.h" 62#include "wps.h"
63#include "statusbar-skinned.h" 63#include "statusbar-skinned.h"
64#include "skin_engine/wps_internals.h"
64 65
65#define RESTORE_WPS_INSTANTLY 0l 66#define RESTORE_WPS_INSTANTLY 0l
66#define RESTORE_WPS_NEXT_SECOND ((long)(HZ+current_tick)) 67#define RESTORE_WPS_NEXT_SECOND ((long)(HZ+current_tick))
diff --git a/apps/radio/radio.c b/apps/radio/radio.c
index b74371413e..1764495c7f 100644
--- a/apps/radio/radio.c
+++ b/apps/radio/radio.c
@@ -56,6 +56,7 @@
56#include "statusbar-skinned.h" 56#include "statusbar-skinned.h"
57#include "playback.h" 57#include "playback.h"
58#include "presets.h" 58#include "presets.h"
59#include "skin_engine/wps_internals.h"
59 60
60#if CONFIG_TUNER 61#if CONFIG_TUNER
61 62
diff --git a/apps/radio/radio_skin.c b/apps/radio/radio_skin.c
index 4d90c4e241..388da2694c 100644
--- a/apps/radio/radio_skin.c
+++ b/apps/radio/radio_skin.c
@@ -36,6 +36,7 @@
36#include "sound.h" 36#include "sound.h"
37#include "misc.h" 37#include "misc.h"
38#endif 38#endif
39#include "skin_engine/wps_internals.h"
39 40
40 41
41char* default_radio_skin(enum screen_type screen) 42char* default_radio_skin(enum screen_type screen)
diff --git a/apps/recorder/albumart.c b/apps/recorder/albumart.c
index 9ff9c72f80..e94ffcfb80 100644
--- a/apps/recorder/albumart.c
+++ b/apps/recorder/albumart.c
@@ -297,74 +297,4 @@ bool find_albumart(const struct mp3entry *id3, char *buf, int buflen,
297 return search_albumart_files(id3, size_string, buf, buflen); 297 return search_albumart_files(id3, size_string, buf, buflen);
298} 298}
299 299
300/* Draw the album art bitmap from the given handle ID onto the given WPS.
301 Call with clear = true to clear the bitmap instead of drawing it. */
302void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear)
303{
304 if (!gwps || !gwps->data || !gwps->display || handle_id < 0)
305 return;
306
307 struct wps_data *data = gwps->data;
308 struct skin_albumart *aa = SKINOFFSETTOPTR(get_skin_buffer(data), data->albumart);
309
310 if (!aa)
311 return;
312
313 struct bitmap *bmp;
314 if (bufgetdata(handle_id, 0, (void *)&bmp) <= 0)
315 return;
316
317 short x = aa->x;
318 short y = aa->y;
319 short width = bmp->width;
320 short height = bmp->height;
321
322 if (aa->width > 0)
323 {
324 /* Crop if the bitmap is too wide */
325 width = MIN(bmp->width, aa->width);
326
327 /* Align */
328 if (aa->xalign & WPS_ALBUMART_ALIGN_RIGHT)
329 x += aa->width - width;
330 else if (aa->xalign & WPS_ALBUMART_ALIGN_CENTER)
331 x += (aa->width - width) / 2;
332 }
333
334 if (aa->height > 0)
335 {
336 /* Crop if the bitmap is too high */
337 height = MIN(bmp->height, aa->height);
338
339 /* Align */
340 if (aa->yalign & WPS_ALBUMART_ALIGN_BOTTOM)
341 y += aa->height - height;
342 else if (aa->yalign & WPS_ALBUMART_ALIGN_CENTER)
343 y += (aa->height - height) / 2;
344 }
345
346 if (!clear)
347 {
348 /* Draw the bitmap */
349 gwps->display->bitmap_part((fb_data*)bmp->data, 0, 0,
350 STRIDE(gwps->display->screen_type,
351 bmp->width, bmp->height),
352 x, y, width, height);
353#ifdef HAVE_LCD_INVERT
354 if (global_settings.invert) {
355 gwps->display->set_drawmode(DRMODE_COMPLEMENT);
356 gwps->display->fillrect(x, y, width, height);
357 gwps->display->set_drawmode(DRMODE_SOLID);
358 }
359#endif
360 }
361 else
362 {
363 /* Clear the bitmap */
364 gwps->display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
365 gwps->display->fillrect(x, y, width, height);
366 gwps->display->set_drawmode(DRMODE_SOLID);
367 }
368}
369
370#endif /* PLUGIN */ 300#endif /* PLUGIN */
diff --git a/apps/recorder/albumart.h b/apps/recorder/albumart.h
index 80cacaf5f0..0d663d3d92 100644
--- a/apps/recorder/albumart.h
+++ b/apps/recorder/albumart.h
@@ -35,12 +35,6 @@
35bool find_albumart(const struct mp3entry *id3, char *buf, int buflen, 35bool find_albumart(const struct mp3entry *id3, char *buf, int buflen,
36 const struct dim *dim); 36 const struct dim *dim);
37 37
38#ifndef PLUGIN
39/* Draw the album art bitmap from the given handle ID onto the given Skin.
40 Call with clear = true to clear the bitmap instead of drawing it. */
41void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear);
42#endif
43
44bool search_albumart_files(const struct mp3entry *id3, const char *size_string, 38bool search_albumart_files(const struct mp3entry *id3, const char *size_string,
45 char *buf, int buflen); 39 char *buf, int buflen);
46 40