+
+/* wrap build_tree_from_lengths to allow zero entries in the histogram */
+void build_tree_from_lengths0(int vals, long *hist, long *lengths){
+
+ /* pack the 'sparse' hit list into a dense list, then unpack
+ the lengths after the build */
+
+ int upper=0,i;
+ long *lengthlist=_ogg_calloc(vals,sizeof(long));
+ long *newhist=alloca(vals*sizeof(long));
+
+ for(i=0;i<vals;i++)
+ if(hist[i]>0)
+ newhist[upper++]=hist[i];
+
+ if(upper != vals){
+ fprintf(stderr,"\rEliminating %d unused entries; %d entries remain\n",
+ vals-upper,upper);
+ }
+
+ build_tree_from_lengths(upper,newhist,lengthlist);
+
+ upper=0;
+ for(i=0;i<vals;i++)
+ if(hist[i]>0)
+ lengths[i]=lengthlist[upper++];
+ else
+ lengths[i]=0;
+
+ free(lengthlist);
+}
+
+void write_codebook(FILE *out,char *name,const static_codebook *c){
+ int i,j,k;
+
+ /* save the book in C header form */
+
+ /* first, the static vectors, then the book structure to tie it together. */
+ /* quantlist */
+ if(c->quantlist){
+ long vals=(c->maptype==1?_book_maptype1_quantvals(c):c->entries*c->dim);
+ fprintf(out,"static const long _vq_quantlist_%s[] = {\n",name);
+ for(j=0;j<vals;j++){
+ fprintf(out,"\t%ld,\n",c->quantlist[j]);
+ }
+ fprintf(out,"};\n\n");
+ }
+
+ /* lengthlist */
+ fprintf(out,"static const char _vq_lengthlist_%s[] = {\n",name);
+ for(j=0;j<c->entries;){
+ fprintf(out,"\t");
+ for(k=0;k<16 && j<c->entries;k++,j++)
+ fprintf(out,"%2ld,",c->lengthlist[j]);
+ fprintf(out,"\n");
+ }
+ fprintf(out,"};\n\n");
+
+ /* tie it all together */
+
+ fprintf(out,"static const static_codebook %s = {\n",name);
+
+ fprintf(out,"\t%ld, %ld,\n",c->dim,c->entries);
+ fprintf(out,"\t(char *)_vq_lengthlist_%s,\n",name);
+ fprintf(out,"\t%d, %ld, %ld, %d, %d,\n",
+ c->maptype,c->q_min,c->q_delta,c->q_quant,c->q_sequencep);
+ if(c->quantlist)
+ fprintf(out,"\t(long *)_vq_quantlist_%s,\n",name);
+ else
+ fprintf(out,"\tNULL,\n");
+
+ fprintf(out,"\t0\n};\n\n");
+}