001 #include "Studio.HC";
002 U64 SerReadU64(U8 **_ptr) {
003   U64 r=(*_ptr)[0](U64);
004   *_ptr+=8;
005   return r;
006 }
007 U64 SerReadU8(U8 **_ptr) {
008   U64 r=(*_ptr)[0];
009   *_ptr+=1;
010   return r;
011 }
012 U8 *SerReadStr(U8 *to,U8 **_ptr) {
013   U8 *ptr=*_ptr;
014   I64 l=StrLen(ptr);
015   MemCpy(to,ptr,l+1);
016   *_ptr=ptr+l+1;
017   return ptr;
018 }
019 U0 SerWriteU64(CU8Set *s,U64 f) {
020   U8SetAddBytes(s,&f,8); 
021 }
022 U0 SerWriteF64(CU8Set *s,F64 f) {
023   U8SetAddBytes(s,&f,8); 
024 }
025 U0 SerWriteU8(CU8Set *s,U8 f) {
026   U8SetAddBytes(s,&f,1); 
027 }
028 U0 SerWriteStr(CU8Set *s,U8 *str) {
029   U8SetAddBytes(s,str,StrLen(str)+1);
030 }
031 CFrogThing *LoadThing0(U8 **_str,U8 *_member=NULL) {
032   CFrogThing *ret=FROG_SMALL_NIL,*tmp;
033   CI64Set *init_list=FramePtr("STInitList");
034   U8 member[STR_LEN],cls[STR_LEN],dummy[STR_LEN];
035   U8 *member_ptr=member,*cls_ptr=cls;
036   F64 num;
037   I64 inum,ch,ptr;
038 again:
039   ch=SerReadU8(_str);
040   if(ch=='^') {
041     ptr=SerReadU64(_str);
042     SerReadStr(member,_str);
043     if(_member) StrCpy(_member,member);
044     StrPrint(member,"PTR.%d",ptr);
045     if(!FramePtr(member))  {
046 //Nroot here,Pointers are first defined then used as pointers in SaveDefacto.
047 //You(should) never reach here
048       if(!(ptr&0x7))
049         PrintI("internalWTF(undef pointer)",ptr);
050       else
051         ret=ptr;
052     } else if(ptr)
053       ret=FramePtr(member);
054     if(**_str=='.') _str[0]++;
055     goto en;
056   }
057   if(ch=='-') {
058     ptr=SerReadU64(_str);
059     SerReadStr(member,_str);
060     SerReadStr(cls,_str);
061     if(_member) StrCpy(_member,member);
062     if(!StrCmp(cls,"CFrogDictionary")) {
063       ret=ConstructThing("CFrogDictionary");
064       while(**_str!='.') {
065         tmp=LoadThing0(_str,member);
066         CallScript("at:put:",ret,FrogStrNew(member),tmp);
067       }    
068       StrPrint(dummy,"PTR.%d",ptr);
069       FramePtrAdd(dummy,ret);
070     } else if(!StrCmp(cls,"CFrogSymbol")&&member[0]=='#') {
071       FrogSymbol(member+1)->value=LoadThing0(_str,dummy);
072     } else if(!StrCmp(cls,"CFrogNum")) {
073       inum=SerReadU64(_str);
074       ret=FrogNumNew(inum(F64));
075     } else if(!StrCmp(cls,"CFrogChr")) { 
076       inum=SerReadU8(_str);
077       ret=FrogChrNew(inum);
078     } else if(!StrCmp(cls,"CFrogClass")) {
079       SerReadStr(cls_ptr,_str);
080       ret=FrogClassNew(NameToUniverseNumber(cls));
081     } else if(!StrCmp(cls,"CFrogArray")) {
082       inum=SerReadU64(_str);
083       ret=FrogArrayNew;
084       StrPrint(dummy,"PTR.%d",ptr);
085       FramePtrAdd(dummy,ret);
086       while(--inum>=0) {
087         I64SetAdd(ret(CFrogArray*)->items,LoadThing0(_str));
088       }
089     } else if(!StrCmp(cls,"CFrogStr")) {
090       ret=FrogStrNew("");
091       StrPrint(dummy,"PTR.%d",ptr);
092       FramePtrAdd(dummy,ret);
093       inum=SerReadU64(_str);
094       U8SetAddBytes(ret(CFrogStr*)->items,*_str,inum);
095       *_str+=inum;
096     } else {
097       ret=ConstructThing(cls);
098       StrPrint(dummy,"PTR.%d",ptr);
099       FramePtrAdd(dummy,ret);
100       if(ret) CallScript("beforeRestore",ret);
101       while(**_str&&**_str!='.') {
102         tmp=LoadThing0(_str,member);
103         if(ret&&tmp) SetClassMemberVal(ret,member,tmp);
104       }
105     }
106     if(**_str=='.') _str[0]++;
107   } else if(**_str) {
108   }
109   I64SetAdd(init_list,ret);
110 en:
111   return ret;
112 }
113 CFrogThing *RestoreThing0(U8 *s) {
114   CI64Set *init_list=I64SetNew;
115   CHashTable *table=HashTableNew(0x100);
116   table->next=Fs->hash_table;
117   Fs->hash_table=table;
118   FramePtrAdd("STInitList",init_list);
119   I64 cnt;
120   U8 *s2=s;
121   gc_lock_cnt++;
122   CFrogThing *r=LoadThing0(&s2); 
123   gc_lock_cnt--;
124   cnt=init_list->cnt; 
125   while(--cnt>=0) {
126     CallScript("afterRestore",init_list->body[cnt]);
127   }
128   Fs->hash_table=table->next;
129   HashTableDel(table);
130   I64SetDel(init_list);
131   FramePtrDel(init_list);
132   return r;
133 }
134 U0 SaveDefacto0(CU8Set *doc,U8 *str,CFrogThing *have,I64 depth=1,CI64Set *save_list) {
135   if(I64SetHas(save_list,have)) {
136 //Pointer
137     SerWriteU8(doc,'^');
138     SerWriteU64(doc,have);
139     SerWriteStr(doc,str);
140     SerWriteU8(doc,'.');
141     return;
142   }
143   SerWriteU8(doc,'-');
144   if(!(have&1)) //Dont save primtive types
145     I64SetAdd(save_list,have);
146   if(depth<=0) return;
147   gc_lock_cnt++;
148   I64 cnt,val,idx,force_ser;
149   F64 fval;
150   U8 *ptr,buf[STR_LEN];
151   CHashClass *cls;
152   CMemberLst *mlst;
153   CHashTable *dtab;
154   CHashGeneric *dtab_e;
155   CFrogThing *as,**array_body,dummy;
156   CallScript("beforeSave",have);
157   if(ThingHasClass(have,"CFrogSymbol")) {
158     SerWriteU64(doc,have);
159     SerWriteU8(doc,'#');
160     SerWriteStr(doc,have(CFrogSymbol*)->name);
161     SerWriteStr(doc,"CFrogSymbol");
162     SaveDefacto0(doc,"value",have(CFrogSymbol*)->value,depth+1,save_list);
163     SerWriteU8(doc,'.');
164   } else if(ThingHasClass(have,"CFrogNum")) {
165     SerWriteU64(doc,0);
166     SerWriteStr(doc,str);
167     SerWriteStr(doc,"CFrogNum");
168     SerWriteF64(doc,AsF64(have));
169     SerWriteU8(doc,'.');
170   } else if(ThingHasClass(have,"CFrogUndefined")) {
171 nil:
172     SerWriteU64(doc,0);
173     SerWriteStr(doc,str);
174     SerWriteStr(doc,"CFrogUndefined");
175     SerWriteU8(doc,'.');
176   } else if(ThingHasClass(have,"CFrogChr")) {
177     SerWriteU64(doc,0);
178     SerWriteStr(doc,str);
179     SerWriteStr(doc,"CFrogChr");
180     SerWriteU8(doc,AsChar(have));
181     SerWriteU8(doc,'.');
182   } else if(ThingHasClass(have,"CFrogDictionary")) {
183     dtab=have(CFrogDictionary*)->t;
184     cnt=dtab->mask+1;
185     SerWriteU64(doc,have);
186     SerWriteStr(doc,str);
187     SerWriteStr(doc,"CFrogDictionary");
188     for(idx=0;idx!=cnt;idx++) {
189       for(dtab_e=dtab->body[idx];dtab_e;dtab_e=dtab_e->next) {
190         SaveDefacto0(doc,dtab_e->str,dtab_e->user_data1,depth+1,save_list);
191       }
192     }
193     SerWriteU8(doc,'.');
194   } else if(ThingHasClass(have,"CFrogClass")) {
195     SerWriteU64(doc,have);
196     SerWriteStr(doc,str);
197     SerWriteStr(doc,"CFrogClass");
198     SerWriteStr(doc,UniverseNumberToName(have>>16));
199     SerWriteU8(doc,'.');
200   } else if(ThingHasClass(have,"CFrogBlock")) {
201     goto nil;
202   } else if(ThingHasClass(have,"CFrogStr")) {
203     SerWriteU64(doc,have);
204     SerWriteStr(doc,str);
205     SerWriteStr(doc,"CFrogStr");
206     SerWriteU64(doc,have(CFrogStr*)->items->cnt);
207     U8SetAddBytes(doc,have(CFrogStr*)->items->body,have(CFrogStr*)->items->cnt);
208     SerWriteU8(doc,'.');
209   } else if(ThingHasClass(have,"CFrogArray")) {
210     SerWriteU64(doc,have);
211     SerWriteStr(doc,str);
212     SerWriteStr(doc,"CFrogArray");
213     SerWriteU64(doc,have(CFrogArray*)->items->cnt);
214     cnt=have(CFrogArray*)->items->cnt;
215     array_body=have(CFrogArray*)->items->body;
216     for(idx=0;idx!=cnt;idx++) {
217       StrPrint(buf,"%X",idx);
218       SaveDefacto0(doc,buf,array_body[idx],depth+1,save_list);
219     }
220     SerWriteU8(doc,'.');
221   } else {
222     SerWriteU64(doc,have);
223     SerWriteStr(doc,str);
224     SerWriteStr(doc,FrogThingClassName(have));
225     cls=HashFind(FrogThingClassName(have),frog_mem_task->hash_table,HTT_CLASS);
226     MemSet(&dummy,0,sizeof CFrogThing);
227     while(cls)  {
228       if(!StrCmp("CFrogThing",cls->str))
229         break;
230       mlst=cls->member_lst_and_root;
231       while(mlst) {
232         if(mlst->member_class->ptr_stars_cnt==1) {
233           dummy.universe_class_idx=UniverseAddClass(mlst->member_class[-1].str);
234           if(!MemberMetaFind("no_serialize",mlst)) {
235             force_ser=ToBool(MemberMetaFind("recur_serialize",mlst));
236             if(ThingHasClass(&dummy,"CFrogThing")) {
237               val=GetClassMemberValI64(have,mlst->str);
238               SaveDefacto0(doc,mlst->str,val,depth+force_ser,save_list);
239             }
240          }
241         } else if(!mlst->member_class->ptr_stars_cnt) {
242           SaveDefacto0(doc,mlst->str,FrogNumNew(GetClassMemberValF64(have,mlst->str)),depth+force_ser,save_list);
243         }
244         mlst=mlst->next;
245       }
246       cls=cls->base_class;
247     }
248     SerWriteU8(doc,'.');
249   }
250   gc_lock_cnt--;
251 }
252 CFrogStr *SaveThing(CFrogStr *t,I64 *argv,I64 argc) {
253   CU8Set *set =U8SetNew(frog_mem_task);
254   CI64Set *save_list=I64SetNew;
255   SaveDefacto0(set,"",t,,save_list);
256   I64SetDel(save_list);
257   t=FrogStrNew("");
258   U8SetDel(t->items);
259   t->items=set;
260   return t;
261 }
262 CFrogStr *SaveThingToSaveFile(CFrogThing *t,I64 *argv,I64 argc) {
263   U8 *name=AsString(argv[0]);
264   if(!name) return FROG_SMALL_NIL;
265   U8 *in_dir=MStrPrint("/FrogSaves/%s.DD",name);
266   if(!FileFind("/FrogSaves")) DirMk("/FrogSaves");
267   CU8Set *doc=U8SetNew;
268   CI64Set *save_list=I64SetNew;
269   SaveDefacto0(doc,"",t,,save_list);
270   I64SetDel(save_list);
271   FileWrite(in_dir,doc->body,doc->cnt);
272   Free(in_dir);
273   U8SetDel(doc);
274   Free(name);
275   return FROG_SMALL_NIL;
276 }
277 CFrogThing *RestoreThingFromSaveFile(CFrogStr *t,I64 *argv,I64 argc) {
278   U8 *name=AsString(t);
279   if(!name) return FROG_SMALL_NIL;
280   CFrogThing *ret=FROG_SMALL_NIL;
281   U8 *in_dir=MStrPrint("/FrogSaves/%s.DD",name),*data,*d2;
282   data=FileRead(in_dir);
283   Free(name);
284   Free(in_dir);
285   if(data) {
286     ret=RestoreThing0(data);
287     Free(data);
288   }
289   return ret;
290 }
291 CFrogThing *RestoreThing(CFrogStr *t,I64 *argv,I64 argc) {
292   return RestoreThing0(t->items->body);
293 }
294 
295 AddMethod("CFrogThing","saveThingToSaveFile:",&SaveThingToSaveFile);
296 AddMethod("CFrogStr","restoreThingFromSaveFile",&RestoreThingFromSaveFile);
297 AddMethod("CFrogThing","saveThing",&SaveThing);
298 AddMethod("CFrogThing","basicSaveThing",&SaveThing);
299 AddMethod("CFrogStr","restoreThing",&RestoreThing);