7 A Linux/Unix toolset and driver for Nokia mobile phones.
9 Copyright (C) 1999, 2000 Hugh Blemings & Pavel JanÃk ml.
11 Released under the terms of the GNU GPL, see file COPYING for more details.
13 Functions to read and write common file types.
16 Revision 1.1.1.1 2001/11/25 21:59:00 short
17 :pserver:cvs@pserver.samba.org:/cvsroot - gnokii - Sun Nov 25 22:56 CET 2001
19 Revision 1.18 2001/09/20 21:46:20 pkot
20 Locale cleanups (Pawel Kot)
31 #include "gsm-common.h"
32 #include "gsm-filetypes.h"
33 #include "gsm-bitmaps.h"
34 #include "gsm-ringtones.h"
42 /* Ringtone File Functions */
43 /* ####################### */
46 /* Function to convert scale field in to correct number. */
48 int GetDuration (char *num)
76 int GetScale (char *num)
78 /* This may well need improving. */
81 if ((atoi(num)) < 4) scale = (atoi(num));
82 if ((atoi(num)) > 4) scale = (atoi(num)) - 4;
88 /* Currently only reads rttl and ott files - can be later extended to midi etc. */
90 GSM_Error GSM_ReadRingtoneFile(char *FileName, GSM_Ringtone *ringtone)
94 GSM_Filetypes filetype;
96 file = fopen(FileName, "rb");
99 return(GE_CANTOPENFILE);
101 /* FIXME: for now identify the filetype based on the extension */
102 /* I don't like this but I haven't got any .ott files to work out a better way */
105 if (strstr(FileName, ".ott")) filetype = OTT; /* OTT files saved by NCDS3 */
109 rewind(file); /* Not necessary for now but safer */
113 error = loadrttl(file, ringtone);
117 error = loadott(file, ringtone);
121 error = GE_INVALIDFILEFORMAT;
129 GSM_Error loadott(FILE *file, GSM_Ringtone *ringtone)
134 i = fread(Buffer, 1, 2000, file);
135 if (!feof(file)) return GE_FILETOOLONG;
136 return GSM_UnPackRingtone(ringtone, Buffer, i);
140 GSM_Error loadrttl(FILE *file, GSM_Ringtone *ringtone)
144 int DefNoteScale = 2;
145 int DefNoteDuration = 4;
146 unsigned char buffer[2000];
147 unsigned char *def, *notes, *ptr;
149 fread(buffer, 2000, 1, file);
151 /* This is for buggy RTTTL ringtones without name. */
152 if (buffer[0] != RTTTL_SEP[0]) {
153 strtok(buffer, RTTTL_SEP);
154 sprintf(ringtone->name, "%s", buffer);
155 def = strtok(NULL, RTTTL_SEP);
156 notes = strtok(NULL, RTTTL_SEP);
158 sprintf(ringtone->name, "GNOKII");
159 def = strtok(buffer, RTTTL_SEP);
160 notes = strtok(NULL, RTTTL_SEP);
163 ptr = strtok(def, ", ");
164 /* Parsing the <defaults> section. */
172 DefNoteDuration=GetDuration(ptr+2);
176 DefNoteScale=GetScale(ptr+2);
180 ringtone->tempo=atoi(ptr+2);
184 ptr=strtok(NULL,", ");
187 dprintf("DefNoteDuration = %d\n", DefNoteDuration);
188 dprintf("DefNoteScale = %d\n", DefNoteScale);
190 /* Parsing the <note-command>+ section. */
191 ptr = strtok(notes, ", ");
192 while (ptr && (NrNote < MAX_RINGTONE_NOTES)) {
195 ringtone->notes[NrNote].duration = GetDuration(ptr);
196 if (ringtone->notes[NrNote].duration == 0)
197 ringtone->notes[NrNote].duration = DefNoteDuration;
199 /* Skip all numbers in duration specification. */
200 while (isdigit(*ptr))
205 if ((*ptr >= 'a') && (*ptr <= 'g')) ringtone->notes[NrNote].note = ((*ptr - 'a') * 2) + 10;
206 else if ((*ptr >= 'A') && (*ptr <= 'G')) ringtone->notes[NrNote].note = ((*ptr - 'A') * 2) + 10;
207 else if ((*ptr == 'H') || (*ptr == 'h')) ringtone->notes[NrNote].note = 12;
208 else ringtone->notes[NrNote].note = 255;
210 if ((ringtone->notes[NrNote].note > 13) && (ringtone->notes[NrNote].note != 255))
211 ringtone->notes[NrNote].note -= 14;
216 ringtone->notes[NrNote].note++;
217 if ((ringtone->notes[NrNote].note == 5) || (ringtone->notes[NrNote].note == 13))
218 ringtone->notes[NrNote].note++;
222 /* Check for dodgy rttl */
223 /* [<special-duration>] */
225 ringtone->notes[NrNote].duration *= 1.5;
230 if (ringtone->notes[NrNote].note != 255) {
232 ringtone->notes[NrNote].note += GetScale(ptr) * 14;
235 ringtone->notes[NrNote].note += DefNoteScale * 14;
239 /* [<special-duration>] */
241 ringtone->notes[NrNote].duration *= 1.5;
246 ptr = strtok(NULL, ", ");
249 ringtone->NrNotes = NrNote;
255 /* Save the ringtone file - this will overwrite the file */
256 /* Confirming must be done before this is called */
257 GSM_Error GSM_SaveRingtoneFile(char *FileName, GSM_Ringtone *ringtone)
262 file = fopen(FileName, "wb");
265 return(GE_CANTOPENFILE);
268 /* We need a way of passing these functions a filetype rather than rely on the extension */
269 if (strstr(FileName, ".ott")) {
270 error = saveott(file, ringtone);
272 error = saverttl(file, ringtone);
279 GSM_Error saveott(FILE *file, GSM_Ringtone *ringtone)
284 /* PackRingtone writes up to i chars and returns in i the number written */
285 GSM_PackRingtone(ringtone, Buffer, &i);
288 fwrite(Buffer, 1, i, file);
291 return GE_FILETOOLONG;
295 GSM_Error saverttl(FILE *file, GSM_Ringtone *ringtone)
297 int DefDuration, DefScale = 2, CurrentNote;
301 /* Saves ringtone name */
302 fprintf(file, "%s:", ringtone->name);
304 /* Find the most frequently used duration and use this for the default */
305 for (i = 0; i < 6; i++) buffer[i] = 0;
306 for (i = 0; i < ringtone->NrNotes; i++) {
307 switch (ringtone->notes[i].duration) {
335 /* Now find the most frequently used */
337 for (i = 0; i < 6; i++) {
344 /* Finally convert and save the default duration */
348 fprintf(file, "d=1,");
352 fprintf(file, "d=2,");
356 fprintf(file, "d=4,");
360 fprintf(file, "d=8,");
364 fprintf(file, "d=16,");
368 fprintf(file, "d=32,");
372 fprintf(file, "d=8,");
376 /* Find the most frequently used scale and use this for the default */
377 for (i = 0; i < 6; i++) buffer[i] = 0;
378 for (i = 0; i < ringtone->NrNotes; i++) {
379 if (ringtone->notes[i].note != 255) {
380 buffer[ringtone->notes[i].note/14]++;
384 for (i = 0; i < 6; i++) {
391 /* Save the default scale and tempo */
392 fprintf(file, "o=%i,", DefScale+4);
393 fprintf(file, "b=%i:", ringtone->tempo);
395 dprintf("DefNoteDuration=%d\n", DefDuration);
396 dprintf("DefNoteScale=%d\n", DefScale);
397 dprintf("Number of notes=%d\n",ringtone->NrNotes);
399 /* Now loop round for each note */
400 for (i = 0; i < ringtone->NrNotes; i++) {
401 CurrentNote = ringtone->notes[i].note;
403 /* This note has a duration different than the default. We must save it */
404 if (ringtone->notes[i].duration != DefDuration) {
405 switch (ringtone->notes[i].duration) {
406 case 192: //192=128*1.5
407 fprintf(file, "1"); break;
409 fprintf(file, "1"); break;
411 fprintf(file, "2"); break;
413 fprintf(file, "2"); break;
415 fprintf(file, "4"); break;
417 fprintf(file, "4"); break;
418 case 24: //24=16*1.5;
419 fprintf(file, "8"); break;
421 fprintf(file, "8"); break;
423 fprintf(file, "16"); break;
425 fprintf(file, "16"); break;
427 fprintf(file, "32"); break;
429 fprintf(file, "32"); break;
435 /* Now save the actual note */
436 switch (GSM_GetNote(CurrentNote)) {
437 case Note_C :fprintf(file, "c"); break;
438 case Note_Cis:fprintf(file, "c#"); break;
439 case Note_D :fprintf(file, "d"); break;
440 case Note_Dis:fprintf(file, "d#"); break;
441 case Note_E :fprintf(file, "e"); break;
442 case Note_F :fprintf(file, "f"); break;
443 case Note_Fis:fprintf(file, "f#"); break;
444 case Note_G :fprintf(file, "g"); break;
445 case Note_Gis:fprintf(file, "g#"); break;
446 case Note_A :fprintf(file, "a"); break;
447 case Note_Ais:fprintf(file, "a#"); break;
448 case Note_H :fprintf(file, "h"); break;
449 default :fprintf(file, "p"); break; //Pause ?
452 /* Saving info about special duration */
453 if (ringtone->notes[i].duration == 128 * 1.5 ||
454 ringtone->notes[i].duration == 64 * 1.5 ||
455 ringtone->notes[i].duration == 32 * 1.5 ||
456 ringtone->notes[i].duration == 16 * 1.5 ||
457 ringtone->notes[i].duration == 8 * 1.5 ||
458 ringtone->notes[i].duration == 4 * 1.5)
461 /* This note has a scale different than the default, so save it */
462 if ( (CurrentNote != 255) && (CurrentNote/14 != DefScale))
463 fprintf(file, "%i",(CurrentNote/14) + 4);
465 /* And a separator before next note */
466 if (i!=ringtone->NrNotes - 1)
474 /* Bitmap file functions */
475 /* ##################### */
477 GSM_Error GSM_ReadBitmapFile(char *FileName, GSM_Bitmap *bitmap)
481 unsigned char buffer[300];
483 GSM_Filetypes filetype = None;
485 file = fopen(FileName, "rb");
488 return(GE_CANTOPENFILE);
490 fread(buffer, 1, 9, file); /* Read the header of the file. */
492 /* Attempt to identify filetype */
494 if (memcmp(buffer, "NOL", 3) == 0) { /* NOL files have 'NOL' at the start */
496 } else if (memcmp(buffer, "NGG", 3) == 0) { /* NGG files have 'NGG' at the start */
498 } else if (memcmp(buffer, "FORM", 4) == 0) { /* NSL files have 'FORM' at the start */
500 } else if (memcmp(buffer, "NLM", 3) == 0) { /* NLM files have 'NLM' at the start */
502 } else if (memcmp(buffer, "BM", 2) == 0) { /* BMP, I61 and GGP files have 'BM' at the start */
504 } else if (memcmp(buffer, "/* XPM */", 9) == 0) { /* XPM files have 'XPM' at the start */
506 } else filetype = None;
508 if (strstr(FileName, ".otb")) filetype = OTA; /* OTA files saved by NCDS3 */
515 error = loadnol(file, bitmap);
519 error = loadngg(file, bitmap);
523 error = loadnsl(file, bitmap);
527 error = loadnlm(file, bitmap);
531 error = loadota(file, bitmap);
535 error = loadbmp(file, bitmap);
541 error = loadxpm(FileName, bitmap);
545 error = GE_INVALIDFILEFORMAT;
555 GSM_Error loadxpm(char *filename, GSM_Bitmap *bitmap)
561 error = XpmReadFileToXpmImage(filename, &image, &info);
564 case XpmColorError: return GE_WRONGCOLORS; break;
565 case XpmColorFailed: return GE_WRONGCOLORS; break;
566 case XpmOpenFailed: return GE_CANTOPENFILE; break;
567 case XpmFileInvalid: return GE_INVALIDFILEFORMAT; break;
568 case XpmSuccess: break;
572 if (image.ncolors != 2) return GE_WRONGNUMBEROFCOLORS;
574 /* All xpms are loaded as startup logos - but can be resized later */
576 bitmap->type = GSM_StartupLogo;
578 bitmap->height = image.height;
579 bitmap->width = image.width;
580 bitmap->size = ((bitmap->height / 8) + (bitmap->height % 8 > 0)) * bitmap->width;
582 if (bitmap->size > GSM_MAX_BITMAP_SIZE) {
583 fprintf(stdout, "Bitmap too large\n");
584 return GE_INVALIDIMAGESIZE;
587 GSM_ClearBitmap(bitmap);
589 for(y = 0; y < image.height; y++) {
590 for(x = 0; x < image.width; x++) {
591 if (image.data[y * image.width + x] == 0) GSM_SetPointBitmap(bitmap, x, y);
601 /* Based on the article from the Polish Magazine "Bajtek" 11/92 */
602 /* Marcin-Wiacek@Topnet.PL */
604 /* This loads the image as a startup logo - but is resized as necessary later */
606 GSM_Error loadbmp(FILE *file, GSM_Bitmap *bitmap)
608 unsigned char buffer[34];
610 int w, h, pos, y, x, i, sizeimage;
612 bitmap->type = GSM_StartupLogo;
615 bitmap->size = bitmap->width * bitmap->height / 8;
617 GSM_ClearBitmap(bitmap);
619 fread(buffer, 1, 34, file); //required part of header
621 h = buffer[22] + 256 * buffer[21]; //height of image in the file
622 w = buffer[18] + 256 * buffer[17]; //width of image in the file
623 dprintf("Image Size in BMP file: %dx%d\n", w, h);
625 dprintf("Number of colors in BMP file: ");
626 switch (buffer[28]) {
627 case 1: dprintf("2 (supported by gnokii)\n"); break;
628 case 4: dprintf("16 (not supported by gnokii)\n"); break;
629 case 8: dprintf("256 (not supported by gnokii)\n"); break;
630 case 24: dprintf("True Color (not supported by gnokii)\n"); break;
631 default: dprintf("unknown\n"); break;
634 if (buffer[28] != 1) {
635 fprintf(stdout, "Wrong number of colors\n"); //we support only 2 colors images !
636 return GE_WRONGNUMBEROFCOLORS;
639 dprintf("Compression in BMP file: ");
640 switch (buffer[30]) {
641 case 0: dprintf("no compression (supported by gnokii)\n"); break;
642 case 1: dprintf("RLE8 (not supported by gnokii)\n"); break;
643 case 2: dprintf("RLE4 (not supported by gnokii)\n"); break;
644 default: dprintf("unknown\n"); break;
647 if (buffer[30] != 0) {
648 dprintf("Subformat not supported\n"); //we don't support RLE compression
649 return GE_SUBFORMATNOTSUPPORTED;
652 pos = buffer[10] - 34;
653 fread(buffer, 1, pos, file); //rest of header (if exists) and color palette
655 dprintf("First color in BMP file: %i %i %i ", buffer[pos-8], buffer[pos-7], buffer[pos-6]);
656 if (buffer[pos-8] == 0 && buffer[pos-7] == 0 && buffer[pos-6] == 0) dprintf("(white)");
657 if (buffer[pos-8] == 0xFF && buffer[pos-7] == 0xFF && buffer[pos-6] == 0xFF) dprintf("(black)");
658 if (buffer[pos-8] == 102 && buffer[pos-7] == 204 && buffer[pos-6] == 102) dprintf("(green)");
661 dprintf("Second color in BMP file: %i %i %i ",buffer[pos-4], buffer[pos-3], buffer[pos-2]);
662 if (buffer[pos-4] == 0 && buffer[pos-3] == 0 && buffer[pos-2] == 0) dprintf("(white)");
663 if (buffer[pos-4] == 0xFF && buffer[pos-3] == 0xFF && buffer[pos-2] == 0xFF) dprintf("(black)");
667 if (buffer[pos-8] != 0 || buffer[pos-7] != 0 || buffer[pos-6] != 0) first_white = false;
671 for (y = h-1; y >= 0; y--) { //lines are written from the last to the first
673 for (x = 0; x < w; x++) {
674 if (pos == 7) { //new byte !
675 fread(buffer, 1, 1, file);
678 if (i == 5) i = 1; //each line is written in multiply of 4 bytes
680 if (x <= bitmap->width && y <= bitmap->height) { //we have top left corner !
682 if ((buffer[0] & (1 << pos)) <= 0) GSM_SetPointBitmap(bitmap, x, y);
684 if ((buffer[0] & (1 << pos)) > 0) GSM_SetPointBitmap(bitmap, x, y);
688 if (pos < 0) pos = 7; //going to new byte
690 pos = 7; //going to new byte
691 while (i != 5) { //each line is written in multiples of 4 bytes
692 fread(buffer, 1, 1, file);
697 dprintf("Data size in BMP file: %i\n", sizeimage);
701 GSM_Error loadnol(FILE *file, GSM_Bitmap *bitmap)
703 unsigned char buffer[2000];
706 bitmap->type = GSM_OperatorLogo;
708 fread(buffer, 1, 6, file);
709 fread(buffer, 1, 4, file);
710 sprintf(bitmap->netcode, "%d %02d", buffer[0] + 256 * buffer[1], buffer[2]);
712 fread(buffer, 1, 4, file); /* Width and height of the icon. */
713 bitmap->width = buffer[0];
714 bitmap->height = buffer[2];
715 bitmap->size = bitmap->height * bitmap->width / 8;
717 if ((bitmap->height != 14) || (bitmap->width != 72)) {
718 dprintf("Invalid Image Size (%dx%d).\n",bitmap->width,bitmap->height);
719 return GE_INVALIDIMAGESIZE;
722 fread(buffer, 1, 6, file); /* Unknown bytes. */
724 for (i = 0; i < bitmap->size; i++) {
725 if (fread(buffer, 1, 8, file) == 8) {
726 bitmap->bitmap[i] = 0;
727 for (j = 7; j >= 0; j--)
728 if (buffer[7-j] == '1')
729 bitmap->bitmap[i] |= (1 << j);
731 return(GE_FILETOOSHORT);
735 /* Some programs writes here fileinfo */
736 if (fread(buffer, 1, 1, file) == 1) {
737 dprintf("Fileinfo: %c", buffer[0]);
738 while (fread(buffer, 1, 1, file) == 1) {
739 if (buffer[0] != 0x0A) dprintf("%c",buffer[0]);
746 GSM_Error loadngg(FILE *file, GSM_Bitmap *bitmap)
748 unsigned char buffer[2000];
751 bitmap->type = GSM_CallerLogo;
753 fread(buffer, 1, 6, file);
754 fread(buffer, 1, 4, file); /* Width and height of the icon. */
755 bitmap->width = buffer[0];
756 bitmap->height = buffer[2];
757 bitmap->size = bitmap->height * bitmap->width / 8;
759 if ((bitmap->height != 14) || (bitmap->width != 72)) {
760 dprintf("Invalid Image Size (%dx%d).\n", bitmap->width, bitmap->height);
761 return GE_INVALIDIMAGESIZE;
764 fread(buffer, 1, 6, file); /* Unknown bytes. */
766 for (i = 0; i < bitmap->size; i++) {
767 if (fread(buffer, 1, 8, file) == 8){
768 bitmap->bitmap[i] = 0;
769 for (j = 7; j >= 0;j--)
770 if (buffer[7-j] == '1')
771 bitmap->bitmap[i] |= (1 << j);
773 return(GE_FILETOOSHORT);
777 /* Some programs writes here fileinfo */
778 if (fread(buffer, 1, 1, file) == 1) {
779 dprintf("Fileinfo: %c",buffer[0]);
780 while (fread(buffer, 1, 1, file) == 1) {
781 if (buffer[0] != 0x0A) dprintf("%c", buffer[0]);
788 GSM_Error loadnsl(FILE *file, GSM_Bitmap *bitmap)
790 unsigned char block[6], buffer[505];
795 while (fread(block, 1, 6, file) == 6) {
796 block_size = block[4] * 256 + block[5];
797 dprintf("Block %c%c%c%c, size %i\n", block[0], block[1], block[2], block[3], block_size);
798 if (!strncmp(block, "FORM", 4)) {
799 dprintf(" File ID\n");
801 if (block_size > 504) return(GE_INVALIDFILEFORMAT);
803 if (block_size != 0) {
805 fread(buffer, 1, block_size, file);
806 buffer[block_size] = 0; //if it's string, we end it with \0
808 if (!strncmp(block, "VERS", 4)) dprintf(" File saved by: %s\n", buffer);
809 if (!strncmp(block, "MODL", 4)) dprintf(" Logo saved from: %s\n", buffer);
810 if (!strncmp(block, "COMM", 4)) dprintf(" Phone was connected to COM port: %s\n", buffer);
812 if (!strncmp(block, "NSLD", 4)) {
813 bitmap->type = GSM_StartupLogo;
816 bitmap->size = (bitmap->height * bitmap->width) / 8;
818 memcpy(bitmap->bitmap, buffer, bitmap->size);
820 dprintf(" Startup logo (size %i)\n", block_size);
825 if (bitmap->size == 0) return(GE_FILETOOSHORT);
829 GSM_Error loadnlm (FILE *file, GSM_Bitmap *bitmap)
831 unsigned char buffer[84*48];
835 fread(buffer, 1, 5, file);
836 fread(buffer, 1, 1, file);
840 bitmap->type = GSM_OperatorLogo;
843 bitmap->type = GSM_CallerLogo;
846 bitmap->type = GSM_StartupLogo;
849 bitmap->type = GSM_PictureImage;
852 return(GE_SUBFORMATNOTSUPPORTED);
855 fread(buffer, 1, 4, file);
856 bitmap->width = buffer[1];
857 bitmap->height = buffer[2];
858 bitmap->size = bitmap->width * bitmap->height / 8;
860 division = div(bitmap->width, 8);
861 if (division.rem != 0) division.quot++; /* For startup logos */
863 if (fread(buffer, 1, (division.quot * bitmap->height), file) != (division.quot * bitmap->height))
864 return(GE_FILETOOSHORT);
866 GSM_ClearBitmap(bitmap);
869 for (y = 0; y < bitmap->height; y++) {
870 for (x = 0; x < bitmap->width; x++) {
871 if ((buffer[pos] & (1 << pos2)) > 0) GSM_SetPointBitmap(bitmap, x, y);
873 if (pos2 < 0) {pos2 = 7; pos++;} //going to new byte
875 if (pos2 != 7) {pos2 = 7; pos++;} //for startup logos-new line means new byte
880 GSM_Error loadota(FILE *file, GSM_Bitmap *bitmap)
884 /* We could check for extended info here - indicated by the 7th bit being set in the first byte */
885 fread(buffer,1,4,file);
887 bitmap->width = buffer[1];
888 bitmap->height = buffer[2];
889 bitmap->size = bitmap->width * bitmap->height / 8;
891 if ((bitmap->height == 48) && (bitmap->width == 84)) {
892 bitmap->type = GSM_StartupLogo;
894 else if ((bitmap->height == 14) && (bitmap->width == 72)) {
895 bitmap->type = GSM_CallerLogo;
897 dprintf("Invalid Image Size (%dx%d).\n", bitmap->width, bitmap->height);
898 return GE_INVALIDIMAGESIZE;
900 if (fread(bitmap->bitmap,1,bitmap->size,file) != bitmap->size)
901 return(GE_FILETOOSHORT);
905 /* This overwrites an existing file - so this must be checked before calling */
906 GSM_Error GSM_SaveBitmapFile(char *FileName, GSM_Bitmap *bitmap)
911 /* XPMs are a bit messy because we have to pass it the filename */
914 if (strstr(FileName, ".xpm")) {
915 savexpm(FileName, bitmap);
919 file = fopen(FileName, "wb");
922 return(GE_CANTOPENFILE);
924 if (strstr(FileName, ".nlm")) {
925 savenlm(file, bitmap);
928 if (strstr(FileName, ".ngg")) {
929 savengg(file, bitmap);
932 if (strstr(FileName, ".nsl")) {
933 savensl(file, bitmap);
936 if (strstr(FileName, ".otb")) {
937 saveota(file, bitmap);
940 if (strstr(FileName, ".nol")) {
941 savenol(file, bitmap);
944 if (strstr(FileName, ".bmp") ||
945 strstr(FileName, ".ggp") ||
946 strstr(FileName, ".i61")) {
947 savebmp(file, bitmap);
952 switch (bitmap->type) {
954 savengg(file, bitmap);
956 case GSM_OperatorLogo:
957 savenol(file, bitmap);
959 case GSM_StartupLogo:
960 savensl(file, bitmap);
962 case GSM_PictureImage:
963 savenlm(file, bitmap);
965 case GSM_WelcomeNoteText:
967 case GSM_DealerNoteText:
981 /* FIXME - this should not ask for confirmation here - I'm not sure what calls it though */
982 /* mode == 0 -> overwrite
984 * mode == 2 -> append
986 int GSM_SaveTextFile(char *FileName, char *text, int mode)
993 /* Ask before overwriting */
994 if ((mode == 1) && (stat(FileName, &buf) == 0)) {
995 fprintf(stdout, _("File %s exists.\n"), FileName);
996 while (confirm < 0) {
997 fprintf(stderr, _("Overwrite? (yes/no) "));
998 GetLine(stdin, ans, 4);
999 if (!strcmp(ans, _("yes"))) confirm = 1;
1000 else if (!strcmp(ans, _("no"))) confirm = 0;
1002 if (!confirm) return -1;
1005 if (mode == 2) file = fopen(FileName, "a");
1006 else file = fopen(FileName, "w");
1009 fprintf(stderr, _("Failed to write file %s\n"), FileName);
1012 fprintf(file, "%s\n", text);
1019 void savexpm(char *filename, GSM_Bitmap *bitmap)
1021 XpmColor colors[2] = {{".","c","#000000","#000000","#000000","#000000"},
1022 {"#","c","#ffffff","#ffffff","#ffffff","#ffffff"}};
1024 unsigned int data[6240];
1027 image.height = bitmap->height;
1028 image.width = bitmap->width;
1031 image.colorTable = colors;
1034 for (y = 0; y < image.height; y++) {
1035 for (x = 0; x < image.width; x++)
1036 if (GSM_IsPointBitmap(bitmap, x, y))
1037 data[y * image.width + x] = 0;
1039 data[y * image.width + x] = 1;
1042 XpmWriteFileFromXpmImage(filename, &image, NULL);
1046 /* Based on the article from the Polish Magazine "Bajtek" 11/92 */
1047 /* Marcin-Wiacek@Topnet.PL */
1048 void savebmp(FILE *file, GSM_Bitmap *bitmap)
1050 int x, y, pos, i, sizeimage;
1051 unsigned char buffer[1];
1055 /*1'st header*/ 'B','M', /* BMP file ID */
1056 0x00,0x00,0x00,0x00, /* Size of file */
1057 0x00,0x00, /* Reserved for future use */
1058 0x00,0x00, /* Reserved for future use */
1059 62,0x00,0x00,0x00, /* Offset for image data */
1061 /*2'nd header*/ 40,0x00,0x00,0x00, /* Length of this part of header */
1062 0x00,0x00,0x00,0x00, /* Width of image */
1063 0x00,0x00,0x00,0x00, /* Height of image */
1064 1,0x00, /* How many planes in target device */
1065 1,0x00, /* How many colors in image. 1 means 2^1=2 colors */
1066 0x00,0x00,0x00,0x00, /* Type of compression. 0 means no compression */
1067 /*Sometimes */ 0x00,0x00,0x00,0x00, /* Size of part with image data */
1068 /*ttttttt...*/ 0xE8,0x03,0x00,0x00, /* XPelsPerMeter */
1069 /*hhiiiiissss*/ 0xE8,0x03,0x00,0x00, /* YPelsPerMeter */
1070 /*part of header*/2,0x00,0x00,0x00, /* How many colors from palette is used */
1071 /*doesn't exist*/ 0x00,0x00,0x00,0x00, /* How many colors from palette is required to display image. 0 means all */
1073 /*Color palette*/ 0x00,0x00,0x00, /* First color in palette in Blue, Green, Red. Here white */
1074 0x00, /* Each color in palette is end by 4'th byte */
1075 0xFF,0xFF,0xFF, /* Second color in palette in Blue, Green, Red. Here black */
1076 0x00}; /* Each color in palette is end by 4'th byte */
1078 header[22] = bitmap->height;
1079 header[18] = bitmap->width;
1083 for (y = bitmap->height - 1; y >= 0; y--) { //lines are written from the last to the first
1085 for (x = 0; x < bitmap->width; x++) {
1086 if (pos == 7) { //new byte !
1089 if (i == 5) i = 1; //each line is written in multiply of 4 bytes
1092 if (pos < 0) pos = 7; //going to new byte
1094 pos = 7; //going to new byte
1095 while (i != 5) { //each line is written in multiply of 4 bytes
1100 dprintf("Data size in BMP file: %i\n", sizeimage);
1101 division = div(sizeimage, 256);
1102 header[35] = division.quot;
1103 header[34] = sizeimage - (division.quot * 256);
1105 sizeimage = sizeimage + sizeof(header);
1106 dprintf("Size of BMP file: %i\n", sizeimage);
1107 division = div(sizeimage, 256);
1108 header[3] = division.quot;
1109 header[2] = sizeimage - (division.quot * 256);
1111 fwrite(header, 1, sizeof(header), file);
1114 for (y = bitmap->height - 1; y >= 0; y--) { //lines are written from the last to the first
1116 for (x = 0; x < bitmap->width; x++) {
1117 if (pos == 7) { //new byte !
1118 if (x != 0) fwrite(buffer, 1, sizeof(buffer), file);
1120 if(i == 5) i = 1; //each line is written in multiply of 4 bytes
1123 if (GSM_IsPointBitmap(bitmap, x, y)) buffer[0] |= (1 << pos);
1125 if (pos < 0) pos = 7; //going to new byte
1127 pos = 7; //going to new byte
1128 fwrite(buffer, 1, sizeof(buffer), file);
1129 while (i != 5) { //each line is written in multiply of 4 bytes
1131 fwrite(buffer, 1, sizeof(buffer), file);
1137 void savengg(FILE *file, GSM_Bitmap *bitmap)
1140 char header[] = {'N','G','G',0x00,0x01,0x00,
1141 0x00,0x00, /* Width */
1142 0x00,0x00, /* Height */
1143 0x01,0x00,0x01,0x00,
1144 0x00, /* Unknown.Can't be checksum - for */
1145 /* the same logo files can be different */
1150 /* This could be the phone info... */
1151 GSM_Information info={"",0,0,0,0,0,0,0,0,0,0,0,0,0,14,72};
1153 GSM_ResizeBitmap(bitmap, GSM_CallerLogo, &info);
1155 header[6] = bitmap->width;
1156 header[8] = bitmap->height;
1158 fwrite(header, 1, sizeof(header), file);
1160 for (i = 0; i < bitmap->size; i++) {
1161 for (j = 7; j >= 0;j--)
1162 if ((bitmap->bitmap[i] & (1 << j)) > 0) {
1167 fwrite(buffer, 1, 8, file);
1171 void savenol(FILE *file, GSM_Bitmap *bitmap)
1174 char header[] = {'N','O','L',0x00,0x01,0x00,
1175 0x00,0x00, /* MCC */
1176 0x00,0x00, /* MNC */
1177 0x00,0x00, /* Width */
1178 0x00,0x00, /* Height */
1179 0x01,0x00,0x01,0x00,
1180 0x00, /* Unknown.Can't be checksum - for */
1181 /* the same logo files can be different */
1184 int i, j, country, net;
1185 /* This could be the phone info... */
1186 GSM_Information info={"",0,0,0,0,0,0,0,0,0,0,0,14,72,0,0};
1188 GSM_ResizeBitmap(bitmap, GSM_OperatorLogo, &info);
1190 sscanf(bitmap->netcode, "%d %d", &country, &net);
1192 header[6] = country % 256;
1193 header[7] = country / 256;
1194 header[8] = net % 256;
1195 header[9] = net / 256;
1196 header[10] = bitmap->width;
1197 header[12] = bitmap->height;
1199 fwrite(header, 1, sizeof(header), file);
1201 for (i = 0; i < bitmap->size; i++) {
1202 for (j = 7; j >= 0; j--)
1203 if ((bitmap->bitmap[i] & (1 << j)) > 0) {
1208 fwrite(buffer, 1, 8, file);
1212 void savensl(FILE *file, GSM_Bitmap *bitmap)
1215 u8 header[] = {'F','O','R','M', 0x01,0xFE, /* File ID block, size 1*256+0xFE=510*/
1216 'N','S','L','D', 0x01,0xF8}; /* Startup Logo block, size 1*256+0xF8=504*/
1217 /* This could be the phone info... */
1218 GSM_Information info={"",0,0,0,0,0,0,0,0,0,48,84,0,0,0,0};
1220 GSM_ResizeBitmap(bitmap, GSM_StartupLogo, &info);
1222 fwrite(header, 1, sizeof(header), file);
1224 fwrite(bitmap->bitmap, 1, bitmap->size, file);
1227 void saveota(FILE *file, GSM_Bitmap *bitmap)
1229 char header[] = {0x01,
1234 header[1] = bitmap->width;
1235 header[2] = bitmap->height;
1237 fwrite(header, 1, sizeof(header), file);
1239 fwrite(bitmap->bitmap, 1, bitmap->size, file);
1242 void savenlm(FILE *file, GSM_Bitmap *bitmap)
1244 char header[] = {'N','L','M', /* Nokia Logo Manager file ID. */
1247 0x00, /* 0x00 (OP), 0x01 (CLI), 0x02 (Startup), 0x03 (Picture)*/
1253 unsigned char buffer[11 * 48];
1254 int x, y, pos, pos2;
1257 switch (bitmap->type) {
1258 case GSM_OperatorLogo:
1261 case GSM_CallerLogo:
1264 case GSM_StartupLogo:
1267 case GSM_PictureImage:
1270 case GSM_WelcomeNoteText:
1272 case GSM_DealerNoteText:
1278 header[7] = bitmap->width;
1279 header[8] = bitmap->height;
1282 for (y = 0; y < bitmap->height; y++) {
1283 for (x = 0; x < bitmap->width; x++) {
1284 if (pos2 == 7) buffer[pos] = 0;
1285 if (GSM_IsPointBitmap(bitmap, x, y)) buffer[pos] |= (1 << pos2);
1287 if (pos2 < 0) {pos2 = 7; pos++;} //going to new line
1289 if (pos2 != 7) {pos2 = 7; pos++;} //for startup logos - new line with new byte
1292 division = div(bitmap->width, 8);
1293 if (division.rem != 0) division.quot++; /* For startup logos */
1295 fwrite(header, 1, sizeof(header), file);
1297 fwrite(buffer,1,(division.quot*bitmap->height),file);
1300 GSM_Error GSM_ShowBitmapFile(char *FileName)
1303 unsigned char buffer[300];
1305 GSM_Filetypes filetype = None;
1309 file = fopen(FileName, "rb");
1312 return (GE_CANTOPENFILE);
1314 fread(buffer, 1, 9, file);
1316 if (memcmp(buffer, "NOL", 3) == 0) {
1318 } else if (memcmp(buffer, "NGG", 3) == 0) {
1320 } else if (memcmp(buffer, "FORM", 4) == 0) {
1322 } else if (memcmp(buffer, "NLM", 3) == 0) {
1324 } else if (memcmp(buffer, "BM", 2) == 0) {
1326 } else if (memcmp(buffer, "XPM", 3) == 0) {
1328 } else filetype = None;
1330 if (strstr(FileName, ".otb")) filetype = OTA;
1336 error = loadnol(file, &bitmap);
1340 error = loadngg(file, &bitmap);
1344 error = loadnsl(file, &bitmap);
1348 error = loadota(file, &bitmap);
1352 error = loadbmp(file, &bitmap);
1358 error = loadxpm(FileName, &bitmap);
1362 error = GE_INVALIDFILEFORMAT;
1366 if (error != GE_NONE)
1369 for (i = 0; i < bitmap.size; i++) {
1372 for (j = 7; j >= 0; j--) {
1373 if ((bitmap.bitmap[i] & (1 << j))) {
1374 fprintf(stdout, "#");
1376 fprintf(stdout, " ");
1378 if (!(++k % bitmap.width))
1379 fprintf(stdout, "\n");