Utility functions

## Utility functions Utility functions — libMirage's helper and utility functions |

## Synopsis

    #include <mirage.h>

    enum                MIRAGE_SubChannel;
    #define             MIRAGE_CAST_DATA                    (buf,off,type)
    #define             MIRAGE_CAST_PTR                     (buf,off,type)
    #define             MIRAGE_CHECK_ARG                    (arg)
    #define             G_LIST_FOR_EACH                     (cursor,list)
    gchar *             mirage_helper_find_data_file        (const gchar *filename,
                                                             const gchar *path);
    gchar *             mirage_helper_get_suffix            (gchar *filename);
    gboolean            mirage_helper_has_suffix            (gchar *filename,
                                                             gchar *suffix);
    gboolean            mirage_helper_match_suffixes        (gchar *filename,
                                                             gchar **suffixes);
    gint                mirage_helper_strcasecmp            (const gchar *str1,
                                                             const gchar *str2);
    gint                mirage_helper_strncasecmp           (const gchar *str1,
                                                             const gchar *str2,
                                                             gint len);
    void                mirage_helper_lba2msf               (gint lba,
                                                             gboolean diff,
                                                             guint8 *m,
                                                             guint8 *s,
                                                             guint8 *f);
    gchar *             mirage_helper_lba2msf_str           (gint lba,
                                                             gboolean diff);
    gint                mirage_helper_msf2lba               (guint8 m,
                                                             guint8 s,
                                                             guint8 f,
                                                             gboolean diff);
    gint                mirage_helper_msf2lba_str           (gchar *msf,
                                                             gboolean diff);
    gint                mirage_helper_hex2bcd               (gint hex);
    gint                mirage_helper_bcd2hex               (gint bcd);
    guint8              mirage_helper_ascii2isrc            (gchar c);
    gchar               mirage_helper_isrc2ascii            (guint8 c);
    guint16             mirage_helper_subchannel_q_calculate_crc
                                                            (guint8 *data);
    void                mirage_helper_subchannel_q_encode_mcn
                                                            (guint8 *buf,
                                                             gchar *mcn);
    void                mirage_helper_subchannel_q_decode_mcn
                                                            (guint8 *buf,
                                                             gchar *mcn);
    void                mirage_helper_subchannel_q_encode_isrc
                                                            (guint8 *buf,
                                                             gchar *isrc);
    void                mirage_helper_subchannel_q_decode_isrc
                                                            (guint8 *buf,
                                                             gchar *isrc);
    void                mirage_helper_subchannel_interleave (gint subchan,
                                                             guint8 *channel12,
                                                             guint8 *channel96);
    void                mirage_helper_subchannel_deinterleave
                                                            (gint subchan,
                                                             guint8 *channel96,
                                                             guint8 *channel12);
    void                mirage_helper_sector_edc_ecc_compute_edc_block
                                                            (const guint8 *src,
                                                             guint16 size,
                                                             guint8 *dest);
    void                mirage_helper_sector_edc_ecc_compute_ecc_block
                                                            (guint8 *src,
                                                             guint32 major_count,
                                                             guint32 minor_count,
                                                             guint32 major_mult,
                                                             guint32 minor_inc,
                                                             guint8 *dest);

## Description

These functions are exported because, while primarily designed to be used within libMirage, they could also prove useful to other applications. They cover the following functionality:

- File finding: mirage_helper_find_data_file
- File suffix retrieval and matching: `mirage_helper_get_suffix()`, `mirage_helper_has_suffix()`, `mirage_helper_match_suffixes()`.
- UTF-8 compatible case-insensitive string comparison: `mirage_helper_strcasecmp()`, `mirage_helper_strncasecmp()`.
- MSF/LBA conversion: `mirage_helper_lba2msf()`, `mirage_helper_lba2msf_str()`, `mirage_helper_msf2lba()`, `mirage_helper_msf2lba_str()`.
- Hex/BCD conversion: `mirage_helper_hex2bcd()`, `mirage_helper_bcd2hex()`.
- ASCII/ISRC conversion: `mirage_helper_ascii2isrc()`, `mirage_helper_isrc2ascii()`.
- Q subchannel generation; CRC calculation, MCN and ISRC encoding/decoding: `mirage_helper_subchannel_q_calculate_crc()`, `mirage_helper_subchannel_q_encode_mcn()`, `mirage_helper_subchannel_q_decode_mcn()`, `mirage_helper_subchannel_q_encode_isrc()`, `mirage_helper_subchannel_q_decode_isrc()`.
- Subchannel interleaving/deinterleaving: `mirage_helper_subchannel_interleave()`, `mirage_helper_subchannel_deinterleave()`.
- EDC/ECC generation: `mirage_helper_sector_edc_ecc_compute_edc_block()`, `mirage_helper_sector_edc_ecc_compute_ecc_block()`.

## Details

### enum MIRAGE_SubChannel

    typedef enum {
        SUBCHANNEL_W = 0,
        SUBCHANNEL_V = 1,
        SUBCHANNEL_U = 2,
        SUBCHANNEL_T = 3,
        SUBCHANNEL_S = 4,
        SUBCHANNEL_R = 5,
        SUBCHANNEL_Q = 6,
        SUBCHANNEL_P = 7,
    } MIRAGE_SubChannel;

Subchannel type for interleaving/deinterleaving.

`SUBCHANNEL_W` | W subchannel data
`SUBCHANNEL_V` | V subchannel data
`SUBCHANNEL_U` | U subchannel data
`SUBCHANNEL_T` | T subchannel data
`SUBCHANNEL_S` | S subchannel data
`SUBCHANNEL_R` | R subchannel data
`SUBCHANNEL_Q` | Q subchannel data
`SUBCHANNEL_P` | P subchannel data

### MIRAGE_CAST_DATA()

    #define MIRAGE_CAST_DATA(buf,off,type) (*((type *)(buf+off)))

A macro for easy retrieval of data from (unsigned integer) buffer. Mostly to be used in binary image parsers, for example, to retrieve guint32 or guint16 value from buffer.

`buf` : | buffer to get data from
`off` : | offset in buffer at which to get data
`type` : | data type (i.e. 'guint64')

### MIRAGE_CAST_PTR()

    #define MIRAGE_CAST_PTR(buf,off,type) ((type)(buf+off))

A macro for easy placing of pointers within (unsigned integer) buffer. Mostly to be used in binary image parsers, for example, to retrieve a string or a structure from buffer.

`buf` : | buffer to place pointer in
`off` : | offset in buffer at which to place pointer
`type` : | pointer type (i.e. 'gchar *')

### MIRAGE_CHECK_ARG()

    #define             MIRAGE_CHECK_ARG(arg)

A macro to be used within libMirage objects. It checks whether `arg` is valid pointer argument (non-NULL). If it is not, it returns false and error is set to `MIRAGE_E_INVALIDARG`. The existance of local variable `error` of type GError** is assumed.

`arg` : | argument to be checked

### G_LIST_FOR_EACH()

    #define             G_LIST_FOR_EACH(cursor,list)

A macro providing for loop on GList. `cursor` is a cursor of type GList*, and is used to store current element in the list. `list` is a GLib's double linked list that for loop should be performed on.

`cursor` : | cursor
`list` : | list

### mirage_helper_find_data_file ()

    gchar *             mirage_helper_find_data_file        (const gchar *filename,
                                                             const gchar *path);

Attempts to find a file with filename `filename` and path `path`. `filename` can be file's basename or an absolute path. `path` can be either directory path (in this case, it must end with '/') or a filename (i.e. of file descriptor).

If `filename` is an absolute path, its existence is first checked. If it doesn't exist, `path`'s dirname is combined with `filename`'s basename, and the combination's existence is checked. If that fails as well, then directory, specified by `path`'s dirname is opened and its content is case-insensitively compared to `filename`'s basename. This way, all possible case variations are taken into account (i.e. file.iso, FILE.ISO, FiLe.IsO, etc.). If at any of above steps the result is positive, the resulting filename is returned as a newly allocated string.

The returned string should be freed when no longer needed.

`filename` : | declared filename
`path` : | location to store output filename, or `NULL`
Returns : | a newly allocated string containing the fullpath of file, or `NULL`.

### mirage_helper_get_suffix ()

    gchar *             mirage_helper_get_suffix            (gchar *filename);

Retrieves suffix from `filename`.

`filename` : | filename
Returns : | pointer to character in `filename` at which the suffix starts.

### mirage_helper_has_suffix ()

    gboolean            mirage_helper_has_suffix            (gchar *filename,
                                                             gchar *suffix);

Checks whether file name `filename` ends with suffix `suffix`.

`filename` : | filename
`suffix` : | suffix
Returns : | `TRUE` if `filename` contains suffix `suffix`, `FALSE` if not

### mirage_helper_match_suffixes ()

    gboolean            mirage_helper_match_suffixes        (gchar *filename,
                                                             gchar **suffixes);

Checks whether `filename` ends with a suffix from `suffixes`.

`filename` : | filename
`suffixes` : | NULL-terminated array of suffixes
Returns : | `TRUE` if `filename` contains suffix from `suffixes`, `FALSE` if not

### mirage_helper_strcasecmp ()

    gint                mirage_helper_strcasecmp            (const gchar *str1,
                                                             const gchar *str2);

Replacement function for g_strcasecmp/strcasecmp, which can properly handle UTF-8. Glib docs state this is only an approximation, albeit it should be a fairly good one.

It compares the two strings `str1` and `str2`, ignoring the case of the characters. It returns an integer less than, equal to, or greater than zero if `str1` is found, respectively, to be less than, to match, or be greater than `str2`.

`str1` : | first string
`str2` : | second string
Returns : | an integer less than, equal to, or greater than zero if `str1` is found, respectively, to be less than, to match, or be greater than `str2`.

### mirage_helper_strncasecmp ()

    gint                mirage_helper_strncasecmp           (const gchar *str1,
                                                             const gchar *str2,
                                                             gint len);

Replacement function for g_strncasecmp/strncasecmp, which can properly handle UTF-8. Glib docs state this is only an approximation, albeit it should be a fairly good one.

It compares first `len` characters of string `str1` and `str2`, ignoring the case of the characters. It returns an integer less than, equal to, or greater than zero if first `len` characters of `str1` is found, respectively, to be less than, to match, or be greater than first `len` characters of `str2`.

`str1` : | first string
`str2` : | second string
`len` : | length of string to compare
Returns : | an integer less than, equal to, or greater than zero if first `len` characters of `str1` is found, respectively, to be less than, to match, or be greater than first `len` characters of `str2`.

### mirage_helper_lba2msf ()

    void                mirage_helper_lba2msf               (gint lba,
                                                             gboolean diff,
                                                             guint8 *m,
                                                             guint8 *s,
                                                             guint8 *f);

Converts LBA sector address stored in `lba` into MSF address, storing each field into `m`, `s` and `f`, respectively.

If `diff` is `TRUE`, 150 frames difference is accounted for; this should be used when converting absolute addresses. When converting relative addresses (or lengths), `diff` should be set to `FALSE`.

`lba` : | LBA address
`diff` : | account for the difference
`m` : | location to store minutes, or `NULL`
`s` : | location to store seconds, or `NULL`
`f` : | location to store frames, or `NULL`

### mirage_helper_lba2msf_str ()

    gchar *             mirage_helper_lba2msf_str           (gint lba,
                                                             gboolean diff);

Converts LBA sector address stored in `lba` into MSF address.

If `diff` is `TRUE`, 150 frames difference is accounted for; this should be used when converting absolute addresses. When converting relative addresses (or lengths), `diff` should be set to `FALSE`.

`lba` : | LBA address
`diff` : | account for the difference
Returns : | a newly-allocated string containing MSF address; it should be freed with `g_free()` when no longer needed.

### mirage_helper_msf2lba ()

    gint                mirage_helper_msf2lba               (guint8 m,
                                                             guint8 s,
                                                             guint8 f,
                                                             gboolean diff);

Converts MSF sector address stored in `m`, `s` and `f` into LBA address.

If `diff` is `TRUE`, 150 frames difference is accounted for; this should be used when converting absolute addresses. When converting relative addresses (or lengths), `diff` should be set to `FALSE`.

`m` : | minutes
`s` : | seconds
`f` : | frames
`diff` : | difference
Returns : | integer representing LBA address

### mirage_helper_msf2lba_str ()

    gint                mirage_helper_msf2lba_str           (gchar *msf,
                                                             gboolean diff);

Converts MSF sector address stored in `msf` string into LBA address.

If `diff` is `TRUE`, 150 frames difference is accounted for; this should be used when converting absolute addresses. When converting relative addresses (or lengths), `diff` should be set to `FALSE`.

`msf` : | MSF string
`diff` : | difference
Returns : | integer representing LBA address

### mirage_helper_hex2bcd ()

    gint                mirage_helper_hex2bcd               (gint hex);

Converts hex-encoded integer into bcd-encoded integer.

`hex` : | hex-encoded integer
Returns : | bcd-encoded integer

### mirage_helper_bcd2hex ()

    gint                mirage_helper_bcd2hex               (gint bcd);

Converts bcd-encoded integer into hex-encoded integer.

`bcd` : | bcd-encoded integer
Returns : | hex-encoded integer

### mirage_helper_ascii2isrc ()

    guint8              mirage_helper_ascii2isrc            (gchar c);

Converts ASCII character `c` into ISRC character.

`c` : | ASCII character
Returns : | ISRC character

### mirage_helper_isrc2ascii ()

    gchar               mirage_helper_isrc2ascii            (guint8 c);

Converts ISRC character `c` into ASCII character.

`c` : | ISRC character
Returns : | ACSII character

### mirage_helper_subchannel_q_calculate_crc ()

    guint16             mirage_helper_subchannel_q_calculate_crc
                                                            (guint8 *data);

Calculates the CRC-16 checksum of the Q subchannel data stored in `data`.

`data` : | buffer containing Q subchannel data
Returns : | CRC-16 checksum of Q subchannel data

### mirage_helper_subchannel_q_encode_mcn ()

    void                mirage_helper_subchannel_q_encode_mcn
                                                            (guint8 *buf,
                                                             gchar *mcn);

Encodes MCN string `mcn` into buffer `buf`.

`buf` : | buffer to encode MCN into
`mcn` : | MCN string

### mirage_helper_subchannel_q_decode_mcn ()

    void                mirage_helper_subchannel_q_decode_mcn
                                                            (guint8 *buf,
                                                             gchar *mcn);

Decodes MCN stored in `buf` into string `mcn`.

`buf` : | buffer containing encoded MCN
`mcn` : | string to decode MCN into

### mirage_helper_subchannel_q_encode_isrc ()

    void                mirage_helper_subchannel_q_encode_isrc
                                                            (guint8 *buf,
                                                             gchar *isrc);

Encodes ISRC string `isrc` into buffer `buf`.

`buf` : | buffer to encode ISRC into
`isrc` : | ISRC string

### mirage_helper_subchannel_q_decode_isrc ()

    void                mirage_helper_subchannel_q_decode_isrc
                                                            (guint8 *buf,
                                                             gchar *isrc);

Decodes ISRC stored in `buf` into string `isrc`.

`buf` : | buffer containing encoded ISRC
`isrc` : | string to decode ISRC into

### mirage_helper_subchannel_interleave ()

    void                mirage_helper_subchannel_interleave (gint subchan,
                                                             guint8 *channel12,
                                                             guint8 *channel96);

Interleaves subchannel data of type `subchan` stored in `channel12` into subchannel data stored in `subchannel96`.

`subchan` : | subchannel type
`channel12` : | buffer containing subchannel data to interleave
`channel96` : | buffer to interleave subchannel data into

### mirage_helper_subchannel_deinterleave ()

    void                mirage_helper_subchannel_deinterleave
                                                            (gint subchan,
                                                             guint8 *channel96,
                                                             guint8 *channel12);

Deinterleaves subchannel data of type `subchan` from subchannel data stored in `channel96` and writes the resulting subhcannel data into `subchannel12`.

`subchan` : | subchannel type
`channel96` : | buffer containing subchannel data to deinterleave
`channel12` : | buffer to deinterleave subchannel data into

### mirage_helper_sector_edc_ecc_compute_edc_block ()

    void                mirage_helper_sector_edc_ecc_compute_edc_block
                                                            (const guint8 *src,
                                                             guint16 size,
                                                             guint8 *dest);

Calculates EDC (error detection code) for data in `src` of length `size` and writes the result into `dest`.

To calculate EDC for different types of sectors and store it into sector data, use:

- Mode 1 sector:

  `mirage_helper_sector_edc_ecc_compute_edc_block(sector_buffer+0x00, 0x810, sector_buffer+0x810);`

- Mode 2 Form 1 sector:

  `mirage_helper_sector_edc_ecc_compute_edc_block(sector_buffer+0x10, 0x808, sector_buffer+0x818);`

- Mode 2 Form 2 sector:

  `mirage_helper_sector_edc_ecc_compute_edc_block(sector_buffer+0x10, 0x91C, sector_buffer+0x92C);`

(This is assuming all other sector data is already stored in sector_buffer and that sector_buffer is 2532 bytes long)

`src` : | data to calculate EDC data for
`size` : | size of data in `src`
`dest` : | buffer to write calculated EDC data into

### mirage_helper_sector_edc_ecc_compute_ecc_block ()

    void                mirage_helper_sector_edc_ecc_compute_ecc_block
                                                            (guint8 *src,
                                                             guint32 major_count,
                                                             guint32 minor_count,
                                                             guint32 major_mult,
                                                             guint32 minor_inc,
                                                             guint8 *dest);

Calculates ECC (error correction code) for data in `src` and writes the result into `dest`. The code assumes 2352 byte sectors. It can calculate both P and Q layer of ECC data, depending on `major_count`, `minor_count`, `major_mult` and minor_inc.

To calculate ECC (first P, then Q layer) for different types of sectors and store it into sector data, use:

- Mode 1 sector:

  `mirage_helper_sector_edc_ecc_compute_ecc_block(sector_buffer+0xC, 86, 24, 2, 86, sector_buffer+0x81C); mirage_helper_sector_edc_ecc_compute_ecc_block(sector_buffer+0xC, 52, 43, 86, 88, sector_buffer+0x8C8);`

- Mode 2 Form 1 sector:

  `mirage_helper_sector_edc_ecc_compute_ecc_block(sector_buffer+0xC, 86, 24, 2, 86, sector_buffer+0x81C); mirage_helper_sector_edc_ecc_compute_ecc_block(sector_buffer+0xC, 52, 43, 86, 88, sector_buffer+0x8C8);`

(This is assuming all other sector data, including EDC, is already stored in sector_buffer and that sector_buffer is 2532 bytes long)

`src` : | data to calculate ECC data for
`major_count` : | major count
`minor_count` : | minor count
`major_mult` : | major multiplicator
`minor_inc` : | minor increment
`dest` : | buffer to write calculated ECC data into