summaryrefslogtreecommitdiff
path: root/apps/codecs/libfaad/codebook/hcb_8.h
blob: d75da9030e84314547c005ec0f67e08cabfcc690 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*
** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com
**  
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** 
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
** 
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software 
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
** Any non-GPL usage of this software or parts of this software is strictly
** forbidden.
**
** Commercial non-GPL licensing of this software is possible.
** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
**
** $Id$
**/

/* 2-step huffman table HCB_8 */


/* 1st step: 5 bits
 *           2^5 = 32 entries
 *
 * Used to find offset into 2nd step table and number of extra bits to get
 */
static hcb hcb8_1[] = {
    /* 3 bit codeword */
    { /* 00000 */ 0, 0 },
    { /*       */ 0, 0 },
    { /*       */ 0, 0 },
    { /*       */ 0, 0 },

    /* 4 bit codewords */
    { /* 00100 */ 1, 0 },
    { /*       */ 1, 0 },
    { /* 00110 */ 2, 0 },
    { /*       */ 2, 0 },
    { /* 01000 */ 3, 0 },
    { /*       */ 3, 0 },
    { /* 01010 */ 4, 0 },
    { /*       */ 4, 0 },
    { /* 01100 */ 5, 0 },
    { /*       */ 5, 0 },

    /* 5 bit codewords */
    { /* 01110 */ 6, 0 },
    { /* 01111 */ 7, 0 },
    { /* 10000 */ 8, 0 },
    { /* 10001 */ 9, 0 },
    { /* 10010 */ 10, 0 },
    { /* 10011 */ 11, 0 },
    { /* 10100 */ 12, 0 },

    /* 6 bit codewords */
    { /* 10101 */ 13, 1 },
    { /* 10110 */ 15, 1 },
    { /* 10111 */ 17, 1 },
    { /* 11000 */ 19, 1 },
    { /* 11001 */ 21, 1 },

    /* 7 bit codewords */
    { /* 11010 */ 23, 2 },
    { /* 11011 */ 27, 2 },
    { /* 11100 */ 31, 2 },

    /* 7/8 bit codewords */
    { /* 11101 */ 35, 3 },

    /* 8 bit codewords */
    { /* 11110 */ 43, 3 },

    /* 8/9/10 bit codewords */
    { /* 11111 */ 51, 5 }
};

/* 2nd step table
 *
 * Gives size of codeword and actual data (x,y,v,w)
 */
static hcb_2_pair hcb8_2[] = {
    /* 3 bit codeword */
    { 3,  1,  1 },

    /* 4 bit codewords */
    { 4,  2,  1 },
    { 4,  1,  0 },
    { 4,  1,  2 },
    { 4,  0,  1 },
    { 4,  2,  2 },

    /* 5 bit codewords */
    { 5,  0,  0 },
    { 5,  2,  0 },
    { 5,  0,  2 },
    { 5,  3,  1 },
    { 5,  1,  3 },
    { 5,  3,  2 },
    { 5,  2,  3 },

    /* 6 bit codewords */
    { 6,  3,  3 },
    { 6,  4,  1 },
    { 6,  1,  4 },
    { 6,  4,  2 },
    { 6,  2,  4 },
    { 6,  3,  0 },
    { 6,  0,  3 },
    { 6,  4,  3 },
    { 6,  3,  4 },
    { 6,  5,  2 },

    /* 7 bit codewords */
    { 7,  5,  1 },
    { 7,  2,  5 },
    { 7,  1,  5 },
    { 7,  5,  3 },
    { 7,  3,  5 },
    { 7,  4,  4 },
    { 7,  5,  4 },
    { 7,  0,  4 },
    { 7,  4,  5 },
    { 7,  4,  0 },
    { 7,  2,  6 },
    { 7,  6,  2 },

    /* 7/8 bit codewords */
    { 7,  6,  1 }, { 7,  6,  1 },
    { 7,  1,  6 }, { 7,  1,  6 },
    { 8,  3,  6 },
    { 8,  6,  3 },
    { 8,  5,  5 },
    { 8,  5,  0 },

    /* 8 bit codewords */
    { 8,  6,  4 },
    { 8,  0,  5 },
    { 8,  4,  6 },
    { 8,  7,  1 },
    { 8,  7,  2 },
    { 8,  2,  7 },
    { 8,  6,  5 },
    { 8,  7,  3 },

    /* 8/9/10 bit codewords */
    { 8,  1,  7 }, { 8,  1,  7 }, { 8,  1,  7 }, { 8,  1,  7 },
    { 8,  5,  6 }, { 8,  5,  6 }, { 8,  5,  6 }, { 8,  5,  6 },
    { 8,  3,  7 }, { 8,  3,  7 }, { 8,  3,  7 }, { 8,  3,  7 },
    { 9,  6,  6 }, { 9,  6,  6 },
    { 9,  7,  4 }, { 9,  7,  4 },
    { 9,  6,  0 }, { 9,  6,  0 },
    { 9,  4,  7 }, { 9,  4,  7 },
    { 9,  0,  6 }, { 9,  0,  6 },
    { 9,  7,  5 }, { 9,  7,  5 },
    { 9,  7,  6 }, { 9,  7,  6 },
    { 9,  6,  7 }, { 9,  6,  7 },
    { 10,  5,  7 },
    { 10,  7,  0 },
    { 10,  0,  7 },
    { 10,  7,  7 }
};
); } while(0) static void advance(struct context_t *ctx, int nr_chars) { while(nr_chars--) { if(*(ctx->ptr++) == '\n') ctx->line++; } } static inline bool eof(struct context_t *ctx) { return ctx->ptr == ctx->end; } static inline bool next_valid(struct context_t *ctx, int nr) { return ctx->ptr + nr < ctx->end; } static inline char cur_char(struct context_t *ctx) { return *ctx->ptr; } static inline char next_char(struct context_t *ctx, int nr) { return ctx->ptr[nr]; } static inline void locate_lexem(struct lexem_t *lex, struct context_t *ctx) { lex->file = ctx->file; lex->line = ctx->line; } static void __parse_string(struct context_t *ctx, void *user, void (*emit_fn)(void *user, char c)) { while(!eof(ctx)) { if(cur_char(ctx) == '"') break; else if(cur_char(ctx) == '\\') { advance(ctx, 1); if(eof(ctx)) parse_error(ctx, "Unfinished string\n"); if(cur_char(ctx) == '\\') emit_fn(user, '\\'); else if(cur_char(ctx) == '\'') emit_fn(user, '\''); else if(cur_char(ctx) == '\"') emit_fn(user, '\"'); else parse_error(ctx, "Unknown escape sequence \\%c\n", cur_char(ctx)); advance(ctx, 1); } else { emit_fn(user, cur_char(ctx)); advance(ctx, 1); } } if(eof(ctx) || cur_char(ctx) != '"') parse_error(ctx, "Unfinished string\n"); advance(ctx, 1); } static void __parse_string_emit(void *user, char c) { char **pstr = (char **)user; *(*pstr)++ = c; } static void __parse_string_count(void *user, char c) { (void) c; (*(int *)user)++; } static void parse_string(struct context_t *ctx, struct lexem_t *lexem) { locate_lexem(lexem, ctx); /* skip " */ advance(ctx, 1); /* compute length */ struct context_t cpy_ctx = *ctx; int length = 0; __parse_string(&cpy_ctx, (void *)&length, __parse_string_count); /* parse again */ lexem->type = LEX_STRING; lexem->str = xmalloc(length + 1); lexem->str[length] = 0; char *pstr = lexem->str; __parse_string(ctx, (void *)&pstr, __parse_string_emit); } static void parse_ascii_number(struct context_t *ctx, struct lexem_t *lexem) { locate_lexem(lexem, ctx); /* skip ' */ advance(ctx, 1); /* we expect n<=4 character and then ' */ int len = 0; uint32_t value = 0; while(!eof(ctx)) { if(cur_char(ctx) != '\'') { value = value << 8 | cur_char(ctx); len++; advance(ctx, 1); } else break; } if(eof(ctx) || cur_char(ctx) != '\'') parse_error(ctx, "Unterminated ascii number literal\n"); if(len == 0 || len > 4) parse_error(ctx, "Invalid ascii number literal length: only 1 to 4 characters allowed\n"); /* skip ' */ advance(ctx, 1); lexem->type = LEX_NUMBER; lexem->num = value; } static void parse_number(struct context_t *ctx, struct lexem_t *lexem) { locate_lexem(lexem, ctx); /* check base */ int base = 10; if(cur_char(ctx) == '0' && next_valid(ctx, 1) && next_char(ctx, 1) == 'x') { advance(ctx, 2); base = 16; } lexem->type = LEX_NUMBER; lexem->num = 0; while(!eof(ctx) && isxdigit(cur_char(ctx))) { if(base == 10 && !isdigit(cur_char(ctx))) break; byte v; if(convxdigit(cur_char(ctx), &v)) break; lexem->num = base * lexem->num + v; advance(ctx, 1); } } static void parse_identifier(struct context_t *ctx, struct lexem_t *lexem) { locate_lexem(lexem, ctx); /* remember position */ char *old = ctx->ptr; while(!eof(ctx) && (isalnum(cur_char(ctx)) || cur_char(ctx) == '_')) advance(ctx, 1); lexem->type = LEX_IDENTIFIER; int len = ctx->ptr - old; lexem->str = xmalloc(len + 1); lexem->str[len] = 0; memcpy(lexem->str, old, len); } static void next_lexem(struct context_t *ctx, struct lexem_t *lexem) { #define ret_simple(t, adv) \ do {locate_lexem(lexem, ctx); \ lexem->type = t; \ advance(ctx, adv); \ return;} while(0) while(!eof(ctx)) { char c = cur_char(ctx); /* skip whitespace */ if(c == ' ' || c == '\t' || c == '\n' || c == '\r') { advance(ctx, 1); continue; } /* skip C++ style comments */ if(c == '/' && next_valid(ctx, 1) && next_char(ctx, 1) == '/') { while(!eof(ctx) && cur_char(ctx) != '\n') advance(ctx, 1); continue; } /* skip C-style comments */ if(c == '/' && next_valid(ctx, 1) && next_char(ctx, 1) == '*') { advance(ctx, 2); while(true) { if(!next_valid(ctx, 1)) parse_error(ctx, "Unterminated comment"); if(cur_char(ctx) == '*' && next_char(ctx, 1) == '/') { advance(ctx, 2); break; } advance(ctx, 1); } continue; } break; } if(eof(ctx)) ret_simple(LEX_EOF, 0); char c = cur_char(ctx); bool nv = next_valid(ctx, 1); char nc = nv ? next_char(ctx, 1) : 0; if(c == '(') ret_simple(LEX_LPAREN, 1); if(c == ')') ret_simple(LEX_RPAREN, 1); if(c == '{') ret_simple(LEX_LBRACE, 1); if(c == '}') ret_simple(LEX_RBRACE, 1); if(c == '>') ret_simple(LEX_RANGLE, 1); if(c == '=') ret_simple(LEX_EQUAL, 1); if(c == ';') ret_simple(LEX_SEMICOLON, 1); if(c == ',') ret_simple(LEX_COLON, 1); if(c == '|') ret_simple(LEX_OR, 1); if(c == '<' && nv && nc == '<') ret_simple(LEX_LSHIFT, 2); if(c == '<' && nv && nc == '=') ret_simple(LEX_LE, 2); if(c == '"') return parse_string(ctx, lexem); if(c == '\'') return parse_ascii_number(ctx, lexem); if(isdigit(c)) return parse_number(ctx, lexem); if(isalpha(c) || c == '_') return parse_identifier(ctx, lexem); parse_error(ctx, "Unexpected character '%c'\n", c); #undef ret_simple } #if 0 static void log_lexem(struct lexem_t *lexem) { switch(lexem->type) { case LEX_EOF: printf("<eof>"); break; case LEX_EQUAL: printf("="); break; case LEX_IDENTIFIER: printf("id(%s)", lexem->str); break; case LEX_LPAREN: printf("("); break; case LEX_RPAREN: printf(")"); break; case LEX_LBRACE: printf("{"); break; case LEX_RBRACE: printf("}"); break; case LEX_SEMICOLON: printf(";"); break; case LEX_NUMBER: printf("num(%d)", lexem->num); break; case LEX_STRING: printf("str(%s)", lexem->str); break; case LEX_OR: printf("|"); break; case LEX_LSHIFT: printf("<<"); break; default: printf("<unk>"); } } #endif struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id) { struct cmd_source_t *src = cmd_file->source_list; while(src) { if(strcmp(src->identifier, id) == 0) return src; src = src->next; } return NULL; } struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char *name) { while(opt) { if(strcmp(opt->name, name) == 0) return opt; opt = opt->next; } return NULL; } #define INVALID_SB_SUBVERSION 0xffff static uint16_t parse_sb_subversion(char *str) { int len = strlen(str); uint16_t n = 0; if(len == 0 || len > 4) return INVALID_SB_SUBVERSION; for(int i = 0; i < len; i++) { if(!isdigit(str[i])) return INVALID_SB_SUBVERSION; n = n << 4 | (str[i] - '0'); } return n; } bool db_parse_sb_version(struct sb_version_t *ver, char *str) { int len = strlen(str); int cnt = 0; int pos[2]; for(int i = 0; i < len; i++) { if(str[i] != '.') continue; if(cnt == 2) return false; pos[cnt++] = i + 1; str[i] = 0; } if(cnt != 2) return false; ver->major = parse_sb_subversion(str); ver->minor = parse_sb_subversion(str + pos[0]); ver->revision = parse_sb_subversion(str + pos[1]); return ver->major != INVALID_SB_SUBVERSION && ver->minor != INVALID_SB_SUBVERSION && ver->revision != INVALID_SB_SUBVERSION; } #undef parse_error #define parse_error(lexem, ...) \ do { fprintf(stderr, "%s:%d: ", lexem.file, lexem.line); \ fprintf(stderr, __VA_ARGS__); exit(2); } while(0) struct lex_ctx_t { struct context_t ctx; struct lexem_t lexem; }; /* When lexems hold strings (like identifier), it might be useful to steal * the pointer and don't clean the lexem but in other case, one don't want * to keep the pointer to the string and just want to release the memory. * Thus clean_lexem should be true except when one keeps a pointer */ static inline void next(struct lex_ctx_t *ctx, bool clean_lexem) { if(clean_lexem) free(ctx->lexem.str); memset(&ctx->lexem, 0, sizeof(struct lexem_t)); next_lexem(&ctx->ctx, &ctx->lexem); } static uint32_t parse_term_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list) { uint32_t ret = 0; if(ctx->lexem.type == LEX_NUMBER) ret = ctx->lexem.num; else if(ctx->lexem.type == LEX_IDENTIFIER) { struct cmd_option_t *c = db_find_option_by_id(const_list, ctx->lexem.str); if(c == NULL) parse_error(ctx->lexem, "Undefined reference to constant '%s'\n", ctx->lexem.str); if(c->is_string) parse_error(ctx->lexem, "Internal error: constant '%s' is not an integer\n", ctx->lexem.str); ret = c->val; } else parse_error(ctx->lexem, "Number or constant identifier expected\n"); next(ctx, true); return ret; } static uint32_t parse_shift_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list) { uint32_t v = parse_term_expr(ctx, const_list); while(ctx->lexem.type == LEX_LSHIFT) { next(ctx, true); v <<= parse_term_expr(ctx, const_list); } return v; } static uint32_t parse_or_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list) { uint32_t v = parse_shift_expr(ctx, const_list); while(ctx->lexem.type == LEX_OR) { next(ctx, true); v |= parse_shift_expr(ctx, const_list); } return v; } static uint32_t parse_intexpr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list) { return parse_or_expr(ctx, const_list); } #define NR_INITIAL_CONSTANTS 4 static char *init_const_name[NR_INITIAL_CONSTANTS] = {"true", "false", "yes", "no"}; static uint32_t init_const_value[NR_INITIAL_CONSTANTS] = {1, 0, 1, 0}; struct cmd_file_t *db_parse_file(const char *file) { size_t size; FILE *f = fopen(file, "r"); if(f == NULL) bugp("Cannot open file '%s'", file); fseek(f, 0, SEEK_END); size = ftell(f); fseek(f, 0, SEEK_SET); char *buf = xmalloc(size); if(fread(buf, size, 1, f) != 1) bugp("Cannot read file '%s'", file); fclose(f); if(g_debug) printf("Parsing db file '%s'\n", file); struct cmd_file_t *cmd_file = xmalloc(sizeof(struct cmd_file_t)); memset(cmd_file, 0, sizeof(struct cmd_file_t)); /* add initial constants */ for(int i = 0; i < NR_INITIAL_CONSTANTS; i++) { struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); memset(opt, 0, sizeof(struct cmd_option_t)); opt->name = strdup(init_const_name[i]); opt->is_string = false; opt->val = init_const_value[i]; opt->next = cmd_file->constant_list; cmd_file->constant_list = opt; } struct lex_ctx_t lctx; lctx.ctx.file = file; lctx.ctx.line = 1; lctx.ctx.begin = buf; lctx.ctx.ptr = buf; lctx.ctx.end = buf + size; #define next(clean_lexem) next(&lctx, clean_lexem) #define lexem lctx.lexem /* init lexer */ next(false); /* don't clean init lexem because it doesn't exist */ /* constants ? */ if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "constants")) { next(true); if(lexem.type != LEX_LBRACE) parse_error(lexem, "'{' expected after 'constants'\n"); while(true) { struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); memset(opt, 0, sizeof(struct cmd_option_t)); next(true); if(lexem.type == LEX_RBRACE) break; if(lexem.type != LEX_IDENTIFIER) parse_error(lexem, "Identifier expected in constants\n"); opt->name = lexem.str; next(false); /* lexem string is kept as option name */ if(lexem.type != LEX_EQUAL) parse_error(lexem, "'=' expected after identifier\n"); next(true); opt->is_string = false; opt->val = parse_intexpr(&lctx, cmd_file->constant_list); opt->next = cmd_file->constant_list; cmd_file->constant_list = opt; if(lexem.type != LEX_SEMICOLON) parse_error(lexem, "';' expected after string\n"); } next(true); } /* options ? */ if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "options")) { next(true); if(lexem.type != LEX_LBRACE) parse_error(lexem, "'{' expected after 'options'\n"); while(true) { next(true); if(lexem.type == LEX_RBRACE) break; struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); memset(opt, 0, sizeof(struct cmd_option_t)); if(lexem.type != LEX_IDENTIFIER) parse_error(lexem, "Identifier expected in options\n"); opt->name = lexem.str; next(false); /* lexem string is kept as option name */ if(lexem.type != LEX_EQUAL) parse_error(lexem, "'=' expected after identifier\n"); next(true); if(lexem.type == LEX_STRING) { opt->is_string = true; opt->str = lexem.str; next(false); /* lexem string is kept as option name */ } else { opt->is_string = false; opt->val = parse_intexpr(&lctx, cmd_file->constant_list); } opt->next = cmd_file->opt_list; cmd_file->opt_list = opt; if(lexem.type != LEX_SEMICOLON) parse_error(lexem, "';' expected after string\n"); } next(true); } /* sources */ if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "sources")) parse_error(lexem, "'sources' expected\n"); next(true); if(lexem.type != LEX_LBRACE) parse_error(lexem, "'{' expected after 'sources'\n"); while(true) { next(true); if(lexem.type == LEX_RBRACE) break; struct cmd_source_t *src = xmalloc(sizeof(struct cmd_source_t)); memset(src, 0, sizeof(struct cmd_source_t)); if(lexem.type != LEX_IDENTIFIER) parse_error(lexem, "identifier expected in sources\n"); src->identifier = lexem.str; next(false); /* lexem string is kept as source name */ if(lexem.type != LEX_EQUAL) parse_error(lexem, "'=' expected after identifier\n"); next(true); if(lexem.type == LEX_STRING) { src->is_extern = false; src->filename = lexem.str; next(false); /* lexem string is kept as file name */ } else if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "extern")) { src->is_extern = true;