int handle_bad_ioasa(struct ctx *p_ctx, __u64 data)
{
    __u64 *p_u64;
    __u32 *p_u32;
    __u64 lba=0;
    sisl_ioarcb_t *rcb;
    rcb = (sisl_ioarcb_t *)malloc(sizeof(sisl_ioarcb_t));

    fill_buf((__u64*)&p_ctx->wbuf[0][0],
             sizeof(p_ctx->wbuf[0])/sizeof(__u64),data);

    memset(&(rcb->cdb[0]), 0, sizeof(rcb->cdb));
    p_u64 = (__u64*)&(rcb->cdb[2]);

    rcb->res_hndl = p_ctx->res_hndl;
    rcb->req_flags = SISL_REQ_FLAGS_RES_HNDL;
    rcb->req_flags |= SISL_REQ_FLAGS_HOST_WRITE;
    write_lba(p_u64, lba);

    rcb->data_ea = (__u64) &p_ctx->wbuf[0][0];

    rcb->data_len = sizeof(p_ctx->wbuf[0]);
    rcb->cdb[0] = 0x8A;

    p_u32 = (__u32*)&(rcb->cdb[10]);
    write_32(p_u32, p_ctx->blk_len);

    asm volatile( "lwsync" : : );
    write_64(&p_ctx->p_host_map->ioarrin,(__u64)rcb);
    return 0;

}
Beispiel #2
0
void fill_send_read(struct ctx *p_ctx, __u64 vlba,
         __u32 flags)
{
	__u64 *p_u64;
	__u32 *p_u32;
	__u64 plba;
	
	memset(&p_ctx->rbuf[0][0], 0, sizeof(p_ctx->rbuf[0]));

	memset(&p_ctx->cmd[0].rcb.cdb[0], 0, sizeof(p_ctx->cmd[0].rcb.cdb));

	p_ctx->cmd[0].rcb.cdb[0] = 0x88; // read(16)
	p_u64 = (__u64*)&p_ctx->cmd[0].rcb.cdb[2];

    if (flags & VLBA){
        p_ctx->cmd[0].rcb.req_flags = SISL_REQ_FLAGS_RES_HNDL;
        p_ctx->cmd[0].rcb.req_flags |= SISL_REQ_FLAGS_HOST_READ;
        p_ctx->cmd[0].rcb.res_hndl   = p_ctx->res_hndl;
        write_64(p_u64, vlba); // Read(16) Virtual LBA
		debug("send read for vlba =0x%lX\n",vlba);

    }
    else
    {
		p_ctx->cmd[0].rcb.lun_id = lun_id;
		p_ctx->cmd[0].rcb.port_sel = fc_port; // either FC port
		p_ctx->cmd[0].rcb.req_flags = SISL_REQ_FLAGS_HOST_READ;
		if(flags & NO_XLATE){
			plba = vlba;
		}
		else {
			(void)mc_xlate_lba(p_ctx->mc_hndl, p_ctx->res_hndl, vlba, &plba);
		}
        write_64(p_u64, plba); // physical LBA#
		debug("send read for plba =0x%lX\n",plba);
    }

	p_ctx->cmd[0].rcb.data_len = sizeof(p_ctx->rbuf[0]);
	p_ctx->cmd[0].rcb.data_ea = (__u64) &p_ctx->rbuf[0][0];

	p_u32 = (__u32*)&p_ctx->cmd[0].rcb.cdb[10];

	write_32(p_u32, LBA_BLK);

	p_ctx->cmd[0].sa.host_use[0] = 0; // 0 means active
	p_ctx->cmd[0].sa.ioasc = 0;
}
Beispiel #3
0
void fill_send_write(struct ctx *p_ctx, __u64 vlba,
        __u64 data, __u64 stride, __u32 flags)
{
    __u64 *p_u64;
    __u32 *p_u32;
    __u64 plba;
	int i;

	for(i = 0 ; i < NUM_CMDS; i++) {
		vlba  = i * stride;

    fill_buf((__u64*)&p_ctx->wbuf[i][0],
        sizeof(p_ctx->wbuf[i])/sizeof(__u64),data);

    memset(&p_ctx->cmd[i].rcb.cdb[0], 0, sizeof(p_ctx->cmd[i].rcb.cdb));
    p_u64 = (__u64*)&p_ctx->cmd[i].rcb.cdb[2];

	if(flags & VLBA){
		p_ctx->cmd[i].rcb.res_hndl = p_ctx->res_hndl;
		p_ctx->cmd[i].rcb.req_flags = SISL_REQ_FLAGS_RES_HNDL;
		p_ctx->cmd[i].rcb.req_flags |= SISL_REQ_FLAGS_HOST_WRITE;
		write_64(p_u64, vlba); // write(16) Virtual LBA
	}else {
		p_ctx->cmd[i].rcb.lun_id = lun_id;
		p_ctx->cmd[i].rcb.port_sel = fc_port; // either FC port
		p_ctx->cmd[i].rcb.req_flags = SISL_REQ_FLAGS_HOST_WRITE;
		if(flags & NO_XLATE){
			plba = vlba;
		}
		else {
			(void)mc_xlate_lba(p_ctx->mc_hndl, p_ctx->res_hndl, vlba, &plba);
		}
		write_64(p_u64, plba); // physical LBA#
	}
    p_ctx->cmd[i].rcb.data_ea = (__u64) &p_ctx->wbuf[0][0];

    p_ctx->cmd[i].rcb.data_len = sizeof(p_ctx->wbuf[0]);
    p_ctx->cmd[i].rcb.cdb[0] = 0x8A;

    p_u32 = (__u32*)&p_ctx->cmd[i].rcb.cdb[10];
    write_32(p_u32, LBA_BLK);

    p_ctx->cmd[i].sa.host_use[0] = 0; // 0 means active
    p_ctx->cmd[i].sa.ioasc = 0;
	}
}
Beispiel #4
0
int bg_f_chunk_write_header(bg_f_io_t * io, bg_f_chunk_t * ch, bg_f_chunk_type_t type)
  {
  ch->type = type;
  ch->start = io->ftell_callback(io->data);
  if(!write_32(io, ch->type) ||
     !write_64(io, ch->size))
    return 0;
  return 1;
  }
Beispiel #5
0
int bg_f_chunk_write_footer(bg_f_io_t * io, bg_f_chunk_t * ch)
  {
  int64_t end_pos = io->ftell_callback(io->data);
  io->seek_callback(io->data, ch->start + 4, SEEK_SET);
  ch->size = end_pos - ch->start - 12;
  if(!write_64(io, ch->size))
    return 0;
  io->seek_callback(io->data, end_pos, SEEK_SET);
  return 1;
  }
Beispiel #6
0
int CDECL main(int argc, char **argv)
{
   if (argc ==1)
   {
	 cerr << "Usage: makeeco eco_file" << endl;
	 return -1;
   }
   Bitboard::init();
   initOptions(argv[0]);
   Attacks::init();
   Scoring::init();
   if (!initGlobals(argv[0], false)) {
       cleanupGlobals();
       exit(-1);
   }
   atexit(cleanupGlobals);
   
   ifstream eco_file( argv[argc-1], ios::in);
   if (!eco_file.good())
   {
         cerr << "Cannot open file: " << argv[argc-1] << endl;
	 return -1;
   }
   Board b;
   cout << "// This is a machine-generated file.  Do not edit." << endl;
   cout << endl;   
   cout << "#include \"ecodata.h\"" << endl << endl;
   cout << "const struct ECOData eco_codes[] =" << endl;
   cout << "{{" << '"' << "A00" << '"' << ", ";
   write_64(b.hashCode(),cout);
   cout << ", " << '"' << '"' << "}," << endl;
   int lines = 1;
   while (eco_file.good() && !eco_file.eof())
   {
       string eco_line;
       getline(eco_file,eco_line);
       if (do_eco(eco_line)) {
           cerr << "error in ECO file, line " << lines << endl;
       }
       ++lines;
   }
   cout << "{0,0," << '"' << '"' << "}};" << endl;
   return 0;
}
int place_bad_addresses(struct ctx *p_ctx, int action)
{
    int cnt = NUM_CMDS;
    int wait_try=MAX_TRY_WAIT;
    int p_cmd = 0;
    int i;
    __u64 room;
    __u64 baddr = 0x1234;

    /* make memory updates visible to AFU before MMIO */
    asm volatile( "lwsync" : : );
    if (2 == action)
    {
        // set up bad HRRQ address
        write_64(&p_ctx->p_host_map->rrq_start, (__u64)0x456123);
        write_64(&p_ctx->p_host_map->rrq_end, (__u64)0x895e6fe);
        bad_address= true;
    }

    if (3 == action)
    {
        //cmd_room violation
        room = read_64(&p_ctx->p_host_map->cmd_room);
        debug("%d:placing %d cmds in 0X%"PRIX64" cmd_room...\n",pid,NUM_CMDS,room);
        for (i=0;i<NUM_CMDS ;i++)
            write_64(&p_ctx->p_host_map->ioarrin,
                     (__u64)&p_ctx->cmd[i].rcb);
        bad_address= true;
        return 0;
    }
    while (cnt)
    {
        room = read_64(&p_ctx->p_host_map->cmd_room);
        if (0 == room)
        {
            usleep(MC_BLOCK_DELAY_ROOM);
            wait_try--;
        }
        if (0 == wait_try)
        {
            fprintf(stderr, "%d: send cmd wait over %d cmd remain\n",
                    pid, cnt);
            return -1;
        }
        for (i = 0; i < room; i++)
        {
            // add a usleep here if room=0 ?
            // write IOARRIN
            if (1 == action)
            {
                //bad RCB address
                write_64(&p_ctx->p_host_map->ioarrin, baddr*i);
                bad_address= true;
            }
            else
            {
                write_64(&p_ctx->p_host_map->ioarrin,
                         (__u64)&p_ctx->cmd[p_cmd++].rcb);
            }
            wait_try = MAX_TRY_WAIT; //each cmd give try max time
            if (cnt-- == 1) break;
        }
    }
    return 0;
}
Beispiel #8
0
int test_mc_invalid_opcode()
{
    int rc;
    struct ctx myctx;
    struct ctx *p_ctx = &myctx;
    __u64 chunks=10;
    __u64 actual_size=0;
    __u64 vlba =0;
    __u64 *p_u64;
    __u32 *p_u32;
	mc_stat_t l_mc_stat;
    pthread_t thread;

    if(mc_init() !=0 ) {
    fprintf(stderr, "mc_init failed.\n");
    return -1;
        }
    debug("mc_init success.\n");

    rc = ctx_init(p_ctx);
    if(rc != 0)
    {
        fprintf(stderr, "Context init failed, errno %d\n", errno);
        return -1;
    }
    pthread_create(&thread,NULL,ctx_rrq_rx, p_ctx);
	rc = mc_register(master_dev_path, p_ctx->ctx_hndl,
        (volatile __u64 *)p_ctx->p_host_map,&p_ctx->mc_hndl);
    if(rc != 0)
    {
        fprintf(stderr, "ctx _reg failed, ctx_hndl %d,rc %d\n",p_ctx->ctx_hndl, rc );
        return -1;
    }

    rc = mc_open(p_ctx->mc_hndl,MC_RDWR, &p_ctx->res_hndl);
    if (rc != 0) {
        fprintf(stderr, "error opening res_hndl rc %d\n", rc);
        return -1;
    }

    rc = mc_size(p_ctx->mc_hndl, p_ctx->res_hndl,chunks, &actual_size);
	CHECK_RC(rc, "mc_size");

	rc = mc_stat(p_ctx->mc_hndl, p_ctx->res_hndl, &l_mc_stat);
	CHECK_RC(rc, "mc_stat");
	
	pid = getpid();
	vlba = (actual_size * (1 << l_mc_stat.nmask))-1;
	fill_buf((__u64*)&p_ctx->wbuf[0][0],
		sizeof(p_ctx->wbuf[0])/sizeof(__u64),pid);

	memset(&p_ctx->cmd[0].rcb.cdb[0], 0, sizeof(p_ctx->cmd[0].rcb.cdb));
	p_u64 = (__u64*)&p_ctx->cmd[0].rcb.cdb[2];

	p_ctx->cmd[0].rcb.res_hndl = p_ctx->res_hndl;
	p_ctx->cmd[0].rcb.req_flags = SISL_REQ_FLAGS_RES_HNDL;
	p_ctx->cmd[0].rcb.req_flags |= SISL_REQ_FLAGS_HOST_WRITE;
	write_64(p_u64, vlba); // write(16) Virtual LBA

	p_ctx->cmd[0].rcb.data_ea = (__u64) &p_ctx->wbuf[0][0];

	p_ctx->cmd[0].rcb.data_len = sizeof(p_ctx->wbuf[0]);
	p_ctx->cmd[0].rcb.cdb[0] = 0xFA; // invalid opcode

	p_u32 = (__u32*)&p_ctx->cmd[0].rcb.cdb[10];
	write_32(p_u32, 8); // 8 LBAs for 4K

	p_ctx->cmd[0].sa.host_use[0] = 0; // 0 means active
	p_ctx->cmd[0].sa.ioasc = 0;
	send_single_cmd(p_ctx);
	rc = wait_single_resp(p_ctx);
	return rc;
}
Buffer::Pointer
Buffer::write(uint64_t in_value) throw(KafkaError) {
    write_64(&in_value);
    return shared_from_this();
}
Beispiel #10
0
extern int mp4_fragment_file(struct mp4_context_t const* mp4_context,
struct bucket_t** buckets)
{
	uint64_t filepos = 0;
	int result = 1;

	moov_t* moov = mp4_context->moov;
	moov_t* fmoov;
	struct woov_t* woov = NULL;
	mfra_t* mfra;

	if(!moov_build_index(mp4_context, mp4_context->moov))
	{
		return 0;
	}

	// Start with the ftyp
	{
		unsigned char ftyp[28];
		unsigned char* buffer = ftyp;
		buffer = write_32(buffer, 28);
		buffer = write_32(buffer, FOURCC('f', 't', 'y', 'p'));
		buffer = write_32(buffer, FOURCC('a', 'v', 'c', '1'));  // major_brand
		buffer = write_32(buffer, 0);                           // minor_version
		buffer = write_32(buffer, FOURCC('i', 's', 'o', 'm'));  // compatible_brands
		buffer = write_32(buffer, FOURCC('i', 's', 'o', '2'));
		buffer = write_32(buffer, FOURCC('f', 'r', 'a', 'g'));
		bucket_insert_tail(buckets, bucket_init_memory(ftyp, sizeof(ftyp)));
		filepos += sizeof(ftyp);
	}
	{
		uint32_t i;
		struct trak_weight_t{
			int w;
			void* v;
		}wtrack[MAX_TRACKS];

		for(i = 0; i < moov->tracks_; i++)
		{
			if(moov->traks_[i]->mdia_->hdlr_->handler_type_  == FOURCC('s', 'o', 'u', 'n'))
			{wtrack[i].w=1;wtrack[i].v=moov->traks_[i];}
			else if(moov->traks_[i]->mdia_->hdlr_->handler_type_  == FOURCC('v', 'i', 'd', 'e'))
			{wtrack[i].w=2;wtrack[i].v=moov->traks_[i];}
			else
			{wtrack[i].w=3;wtrack[i].v=moov->traks_[i];}
		}
		for (i = 1; i < moov->tracks_; ++i)
		{
			unsigned int j;
			for (j= moov->tracks_ - 1; j>=i;j--)
			{
				if(wtrack[j].w < wtrack[j-1].w)
				{
					struct trak_weight_t t = wtrack[j];
					wtrack[j] = wtrack[j-1];
					wtrack[j-1] = t;
				}
			}
		}
		for (i = 0; i < moov->tracks_; ++i)
		{
			moov->traks_[i] = wtrack[i].v;
			moov->traks_[i]->tkhd_->track_id_=i+1;
		}
		moov->mvhd_->next_track_id_=i+1;

	}

	// A fragmented MPEG4 file starts with a MOOV atom with only the mandatory
	// atoms
	fmoov = moov_init();
	{
		unsigned int i;
		mvex_t* mvex = mvex_init();

		fmoov->mvhd_ = mvhd_copy(moov->mvhd_);
		fmoov->mvhd_->duration_ = 0;
		fmoov->tracks_ = moov->tracks_;
		fmoov->mvex_ = mvex;

		for(i = 0; i != moov->tracks_; ++i)
		{
			unsigned int s;
			trak_t* trak = moov->traks_[i];
			trak_t* ftrak = trak_init();
			mdia_t* mdia = trak->mdia_;
			mdia_t* fmdia = mdia_init();
			minf_t* minf = mdia->minf_;
			minf_t* fminf = minf_init();
			stbl_t* stbl = minf->stbl_;
			stbl_t* fstbl = stbl_init();

			fmoov->traks_[i] = ftrak;
			ftrak->tkhd_ = tkhd_copy(trak->tkhd_);
			ftrak->tkhd_->duration_ = 0;
			ftrak->mdia_ = fmdia;
			ftrak->samples_size_ = trak->samples_size_;
			ftrak->samples_ = (samples_t*)
				malloc((trak->samples_size_ + 1) * sizeof(samples_t));
			memcpy(ftrak->samples_, trak->samples_,
				(trak->samples_size_ + 1) * sizeof(samples_t));
			ftrak->smoothes_size_ = trak->smoothes_size_;
			ftrak->smoothes_ = (struct smooth_t*)
				malloc((trak->samples_size_ + 1) * sizeof(struct smooth_t));
			memcpy(ftrak->smoothes_, trak->smoothes_,
				(trak->smoothes_size_ + 1) * sizeof(struct smooth_t));
			fmdia->mdhd_ = mdhd_copy(mdia->mdhd_);
			// convert trak's timescale and duration
			fmdia->mdhd_->version_ = 1;
			fmdia->mdhd_->timescale_ = 10000000;
			fmdia->mdhd_->duration_ = 0;
			//        trak_time_to_moov_time(fmdia->mdhd_->duration_,
			//          fmdia->mdhd_->timescale_, mdia->mdhd_->timescale_);

			fmdia->hdlr_ = hdlr_copy(mdia->hdlr_);
			fmdia->minf_ = fminf;
			fminf->smhd_ = minf->smhd_ == NULL ? NULL : smhd_copy(minf->smhd_);
			fminf->vmhd_ = minf->vmhd_ == NULL ? NULL : vmhd_copy(minf->vmhd_);
			fminf->dinf_ = dinf_copy(minf->dinf_);
			fminf->stbl_ = fstbl;
			fstbl->stts_ = stts_init();
			fstbl->ctts_ = ctts_init();
			fstbl->stsz_ = stsz_init();
			fstbl->stsc_ = stsc_init();
			fstbl->stco_ = stco_init();
			fstbl->stsd_ = stsd_copy(stbl->stsd_);

			for(s = 0; s != ftrak->samples_size_ + 1; ++s)
			{
				// SmoothStreaming uses a fixed 10000000 timescale
				ftrak->samples_[s].pts_ = trak_time_to_moov_time(
					ftrak->samples_[s].pts_, ftrak->mdia_->mdhd_->timescale_,
					trak->mdia_->mdhd_->timescale_);
				ftrak->samples_[s].cto_ = (unsigned int)(trak_time_to_moov_time(
					ftrak->samples_[s].cto_, ftrak->mdia_->mdhd_->timescale_,
					trak->mdia_->mdhd_->timescale_));
			}

			{
				// update trak duration
				samples_t const* first = (samples_t const*)&ftrak->samples_[0];
				samples_t const* last  = (samples_t const*)&ftrak->samples_[ftrak->samples_size_];
				ftrak->mdia_->mdhd_->duration_ = last->pts_ - first->pts_;
				ftrak->tkhd_->duration_ = trak_time_to_moov_time(ftrak->mdia_->mdhd_->duration_,
					fmoov->mvhd_->timescale_, ftrak->mdia_->mdhd_->timescale_);

				// update movie duration
				if(ftrak->tkhd_->duration_ > fmoov->mvhd_->duration_)
				{
					fmoov->mvhd_->duration_ = ftrak->tkhd_->duration_ ;
				}
			}

			{
				trex_t* trex = trex_init();
				trex->track_id_ = trak->tkhd_->track_id_;
				trex->default_sample_description_index_ = 1;
				mvex->trexs_[mvex->tracks_] = trex;
				++mvex->tracks_;
			}

		}

		{
			unsigned char* moov_data = mp4_context->moov_data;
			uint32_t moov_size = moov_write(fmoov, moov_data);
			bucket_insert_tail(buckets, bucket_init_memory(moov_data, moov_size));
			filepos += moov_size;
		}
	}

	woov = woov_init(mp4_context, fmoov);

	mfra = mfra_init();
	mfra->tracks_ = fmoov->tracks_;

	{
		unsigned int i;
		unsigned int tfra_entries = 0;
		for(i = 0; i != fmoov->tracks_; ++i)
		{
			trak_t const* trak = fmoov->traks_[i];

			struct tfra_t* tfra = tfra_init();
			mfra->tfras_[i] = tfra;
			tfra->version_ = 1;
			tfra->flags_ = 0;
			tfra->track_id_ = trak->tkhd_->track_id_;
			tfra->length_size_of_traf_num_ = 1;
			tfra->length_size_of_trun_num_ = 1;
			tfra->length_size_of_sample_num_ = 1;

			// count the number of smooth sync samples (nr of moofs)
			tfra->number_of_entry_ = 0;
			{
				unsigned int start;
				for(start = 0; start != trak->samples_size_; ++start)
				{
					{
						if(trak->samples_[start].is_smooth_ss_)
						{
							++tfra->number_of_entry_;
						}
					}
				}
			}
			tfra->table_ = (tfra_table_t*)
				malloc(tfra->number_of_entry_ * sizeof(tfra_table_t));

			tfra_entries += tfra->number_of_entry_;

			// next track
		}

		{

			unsigned int tfra_index = 0;
			trak_t const* base_trak = fmoov->traks_[0];
			while(tfra_index != base_trak->smoothes_size_)
			{

				// insert moof bucket
				{
					moof_t* moof = moof_init();

					bucket_t* bucket = bucket_init(BUCKET_TYPE_MEMORY);
					bucket_insert_tail(buckets, bucket);

					// create moof and write samples
					moof_create(mp4_context, fmoov, woov,  moof, mfra, filepos, tfra_index+1, buckets, 0 /* OUTPUT_FORMAT_MP4 */);

					//          if(options->output_format == OUTPUT_FORMAT_MP4)
					{
						unsigned int samples_count = 0;
						unsigned char* moof_data = NULL;
						unsigned int moof_size = 0;
						for(i = 0;i < moof->tracks_; ++i)
							samples_count += moof->trafs_[i]->trun_->sample_count_;
						moof_data =	(unsigned char*)malloc(8192 + (samples_count) * 12);
						moof_size = moof_write(moof, moof_data);

						// now that we know the size of the moof atom, we know where the mdat
						// will start. We patch the 'data_offset' field to skip the
						// moof atom and the mdat header.
						moof->trafs_[0]->trun_->data_offset_ = moof_size + ATOM_PREAMBLE_SIZE;
						moof_size = moof_write(moof, moof_data);

						bucket->buf_ = malloc(moof_size);
						bucket->size_ = moof_size;
						memcpy(bucket->buf_, moof_data, (size_t)bucket->size_);
						free(moof_data);
					}
					moof_exit(moof);

					// advance filepos for moof and mdat atom
					while(*buckets != bucket)
					{
						filepos += bucket->size_;
						bucket = bucket->next_;
					}
				}

				// next fragment
				++tfra_index;
			}
		}

		moov_exit(fmoov);

		{
			uint32_t woov_size = woov_write(mp4_context, woov, buckets);
			int offset = 0;

			offset += 28; // ftyp
			offset += woov_size; //woov
			offset += ATOM_PREAMBLE_SIZE; //mdat
			woov->mdat_size+=8;	// header;
			if(woov->mdat_size > UINT32_MAX)
			{
				offset+=8;
				woov->mdat_size+=8;
			}	

			for(i = 0; i != woov->moov->tracks_; ++i)
			{
				trak_t* trak = woov->moov->traks_[i];
				stco_shift_offsets_inplace(
					(unsigned char*)trak->mdia_->minf_->stbl_->stco_->stco_inplace_,
					(int)offset);
			}

			write_32(woov_data + 8, woov_size);
			write_64(woov_data + 12, woov->mdat_size);
			bucket_insert_tail(buckets,
				bucket_init_memory(woov_data, sizeof(woov_data)));

			woov_exit(woov);
		}
		// Write the Movie Fragment Random Access (MFRA) atom
		{
			unsigned char* mfra_data =
				(unsigned char*)malloc(8192 + tfra_entries * 28);
			uint32_t mfra_size = mfra_write(mfra, mfra_data);
			bucket_insert_tail(buckets, bucket_init_memory(mfra_data, mfra_size));
			mfra_exit(mfra);
			free(mfra_data);
		}
	}

	return result;
}
Beispiel #11
0
int do_eco(const string &eco_line)
{
    ColorType side = White;
    Board board;
    int movecount = 0;
    stringstream s(eco_line);
    const string &str = s.str();
    string::const_iterator it = str.begin();

    // Follow the opening line
    string token;
    string code;
    string name;
    int first_token = 1;
    while (it != str.end()) {
       // skip spaces
       while (isspace(*it) && it != str.end()) it++;
       if (it == str.end()) break;
       // extract text
       string text;
       int first = 1;
       int quoted = 0;
       while (it != str.end() && (quoted ? (*it != '"') : !isspace(*it))) {
           if (first && *it == '"') {
               quoted++;
               it++;
               first = 0;
               continue;
           }
           text += *it++;
       }
       if (first_token) {
           code = text;
           first_token = 0;
           continue;
       }
       else if (quoted) {
           name = text;
           break;
       } else if (text.length() == 0) {
           break;
       }
       // skip numbers
       if (isdigit(text[0])) continue;
       if (!isalpha(text[0])) return -1;
       // parse the move
       Move m = Notation::value(board,side,Notation::SAN_IN,text);
       if (IsNull(m) ||
       	   !legalMove(board,StartSquare(m),DestSquare(m)))
       {
           cerr << "Illegal or invalid move: " << text << endl;
	   return -1;
       }
       else
       {
           ++movecount;
	   board.doMove(m);
       }
       side = OppositeColor(side);
    }
    if (code.length()) {
        cout << '{' << '"' << code << '"' << ", ";
        write_64(board.hashCode(),cout);
        cout << " ,";
        if (name.length())
            cout << '"' << name << '"';
        else
            cout << '"' << '"';
        cout << "},";
        cout << endl;
    }
    return 0;
}