5 A Linux/Unix toolset and driver for Nokia mobile phones.
7 Copyright (C) 1999, 2000 Hugh Blemings & Pavel JanÃk ml.
9 Released under the terms of the GNU GPL, see file COPYING for more details.
11 Functions to read and write common file types.
13 Last modified: Mon Mar 20 22:02:15 CET 2000
14 Modified by Chris Kemp
27 #include "gsm-common.h"
28 #include "gsm-ringtones.h"
29 #include "gsm-bitmaps.h"
30 #include "files/gsm-filetypes.h"
31 #include "files/midifile.h"
32 #include "gsm-coding.h"
34 #include "newmodules/n7110.h"
35 #include "newmodules/n6110.h"
44 * Fills vCalendar time string into GSM_DateTime structure
47 * dt: datetime structure
48 * time: string in format yyyymmddThhmmss
52 int GetvCalTime(GSM_DateTime *dt, char *time)
54 char year[5]="", month[3]="", day[3]="", hour[3]="", minute[3]="", second[3]="";
55 dt->Year=dt->Month=dt->Day=dt->Hour=dt->Minute=dt->Second=dt->Timezone=0;
57 strncpy(year, time, 4);
58 strncpy(month, time+4, 2);
59 strncpy(day, time+6, 2);
60 strncpy(hour, time+9, 2);
61 strncpy(minute, time+11, 2);
62 strncpy(second, time+13, 2);
64 /* FIXME: Should check ranges... */
66 dt->Month=atoi(month);
69 dt->Minute=atoi(minute);
70 dt->Second=atoi(second);
80 * Fills calendar data from strings into calendar note
83 * note: calendar note structure
84 * type: type of calendar note
85 * text: text or phonenumber
86 * time: string in format yyyymmddThhmmss
91 int FillCalendarNote(GSM_CalendarNote *note, char *type,
92 char *text, char *time, char *alarm)
94 GetvCalTime(¬e->Time, time);
95 GetvCalTime(¬e->Alarm, alarm);
99 strncpy(note->Text, text, MAX_CALENDAR_TEXT_LENGTH);
100 strcpy(note->Phone, ""); /* correct in most cases */
102 /* FIXME: Handle additional strings, maybe from configuration file */
104 if(!strcmp(type, "PHONE CALL"))
106 strncpy(note->Phone, text, MAX_CALENDAR_PHONE_LENGTH);
109 else if(!strcmp(type, "MEETING"))
110 note->Type=GCN_MEETING;
111 else if(!strcmp(type, "SPECIAL OCCASION"))
112 note->Type=GCN_BIRTHDAY;
114 note->Type=GCN_REMINDER;
120 * GSM_ReadVCalendarFile
122 * Reads vCalendar file
125 * FileName: name of vCalendar file
126 * cnote: pointer to calendar note
127 * number: number in file of calendar note to read
131 GSM_Error GSM_ReadVCalendarFile(char *FileName, GSM_CalendarNote *cnote, int *number)
134 char type[21]="", text[40]="", time[16]="", alarm[16]="";
144 char *Line, OLine[1024], BackLine[1024];
148 file=fopen(FileName, "r");
151 fprintf(stderr, _("File cannot be opened!\n"));
153 return GE_CANTOPENFILE;
156 /* Go through data from file. */
157 while (GetLine(file, Line, sizeof(OLine))!=-1) {
159 strcpy(BackLine, Line);
163 if (!strcmp(Line,"BEGIN:VCALENDAR"))
167 if (!strcmp(Line,"BEGIN:VEVENT")) {
171 if (!strcmp(Line,"END:VCALENDAR"))
175 if (veventcounter==*number) {
176 if (!strncmp(Line,"CATEGORIES:",11)) {
177 strncpy(type,Line+11,strlen(Line)-11);
178 type[strlen(Line)-11]=0;
180 if (!strncmp(Line,"DESCRIPTION:",12)) {
181 strncpy(phone,Line+12,strlen(Line)-12);
182 phone[strlen(Line)-12]=0;
184 if (!strncmp(Line,"SUMMARY:",8)) {
185 strncpy(text,Line+8,strlen(Line)-8);
186 text[strlen(Line)-8]=0;
188 if (!strncmp(Line,"SUMMARY;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:",48)) {
189 DecodeUTF8(text,Line+48,strlen(Line)-48);
190 text[strlen(Line)-48]=0;
192 if (!strncmp(Line,"DTSTART:",8)) {
193 strncpy(time,Line+8,strlen(Line)-8);
194 time[strlen(Line)-8]=0;
196 if (!strncmp(Line,"DALARM:",7)) {
197 strncpy(alarm,Line+7,strlen(Line)-7);
198 alarm[strlen(Line)-7]=0;
202 if (!strncmp(Line,"RECURR:",7)) {
203 recurr=mem_to_int(Line+7,strlen(Line)-7);
206 if (!strncmp(Line,"RRULE:D1 :",9)) {
209 if (!strncmp(Line,"RRULE:W1 :",9)) {
212 if (!strncmp(Line,"RRULE:W2 :",9)) {
215 if (!strncmp(Line,"RRULE:YD1 :",10)) {
219 if (!strncmp(Line,"ALTYPE:",7)) {
220 altype=(!strncmp("TONE",Line+7,4)) ? 0x00 : 0x01;
223 if (!strcmp(Line,"END:VEVENT")) {
224 if (veventcounter==*number) NoteOK=true;
234 *number=veventcounter;
236 fprintf(stdout,_("Note not found in VCalendarfile\n"));
241 FillCalendarNote(cnote, type, text, time, alarm);
243 cnote->Recurrance = recurr*24; /* it was in days. I convert in hours */
244 cnote->AlarmType = altype;
246 if( strcmp( phone, "" ) ) { /* Invert data if CALL ... */
247 strcpy( cnote->Text, phone );
248 strcpy( cnote->Phone, text ); // alread FillCalendar does it ..
256 GSM_Error GSM_ReadBinRingtoneFile(char *FileName, GSM_BinRingtone *ringtone)
260 file = fopen(FileName, "rb");
263 return(GE_CANTOPENFILE);
265 // fseek(file,3474485,0);
267 ringtone->length=fread(ringtone->frame, 1, 500, file);
271 if (ringtone->frame[0]!=0x00 || ringtone->frame[1]!=0x00 ||
272 ringtone->frame[2]!=0x0C || ringtone->frame[3]!=0x01)
273 return GE_NOTSUPPORTED;
278 /* Function to convert scale field in to correct number. */
279 int GetRTTLDuration (char *num)
286 case 1: duration=128; break;
287 case 2: duration= 64; break;
288 case 4: duration= 32; break;
289 case 8: duration= 16; break;
290 case 16: duration= 8; break;
291 case 32: duration= 4; break;
298 int GetRTTLScale (char *num)
301 /* This may well need improving. */
305 if ((atoi(num))<4) scale=(atoi(num));
306 if ((atoi(num))>4) scale=(atoi(num))-4;
311 GSM_Error GSM_ReadRingtoneFile(char *FileName, GSM_Ringtone *ringtone)
314 unsigned char buffer[300];
316 GSM_Filetypes filetype=RTTL;
318 file = fopen(FileName, "rb");
321 return(GE_CANTOPENFILE);
323 fread(buffer, 1, 4, file); /* Read the header of the file. */
325 /* Attempt to identify filetype */
327 if (memcmp(buffer, "MThd",3)==0) /* MIDI files have 'MThd' at the start */
330 if (buffer[0]==0xc7 && buffer[1]==0x45 && buffer[2]==0xc1 && buffer[3]==0x53)
331 filetype=COMMUNICATOR;
333 if (strstr(FileName,".ott")) filetype=OTT; /* OTT files saved by NCDS3 */
341 error=loadrttl(file,ringtone);
345 error=loadott(file,ringtone);
349 error=loadcommunicator(file,ringtone);
354 error=loadmid(FileName,ringtone);
357 error=GE_INVALIDFILEFORMAT;
364 GSM_Error loadott(FILE *file, GSM_Ringtone *ringtone)
369 i=fread(Buffer, 1, 2000, file);
371 if (!feof(file)) return GE_TOOLONG;
373 return GSM_UnPackRingtone(ringtone, Buffer, i);
376 GSM_Error loadcommunicator(FILE *file, GSM_Ringtone *ringtone)
381 i=fread(Buffer, 1, 4000, file);
383 if (!feof(file)) return GE_TOOLONG;
387 if (Buffer[j]==0x00 && Buffer[j+1]==0x02 &&
388 Buffer[j+2]==0x4a && Buffer[j+3]==0x3a) break;
389 if (j==i-4) return GE_INTERNALERROR;
394 return GSM_UnPackRingtone(ringtone, Buffer+j, i-j);
397 /* TODO: spaces should not be interpreted */
398 /* Note: ringtone have to be in one line (without 0x13 and 0x10 chars) */
399 GSM_Error loadrttl(FILE *file, GSM_Ringtone *ringtone)
403 u8 DefNoteScale=2, DefNoteDuration=4;
405 u8 DefNoteStyle=ContinuousStyle;
407 unsigned char buffer[2000];
408 unsigned char *def, *notes, *ptr;
410 ringtone->Loop=15; //default value
412 fread(buffer, 2000, 1, file);
414 /* This is for buggy RTTTL ringtones without name. */
415 if (buffer[0] != RTTTL_SEP[0]) {
416 strtok(buffer, RTTTL_SEP);
417 sprintf(ringtone->name, "%s", buffer);
418 def=strtok(NULL, RTTTL_SEP);
419 notes=strtok(NULL, RTTTL_SEP);
422 sprintf(ringtone->name, "GNOKII");
423 def=strtok(buffer, RTTTL_SEP);
424 notes=strtok(NULL, RTTTL_SEP);
427 ptr=strtok(def, ", ");
429 /* Parsing the <defaults> section. */
435 DefNoteDuration=GetRTTLDuration(ptr+2);
439 DefNoteScale=GetRTTLScale(ptr+2);
443 DefNoteTempo=atoi(ptr+2);
447 ringtone->Loop=atoi(ptr+2);
454 DefNoteStyle=ContinuousStyle;
458 DefNoteStyle=NaturalStyle;
462 DefNoteStyle=StaccatoStyle;
468 DefNoteStyle=ContinuousStyle;
472 DefNoteStyle=NaturalStyle;
476 DefNoteStyle=StaccatoStyle;
482 ptr=strtok(NULL,", ");
486 printf("DefNoteDuration=%d\n", DefNoteDuration);
487 printf("DefNoteScale=%d\n", DefNoteScale);
490 ptr=strtok(notes, ", ");
492 /* Parsing the <note-command>+ section. */
493 while (ptr && NrNote<MAX_RINGTONE_NOTES) {
498 DefNoteScale=GetRTTLScale(ptr+2);
505 DefNoteStyle=ContinuousStyle;
509 DefNoteStyle=NaturalStyle;
513 DefNoteStyle=StaccatoStyle;
519 DefNoteStyle=ContinuousStyle;
523 DefNoteStyle=NaturalStyle;
527 DefNoteStyle=StaccatoStyle;
533 ringtone->notes[NrNote].duration=GetRTTLDuration(ptr);
534 if (ringtone->notes[NrNote].duration==0)
535 ringtone->notes[NrNote].duration=DefNoteDuration;
537 /* Skip all numbers in duration specification. */
542 /* B or b is not in specs, but I decided to put it, because
543 it's in some RTTL files. It's the same to H note */
544 if ((*ptr=='B') || (*ptr=='b')) ringtone->notes[NrNote].note=12;
545 else if ((*ptr=='H') || (*ptr=='h')) ringtone->notes[NrNote].note=12;
546 else if ((*ptr>='a') && (*ptr<='g')) ringtone->notes[NrNote].note=((*ptr-'a')*2)+10;
547 else if ((*ptr>='A') && (*ptr<='G')) ringtone->notes[NrNote].note=((*ptr-'A')*2)+10;
548 else ringtone->notes[NrNote].note=255;
550 if ((ringtone->notes[NrNote].note>13)&&(ringtone->notes[NrNote].note!=255))
551 ringtone->notes[NrNote].note-=14;
556 ringtone->notes[NrNote].note++;
557 if ((ringtone->notes[NrNote].note==5) || (ringtone->notes[NrNote].note==13))
558 ringtone->notes[NrNote].note++;
562 /* Check for dodgy rttl */
563 /* [<special-duration>] */
565 ringtone->notes[NrNote].duration*=1.5;
570 if (ringtone->notes[NrNote].note!=255) {
572 ringtone->notes[NrNote].note+=GetRTTLScale(ptr)*14;
575 ringtone->notes[NrNote].note+=DefNoteScale*14;
578 /* [<special-duration>] */
580 ringtone->notes[NrNote].duration*=1.5;
585 ringtone->notes[NrNote].style=DefNoteStyle;
588 ringtone->notes[NrNote].tempo=DefNoteTempo;
594 ptr=strtok(NULL, ", ");
597 ringtone->NrNotes=NrNote;
602 GSM_Error GSM_SaveRingtoneFile(char *FileName, GSM_Ringtone *ringtone)
608 file = fopen(FileName, "wb");
611 return(GE_CANTOPENFILE);
613 if (strstr(FileName,".ott"))
615 saveott(file, ringtone);
618 if (strstr(FileName,".mid"))
620 savemid(file, ringtone);
624 if (!done) saverttl(file, ringtone);
631 void saveott(FILE *file, GSM_Ringtone *ringtone)
637 GSM_PackRingtone(ringtone, Buffer, &i);
639 fwrite(Buffer, 1, i, file);
642 void saverttl(FILE *file, GSM_Ringtone *ringtone)
644 u8 DefNoteScale=2, DefNoteDuration=4;
646 u8 DefNoteStyle=ContinuousStyle;
652 /* Saves ringtone name */
653 fprintf(file,_("%s:"),ringtone->name);
655 /* Find the most frequently used duration and use this for the default */
657 for (i=0;i<6;i++) buffer[i]=0;
658 for (i=0;i<ringtone->NrNotes;i++) {
659 switch (ringtone->notes[i].duration) {
660 case 192:buffer[0]++; break;
661 case 128:buffer[0]++; break;
662 case 96:buffer[1]++; break;
663 case 64:buffer[1]++; break;
664 case 48:buffer[2]++; break;
665 case 32:buffer[2]++; break;
666 case 24:buffer[3]++; break;
667 case 16:buffer[3]++; break;
668 case 12:buffer[4]++; break;
669 case 8:buffer[4]++; break;
670 case 6:buffer[5]++; break;
671 case 4:buffer[5]++; break;
675 /* Now find the most frequently used */
684 /* Finally convert and save the default duration */
687 case 0: DefNoteDuration=128; fprintf(file, _("d=1,")); break;
688 case 1: DefNoteDuration= 64; fprintf(file, _("d=2,")); break;
689 case 2: DefNoteDuration= 32; fprintf(file, _("d=4,")); break;
690 case 3: DefNoteDuration= 16; fprintf(file, _("d=8,")); break;
691 case 4: DefNoteDuration= 8; fprintf(file,_("d=16,")); break;
692 case 5: DefNoteDuration= 4; fprintf(file,_("d=32,")); break;
693 default: DefNoteDuration= 16; fprintf(file, _("d=8,")); break;
697 /* Find the most frequently used scale and use this for the default */
699 for (i=0;i<6;i++) buffer[i]=0;
700 for (i=0;i<ringtone->NrNotes;i++) {
701 if (ringtone->notes[i].note!=255) {
702 buffer[ringtone->notes[i].note/14]++;
713 if (ringtone->NrNotes!=0) {
714 DefNoteTempo=ringtone->notes[0].tempo;
715 DefNoteStyle=ringtone->notes[0].style;
718 /* Save the default scale */
719 fprintf(file,_("o=%i,"),DefNoteScale+4);
721 switch (DefNoteStyle) {
722 case StaccatoStyle: fprintf(file,_("s=S,")); break;
723 case NaturalStyle : fprintf(file,_("s=N,")); break;
726 /* Save the default tempo */
727 fprintf(file,_("b=%i,"),DefNoteTempo);
729 /* Save the default loop */
730 fprintf(file,_("l=%i:"),ringtone->Loop);
733 printf("DefNoteDuration=%d\n", DefNoteDuration);
734 printf("DefNoteScale=%d\n", DefNoteScale);
735 printf("Number of notes=%d\n",ringtone->NrNotes);
738 /* Now loop round for each note */
740 for (i=0;i<ringtone->NrNotes;i++) {
741 CurrentNote=ringtone->notes[i].note;
743 if (ringtone->notes[i].style!=DefNoteStyle) {
744 DefNoteStyle=ringtone->notes[i].style;
745 switch (DefNoteStyle) {
746 case StaccatoStyle : fprintf(file,_("s=S")); break;
747 case NaturalStyle : fprintf(file,_("s=N")); break;
748 case ContinuousStyle: fprintf(file,_("s=C")); break;
750 /* And a separator before next note */
751 if (i!=ringtone->NrNotes-1)
752 fprintf(file,_(","));
755 if (ringtone->notes[i].tempo!=DefNoteTempo) {
756 DefNoteTempo=ringtone->notes[i].tempo;
757 fprintf(file,_("b=%i"),DefNoteTempo);
758 if (i!=ringtone->NrNotes-1)
759 fprintf(file,_(","));
762 /* This note has a duration different than the default. We must save it */
763 if (ringtone->notes[i].duration!=DefNoteDuration) {
764 switch (ringtone->notes[i].duration) {
765 case 192: fprintf(file, _("1")); break; //192=128*1.5
766 case 128: fprintf(file, _("1")); break;
767 case 96: fprintf(file, _("2")); break; //96=64*1.5
768 case 64: fprintf(file, _("2")); break;
769 case 48: fprintf(file, _("4")); break; //48=32*1.5
770 case 32: fprintf(file, _("4")); break;
771 case 24: fprintf(file, _("8")); break; //24=16*1.5
772 case 16: fprintf(file, _("8")); break;
773 case 12: fprintf(file,_("16")); break; //12=8*1.5
774 case 8: fprintf(file,_("16")); break;
775 case 6: fprintf(file,_("32")); break; //6=4*1.5
776 case 4: fprintf(file,_("32")); break;
782 /* Now save the actual note */
783 switch (GSM_GetNote(CurrentNote)) {
784 case Note_C :fprintf(file,_("c"));break;
785 case Note_Cis:fprintf(file,_("c#"));break;
786 case Note_D :fprintf(file,_("d"));break;
787 case Note_Dis:fprintf(file,_("d#"));break;
788 case Note_E :fprintf(file,_("e"));break;
789 case Note_F :fprintf(file,_("f"));break;
790 case Note_Fis:fprintf(file,_("f#"));break;
791 case Note_G :fprintf(file,_("g"));break;
792 case Note_Gis:fprintf(file,_("g#"));break;
793 case Note_A :fprintf(file,_("a"));break;
794 case Note_Ais:fprintf(file,_("a#"));break;
795 case Note_H :fprintf(file,_("h"));break;
796 default :fprintf(file,_("p"));break; //Pause ?
799 /* Saving info about special duration */
800 if (ringtone->notes[i].duration==128*1.5 ||
801 ringtone->notes[i].duration==64*1.5 ||
802 ringtone->notes[i].duration==32*1.5 ||
803 ringtone->notes[i].duration==16*1.5 ||
804 ringtone->notes[i].duration==8*1.5 ||
805 ringtone->notes[i].duration==4*1.5)
806 fprintf(file,_("."));
808 /* This note has a scale different than the default, so save it */
809 if ( (CurrentNote!=255) && (CurrentNote/14!=DefNoteScale))
810 fprintf(file,_("%i"),(CurrentNote/14)+4);
812 /* And a separator before next note */
813 if (i!=ringtone->NrNotes-1)
814 fprintf(file,_(","));
819 void WriteVarLen(char* midifile, int* current, long value)
823 buffer = value & 0x7f;
825 while (value >>= 7) {
828 buffer += (value & 0x7f);
832 midifile[(*current)++] = buffer;
842 /* FIXME: need adding tempo before each note and scale too ? */
843 void savemid(FILE* file, GSM_Ringtone *ringtone)
845 char midifile[3000] = { 0x4D, 0x54, 0x68, 0x64, // MThd
846 0x00, 0x00, 0x00, 0x06, // chunk length
847 0x00, 0x00, // format 0
848 0x00, 0x01, // one track
849 0x00, 0x20, // 32 per quarter note
850 0x4D, 0x54, 0x72, 0x6B, // MTrk
851 0x00, 0x00, 0x00, 0x00, // chunk length
852 0x00, 0xFF, 0x51, 0x03, // tempo meta event
853 0x00, 0x00, 0x00 // 3 bytes for us for a quarter note
856 //{ "c", "c#", "d", "d#", "e", "f", "f#", "g", "g#", "a", "a#", "h" };
858 { 0, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10 , 11, 11 };
862 int current = 26, i, note, pause = 0;
863 bool notesexisting = false;
865 /* FIXME: we need add tempo before each note or so... */
866 long duration=60000000/63; // us for a quarter note
867 if (ringtone->NrNotes!=0)
868 duration=60000000/ringtone->notes[0].tempo;
869 midifile[current++] = duration >> 16;
870 midifile[current++] = duration >> 8;
871 midifile[current++] = duration;
873 for (i = 0; i < ringtone->NrNotes; i++) {
875 note = ringtone->notes[i].note;
876 if (note == 255) { // readmid does not read pauses at the beginning
879 pause += ringtone->notes[i].duration;
881 WriteVarLen(midifile,¤t,pause);
883 midifile[current++]=0x00; // pause
884 midifile[current++]=0x00;
890 notesexisting = true;
891 note = 48+12*((note/14)%4) + midinotes[note%14];
893 WriteVarLen(midifile,¤t,pause);
895 midifile[current++]=0x90; // note on
896 midifile[current++]=note;
897 midifile[current++]=0x64; // forte
899 WriteVarLen(midifile,¤t,ringtone->notes[i].duration);
900 midifile[current++]=0x80; // note off
901 midifile[current++]=note;
902 midifile[current++]=0x64;
908 WriteVarLen(midifile,¤t,pause);
909 midifile[current++]=0x00; // pause
910 midifile[current++]=0x00; //
912 midifile[current++] = 0x00;
913 midifile[current++] = 0xFF; // track end
914 midifile[current++] = 0x2F;
915 midifile[current++] = 0x00;
916 midifile[length++] = (current-start) >> 8;
917 midifile[length++] = current-start;
919 fwrite(midifile,1,current,file);
922 GSM_Error GSM_ReadBitmapFile(char *FileName, GSM_Bitmap *bitmap)
926 unsigned char buffer[300];
928 GSM_Filetypes filetype=None;
930 file = fopen(FileName, "rb");
933 return(GE_CANTOPENFILE);
935 fread(buffer, 1, 9, file); /* Read the header of the file. */
937 /* Attempt to identify filetype */
939 if (memcmp(buffer, "NOL",3)==0) { /* NOL files have 'NOL' at the start */
941 } else if (memcmp(buffer, "NGG",3)==0) { /* NGG files have 'NGG' at the start */
943 } else if (memcmp(buffer, "FORM",4)==0) { /* NSL files have 'FORM' at the start */
945 } else if (memcmp(buffer, "NLM",3)==0) { /* NLM files have 'NLM' at the start */
947 } else if (memcmp(buffer, "BM",2)==0) { /* BMP, I61 and GGP files have 'BM' at the start */
949 } else if (memcmp(buffer, "/* XPM */",9)==0) { /* XPM files have 'XPM' at the start */
951 } else filetype=None;
953 if (strstr(FileName,".otb")) filetype=OTA; /* OTA files saved by NCDS3 */
960 case NOL: error=loadnol(file,bitmap); fclose(file); break;
961 case NGG: error=loadngg(file,bitmap); fclose(file); break;
962 case NSL: error=loadnsl(file,bitmap); fclose(file); break;
963 case NLM: error=loadnlm(file,bitmap); fclose(file); break;
964 case OTA: error=loadota(file,bitmap); fclose(file); break;
965 case BMP: error=loadbmp(file,bitmap); fclose(file); break;
967 case XPMF:fclose(file);error=loadxpm(FileName,bitmap);break;
969 default : error=GE_INVALIDFILEFORMAT;
977 GSM_Error loadxpm(char *filename, GSM_Bitmap *bitmap)
983 error=XpmReadFileToXpmImage(filename,&image,&info);
986 case XpmColorError: return GE_WRONGCOLORS;break;
987 case XpmColorFailed: return GE_WRONGCOLORS;break;
988 case XpmOpenFailed: return GE_CANTOPENFILE;break;
989 case XpmFileInvalid: return GE_INVALIDFILEFORMAT;break;
990 case XpmSuccess: break;
993 if (image.ncolors!=2) {
994 printf("Wrong number of colors\n");
995 return GE_WRONGNUMBEROFCOLORS;
998 if ((image.height==48) && (image.width==84)) {
999 bitmap->type=GSM_StartupLogo;
1001 else if ((image.height==65) && (image.width==96)) {
1002 bitmap->type=GSM_7110StartupLogo;
1004 else if ((image.height==60) && (image.width==96)) {
1005 bitmap->type=GSM_6210StartupLogo;
1007 else if ((image.height==28) && (image.width==72)) {
1008 bitmap->type=GSM_PictureImage;
1010 else if ((image.height==14) && (image.width==72)) {
1011 bitmap->type=GSM_CallerLogo;
1015 printf("Invalid Image Size (%dx%d).\n",image.width,image.height);
1017 return GE_INVALIDIMAGESIZE;
1020 bitmap->height=image.height;
1021 bitmap->width=image.width;
1022 bitmap->size=bitmap->height*bitmap->width/8;
1024 GSM_ClearBitmap(bitmap);
1026 for(y=0;y<image.height;y++) {
1027 for(x=0;x<image.width;x++) {
1028 if (image.data[y*image.width+x]==0) GSM_SetPointBitmap(bitmap,x,y);
1037 /* Based on the article from the Polish Magazine "Bajtek" 11/92 */
1038 /* Marcin-Wiacek@Topnet.PL */
1039 GSM_Error loadbmp(FILE *file, GSM_Bitmap *bitmap)
1041 unsigned char buffer[34];
1043 int w,h,pos,y,x,i,sizeimage;
1045 fread(buffer, 1, 34, file); //required part of header
1047 h=buffer[22]+256*buffer[21]; //height of image in the file
1048 w=buffer[18]+256*buffer[17]; //width of image in the file
1050 printf("Image Size in BMP file: %dx%d\n",w,h);
1053 bitmap->type=GSM_7110StartupLogo;
1057 if (h==48 && w==84) {
1060 bitmap->type=GSM_StartupLogo;
1062 if (h==60 && w==96) {
1065 bitmap->type=GSM_6210StartupLogo;
1067 if (h==14 && w==72) {
1070 bitmap->type=GSM_CallerLogo;
1072 if (h==28 && w==72) {
1075 bitmap->type=GSM_PictureImage;
1077 if (h==21 && w==78) {
1080 bitmap->type=GSM_7110OperatorLogo;
1084 bitmap->size=(bitmap->width*bitmap->height + 7)/8;
1086 GSM_ClearBitmap(bitmap);
1089 printf("Number of colors in BMP file: ");
1090 switch (buffer[28]) {
1091 case 1:printf("2 (supported by gnokii)\n");break;
1092 case 4:printf("16 (not supported by gnokii)\n");break;
1093 case 8:printf("256 (not supported by gnokii)\n");break;
1094 case 24:printf("True Color (not supported by gnokii)\n");break;
1095 default:printf("unknown\n");break;
1098 if (buffer[28]!=1) {
1099 printf("Wrong number of colors\n"); //we support only 2 colors images !
1100 return GE_WRONGNUMBEROFCOLORS;
1104 printf("Compression in BMP file: ");
1105 switch (buffer[30]) {
1106 case 0:printf("no compression (supported by gnokii)\n");break;
1107 case 1:printf("RLE8 (not supported by gnokii)\n");break;
1108 case 2:printf("RLE4 (not supported by gnokii)\n");break;
1109 default:printf("unknown\n");break;
1112 if (buffer[30]!=0) {
1114 printf("Subformat not supported\n"); //we don't support RLE compression
1116 return GE_SUBFORMATNOTSUPPORTED;
1120 fread(buffer, 1, pos, file); //rest of header (if exists) and color palette
1123 printf("First color in BMP file: %i %i %i ",buffer[pos-8], buffer[pos-7], buffer[pos-6]);
1124 if (buffer[pos-8]==0 && buffer[pos-7]==0 && buffer[pos-6]==0) printf("(white)");
1125 if (buffer[pos-8]==0xFF && buffer[pos-7]==0xFF && buffer[pos-6]==0xFF) printf("(black)");
1126 if (buffer[pos-8]==102 && buffer[pos-7]==204 && buffer[pos-6]==102) printf("(green)");
1129 printf("Second color in BMP file: %i %i %i ",buffer[pos-4], buffer[pos-3], buffer[pos-2]);
1130 if (buffer[pos-4]==0 && buffer[pos-3]==0 && buffer[pos-2]==0) printf("(white)");
1131 if (buffer[pos-4]==0xFF && buffer[pos-3]==0xFF && buffer[pos-2]==0xFF) printf("(black)");
1135 if (buffer[pos-8]!=0 || buffer[pos-7]!=0 || buffer[pos-6]!=0) first_white=false;
1139 for (y=h-1;y>=0;y--) { //lines are written from the last to the first
1142 if (pos==7) { //new byte !
1143 fread(buffer, 1, 1, file);
1146 if(i==5) i=1; //each line is written in multiply of 4 bytes
1148 if (x<=bitmap->width && y<=bitmap->height) { //we have top left corner !
1150 if ((buffer[0]&(1<<pos))<=0) GSM_SetPointBitmap(bitmap,x,y);
1152 if ((buffer[0]&(1<<pos))>0) GSM_SetPointBitmap(bitmap,x,y);
1156 if (pos<0) pos=7; //going to new byte
1158 pos=7; //going to new byte
1160 while (i!=5) //each line is written in multiply of 4 bytes
1162 fread(buffer, 1, 1, file);
1170 printf("Data size in BMP file: %i\n",sizeimage);
1176 GSM_Error loadnol(FILE *file, GSM_Bitmap *bitmap)
1179 unsigned char buffer[2000];
1182 bitmap->type=GSM_OperatorLogo;
1184 fread(buffer, 1, 6, file);
1185 fread(buffer, 1, 4, file);
1186 sprintf(bitmap->netcode, "%d %02d", buffer[0]+256*buffer[1], buffer[2]);
1188 fread(buffer, 1, 4, file); /* Width and height of the icon. */
1189 bitmap->width=buffer[0];
1190 bitmap->height=buffer[2];
1191 bitmap->size=bitmap->height*bitmap->width/8;
1193 if ((bitmap->height!=14) || (bitmap->width!=72)) {
1195 printf("Invalid Image Size (%dx%d).\n",bitmap->width,bitmap->height);
1197 return GE_INVALIDIMAGESIZE;
1200 fread(buffer, 1, 6, file); /* Unknown bytes. */
1202 for (i=0; i<bitmap->size; i++) {
1203 if (fread(buffer, 1, 8, file)==8) {
1204 bitmap->bitmap[i]=0;
1206 if (buffer[7-j] == '1')
1207 bitmap->bitmap[i]|=(1<<j);
1210 return (GE_TOOSHORT);
1214 /* Some programs writes here fileinfo */
1215 if (fread(buffer, 1, 1, file)==1) {
1216 fprintf(stdout, _("Fileinfo: %c"),buffer[0]);
1217 while (fread(buffer, 1, 1, file)==1) {
1218 if (buffer[0]!=0x0A) fprintf(stdout,_("%c"),buffer[0]);
1220 fprintf(stdout, _("\n"));
1227 GSM_Error loadngg(FILE *file, GSM_Bitmap *bitmap)
1230 unsigned char buffer[2000];
1233 bitmap->type=GSM_CallerLogo;
1235 fread(buffer, 1, 6, file);
1236 fread(buffer, 1, 4, file); /* Width and height of the icon. */
1237 bitmap->width=buffer[0];
1238 bitmap->height=buffer[2];
1239 bitmap->size=bitmap->height*bitmap->width/8;
1241 if ((bitmap->height!=14) || (bitmap->width!=72)) {
1243 printf("Invalid Image Size (%dx%d).\n",bitmap->width,bitmap->height);
1245 return GE_INVALIDIMAGESIZE;
1248 fread(buffer, 1, 6, file); /* Unknown bytes. */
1250 for (i=0; i<bitmap->size; i++) {
1251 if (fread(buffer, 1, 8, file)==8){
1252 bitmap->bitmap[i]=0;
1254 if (buffer[7-j] == '1')
1255 bitmap->bitmap[i]|=(1<<j);
1258 return(GE_TOOSHORT);
1262 /* Some programs writes here fileinfo */
1263 if (fread(buffer, 1, 1, file)==1) {
1264 fprintf(stdout, _("Fileinfo: %c"),buffer[0]);
1265 while (fread(buffer, 1, 1, file)==1) {
1266 if (buffer[0]!=0x0A) fprintf(stdout,_("%c"),buffer[0]);
1268 fprintf(stdout, _("\n"));
1275 GSM_Error loadnsl(FILE *file, GSM_Bitmap *bitmap)
1278 unsigned char block[6],buffer[505];
1283 while (fread(block,1,6,file)==6) {
1285 block_size=block[4]*256+block[5];
1288 fprintf(stdout,_("Block %c%c%c%c, size %i\n"),block[0],block[1],block[2],block[3],block_size);
1291 if (!strncmp(block, "FORM", 4)) {
1293 fprintf(stdout,_(" File ID\n"));
1297 if (block_size>504) return(GE_INVALIDFILEFORMAT);
1299 if (block_size!=0) {
1301 fread(buffer,1,block_size,file);
1302 buffer[block_size]=0; //if it's string, we end it with \0
1305 if (!strncmp(block, "VERS", 4)) fprintf(stdout,_(" File saved by: %s\n"),buffer);
1306 if (!strncmp(block, "MODL", 4)) fprintf(stdout,_(" Logo saved from: %s\n"),buffer);
1307 if (!strncmp(block, "COMM", 4)) fprintf(stdout,_(" Phone was connected to COM port: %s\n"),buffer);
1310 if (!strncmp(block, "NSLD", 4)) {
1311 bitmap->type=GSM_StartupLogo;
1314 bitmap->size=(bitmap->height*bitmap->width)/8;
1316 memcpy(bitmap->bitmap,buffer,bitmap->size);
1319 fprintf(stdout,_(" Startup logo (size %i)\n"),block_size);
1326 if (bitmap->size==0) return(GE_TOOSHORT);
1331 GSM_Error loadnlm (FILE *file, GSM_Bitmap *bitmap)
1333 unsigned char buffer[1000];
1337 fread(buffer,1,5,file);
1338 fread(buffer,1,1,file);
1340 switch (buffer[0]) {
1341 case 0x00: bitmap->type=GSM_OperatorLogo; break;
1342 case 0x01: bitmap->type=GSM_CallerLogo; break;
1343 case 0x02: bitmap->type=GSM_StartupLogo; break;
1344 case 0x03: bitmap->type=GSM_PictureImage; break;
1346 return(GE_SUBFORMATNOTSUPPORTED);
1349 fread(buffer,1,4,file);
1350 bitmap->width=buffer[1];
1351 bitmap->height=buffer[2];
1353 if (bitmap->type==GSM_StartupLogo && bitmap->width==96 && bitmap->height==65)
1354 bitmap->type=GSM_7110StartupLogo;
1355 if (bitmap->type==GSM_StartupLogo && bitmap->width==96 && bitmap->height==60)
1356 bitmap->type=GSM_6210StartupLogo;
1357 if (bitmap->type==GSM_OperatorLogo && bitmap->width==78 && bitmap->height==21)
1358 bitmap->type=GSM_7110OperatorLogo;
1360 bitmap->size=bitmap->width*bitmap->height/8;
1362 division=div(bitmap->width,8);
1363 if (division.rem!=0) division.quot++; /* For startup logos */
1365 if (fread(buffer,1,(division.quot*bitmap->height),file)!=(division.quot*bitmap->height))
1366 return(GE_TOOSHORT);
1368 GSM_ClearBitmap(bitmap);
1371 for (y=0;y<bitmap->height;y++) {
1372 for (x=0;x<bitmap->width;x++) {
1373 if ((buffer[pos]&(1<<pos2))>0) GSM_SetPointBitmap(bitmap,x,y);
1375 if (pos2<0) {pos2=7;pos++;} //going to new byte
1377 if (pos2!=7) {pos2=7;pos++;} //for startup logos-new line means new byte
1383 GSM_Error loadota(FILE *file, GSM_Bitmap *bitmap)
1388 fread(buffer,1,4,file);
1390 bitmap->width=buffer[1];
1391 bitmap->height=buffer[2];
1392 bitmap->size=bitmap->width*bitmap->height/8;
1394 if ((bitmap->height==48) && (bitmap->width==84)) {
1395 bitmap->type=GSM_StartupLogo;
1397 else if ((bitmap->height==14) && (bitmap->width==72)) {
1398 bitmap->type=GSM_CallerLogo;
1402 printf("Invalid Image Size (%dx%d).\n",bitmap->width,bitmap->height);
1404 return GE_INVALIDIMAGESIZE;
1407 if (fread(bitmap->bitmap,1,bitmap->size,file)!=bitmap->size)
1408 return(GE_TOOSHORT);
1413 GSM_Error GSM_SaveBitmapFile(char *FileName, GSM_Bitmap *bitmap)
1419 file = fopen(FileName, "wb");
1422 return(GE_CANTOPENFILE);
1424 if (strstr(FileName,".xpm")) { savexpm(file, bitmap); done=true; }
1425 if (strstr(FileName,".nlm")) { savenlm(file, bitmap); done=true; }
1426 if (strstr(FileName,".ngg")) { savengg(file, bitmap); done=true; }
1427 if (strstr(FileName,".nsl")) { savensl(file, bitmap); done=true; }
1428 if (strstr(FileName,".otb")) { saveota(file, bitmap); done=true; }
1429 if (strstr(FileName,".nol")) { savenol(file, bitmap); done=true; }
1430 if (strstr(FileName,".bmp") ||
1431 strstr(FileName,".ggp") ||
1432 strstr(FileName,".i61"))
1434 savebmp(file, bitmap);
1440 switch (bitmap->type) {
1441 case GSM_CallerLogo : savengg(file, bitmap); break;
1442 case GSM_OperatorLogo : savenol(file, bitmap); break;
1443 case GSM_7110OperatorLogo: savebmp(file, bitmap); break;
1444 case GSM_7110StartupLogo : savebmp(file, bitmap); break;
1445 case GSM_6210StartupLogo : savebmp(file, bitmap); break;
1446 case GSM_StartupLogo : savensl(file, bitmap); break;
1447 case GSM_PictureImage : savenlm(file, bitmap); break;
1448 case GSM_WelcomeNoteText : break;
1449 case GSM_DealerNoteText : break;
1450 case GSM_None : break;
1459 void savexpm(FILE *file, GSM_Bitmap *bitmap)
1463 fprintf(file,_("/* XPM */\n"));
1464 fprintf(file,_("static char * ala_xpm[] = {\n"));
1465 fprintf(file,_("\"%i %i 2 1\",\n"),bitmap->width,bitmap->height);
1466 fprintf(file,_("\". s c m #000000 g4 #000000 g #000000 c #000000\",\n"));
1467 fprintf(file,_("\"# s c m #ffffff g4 #ffffff g #ffffff c #ffffff\",\n"));
1469 for (y=0;y<bitmap->height;y++) {
1470 fprintf(file,_("\""));
1471 for (x=0;x<bitmap->width;x++)
1472 if (GSM_IsPointBitmap(bitmap,x,y))
1473 fprintf(file,_("."));
1475 fprintf(file,_("#"));
1476 fprintf(file,_("\""));
1477 if (y==bitmap->height-1)
1478 fprintf(file,_("};\n"));
1480 fprintf(file,_(",\n"));
1484 /* Based on the article from the Polish Magazine "Bajtek" 11/92 */
1485 /* Marcin-Wiacek@Topnet.PL */
1486 void savebmp(FILE *file, GSM_Bitmap *bitmap)
1488 int x,y,pos,i,sizeimage;
1489 unsigned char buffer[1];
1492 unsigned char header[]={
1493 /*1'st header*/ 'B','M', /* BMP file ID */
1494 0x00,0x00,0x00,0x00, /* Size of file */
1495 0x00,0x00, /* Reserved for future use */
1496 0x00,0x00, /* Reserved for future use */
1497 62,0x00,0x00,0x00, /* Offset for image data */
1499 /*2'nd header*/ 40,0x00,0x00,0x00, /* Length of this part of header */
1500 0x00,0x00,0x00,0x00, /* Width of image */
1501 0x00,0x00,0x00,0x00, /* Height of image */
1502 1,0x00, /* How many planes in target device */
1503 1,0x00, /* How many colors in image. 1 means 2^1=2 colors */
1504 0x00,0x00,0x00,0x00, /* Type of compression. 0 means no compression */
1505 /*Sometimes */ 0x00,0x00,0x00,0x00, /* Size of part with image data */
1506 /*ttttttt...*/ 0xE8,0x03,0x00,0x00, /* XPelsPerMeter */
1507 /*hhiiiiissss*/ 0xE8,0x03,0x00,0x00, /* YPelsPerMeter */
1508 /*part of header*/2,0x00,0x00,0x00, /* How many colors from palette is used */
1509 /*doesn't exist*/ 0x00,0x00,0x00,0x00, /* How many colors from palette is required to display image. 0 means all */
1511 /*Color palette*/ 0x00,0x00,0x00, /* First color in palette in Blue, Green, Red. Here white */
1512 0x00, /* Each color in palette is end by 4'th byte */
1513 102,204,102, /* Second color in palette in Blue, Green, Red. Here green */
1514 0x00}; /* Each color in palette is end by 4'th byte */
1516 header[22]=bitmap->height;
1517 header[18]=bitmap->width;
1521 for (y=bitmap->height-1;y>=0;y--) { //lines are written from the last to the first
1523 for (x=0;x<bitmap->width;x++) {
1524 if (pos==7) { //new byte !
1525 if (x!=0) sizeimage++;
1527 if(i==5) i=1; //each line is written in multiply of 4 bytes
1530 if (pos<0) pos=7; //going to new byte
1532 pos=7; //going to new byte
1535 while (i!=5) //each line is written in multiply of 4 bytes
1543 printf("Data size in BMP file: %i\n",sizeimage);
1545 division=div(sizeimage,256);
1546 header[35]=division.quot;
1547 header[34]=sizeimage-(division.quot*256);
1549 sizeimage=sizeimage+sizeof(header);
1551 printf("Size of BMP file: %i\n",sizeimage);
1553 division=div(sizeimage,256);
1554 header[3]=division.quot;
1555 header[2]=sizeimage-(division.quot*256);
1557 fwrite(header,1,sizeof(header),file);
1560 for (y=bitmap->height-1;y>=0;y--) { //lines are written from the last to the first
1562 for (x=0;x<bitmap->width;x++) {
1563 if (pos==7) { //new byte !
1564 if (x!=0) fwrite(buffer, 1, sizeof(buffer), file);
1566 if(i==5) i=1; //each line is written in multiply of 4 bytes
1569 if (!GSM_IsPointBitmap(bitmap,x,y)) buffer[0]|=(1<<pos);
1571 if (pos<0) pos=7; //going to new byte
1573 pos=7; //going to new byte
1574 fwrite(buffer, 1, sizeof(buffer), file);
1576 while (i!=5) //each line is written in multiply of 4 bytes
1579 fwrite(buffer, 1, sizeof(buffer), file);
1586 void savengg(FILE *file, GSM_Bitmap *bitmap)
1589 char header[]={'N','G','G',0x00,0x01,0x00,
1590 0x00,0x00, /* Width */
1591 0x00,0x00, /* Height */
1592 0x01,0x00,0x01,0x00,
1593 0x00, /* Unknown.Can't be checksum - for */
1594 /* the same logo files can be different */
1603 GSM_ResizeBitmap(©,GSM_CallerLogo);
1605 header[6]=copy.width;
1606 header[8]=copy.height;
1608 fwrite(header,1,sizeof(header),file);
1610 for (i=0; i<copy.size; i++) {
1612 if ((copy.bitmap[i]&(1<<j))>0) {
1617 fwrite(buffer,1,8,file);
1621 void savenol(FILE *file, GSM_Bitmap *bitmap)
1624 char header[]={'N','O','L',0x00,0x01,0x00,
1625 0x00,0x00, /* MCC */
1626 0x00,0x00, /* MNC */
1627 0x00,0x00, /* Width */
1628 0x00,0x00, /* Height */
1629 0x01,0x00,0x01,0x00,
1630 0x00, /* Unknown.Can't be checksum - for */
1631 /* the same logo files can be different */
1634 int i,j,country,net;
1639 GSM_ResizeBitmap(©,GSM_OperatorLogo);
1641 sscanf(copy.netcode, "%d %d", &country, &net);
1643 header[6]=country%256;
1644 header[7]=country/256;
1647 header[10]=copy.width;
1648 header[12]=copy.height;
1650 fwrite(header,1,sizeof(header),file);
1652 for (i=0; i<copy.size; i++) {
1654 if ((copy.bitmap[i]&(1<<j))>0) {
1659 fwrite(buffer,1,8,file);
1663 void savensl(FILE *file, GSM_Bitmap *bitmap)
1666 u8 header[]={'F','O','R','M', 0x01,0xFE, /* File ID block, size 1*256+0xFE=510*/
1667 'N','S','L','D', 0x01,0xF8}; /* Startup Logo block, size 1*256+0xF8=504*/
1672 GSM_ResizeBitmap(©,GSM_StartupLogo);
1674 fwrite(header,1,sizeof(header),file);
1676 fwrite(copy.bitmap,1,copy.size,file);
1679 void saveota(FILE *file, GSM_Bitmap *bitmap)
1682 char header[]={0x01,
1690 header[1]=copy.width;
1691 header[2]=copy.height;
1693 fwrite(header,1,sizeof(header),file);
1695 fwrite(copy.bitmap,1,copy.size,file);
1698 void savenlm(FILE *file, GSM_Bitmap *bitmap)
1701 char header[]={'N','L','M', /* Nokia Logo Manager file ID. */
1704 0x00, /* 0x00 (OP), 0x01 (CLI), 0x02 (Startup), 0x03 (Picture)*/
1705 0x00, /* Number of images inside file - 1. 0x01==2 images, 0x03==4 images, etc. */
1710 unsigned char buffer[1000];
1717 switch (copy.type) {
1718 case GSM_OperatorLogo : header[5]=0x00; break;
1719 case GSM_7110OperatorLogo: header[5]=0x00; break;
1720 case GSM_CallerLogo : header[5]=0x01; break;
1721 case GSM_StartupLogo : header[5]=0x02; break;
1722 case GSM_7110StartupLogo : header[5]=0x02; break;
1723 case GSM_6210StartupLogo : header[5]=0x02; break;
1724 case GSM_PictureImage : header[5]=0x03; break;
1725 case GSM_WelcomeNoteText : break;
1726 case GSM_DealerNoteText : break;
1727 case GSM_None : break;
1730 header[7]=copy.width;
1731 header[8]=copy.height;
1734 for (y=0;y<copy.height;y++) {
1735 for (x=0;x<copy.width;x++) {
1736 if (pos2==7) buffer[pos]=0;
1738 if (GSM_IsPointBitmap(©,x,y)) buffer[pos]|=(1<<pos2);
1741 if (pos2<0) {pos2=7;pos++;} //going to new line
1743 if (pos2!=7) {pos2=7;pos++;} //for startup logos - new line with new byte
1746 division=div(copy.width,8);
1747 if (division.rem!=0) division.quot++; /* For startup logos */
1749 fwrite(header,1,sizeof(header),file);
1751 fwrite(buffer,1,(division.quot*copy.height),file);
1754 /* mode == 0 -> overwrite
1756 * mode == 2 -> append
1758 int GSM_SaveTextFile(char *FileName, char *text, int mode)
1763 if (mode == 2) file = fopen(FileName, "a");
1764 else file = fopen(FileName, "w");
1766 if (!file) return -1;
1768 fprintf(file, "%s\n\n", text);
1775 GSM_Error GSM_SaveBackupFile(char *FileName, GSM_Backup *backup)
1780 file = fopen(FileName, "wb");
1782 if (!file) return(GE_CANTOPENFILE);
1784 savelmb(file, backup);
1791 void savelmbstartupentry(FILE *file, GSM_Bitmap startup, GSM_Bitmap text, bool available)
1793 /* Welcome note and logo header block */
1794 char req[1000] = {'W','E','L',' ', /*block identifier*/
1795 00,00, /*block data size*/
1796 0x02,00,00,00,00,00,
1797 0x02}; /*number of blocks (like in 6110 frame)*/
1803 count=count+N6110_MakeStartupLogoFrame(req+13,startup);
1807 req[count++]=strlen(text.text);
1808 memcpy(req+count,text.text,strlen(text.text));
1809 count=count+strlen(text.text);
1811 req[4]=(count-12)%256;
1812 req[5]=(count-12)/256;
1814 fwrite(req, 1, count, file);
1817 void savelmbopentry(FILE *file, GSM_Bitmap bitmap)
1819 /* Operator logo header block */
1820 char req[500] = {'O','L','G',' ', /*block identifier*/
1821 0x88,00, /*block data size*/
1822 0x02,00,00,00,00,00,00};
1826 count=count+N6110_MakeOperatorLogoFrame(req+13,bitmap);
1828 req[4]=(count-7)%256;
1829 req[5]=(count-7)/256;
1831 req[17]=req[17]+5; //we fix size of logo block
1833 fwrite(req, 1, count, file);
1836 /* Work in progress ! */
1837 void savelmbspeedentry(FILE *file, GSM_SpeedDial speed)
1839 /* Speed dial header block */
1840 char req[] = {'S','P','D',' ', /*block identifier*/
1841 0x03,00, /*block data size*/
1843 00, /*number of speed dial*/
1845 00, /*number of speed dial*/
1846 03, /*memory type. ME=02;SM=03*/
1847 00}; /*number of location assigned to speed dial*/
1849 req[8]=req[12]=speed.Number;
1851 if (speed.MemoryType==GMT_ME) req[13]=2; //memory type=GMT_ME
1853 req[14]=speed.Location;
1855 fwrite(req, 1, 15, file);
1858 void savelmbcallerentry(FILE *file, GSM_Bitmap bitmap)
1860 char req[500] = {'C','G','R',' ', /*block identifier*/
1861 00,00, /*block data size*/
1863 00, /*group number=0,1,etc.*/
1868 req[8]=bitmap.number;
1870 count=count+N6110_MakeCallerGroupFrame(req+12,bitmap);
1872 req[4]=(count-11)%256;
1873 req[5]=(count-11)/256;
1875 fwrite(req, 1, count, file);
1878 void savelmbpbkentry(FILE *file, GSM_PhonebookEntry entry)
1880 char req[500] = {'P','B','E','2', /*block identifier*/
1881 00,00, /*block data size*/
1883 00, /*position of phonebook entry*/
1885 03, /*memory type. ME=02;SM=03*/
1887 00, /*position of phonebook entry*/
1889 03, /*memory type. ME=02;SM=03*/
1892 int count = 16, blocks;
1894 req[8]=req[12]=entry.Location; //position of this entry
1896 if (entry.MemoryType==GMT_ME) req[10]=req[14]=2;
1898 /* There is NO full compatibility with files created by Logo Manager,
1899 anyway it works OK with files saved by this function - some bytes
1900 are probably random */
1901 count=count+N7110_MakePhonebookFrame(req+16, entry, &blocks);
1903 req[4]=(count-12)%256;
1904 req[5]=(count-12)/256;
1906 fwrite(req, 1, count, file);
1909 void savelmb(FILE *file, GSM_Backup *backup)
1913 char LMBHeader[] = {'L','M','B',' '}; /*file identifier*/
1915 /* Phonebook header block */
1916 char PBKHeader[] = {'P','B','K',' ', /*block identifier*/
1917 0x08,00, /*block data size*/
1919 03, /*memory type. ME=02;SM=03*/
1921 00,00, /*size of phonebook*/
1922 14, /*max length of each position*/
1925 fwrite(LMBHeader, 1, sizeof(LMBHeader), file); /* Write the header of the file. */
1927 if (backup->SIMPhonebookUsed!=0) {
1928 PBKHeader[12]=backup->SIMPhonebookSize%256;
1929 PBKHeader[13]=backup->SIMPhonebookSize/256;
1930 fwrite(PBKHeader, 1, sizeof(PBKHeader), file);
1932 for (i=0;i<backup->SIMPhonebookUsed;i++)
1933 savelmbpbkentry(file, backup->SIMPhonebook[i]);
1936 if (backup->PhonePhonebookUsed!=0) {
1937 PBKHeader[8]=2; //memory type=GMT_ME
1938 PBKHeader[12]=backup->PhonePhonebookSize%256;
1939 PBKHeader[13]=backup->PhonePhonebookSize/256;
1940 PBKHeader[14]=0x16; //max size of one entry
1941 fwrite(PBKHeader, 1, sizeof(PBKHeader), file);
1943 for (i=0;i<backup->PhonePhonebookUsed;i++)
1944 savelmbpbkentry(file, backup->PhonePhonebook[i]);
1947 if (backup->CallerAvailable)
1948 for (i=0;i<5;i++) savelmbcallerentry(file,backup->CallerGroups[i]);
1950 if (backup->SpeedAvailable)
1951 for (i=0;i<8;i++) savelmbspeedentry(file,backup->SpeedDials[i]);
1953 if (backup->OperatorLogoAvailable) savelmbopentry(file,backup->OperatorLogo);
1955 savelmbstartupentry(file,backup->StartupLogo,backup->StartupText,backup->StartupLogoAvailable);
1958 GSM_Error loadlmb(FILE *file, GSM_Backup *backup)
1961 // fread(buffer, 1, 6, file);
1965 GSM_Error GSM_ReadBackupFile(char *FileName, GSM_Backup *backup)
1969 unsigned char buffer[300];
1971 GSM_Filetypes filetype=None;
1973 file = fopen(FileName, "rb");
1975 if (!file) return(GE_CANTOPENFILE);
1977 fread(buffer, 1, 4, file); /* Read the header of the file. */
1979 /* Attempt to identify filetype */
1981 if (memcmp(buffer, "LMB ",4)==0) { /* LMB files have 'LMB ' at the start */
1983 } else filetype=None;
1990 case LMB: error=loadlmb(file,backup); fclose(file); break;
1991 default : error=GE_INVALIDFILEFORMAT;