Exemple #1
0
unsigned stats_get_version(char *type, uint8_t *data){
    /* I could've used iff_parse_chunk instead to determine chunk versions, but this
       would be unnecessarily slow and would require all chunk parsers to be written,
       defeating the purpose of this tool. */

    if(!strcmp(type, "STR#") || !strcmp(type, "CTSS") || !strcmp(type, "FAMs") ||
       !strcmp(type, "TTAs") || !strcmp(type, "CST")  || !strcmp(type, "BHAV") ||
       !strcmp(type, "DGRP") || !strcmp(type, "POSI"))
        return read_uint16le(data);

    if(!strcmp(type, "FCNS") || !strcmp(type, "OBJf") || !strcmp(type, "Optn") ||
       !strcmp(type, "Rcon") || !strcmp(type, "TPRP") || !strcmp(type, "SLOT") ||
       !strcmp(type, "TRCN") || !strcmp(type, "rsmp"))
        return read_uint32le(data+4);

    if(!strcmp(type, "OBJD") || !strcmp(type, "PALT") || !strcmp(type, "SPR2"))
        return read_uint32le(data);

    if(!strcmp(type, "TTAB"))
        return read_uint16le(data+2);

    if(!strcmp(type, "SPR#")){
        if(data[0] == 0) return read_uint32be(data);
        else return read_uint32le(data);
    }

    return -1;
}
Exemple #2
0
bool get_sgc_metadata(int fd, struct mp3entry* id3)
{
   uint32_t sgc_type;
    if ((lseek(fd, 0, SEEK_SET) < 0) ||
         read_uint32be(fd, &sgc_type) != (int)sizeof(sgc_type))
        return false;

    id3->vbr = false;
    id3->filesize = filesize(fd);
    /* we only render 16 bits, 44.1KHz, Stereo */
    id3->bitrate = 706;
    id3->frequency = 44100;
  
    /* Make sure this is an SGC file */
    if (sgc_type != FOURCC('S','G','C',0x1A))
        return false;

    return parse_sgc_header(fd, id3);
}
Exemple #3
0
bool get_nsf_metadata(int fd, struct mp3entry* id3)
{
    uint32_t nsf_type;
    if (lseek(fd, 0, SEEK_SET) < 0 ||
        read_uint32be(fd, &nsf_type) != (int)sizeof(nsf_type))
        return false;

    id3->vbr = false;
    id3->filesize = filesize(fd);
    /* we only render 16 bits, 44.1KHz, Mono */
    id3->bitrate = 706;
    id3->frequency = 44100;

    if (nsf_type == CHAR4_CONST('N', 'S', 'F', 'E'))
        return parse_nsfe(fd, id3);
    else if (nsf_type == CHAR4_CONST('N', 'E', 'S', 'M'))
        return parse_nesm(fd, id3);

    /* not a valid format*/
    return false;
}
int ordered_map_file_open(const char *path, OrderedMapFile **out_omf) {
    *out_omf = nullptr;
    OrderedMapFile *omf = create_zero<OrderedMapFile>();
    if (!omf) {
        ordered_map_file_close(omf);
        return GenesisErrorNoMem;
    }
    if (omf->queue.error() || omf->cond.error() || omf->mutex.error()) {
        ordered_map_file_close(omf);
        return omf->queue.error() || omf->cond.error() || omf->mutex.error();
    }
    omf->list = create_zero<List<OrderedMapFileEntry *>>();
    if (!omf->list) {
        ordered_map_file_close(omf);
        return GenesisErrorNoMem;
    }

    omf->map = create_zero<HashMap<ByteBuffer, OrderedMapFileEntry *, ByteBuffer::hash>>();
    if (!omf->map) {
        ordered_map_file_close(omf);
        return GenesisErrorNoMem;
    }

    omf->running = true;
    int err = omf->write_thread.start(run_write, omf);
    if (err) {
        ordered_map_file_close(omf);
        return err;
    }

    bool open_for_writing = false;
    omf->file = fopen(path, "rb+");
    if (omf->file) {
        int err = read_header(omf);
        if (err == GenesisErrorEmptyFile) {
            open_for_writing = true;
        } else if (err) {
            ordered_map_file_close(omf);
            return err;
        }
    } else {
        open_for_writing = true;
    }
    if (open_for_writing) {
        omf->file = fopen(path, "wb+");
        if (!omf->file) {
            ordered_map_file_close(omf);
            return GenesisErrorFileAccess;
        }
        int err = write_header(omf);
        if (err) {
            ordered_map_file_close(omf);
            return err;
        }
    }

    // read everything into list
    omf->write_buffer.resize(TRANSACTION_METADATA_SIZE);
    omf->transaction_offset = UUID_SIZE;
    for (;;) {
        size_t amt_read = fread(omf->write_buffer.raw(), 1, TRANSACTION_METADATA_SIZE, omf->file);
        if (amt_read != TRANSACTION_METADATA_SIZE) {
            // partial transaction. ignore it and we're done.
            break;
        }
        uint8_t *transaction_ptr = (uint8_t*)omf->write_buffer.raw();
        int transaction_size = read_uint32be(&transaction_ptr[4]);

        omf->write_buffer.resize(transaction_size);
        transaction_ptr = (uint8_t*)omf->write_buffer.raw();

        size_t amt_to_read = transaction_size - TRANSACTION_METADATA_SIZE;
        amt_read = fread(&transaction_ptr[TRANSACTION_METADATA_SIZE], 1, amt_to_read, omf->file);
        if (amt_read != amt_to_read) {
            // partial transaction. ignore it and we're done.
            break;
        }
        uint32_t computed_crc = crc32(0, &transaction_ptr[4], transaction_size - 4);
        uint32_t crc_from_file = read_uint32be(&transaction_ptr[0]);
        if (computed_crc != crc_from_file) {
            // crc check failed. ignore this transaction and we're done.
            break;
        }

        int put_count = read_uint32be(&transaction_ptr[8]);
        int del_count = read_uint32be(&transaction_ptr[12]);

        int offset = TRANSACTION_METADATA_SIZE;
        for (int i = 0; i < put_count; i += 1) {
            int key_size = read_uint32be(&transaction_ptr[offset]); offset += 4;
            int val_size = read_uint32be(&transaction_ptr[offset]); offset += 4;

            OrderedMapFileEntry *entry = create_zero<OrderedMapFileEntry>();
            if (!entry) {
                ordered_map_file_close(omf);
                return GenesisErrorNoMem;
            }

            entry->key = ByteBuffer((char*)&transaction_ptr[offset], key_size); offset += key_size;
            entry->offset = omf->transaction_offset + offset;
            entry->size = val_size;
            offset += val_size;

            auto old_hash_entry = omf->map->maybe_get(entry->key);
            if (old_hash_entry) {
                OrderedMapFileEntry *old_entry = old_hash_entry->value;
                destroy(old_entry, 1);
            }

            omf->map->put(entry->key, entry);
        }
        for (int i = 0; i < del_count; i += 1) {
            int key_size = read_uint32be(&transaction_ptr[offset]); offset += 4;
            ByteBuffer key((char*)&transaction_ptr[offset], key_size); offset += key_size;

            auto hash_entry = omf->map->maybe_get(key);
            if (hash_entry) {
                OrderedMapFileEntry *entry = hash_entry->value;
                omf->map->remove(key);
                destroy(entry, 1);
            }
        }

        omf->transaction_offset += transaction_size;

    }

    // transfer map to list and sort
    auto it = omf->map->entry_iterator();
    if (omf->list->ensure_capacity(omf->map->size())) {
        ordered_map_file_close(omf);
        return GenesisErrorNoMem;
    }
    for (;;) {
        auto *map_entry = it.next();
        if (!map_entry)
            break;

        ok_or_panic(omf->list->append(map_entry->value));
    }
    omf->map->clear();
    destroy_map(omf);

    omf->list->sort<compare_entries>();

    *out_omf = omf;
    return 0;
}
Exemple #5
0
static bool parse_nsfe(int fd, struct mp3entry *id3)
{
    unsigned int chunks_found = 0;
    long track_count = 0;
    long playlist_count = 0;

    struct NSFE_INFOCHUNK info;
    memset(&info, 0, sizeof(struct NSFE_INFOCHUNK));

     /* default values */
    info.nTrackCount = 1;
    id3->length = 150 * 1000;
    
    /* begin reading chunks */
    while (!(chunks_found & CHUNK_NEND))
    {
        uint32_t chunk_size, chunk_type;

        if (read_uint32le(fd, &chunk_size) != (int)sizeof(uint32_t))
            return false;

        if (read_uint32be(fd, &chunk_type) != (int)sizeof(uint32_t))
            return false;

        switch (chunk_type)
        {
        /* first three types are mandatory (but don't worry about NEND
           anyway) */
        case CHAR4_CONST('I', 'N', 'F', 'O'):
        {
            if (chunks_found & CHUNK_INFO)
                return false; /* only one info chunk permitted */

            chunks_found |= CHUNK_INFO;

            /* minimum size */
            if (chunk_size < 8)
                return false;

            ssize_t size = MIN(sizeof(struct NSFE_INFOCHUNK), chunk_size);

            if (read(fd, &info, size) != size)
                return false;

            if (size >= 9)
                track_count = info.nTrackCount;

            chunk_size -= size;
            break;
            }

        case CHAR4_CONST('D', 'A', 'T', 'A'):
        {
            if (!(chunks_found & CHUNK_INFO))
                return false;

            if (chunks_found & CHUNK_DATA)
                return false; /* only one may exist */

            if (chunk_size < 1)
                return false;

            chunks_found |= CHUNK_DATA;
            break;
            }

        case CHAR4_CONST('N', 'E', 'N', 'D'):
        {
            /* just end parsing regardless of whether or not this really is the
               last chunk/data (but it _should_ be) */
            chunks_found |= CHUNK_NEND;
            continue;
            }

        /* remaining types are optional */

        case CHAR4_CONST('a', 'u', 't', 'h'):
        {
            if (chunks_found & CHUNK_auth)
                return false; /* only one may exist */

            chunks_found |= CHUNK_auth;

            /* szGameTitle, szArtist, szCopyright */
            char ** const ar[] = { &id3->title, &id3->artist, &id3->album };

            char *p = id3->id3v2buf;
            long buf_rem = sizeof (id3->id3v2buf);
            unsigned int i;

            for (i = 0; i < ARRAYLEN(ar) && chunk_size && buf_rem; i++)
            {
                long len = read_string(fd, p, buf_rem, '\0', chunk_size);

                if (len < 0)
                    return false;

                *ar[i] = p;
                p += len;
                buf_rem -= len;

                if (chunk_size >= (uint32_t)len)
                    chunk_size -= len;
                else
                    chunk_size = 0;
            }

            break;
            }

        case CHAR4_CONST('p', 'l', 's', 't'):
        {
            if (chunks_found & CHUNK_plst)
                return false; /* only one may exist */

            chunks_found |= CHUNK_plst;

            /* each byte is the index of one track */
            playlist_count = chunk_size;
            break;
            }

        case CHAR4_CONST('t', 'i', 'm', 'e'):
        case CHAR4_CONST('f', 'a', 'd', 'e'):
        case CHAR4_CONST('t', 'l', 'b', 'l'): /* we unfortunately can't use these anyway */
        {
            /* don't care how many of these there are even though there should
               be only one */
            if (!(chunks_found & CHUNK_INFO))
                return false;

        case CHAR4_CONST('B', 'A', 'N', 'K'):
            break;
            }

        default: /* unknown chunk */
        {
            /* check the first byte */
            chunk_type = (uint8_t)chunk_type;

            /* chunk is vital... don't continue */
            if(chunk_type >= 'A' && chunk_type <= 'Z')
                return false;

            /* otherwise, just skip it */
            break;
            }
        } /* end switch */

        lseek(fd, chunk_size, SEEK_CUR);
    } /* end while */

    if (track_count | playlist_count)
        id3->length = MAX(track_count, playlist_count)*1000;

    /* Single subtrack files will be treated differently
        by gme's nsf codec */
    if (id3->length <= 1000) id3->length = 150 * 1000;

    /*
     * if we exited the while loop without a 'return', we must have hit an NEND
     *  chunk if this is the case, the file was layed out as it was expected.
     *  now.. make sure we found both an info chunk, AND a data chunk... since
     *  these are minimum requirements for a valid NSFE file
     */
    return (chunks_found & (CHUNK_INFO | CHUNK_DATA)) ==
            (CHUNK_INFO | CHUNK_DATA);
}