diff options
author | teuf <teuf@f01d2545-417e-4e96-918e-98f8d0dbbcb6> | 2008-06-09 19:59:31 +0000 |
---|---|---|
committer | teuf <teuf@f01d2545-417e-4e96-918e-98f8d0dbbcb6> | 2008-06-09 19:59:31 +0000 |
commit | 447dea0d8e1c0b0990b70ec8eff0597718c1aaf3 (patch) | |
tree | 90ec090cd1aa0fb8becadd885f43ee60160f4186 | |
parent | 69a7740761b910d3d1286e017b164979a8977884 (diff) | |
download | libgpod-447dea0d8e1c0b0990b70ec8eff0597718c1aaf3.tar.gz libgpod-447dea0d8e1c0b0990b70ec8eff0597718c1aaf3.tar.xz libgpod-447dea0d8e1c0b0990b70ec8eff0597718c1aaf3.zip |
* src/itdb_device.c:
* src/itdb_device.h:
* src/itdb_sysinfo_extended_parser.c:
* src/itdb_sysinfo_extended_parser.h: merge Itdb_ArtworkFormat and
SysInfoImageFormat, use artwork formats from SysInfoExtended when
it's available instead of using the hardcoded tables from libgpod
git-svn-id: https://gtkpod.svn.sf.net/svnroot/gtkpod/libgpod/trunk@2011 f01d2545-417e-4e96-918e-98f8d0dbbcb6
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | src/itdb_device.c | 126 | ||||
-rw-r--r-- | src/itdb_device.h | 27 | ||||
-rw-r--r-- | src/itdb_sysinfo_extended_parser.c | 139 | ||||
-rw-r--r-- | src/itdb_sysinfo_extended_parser.h | 7 |
5 files changed, 208 insertions, 100 deletions
@@ -1,5 +1,14 @@ 2008-06-09 Christophe Fergeau <christophe@anevia.com> + * src/itdb_device.c: + * src/itdb_device.h: + * src/itdb_sysinfo_extended_parser.c: + * src/itdb_sysinfo_extended_parser.h: merge Itdb_ArtworkFormat and + SysInfoImageFormat, use artwork formats from SysInfoExtended when + it's available instead of using the hardcoded tables from libgpod + +2008-06-09 Christophe Fergeau <christophe@anevia.com> + * src/db-artwork-writer.c: * src/db-image-parser.h: * src/itdb.h: diff --git a/src/itdb_device.c b/src/itdb_device.c index 28ae5ef..f31795c 100644 --- a/src/itdb_device.c +++ b/src/itdb_device.c @@ -268,100 +268,100 @@ static const gchar *ipod_generation_name_table [] = { static const Itdb_ArtworkFormat ipod_photo_cover_art_info[] = { - { 56, 56, 1017, THUMB_FORMAT_RGB565_LE}, - {140, 140, 1016, THUMB_FORMAT_RGB565_LE}, - { -1, -1, -1, -1} + {1017, 56, 56, THUMB_FORMAT_RGB565_LE}, + {1016, 140, 140, THUMB_FORMAT_RGB565_LE}, + { -1, -1, -1, -1} }; static const Itdb_ArtworkFormat ipod_photo_photo_info[] = { - { 42, 30, 1009, THUMB_FORMAT_RGB565_LE}, - {130, 88, 1015, THUMB_FORMAT_RGB565_LE}, - {220, 176, 1013, THUMB_FORMAT_RGB565_BE_90}, - {720, 480, 1019, THUMB_FORMAT_UYVY_BE}, - { -1, -1, -1, -1} + {1009, 42, 30, THUMB_FORMAT_RGB565_LE}, + {1015, 130, 88, THUMB_FORMAT_RGB565_LE}, + {1013, 220, 176, THUMB_FORMAT_RGB565_BE_90}, + {1019, 720, 480, THUMB_FORMAT_UYVY_BE}, + { -1, -1, -1, -1} }; static const Itdb_ArtworkFormat ipod_nano_cover_art_info[] = { - { 42, 42, 1031, THUMB_FORMAT_RGB565_LE}, - {100, 100, 1027, THUMB_FORMAT_RGB565_LE}, - { -1, -1, -1, -1} + {1031, 42, 42, THUMB_FORMAT_RGB565_LE}, + {1027, 100, 100, THUMB_FORMAT_RGB565_LE}, + { -1, -1, -1, -1} }; static const Itdb_ArtworkFormat ipod_nano_photo_info[] = { - { 42, 37, 1032, THUMB_FORMAT_RGB565_LE}, - {176, 132, 1023, THUMB_FORMAT_RGB565_BE}, - { -1, -1, -1, -1} + {1032, 42, 37, THUMB_FORMAT_RGB565_LE}, + {1023, 176, 132, THUMB_FORMAT_RGB565_BE}, + { -1, -1, -1, -1} }; static const Itdb_ArtworkFormat ipod_video_cover_art_info[] = { - {100, 100, 1028, THUMB_FORMAT_RGB565_LE}, - {200, 200, 1029, THUMB_FORMAT_RGB565_LE}, - { -1, -1, -1, -1} + {1028, 100, 100, THUMB_FORMAT_RGB565_LE}, + {1029, 200, 200, THUMB_FORMAT_RGB565_LE}, + { -1, -1, -1, -1} }; static const Itdb_ArtworkFormat ipod_video_photo_info[] = { - { 50, 41, 1036, THUMB_FORMAT_RGB565_LE}, - {130, 88, 1015, THUMB_FORMAT_RGB565_LE}, - {320, 240, 1024, THUMB_FORMAT_RGB565_LE}, - {720, 480, 1019, THUMB_FORMAT_UYVY_BE}, - { -1, -1, -1, -1} + {1036, 50, 41, THUMB_FORMAT_RGB565_LE}, + {1015, 130, 88, THUMB_FORMAT_RGB565_LE}, + {1024, 320, 240, THUMB_FORMAT_RGB565_LE}, + {1019, 720, 480, THUMB_FORMAT_UYVY_BE}, + { -1, -1, -1, -1} }; static const Itdb_ArtworkFormat ipod_mobile_1_cover_art_info[] = { - { 50, 50, 2002, THUMB_FORMAT_RGB565_BE}, - {150, 150, 2003, THUMB_FORMAT_RGB565_BE}, - { -1, -1, -1, -1} + {2002, 50, 50, THUMB_FORMAT_RGB565_BE}, + {2003, 150, 150, THUMB_FORMAT_RGB565_BE}, + { -1, -1, -1, -1} }; static const Itdb_ArtworkFormat ipod_touch_1_cover_art_info[] = { - {256, 256, 3001, THUMB_FORMAT_REC_RGB555_LE}, - {128, 128, 3002, THUMB_FORMAT_REC_RGB555_LE}, - { 64, 64, 3003, THUMB_FORMAT_REC_RGB555_LE}, - {320, 320, 3005, THUMB_FORMAT_RGB555_LE}, - { 56, 56, 3006, THUMB_FORMAT_RGB555_LE, 8192}, /*pad data to 8192 bytes */ - { 88, 88, 3007, THUMB_FORMAT_RGB555_LE, 16364}, /*pad data to 16384 bytes */ - { -1, -1, -1, -1} + {3001, 256, 256, THUMB_FORMAT_REC_RGB555_LE}, + {3002, 128, 128, THUMB_FORMAT_REC_RGB555_LE}, + {3003, 64, 64, THUMB_FORMAT_REC_RGB555_LE}, + {3005, 320, 320, THUMB_FORMAT_RGB555_LE}, + {3006, 56, 56, THUMB_FORMAT_RGB555_LE, 8192}, /*pad data to 8192 bytes */ + {3007, 88, 88, THUMB_FORMAT_RGB555_LE, 16364}, /*pad data to 16384 bytes */ + { -1, -1, -1, -1} }; static const Itdb_ArtworkFormat ipod_touch_1_photo_info[] = { /* In the album list, if a photo is being used to represent a whole album, PHOTO_SMALL is used. We specify TRUE for the crop option so we fill the square completely. */ - { 56, 55, 3004, THUMB_FORMAT_RGB555_LE, 8192, TRUE}, + {3004, 56, 55, THUMB_FORMAT_RGB555_LE, 8192, TRUE}, /* In thumbnail view, PHOTO_LARGE is used. It's actually 79x79, with a 4px white border on the right and bottom. We specify TRUE for the crop option so we fill the square completely. */ - { 80, 79, 3011, THUMB_FORMAT_RGB555_LE, 0, TRUE}, - {160, 120, 3009, THUMB_FORMAT_RGB555_LE}, + {3011, 80, 79, THUMB_FORMAT_RGB555_LE, 0, TRUE}, + {3009, 160, 120, THUMB_FORMAT_RGB555_LE}, /* When viewing an individual photo, PHOTO_TV_SCREEN is used. Note that it is acceptable to write a thumbnail less than the specified width or height, the iPhone / iTouch will scale it to fit the screen. This is important for images that are taller than they wide. */ - {640, 480, 3008, THUMB_FORMAT_RGB555_LE}, - { -1, -1, -1, -1} + {3008, 640, 480, THUMB_FORMAT_RGB555_LE}, + { -1, -1, -1, -1} }; static const Itdb_ArtworkFormat ipod_classic_1_cover_art_info[] = { /* officially 55x55 -- verify! */ - { 56, 56, 1061, THUMB_FORMAT_RGB565_LE}, - {128, 128, 1055, THUMB_FORMAT_RGB565_LE}, - {320, 320, 1060, THUMB_FORMAT_RGB565_LE}, - { -1, -1, -1, -1} + {1061, 56, 56, THUMB_FORMAT_RGB565_LE}, + {1055, 128, 128, THUMB_FORMAT_RGB565_LE}, + {1060, 320, 320, THUMB_FORMAT_RGB565_LE}, + { -1, -1, -1, -1} }; static const Itdb_ArtworkFormat ipod_classic_1_photo_info[] = { - {720, 480, 1067, THUMB_FORMAT_I420_LE}, - {320, 240, 1024, THUMB_FORMAT_RGB565_LE}, - { 64, 64, 1066, THUMB_FORMAT_RGB565_LE}, - { -1, -1, -1, -1} + {1067, 720, 480, THUMB_FORMAT_I420_LE}, + {1024, 320, 240, THUMB_FORMAT_RGB565_LE}, + {1066, 64, 64, THUMB_FORMAT_RGB565_LE}, + { -1, -1, -1, -1} }; static const Itdb_ArtworkFormat ipod_classic_1_chapter_image_info[] = { /* These are the same as for the iPod video... -- labeled by the iPod as "chapter images" */ - {100, 100, 1028, THUMB_FORMAT_RGB565_LE}, - {200, 200, 1029, THUMB_FORMAT_RGB565_LE}, - { -1, -1, -1, -1} + {1028, 100, 100, THUMB_FORMAT_RGB565_LE}, + {1029, 200, 200, THUMB_FORMAT_RGB565_LE}, + { -1, -1, -1, -1} }; enum ArtworkType { @@ -761,7 +761,8 @@ itdb_device_get_artwork_formats (const Itdb_Device *device, g_return_val_if_reached (NULL); } -GList *itdb_device_get_photo_formats (const Itdb_Device *device) +static GList * +itdb_device_get_photo_formats_fallback (const Itdb_Device *device) { const Itdb_ArtworkFormat *formats; const Itdb_ArtworkFormat *it; @@ -779,7 +780,20 @@ GList *itdb_device_get_photo_formats (const Itdb_Device *device) return photo_formats; } -GList *itdb_device_get_cover_art_formats (const Itdb_Device *device) +GList *itdb_device_get_photo_formats (const Itdb_Device *device) +{ + g_return_val_if_fail (device != NULL, NULL); + + if (device->sysinfo_extended == NULL) { + return itdb_device_get_photo_formats_fallback (device); + } else { + return g_list_copy ((GList *)itdb_sysinfo_properties_get_photo_formats (device->sysinfo_extended)); + } + g_return_val_if_reached (NULL); +} + +static GList * +itdb_device_get_cover_art_formats_fallback (const Itdb_Device *device) { const Itdb_ArtworkFormat *formats; const Itdb_ArtworkFormat *it; @@ -797,6 +811,18 @@ GList *itdb_device_get_cover_art_formats (const Itdb_Device *device) return cover_art_formats; } +GList *itdb_device_get_cover_art_formats (const Itdb_Device *device) +{ + g_return_val_if_fail (device != NULL, NULL); + + if (device->sysinfo_extended == NULL) { + return itdb_device_get_cover_art_formats_fallback (device); + } else { + return g_list_copy ((GList *)itdb_sysinfo_properties_get_cover_art_formats (device->sysinfo_extended)); + } + g_return_val_if_reached (NULL); +} + /* Determine the number of F.. directories in iPod_Control/Music.*/ G_GNUC_INTERNAL gint itdb_musicdirs_number_by_mountpoint (const gchar *mountpoint) diff --git a/src/itdb_device.h b/src/itdb_device.h index 2d733a4..4152f28 100644 --- a/src/itdb_device.h +++ b/src/itdb_device.h @@ -94,16 +94,23 @@ struct _Itdb_Device }; -struct _Itdb_ArtworkFormat -{ - gint16 width; - gint16 height; - gint16 format_id; - ItdbThumbFormat format; - gint32 padding; - /* If true, crop the artwork to completely fill the target size, - rather than leaving empty bars on the top or sides. */ - gboolean crop; +struct _Itdb_ArtworkFormat { + gint16 format_id; + gint16 width; + gint16 height; + ItdbThumbFormat format; + gint32 padding; /* not found in SysInfoExtended, added + * for compatibility with hardcoded artwork formats */ + gboolean crop; + gint rotation; + guint back_color; + + gint display_width; + gboolean interlaced; + gboolean align_row_bytes; + gint color_adjustment; + gdouble gamma; + gint associated_format; }; G_GNUC_INTERNAL GList *itdb_device_get_photo_formats (const Itdb_Device *device); diff --git a/src/itdb_sysinfo_extended_parser.c b/src/itdb_sysinfo_extended_parser.c index ce4c0c9..2102502 100644 --- a/src/itdb_sysinfo_extended_parser.c +++ b/src/itdb_sysinfo_extended_parser.c @@ -31,13 +31,13 @@ * (a GValue *) and to convert it to data structures usable by libgpod. * This is that code which interprets the generic parsed plist data as a * SysInfoExtended file. The SysInfoExtended data is used to fill a - * SysInfoIpodProperties structure and several SysInfoImageFormat structs. + * SysInfoIpodProperties structure and several Itdb_ArtworkFormat structs. * * I tried to make the filling of the structures quite generic, if some * field isn't parsed (which is quite possible since I gathered the various * fields names using a few sample files), all is needed to add it is to * add a field to the appropriate structure (SysInfoIpodProperties or - * SysInfoImageFormat) and to add that field to the appropriate + * Itdb_ArtworkFormat) and to add that field to the appropriate * _fields_mapping structure. Those _fields_mapping structures are then * used to convert from a GValue to the struct, but they are also used by * the _dump and _free functions, so there's no need to modify them when @@ -53,8 +53,12 @@ #include <config.h> #endif #include <glib-object.h> -#include "itdb_sysinfo_extended_parser.h" +#include <stdlib.h> +#include <string.h> + +#include "itdb_device.h" #include "itdb_plist.h" +#include "itdb_sysinfo_extended_parser.h" struct _SysInfoIpodProperties { char *build_id; @@ -105,23 +109,6 @@ struct _SysInfoIpodProperties { gint rental_clock_bias; }; -struct _SysInfoImageFormat { - gint format_id; - gint display_width; - gint render_width; - gint render_height; - char *pixel_format; - gboolean interlaced; - gboolean crop; - gboolean align_row_bytes; - gint rotation; - char *back_color; - gint color_adjustment; - gdouble gamma; - gint associated_format; -}; -typedef struct _SysInfoImageFormat SysInfoImageFormat; - static gint get_int (GHashTable *dict, const char *key) { GValue *val; @@ -233,19 +220,23 @@ static const DictFieldMapping sysinfo_ipod_properties_fields_mapping[] = { }; static const DictFieldMapping sysinfo_image_format_fields_mapping[] = { - { "FormatId", G_TYPE_INT, G_STRUCT_OFFSET (SysInfoImageFormat, format_id) }, - { "DisplayWidth", G_TYPE_INT, G_STRUCT_OFFSET (SysInfoImageFormat, display_width) }, - { "RenderWidth", G_TYPE_INT, G_STRUCT_OFFSET (SysInfoImageFormat, render_width) }, - { "RenderHeight", G_TYPE_INT, G_STRUCT_OFFSET (SysInfoImageFormat, render_height) }, - { "PixelFormat", G_TYPE_STRING, G_STRUCT_OFFSET (SysInfoImageFormat, pixel_format) }, - { "Interlaced", G_TYPE_BOOLEAN, G_STRUCT_OFFSET (SysInfoImageFormat, interlaced) }, - { "Crop", G_TYPE_BOOLEAN, G_STRUCT_OFFSET (SysInfoImageFormat, crop) }, - { "AlignRowBytes", G_TYPE_BOOLEAN, G_STRUCT_OFFSET (SysInfoImageFormat, align_row_bytes) }, - { "Rotation", G_TYPE_INT, G_STRUCT_OFFSET (SysInfoImageFormat, rotation) }, - { "BackColor", G_TYPE_INT, G_STRUCT_OFFSET (SysInfoImageFormat, back_color) }, - { "ColorAdjustment", G_TYPE_INT, G_STRUCT_OFFSET (SysInfoImageFormat, color_adjustment) }, - { "GammaAdjustment", G_TYPE_DOUBLE, G_STRUCT_OFFSET (SysInfoImageFormat, gamma) }, - { "AssociatedFormat", G_TYPE_INT, G_STRUCT_OFFSET (SysInfoImageFormat, associated_format) }, + { "FormatId", G_TYPE_INT, G_STRUCT_OFFSET (Itdb_ArtworkFormat, format_id) }, + { "DisplayWidth", G_TYPE_INT, G_STRUCT_OFFSET (Itdb_ArtworkFormat, display_width) }, + { "RenderWidth", G_TYPE_INT, G_STRUCT_OFFSET (Itdb_ArtworkFormat, width) }, + { "RenderHeight", G_TYPE_INT, G_STRUCT_OFFSET (Itdb_ArtworkFormat, height) }, +/* PixelFormat needs to be converted to ItdbThumbFormat, this is special-cased + * in g_value_to_image_format */ +/* { "PixelFormat", G_TYPE_STRING, G_STRUCT_OFFSET (Itdb_ArtworkFormat, format) },*/ + { "Interlaced", G_TYPE_BOOLEAN, G_STRUCT_OFFSET (Itdb_ArtworkFormat, interlaced) }, + { "Crop", G_TYPE_BOOLEAN, G_STRUCT_OFFSET (Itdb_ArtworkFormat, crop) }, + { "AlignRowBytes", G_TYPE_BOOLEAN, G_STRUCT_OFFSET (Itdb_ArtworkFormat, align_row_bytes) }, + { "Rotation", G_TYPE_INT, G_STRUCT_OFFSET (Itdb_ArtworkFormat, rotation) }, +/* BackColor needs to be converted to a gint, this is special-cased + * in g_value_to_image_format */ +/* { "BackColor", G_TYPE_INT, G_STRUCT_OFFSET (Itdb_ArtworkFormat, back_color) }, */ + { "ColorAdjustment", G_TYPE_INT, G_STRUCT_OFFSET (Itdb_ArtworkFormat, color_adjustment) }, + { "GammaAdjustment", G_TYPE_DOUBLE, G_STRUCT_OFFSET (Itdb_ArtworkFormat, gamma) }, + { "AssociatedFormat", G_TYPE_INT, G_STRUCT_OFFSET (Itdb_ArtworkFormat, associated_format) }, { NULL, G_TYPE_NONE, 0 } }; @@ -319,7 +310,7 @@ static void free_struct (const DictFieldMapping *mapping, g_free (struct_ptr); } -static void free_image_format (SysInfoImageFormat *format) +static void free_image_format (Itdb_ArtworkFormat *format) { free_struct (sysinfo_image_format_fields_mapping, format); } @@ -374,7 +365,7 @@ static void dump_struct (const DictFieldMapping *mapping, } } -static void dump_image_format (SysInfoImageFormat *format) +static void dump_image_format (Itdb_ArtworkFormat *format) { dump_struct (sysinfo_image_format_fields_mapping, format); } @@ -387,20 +378,67 @@ void itdb_sysinfo_properties_dump (SysInfoIpodProperties *props) g_list_foreach (props->chapter_image_formats, (GFunc)dump_image_format, NULL); } -static SysInfoImageFormat *g_value_to_image_format (GValue *value) +static gboolean +set_pixel_format (Itdb_ArtworkFormat *img_spec, GHashTable *dict) +{ + char *pixel_format; + + pixel_format = get_string (dict, "PixelFormat"); + if (pixel_format == NULL) { + return FALSE; + } + + if (strcmp (pixel_format, "32767579" /* 2vuy */) == 0) { + img_spec->format = THUMB_FORMAT_UYVY_BE; + } else if (strcmp (pixel_format, "42353635" /* B565 */) == 0) { + img_spec->format = THUMB_FORMAT_RGB565_BE; + } else if (strcmp (pixel_format, "4C353635" /* L565 */) == 0) { + img_spec->format = THUMB_FORMAT_RGB565_LE; + } else if (strcmp (pixel_format, "79343230" /* y420 */) == 0) { + img_spec->format = THUMB_FORMAT_I420_LE; + } else { + g_free (pixel_format); + return FALSE; + } + g_hash_table_remove (dict, "PixelFormat"); + g_free (pixel_format); + return TRUE; +} + +static void set_back_color (Itdb_ArtworkFormat *img_spec, GHashTable *dict) +{ + char *back_color; + + img_spec->back_color = 0; + back_color = get_string (dict, "BackColor"); + if (back_color == NULL) { + return; + } + img_spec->back_color = strtoul (back_color, NULL, 16); + g_hash_table_remove (dict, "BackColor"); + g_free (back_color); +} + +static Itdb_ArtworkFormat *g_value_to_image_format (GValue *value) { GHashTable *dict; - SysInfoImageFormat *img_spec; + Itdb_ArtworkFormat *img_spec; g_return_val_if_fail (G_VALUE_HOLDS (value, G_TYPE_HASH_TABLE), NULL); dict = g_value_get_boxed (value); g_return_val_if_fail (dict != NULL, NULL); - img_spec = g_new0 (SysInfoImageFormat, 1); + img_spec = g_new0 (Itdb_ArtworkFormat, 1); if (img_spec == NULL) { return NULL; } - + + if (!set_pixel_format (img_spec, dict)) { + g_free (img_spec); + return NULL; + } + set_back_color (img_spec, dict); + dict_to_struct (dict, sysinfo_image_format_fields_mapping, img_spec); return img_spec; @@ -409,7 +447,7 @@ static SysInfoImageFormat *g_value_to_image_format (GValue *value) static void process_one (gpointer key, gpointer value, gpointer user_data) { GList **img_formats = user_data; - SysInfoImageFormat *format; + Itdb_ArtworkFormat *format; format = g_value_to_image_format (value); if (format != NULL) { @@ -487,3 +525,24 @@ itdb_sysinfo_properties_get_firewire_id (const SysInfoIpodProperties *props) g_return_val_if_fail (props != NULL, NULL); return props->firewire_guid; } + +const GList * +itdb_sysinfo_properties_get_cover_art_formats (const SysInfoIpodProperties *props) +{ + g_return_val_if_fail (props != NULL, NULL); + return props->artwork_formats; +} + +const GList * +itdb_sysinfo_properties_get_photo_formats (const SysInfoIpodProperties *props) +{ + g_return_val_if_fail (props != NULL, NULL); + return props->photo_formats; +} + +const GList * +itdb_sysinfo_properties_get_chapter_image_formats (const SysInfoIpodProperties *props) +{ + g_return_val_if_fail (props != NULL, NULL); + return props->chapter_image_formats; +} diff --git a/src/itdb_sysinfo_extended_parser.h b/src/itdb_sysinfo_extended_parser.h index df067f5..ff3214c 100644 --- a/src/itdb_sysinfo_extended_parser.h +++ b/src/itdb_sysinfo_extended_parser.h @@ -44,6 +44,13 @@ itdb_sysinfo_properties_get_serial_number (const SysInfoIpodProperties *props); const char * itdb_sysinfo_properties_get_firewire_id (const SysInfoIpodProperties *props); +G_GNUC_INTERNAL const GList * +itdb_sysinfo_properties_get_cover_art_formats (const SysInfoIpodProperties *); +G_GNUC_INTERNAL const GList * +itdb_sysinfo_properties_get_photo_formats (const SysInfoIpodProperties *); +G_GNUC_INTERNAL const GList * +itdb_sysinfo_properties_get_chapter_image_formats (const SysInfoIpodProperties *); + G_END_DECLS #endif |