# define BF_TYPE 0x4D42 /* "MB" */ void write_word(FILE *f, WORD word) { fwrite(&word,sizeof(WORD),1,f); } void write_dword(FILE *f, DWORD dword) { fwrite(&dword,sizeof(DWORD),1,f); } void write_long(FILE *f, LONG word) { fwrite(&word,sizeof(LONG),1,f); } int /* O - 0 = success, -1 = failure */ SaveDIBitmap(const char *filename, /* I - File to load */ BITMAPINFO *info, /* I - Bitmap information */ void *bits) /* I - Bitmap data */ { FILE *fp; /* Open file pointer */ int size, /* Size of file */ infosize, /* Size of bitmap info */ bitsize; /* Size of bitmap pixels */ /* Try opening the file; use "wb" mode to write this *binary* file. */ if ((fp = fopen(filename, "wb")) == NULL) return (-1); /* Figure out the bitmap size */ if (info->bmiHeader.biSizeImage == 0) bitsize = (info->bmiHeader.biWidth * info->bmiHeader.biBitCount + 7) / 8 * abs(info->bmiHeader.biHeight); else bitsize = info->bmiHeader.biSizeImage; /* Figure out the header size */ infosize = sizeof(BITMAPINFOHEADER); switch (info->bmiHeader.biCompression) { case BI_BITFIELDS : infosize += 12; /* Add 3 RGB doubleword masks */ if (info->bmiHeader.biClrUsed == 0) break; case BI_RGB : if (info->bmiHeader.biBitCount > 8 && info->bmiHeader.biClrUsed == 0) break; case BI_RLE8 : case BI_RLE4 : if (info->bmiHeader.biClrUsed == 0) infosize += (1 << info->bmiHeader.biBitCount) * 4; else infosize += info->bmiHeader.biClrUsed * 4; break; } size = sizeof(BITMAPFILEHEADER) + infosize + bitsize; /* Write the file header, bitmap information, and bitmap pixel data... */ write_word(fp, BF_TYPE); /* bfType */ write_dword(fp, size); /* bfSize */ write_word(fp, 0); /* bfReserved1 */ write_word(fp, 0); /* bfReserved2 */ write_dword(fp, 14 + infosize); /* bfOffBits */ write_dword(fp, info->bmiHeader.biSize); write_long(fp, info->bmiHeader.biWidth); write_long(fp, info->bmiHeader.biHeight); write_word(fp, info->bmiHeader.biPlanes); write_word(fp, info->bmiHeader.biBitCount); write_dword(fp, info->bmiHeader.biCompression); write_dword(fp, info->bmiHeader.biSizeImage); write_long(fp, info->bmiHeader.biXPelsPerMeter); write_long(fp, info->bmiHeader.biYPelsPerMeter); write_dword(fp, info->bmiHeader.biClrUsed); write_dword(fp, info->bmiHeader.biClrImportant); if (infosize > 40) if (fwrite(info->bmiColors, infosize - 40, 1, fp) < 1) { /* Couldn't write the bitmap header - return... */ fclose(fp); return (-1); } if (fwrite(bits, 1, bitsize, fp) < bitsize) { /* Couldn't write the bitmap - return... */ fclose(fp); return (-1); } /* OK, everything went fine - return... */ fclose(fp); return (0); } void Conv89iToBmp(char *source, char *dest) { FILE *f; BITMAPINFO binfo; ECRAN *ecr, ecrCourant; int tailleX, tailleY, reelleTailleX, temp1, temp2, x, y, offset; f=fopen(source,"rb"); if (!f) return; fseek(f, 0x58, SEEK_SET); temp1=fgetc(f); temp2=fgetc(f); tailleY=(temp1<<8)+temp2; temp1=fgetc(f); temp2=fgetc(f); reelleTailleX=(temp1<<8)+temp2; //Arrondir aux 8 supérieur if (reelleTailleX&7) tailleX=(reelleTailleX+8)&~7; else tailleX=reelleTailleX; offset=(tailleX-reelleTailleX)/2; //Pour centrer en X EcranCourant(&ecrCourant); ecr=CreeEcran(tailleX,tailleY); ChoisitEcran(ecr); EffaceEcran(255); for (y=0;ybiSize != sizeof(BITMAPCOREHEADER)) { if (lpbi->biClrUsed != 0) return (WORD)lpbi->biClrUsed; bits = lpbi->biBitCount; } else bits = lpbc->bcBitCount; switch (bits) { case 1: return 2; case 4: return 16; case 8: return 256; default: /* A 24 bitcount DIB has no color table */ return 0; } } WORD PaletteSize (VOID FAR *pv) { LPBITMAPINFOHEADER lpbi; WORD NumColors; lpbi = (LPBITMAPINFOHEADER)pv; NumColors = DibNumColors(lpbi); if (lpbi->biSize == sizeof(BITMAPCOREHEADER)) return NumColors * sizeof(RGBTRIPLE); else return NumColors * sizeof(RGBQUAD); } #define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4) DWORD BytesPerLine( LPBITMAPINFOHEADER lpBMIH ) { return WIDTHBYTES(lpBMIH->biWidth * lpBMIH->biPlanes * lpBMIH->biBitCount); } LPSTR FindDIBBits( LPSTR lpbi ) { return ( lpbi + *(LPDWORD)lpbi + PaletteSize( lpbi ) ); } LPBYTE ReadBMPFile( LPCTSTR szFileName ) { HANDLE hFile; BITMAPFILEHEADER bfh; DWORD dwBytes; LPBYTE lpDIB = NULL, lpTemp = NULL; WORD wPaletteSize = 0; DWORD dwBitsSize = 0; // Open the file if( (hFile=CreateFile( szFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE ) { MessageBox( NULL, "Error opening file", szFileName, MB_OK ); return NULL; } // Read the header if( ( ! ReadFile( hFile, &bfh, sizeof(BITMAPFILEHEADER), &dwBytes, NULL ) ) || ( dwBytes != sizeof( BITMAPFILEHEADER ) ) ) { CloseHandle( hFile ); MessageBox( NULL, "Error reading file", szFileName, MB_OK ); return NULL; } // Does it look like a BMP file? if( ( bfh.bfType != 0x4d42 ) || (bfh.bfReserved1!=0) || (bfh.bfReserved2!=0) ) { CloseHandle( hFile ); MessageBox( NULL, "Not a recognised BMP format file", szFileName, MB_OK ); return NULL; } // Allocate some memory if( (lpDIB = (unsigned char*)malloc( sizeof( BITMAPINFO ) )) == NULL ) { CloseHandle( hFile ); MessageBox( NULL, "Failed to allocate memory for DIB", szFileName, MB_OK ); return NULL; } // Read in the BITMAPINFOHEADER if( (!ReadFile( hFile, lpDIB, sizeof(BITMAPINFOHEADER), &dwBytes, NULL )) || (dwBytes!=sizeof(BITMAPINFOHEADER)) ) { CloseHandle( hFile ); free( lpDIB ); MessageBox( NULL, "Error reading file", szFileName, MB_OK ); return NULL; } if( ((LPBITMAPINFOHEADER)lpDIB)->biSize != sizeof( BITMAPINFOHEADER ) ) { CloseHandle( hFile ); free( lpDIB ); MessageBox( NULL, "OS/2 style BMPs Not Supported", szFileName, MB_OK ); return NULL; } // How big are the elements? wPaletteSize = PaletteSize((LPSTR)lpDIB); dwBitsSize = ((LPBITMAPINFOHEADER)lpDIB)->biHeight * BytesPerLine((LPBITMAPINFOHEADER)lpDIB); // realloc to account for the total size of the DIB if( (lpTemp = (unsigned char *)realloc( lpDIB, sizeof( BITMAPINFOHEADER ) + wPaletteSize + dwBitsSize )) == NULL ) { CloseHandle( hFile ); MessageBox( NULL, "Failed to allocate memory for DIB", szFileName, MB_OK ); free( lpDIB ); return NULL; } lpDIB = lpTemp; // If there is a color table, read it if( wPaletteSize != 0 ) { if( (!ReadFile( hFile, ((LPBITMAPINFO)lpDIB)->bmiColors, wPaletteSize, &dwBytes, NULL )) || (dwBytes!=wPaletteSize) ) { CloseHandle( hFile ); free( lpDIB ); MessageBox( NULL, "Error reading file", szFileName, MB_OK ); return NULL; } } // Seek to the bits // checking against 0 in case some bogus app didn't set this element if( bfh.bfOffBits != 0 ) { if( SetFilePointer( hFile, bfh.bfOffBits, NULL, FILE_BEGIN ) == 0xffffffff ) { CloseHandle( hFile ); free( lpDIB ); MessageBox( NULL, "Error reading file", szFileName, MB_OK ); return NULL; } } // Read the image bits if( (!ReadFile( hFile, FindDIBBits((LPSTR)lpDIB), dwBitsSize, &dwBytes, NULL )) || (dwBytes!=dwBitsSize) ) { CloseHandle( hFile ); free( lpDIB ); MessageBox( NULL, "Error reading file", szFileName, MB_OK ); return NULL; } // clean up CloseHandle( hFile ); return lpDIB; } char *ConvBmpTo89i(const char *fileName, const char *folderName, const char *destFile) { int a; char tempString[MAX_PATH], tempString2[MAX_PATH]; BITMAPINFO *bmpInfo; int largeur, hauteur, x,y, largBase; unsigned char *adr; bmpInfo=(BITMAPINFO*)ReadBMPFile(fileName); largeur=bmpInfo->bmiHeader.biWidth; hauteur=bmpInfo->bmiHeader.biHeight; if (largeur>240 || hauteur>128) return "Taille trop grosse (max 240x128)"; /* EffaceEcran(128); for (y=0;y>8; if (gray>=128) DessPix(x,y,BLANC); else DessPix(x,y,NOIR); } getch();*/ //Copy the filename to tempString and tempString2. sprintf(tempString, "%s",fileName); strcpy(tempString2, tempString); //Replace the .txt extension with .89p in tempString2. char *extension; /* Okay, if we got this far, there is no .89p with the same filename as our source .txt. tempString contains foldername/filename.txt still and is read from later. tempString2 is reuseable, its current value won't be used after this point. */ FILE *orig, *final; /* orig=fopen(tempString, "rt"); if (orig==NULL) { printf("Impossible d'ouvrir %s en écriture",tempString); return -1; }*/ //erase the extension on the filename, including the '.' (In preparation for writing the filename to the output .89t file) extension=strrchr(tempString,'.'); *extension=0; //Check the length of the filename sans extension to make sure it's legal for the TI-89. if (strlen(tempString)>8) { //skip files whose names are > 8 characters long, as those could not have been made by ToTxt, and I'd rather not truncate long filenames, for now. May change my mind later. return "Le nom est trop long (il ne doit pas excéder 8 caractères sans l'extension)"; } //Write the output filename ("../people/bob.89t" to continue our previous example) to tempString2. sprintf(tempString2, "%s", destFile); final=fopen(tempString2, "wb"); if (final==NULL) { return "Impossible d'ouvrir le fichier en écriture"; } //Write stuff out... See 89tformat.txt for file format info. fprintf(final,"%s","**TI92P*"); //**TI92** is also valid, and is what the old TI-89 graph-link software writes. fputc(0x01,final); fputc(0x00,final); //Write the folder name, and follow it with however many nulls is needed to fill 8 characters, if any. int slen=strlen(folderName); for (a=0; a41) { //Just in case... tempString2[41]=0; //If we put the null at 41, only the first 40 characters will be written. } fprintf(final,"%s",tempString2); for (a=slen; a<40; a++) { //buffer it with nulls fputc(0,final); } //Stuff that never changes 'cause there's only one variable in this .89t file fputc(0x01, final); fputc(0x00, final); fputc(0x52, final); fputc(0x00, final); fputc(0x00, final); fputc(0x00, final); //tempString still holds the filename sans extension. slen=strlen(tempString); //We did check the length earlier to make sure it wasn't > 8, so we don't need to check it again for (a=0; abmiColors; for (y=0;y>8; if (gray<128) octet|=cle; cle>>=1; } fputc(octet,final); checksum+=octet; } } /* fputc(0x00, final); fputc(0x01, final); //I've seen all sorts of stuff where we have 00 01, but 00 01 is most common, and I didn't find any rational pattern, although it sometimes seems related to the file size. The 0x20 is always there, though. I've tried always writing 00 01 and haven't seen any problems so far, so we'll keep doing that for now. checksum+=0x01; fputc(0x20, final); checksum+=0x20; //write text int lineStart=2; while (1) { int c=fgetc(orig); if (c==-1) { break; } else if (lineStart==2 && c==0x0c) { fputc(0xc, final); checksum+=0xc; lineStart=1; } else if (lineStart==2 && c==0x0e) { fputc(0x43, final); checksum+=0x43; lineStart=1; } else if (lineStart==2 && c==0x0f) { fputc(0x50, final); checksum+=0x50; lineStart=1; } else if (c==9) { //tab - I wonder if the TI-89 can handle tab characters... In any event, ToTxt does make them from leading spaces, and so it's no problem if that's where they occur. If they were after some text or something, though, they'd get changed to a space here and not changed back by ToTxt later, which might be annoying to some people. I would hope they would complain, if that's the case, though. Or modify the code to their liking, if they knew how (Ain't open-source great?). if (lineStart==2) { fputc(0x20, final); //Line type. checksum+=0x20; lineStart=1; } if (lineStart==1) { fputc(0x20, final); checksum+=0x20; } else { fputc(0x09, final); checksum+=0x09; } } else if (c=='\n') { //J'ai inversé l'ordre... fputc(0x0d, final); //You know, I really have no idea whether \n is 0x0a or 0x0d, but the TI-89 always wants 0x0d, so... :P // if (lineStart==2) { fputc(0x20, final); //Line type. checksum+=0x20; // } // fputc(0x0d, final); //You know, I really have no idea whether \n is 0x0a or 0x0d, but the TI-89 always wants 0x0d, so... :P checksum+=0x0d; lineStart=2; } else { // if (lineStart==2) { // fputc(0x20, final); //Line type. // checksum+=0x20; // } //We aren't going to bother to change back all the things ToTxt does. The readme says what symbols ToTxt changes to what text, by the way. fputc(c, final); checksum+=c; lineStart=0; } } */ fputc(0xDF, final); checksum+=0xDF; //write blank where checksum goes int checksumPos=ftell(final); fwrite(&blank, 2, 1, final); int filesize=ftell(final); fseek(final, 0x4c, SEEK_SET); //fwrite(&filesize, 4, 1, final); fputc(filesize&0xff, final); fputc((filesize>>8)&0xff, final); fputc((filesize>>16)&0xff, final); fputc((filesize>>24)&0xff, final); int textsize=filesize-0x5a; //this should give the correct result fseek(final, 0x56, SEEK_SET); fputc((textsize>>8)&0xff, final); fputc((textsize)&0xff, final); checksum+=(textsize&0xff)+((textsize>>8)&0xff); //write checksum fseek(final, checksumPos, SEEK_SET); fputc(checksum&0xff, final); fputc((checksum>>8)&0xff, final); //It seems that we can write the upper two bytes too, and the TI-89 doesn't complain. Heh. But it may not be healthy still, so we won't (I did try it, though, just to see). //fputc((checksum>>16)&0xff, final); //fputc((checksum>>24)&0xff, final); fclose(final); return NULL; }