1 /******************************************************************************
2 *
3 * Copyright (C) 2006, The Gentee Group. All rights reserved.
4 * This file is part of the Gentee open source project - http://www.gentee.com.
5 *
6 * THIS FILE IS PROVIDED UNDER THE TERMS OF THE GENTEE LICENSE ("AGREEMENT").
7 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE CONSTITUTES RECIPIENTS
8 * ACCEPTANCE OF THE AGREEMENT.
9 *
10 * ID: gesave 18.10.06 0.0.A.
11 *
12 * Author: Alexey Krivonogov ( gentee )
13 *
14 * Summary:
15 *
16 ******************************************************************************/
17 #ifndef RUNTIME
18
19 #include "ge.h"
20 #include "../genteeapi/gentee.h"
21 #include "../vm/vmload.h"
22 #include "../vm/vmres.h"
23 #include "../common/crc.h"
24 #include "../bytecode/bytecode.h"
25
26 pbuf gesave;
27 uint gesaveoff;
28 puint gecodes;
29
30 void STDCALL gesave_addubyte( uint val )
31 {
32 buf_appendch( gesave, ( ubyte )val );
33 }
34
35 void STDCALL gesave_adduint( uint val )
36 {
37 buf_appenduint( gesave, val );
38 }
39
40 void STDCALL gesave_addushort( uint val )
41 {
42 buf_appendushort( gesave, ( ushort )val );
43 }
44
45 void STDCALL gesave_add2uint( uint val1, uint val2 )
46 {
47 gesave_adduint( val1 );
48 gesave_adduint( val2 );
49 }
50
51 void STDCALL gesave_addptr( pubyte data )
52 {
53 buf_append( gesave, data, mem_len( data ) + 1 );
54 }
55
56 void STDCALL gesave_adddata( pubyte data, uint size )
57 {
58 buf_append( gesave, data, size );
59 }
60
61 //--------------------------------------------------------------------------
62
63 uint STDCALL gesave_bwdi( uint val )
64 {
65 if ( val <= 187 )
66 gesave_addubyte( val );
67 else
68 if ( val < 16830 ) // 0xFF *( 253 - 188 ) + 0xFF
69 {
70 gesave_addubyte( 188 + val / 0xFF );
71 gesave_addubyte( val % 0xFF );
72 }
73 else
74 if ( val > MAX_USHORT )
75 {
76 gesave_addubyte( MAX_BYTE );
77 gesave_adduint( val );
78 }
79 else
80 {
81 gesave_addubyte( MAX_BYTE - 1 );
82 gesave_addushort( val );
83 }
84 return val;
85 }
86
87 //--------------------------------------------------------------------------
88
89 uint STDCALL gesave_bwdc( uint val )
90 {
91 if ( val >= KERNEL_COUNT && !gecodes[ val ] )
92 {
93 print("GESAVE ERROR %i\n", val );
94 os_getchar();
95 }
96 return gesave_bwdi( val >= KERNEL_COUNT ? gecodes[ val ] : val );
97 }
98
99 void STDCALL gesave_head( uint type, pubyte name, uint flag )
100 {
101 uint ok = 0;
102 pubyte cur;
103 gesaveoff = buf_len( gesave );
104
105 flag &= 0xFFFFFF;
106
107 if ( name && name[0] )
108 flag |= GHCOM_NAME;
109 else
110 flag &= ~GHCOM_NAME;
111
112 if ( flag & GHCOM_NAME && _compile->flag & CMPL_OPTIMIZE &&
113 _compile->popti->flag & OPTI_NAME )
114 {
115 cur = _compile->popti->nameson;
116 while ( *cur )
117 {
118 if ( ptr_wildcardignore( name, cur ))
119 {
120 ok = 1;
121 break;
122 }
123 cur += mem_len( cur ) + 1;
124 }
125 if ( !ok )
126 flag &= ~GHCOM_NAME;
127 }
128 flag |= GHCOM_PACK;
129
130 gesave_addubyte( type );
131 gesave_adduint( flag );
132 // The size will be inserted in gesave_finish
133 // Now add just one byte
134 gesave_addubyte( 0 );
135
136 if ( flag & GHCOM_NAME )
137 gesave_addptr( name );
138 }
139
140 void STDCALL gesave_finish( void )
141 {
142 buf bt;
143 pbuf pb = gesave;
144 uint size = buf_len( pb ) - gesaveoff;
145
146 if ( size <= 187 )
147 *( pubyte )(( pubyte )buf_ptr( gesave ) + gesaveoff + 5 ) = ( ubyte )size;
148 else
149 {
150 buf_init( &bt );
151 gesave = &bt;
152 if ( size < 16800 )
153 {
154 size++;
155 gesave_bwdi( size );
156 }
157 else
158 if ( size < 0xFFF0 )
159 {
160 gesave_addubyte( 0xFE );
161 size += 2;
162 gesave_addushort( size );
163 }
164 else
165 {
166 gesave_addubyte( 0xFF );
167 size += 4;
168 gesave_adduint( size );
169 }
170 // Write the size
171 // We have already had one byte, so -1
172 buf_insert( pb, gesaveoff + 5, ( pubyte )&size /*any*/, buf_len( gesave ) - 1 );
173 mem_copy( buf_ptr( pb ) + gesaveoff + 5, buf_ptr( gesave ), buf_len( gesave ));
174
175 buf_delete( &bt );
176 gesave = pb;
177 }
178 }
179
180 void STDCALL gesave_var( pvartype var )
181 {
182 uint i;
183 povmtype ptype;
184 pubyte ptr;
185
186 gesave_bwdc( var->type );
187
188 if ( _compile->flag & CMPL_OPTIMIZE &&
189 _compile->popti->flag & OPTI_NAME )
190 var->flag &= ~VAR_NAME;
191
192 gesave_addubyte( var->flag );
193
194 if ( var->flag & VAR_NAME )
195 gesave_addptr( var->name );
196
197 if ( var->flag & VAR_OFTYPE )
198 gesave_bwdc( var->oftype );
199
200 if ( var->flag & VAR_DIM )
201 {
202 gesave_addubyte( var->dim );
203 for ( i = 0; i < var->dim; i++ )
204 gesave_bwdi( var->ptr[i] );
205 }
206 if ( var->flag & VAR_DATA )
207 {
208 ptr = ( pubyte )( var->ptr + var->dim );
209 ptype = ( povmtype )PCMD( var->type );
210 if ( ptype->vmo.flag & GHTY_STACK )
211 i = ptype->size;
212 else
213 if ( var->type == TStr )
214 i = mem_len( ptr ) + 1;
215 else
216 {
217 i = *( puint )ptr;
218 ptr += sizeof( uint );
219 // gesave_adduint( i );
220 gesave_bwdi( i ); // save data size as bwd
221 }
222 gesave_adddata( ptr, i );
223 }
224 }
225
226 void STDCALL gesave_varlist( pvartype pvar, uint count )
227 {
228 uint i;
229
230 gesave_bwdi( count );
231 for ( i = 0; i < count; i++ )
232 gesave_var( pvar++ );
233 }
234
235 void STDCALL gesave_resource( void )
236 {
237 uint i, count;
238 pcollect pres;
239
240 pres = &_vm.resource;
241
242 gesave_head( OVM_RESOURCE, "", 0 );
243
244 count = collect_count( pres );
245 gesave_bwdi( count );
246 for ( i = 0; i < count; i++ )
247 {
248 gesave_bwdc( collect_gettype( pres, i ));
249 gesave_addptr( str_ptr( vmres_getstr( i )) );
250 // print("str=%s\n", str_ptr( vmres_getstr( i )) );
251 }
252 gesave_finish();
253 }
254
255 void STDCALL gesave_bytecode( povmbcode bcode )
256 {
257 pvartype pvar;
258 uint i, count = 0, cmd, val;
259 puint end, ptr;
260
261 gesave_var( bcode->vmf.ret );
262 gesave_varlist( bcode->vmf.params, bcode->vmf.parcount );
263
264 gesave_bwdi( bcode->setcount );
265 for ( i = 0; i < bcode->setcount; i++ )
266 {
267 gesave_bwdi( bcode->sets[i].count );
268 count += bcode->sets[i].count;
269 }
270 pvar = bcode->vars;
271 for ( i = 0; i < count; i++ )
272 gesave_var( pvar++ );
273
274 ptr = ( puint )bcode->vmf.func;
275 if ( ptr )
276 {
277 end = ( puint )( ( pubyte )ptr + bcode->bcsize );
278 while ( ptr < end )
279 {
280 cmd = gesave_bwdc( *ptr++ );
281 if ( cmd >= CNop && cmd < CNop + STACK_COUNT )
282 switch ( cmd )
283 {
284 case CQwload:
285 gesave_adduint( *ptr++ );
286 gesave_adduint( *ptr++ );
287 break;
288 case CDwload:
289 val = *ptr++;
290 if ( val <= 0xFF )
291 {
292 buf_ptr( gesave )[ buf_len( gesave ) - 1 ] = CByload;
293 gesave_addubyte( val );
294 }
295 else
296 if ( val <= 0xFFFF )
297 {
298 buf_ptr( gesave )[ buf_len( gesave ) - 1 ] = CShload;
299 gesave_addushort( val );
300 }
301 else
302 gesave_adduint( val );
303 break;
304 case CDwsload:
305 i = gesave_bwdi( *ptr++ );
306 gesave_adddata( ( pubyte )ptr, i << 2 );
307 ptr += i;
308 break;
309 case CResload:
310 case CCmdload:
311 case CPtrglobal:
312 gesave_bwdc( *ptr++ );
313 break;
314 case CDatasize:
315 i = gesave_bwdi( *ptr++ );
316 gesave_adddata( ( pubyte )ptr, i );
317 ptr += ( i >> 2 ) + ( i & 3 ? 1 : 0 );
318 break;
319 default:
320 switch ( shifts[ cmd - CNop ] )
321 {
322 case SH1_3:
323 case SH2_3:
324 cmd = gesave_bwdi( *ptr++ );
325 case SHN1_2:
326 case SH0_2:
327 case SH1_2:
328 cmd = gesave_bwdi( *ptr++ );
329 break;
330 }
331 }
332 }
333 }
334 }
335
336 void STDCALL gesave_exfunc( povmfunc exfunc )
337 {
338 gesave_var( exfunc->vmf.ret );
339 gesave_varlist( exfunc->vmf.params, exfunc->vmf.parcount );
340
341 if ( exfunc->vmf.vmo.flag & GHEX_IMPORT )
342 {
343 gesave_bwdc( exfunc->import );
344 gesave_addptr( exfunc->original );
345 }
346 }
347
348 void STDCALL gesave_import( povmimport import )
349 {
350 gesave_addptr( import->filename );
351 if ( import->vmo.flag & GHIMP_LINK )
352 {
353 gesave_adduint( import->size );
354 gesave_adddata( import->data, import->size );
355 }
356 }
357
358 void STDCALL gesave_type( povmtype ptype )
359 {
360 uint i, k;
361 uint flag = ptype->vmo.flag;
362
363 if ( flag & GHTY_INHERIT )
364 gesave_bwdc( ptype->inherit );
365
366 if ( flag & GHTY_INDEX )
367 {
368 gesave_bwdc( ptype->index.type );
369 gesave_bwdc( ptype->index.oftype );
370 }
371 if ( flag & GHTY_INITDEL )
372 {
373 gesave_bwdc( ptype->ftype[ FTYPE_INIT ] );
374 gesave_bwdc( ptype->ftype[ FTYPE_DELETE ] );
375 }
376 if ( flag & GHTY_EXTFUNC )
377 {
378 gesave_bwdc( ptype->ftype[ FTYPE_OFTYPE ] );
379 gesave_bwdc( ptype->ftype[ FTYPE_COLLECTION ] );
380 }
381 if ( flag & GHTY_ARRAY )
382 {
383 i = 0;
384 while ( ptype->ftype[ FTYPE_ARRAY + i ] )
385 i++;
386 gesave_bwdc( i == 1 ? ptype->ftype[ FTYPE_ARRAY ] : i );
387 if ( i > 1 )
388 for ( k = 0; k < i; k++ )
389 gesave_bwdc( ptype->ftype[ FTYPE_ARRAY + k ] );
390 }
391 gesave_varlist( ptype->children, ptype->count );
392 }
393
394 void STDCALL gesave_define( povmdefine pdefine )
395 {
396 gesave_varlist( pdefine->macros, pdefine->count );
397 }
398
399 uint STDCALL ge_save( pbuf out )
400 {
401 gehead head;
402 pgehead phead;
403 uint i, count, off = 0;
404 pvmobj pvmo;
405
406 gesave = out;
407 buf_reserve( out, 0x1ffff );
408
409 if ( _compile->flag & CMPL_OPTIMIZE )
410 ge_optimize();
411
412 *( puint )&head.idname = GE_STRING;//0x00004547; // строка GE
413 head.flags = 0;
414 head.crc = 0;
415 head.headsize = sizeof( gehead );
416 head.size = 0;
417 head.vermajor = GEVER_MAJOR;
418 head.verminor = GEVER_MINOR;
419
420 buf_append( out, ( pubyte )&head, sizeof( gehead ));
421 // Save resources at the first !
422 gesave_resource();
423
424 count = arr_count( &_vm.objtbl );
425 // Settings new id depending on GHRT_SKIP
426 gecodes = ( puint )mem_alloc( count * sizeof( uint ));
427 for ( i = KERNEL_COUNT; i < count ; i++ )
428 {
429 pvmo = ( pvmobj )PCMD( i );
430 if ( pvmo->flag & GHRT_SKIP )
431 {
432 gecodes[ i ] = 0;
433 off++;
434 }
435 else
436 gecodes[ i ] = i - off;
437 }
438 for ( i = KERNEL_COUNT; i < count ; i++ )
439 {
440 pvmo = ( pvmobj )PCMD( i );
441 if ( pvmo->flag & GHRT_SKIP )
442 continue;
443 // print("i=%i name=%s\n", i, ((pvmobj)PCMD( i ))->name );
444 gesave_head( pvmo->type, pvmo->flag & GHCOM_NAME ?
445 pvmo->name : NULL, pvmo->flag );
446
447 switch ( pvmo->type )
448 {
449 case OVM_NONE:
450 break;
451 case OVM_BYTECODE:
452 gesave_bytecode( ( povmbcode )pvmo );
453 break;
454 case OVM_EXFUNC:
455 gesave_exfunc( ( povmfunc )pvmo );
456 break;
457 case OVM_TYPE:
458 gesave_type( ( povmtype )pvmo );
459 break;
460 case OVM_GLOBAL:
461 gesave_var( (( povmglobal )pvmo)->type );
462 break;
463 case OVM_DEFINE:
464 gesave_define( ( povmdefine )pvmo );
465 break;
466 case OVM_IMPORT:
467 gesave_import( ( povmimport )pvmo );
468 break;
469 case OVM_ALIAS:
470 gesave_bwdc( (( povmalias )pvmo)->idlink );
471 break;
472 }
473 gesave_finish();
474 }
475 mem_free( gecodes );
476 // Specify the full size and crc
477 phead = ( pgehead )buf_ptr( out );
478 phead->size = buf_len( out );
479 phead->crc = crc( ( pubyte )phead + 12, phead->size - 12, 0xFFFFFFFF );
480
481 return 1;
482 }
483
484 #endif