Newsgroup: it.comp.lang.pascal
Titolo: Bagaglio pesante

-- Come portarsi dietro files. Scritto un sabato pomeriggio che
   la spiaggia no, Calcolo Numerico neanche --  ver 0.1
by Dreadnaut
Capita spesso (non so' se volentieri) di dover accompagnare altri file ai
nostri eseguibili, a volte semplicemente files e font BGI, altre volte dati.
Meno spesso, ma non di rado, vorremo che questi file non si perdessero
per il file system, ma possibilmente facessero parte dell'eseguibile stesso.
Come portarceli dietro ?
-- Piccoli file ( fino a 64kb) --
Assieme al tp7 viene un piccolo e malvagio tool chiamato binobj, che nessuno
degna mai di uno sguardo ma sta' li in \bin... questo programma permette di
trasformare un file qualunque (per tipo, non per dimensioni...) in un file
OBJ, cioe' `oggetto', che puo' essere linkato nell'eseguibile utilizzando la
direttiva {$L <nomefile>}  [ da non confondere con {$L +/-} ]
In teoria $L andrebbe usato per inserire blocchi eseguibili binari (a.e.
procedure scritte in asm), ma funziona benissimo anche per i files di dati !
In pratica si fa' cosi':
1) binobj <filedati> <fileoggetto.OBJ> <oggetto>
con questo comando convertiamo il nostro file di dati (speranzosamente
piccolo) in un file oggetto con estensione OBJ. Dato che in teoria il binobj
e' fatto per essere applicato a file contenenti codice, ci fornisce anche il
terzo parametro, che sara' l'identificatore con cui indicheremo il nostro
file all'interno del programma.
2)procedure <oggetto>; far; external; {$L <fileoggetto.OBJ>}
nel nostro codice linkiamo il file creato e prepariamo un riferimento ad
esso: <oggetto> sara' il nostro identificatore, e con @<oggetto> otterremo
la posizione in memoria dell'oggetto stesso, al quale potremo accedere come
facciamo per qualsiasi variabile in memoria. Ovviamente non ci sono
controlli sui puntatori, quindi superare la dimensione del nostro file ci
portera' dritti dritti a leggere (o peggio ancora a scrivere) in mezzo al
codice del programma.
[--- esempio
prendiamo un file info.txt di dimensione <size> e lo trasformiamo in
info.obj specificando che l'oggetto creato si chiami INFOTEXT.
Questo progr mostrera' l'intero contenuto del file che adesso si trova
all'interno dell'eseguibile... inserendo un qualche `marcatore' alla fine
del file txt si potrebbe rendere il programma indipendente da <size>
{$X+} { per l'es mi servono le operazioni sui puntatori }
procedure INFOTEXT; far; external;
{$L info.obj}
var
 c: ^char;
 n: word;
begin
 c := @INFOTEXT;
 for n := 1 to <size> do
  begin
   write(c^);
   inc(c);
  end;
end.
!! tentare di eseguire la procedura INFOTEXT
   piantera' sicuramente qualunque programma !!
---]
I files linkati in questo modo entreranno a far parte del segmento *codice*
del modulo (programma principale o unit) in cui sono linkati, senza influire
percio' sullo spazio riservato ai dati... ovvio che se il programma e' molto
complesso si rischia dal lato opposto di riempire il segmento codice e
beccarsi a link-time un bel "Error 48: code segment too large"
-- Font e driver BGI --
Questi file sono un caso particolare di file piccolo, in quanto la unit
graph ci mette a disposizione due procedure per portarceli dietro ed
utilizzarli senza doverli estrarre: RegisterBGIDriver e RegisterBGIFont.
Utilizzando binobj possiamo linkare il driver/font che ci interessa allo
eseguibile e `registrarlo' a run-time: verra' restituito un intero da
passare alla InitGraph/SetTextStyle per fare riferimento ad esso,
oppure la costante grInvalidDriver/Font se il file non e' di tipo corretto.
L'help del tp7 offre gia' qualche bella e densa pagina su queste due
funzioni e in piu' nella dir \examples\bgi c'e' un esempio completo
(bgilink.pas) dal quale prendere spunto [e codice], quindi mi sembra
inutile ricopiarli qua :-)
-- Grandi file ( piu' di 64kb) --
Tormentati dal problema dei segmenti e dei 64kb, non possiamo infilarli nel
codice, ne linkarli in alcun modo che ne preveda il caricamento in memoria.
Quindi non possiamo metterli nell'eseguibile... ma cos'e' un eseguibile ?
Il formato EXE e' un'estensione dei file COMpilati: a differenza di questi
un EXE non si compone semplicemente di codice che puo' venir caricato in
blocco ed eseguito, ma contiene un  header che ne specifica le richieste, il
metodo di caricamento in memoria e le dimensioni.  Le `dimensioni' ? eh si
 "offset 04-05:  Number of blocks in the file that are part of the EXE file"
E se noi aggiungessimo bytes all'eseguibile e non cambiassimo l'header ?
L'effetto e' che al caricamento soltanto la parte "prevista" dell'eseguibile
viene effettivamente caricata in memoria, mentre il resto rimane li, su
disco e non viene considerato.  File grandi (e per grandi intendo
GRANDI a piacere) possono venir comodamente accodati all'eseguibile
senza pregiudicarne il funzionamento: abbiamo trovato un modo per
portarci dietro dati !
- Problemi (e per quanto possibile, soluzioni)
a) accodare i dati all'eseguibile
beh questo e' facile... possiamo scrivere da noi un programma che lo faccia
ma il comando "copy" ci offre gia' questa feature:
 copy /b filea + fileb filec
costruisce il filec saldando assieme (/b se sono file binari) filea e fileb
b) accedere all'eseguibile per leggere i file
anche questo non e' difficile: ParamStr(0) ci ritorna il nome
dell'eseguibile.
La cosa piu' fastidiosa e' che i dati si trovano in fondo all'eseguibile, ma
per poterci accedere dobbiamo sapere quanto e' grosso l'exe senza dati
e codificarlo nell'exe stesso... cosi' ci mordiamo la coda e siamo costretti
a mettere una costante, compilare, poi modificarne il valore con la
dimensione dell'exe ottenuto, ricompilare... e questo ad ogni modifica del
sorgente... noiosetto :-)
Una soluzione e' lavorare al contrario sull'eseguibile: aggiungere un altro
header "in fondo" che contenga informazioni su come i dati sono attaccati
all'exe, ma sempre facendo riferimento alla fine del file invece che
all'inizio.
L'implementazione base di questo metodo e' molto semplice: basta scrivere
in fondo ai dati la dimensione dei dati stessi, e poi saldarli all'exe:
qualunque sia la dimensione dell'eseguibile (anche zero) e possibile
accedere ai dati con relativa facilita'.
0  { inzio file }
|  - eseguibile
<exesize> { fine eseguibile - inizio dati }
|  - dati
<exesize+datasize> { fine dati - inizio `header' }
| - datasize (4 byte)
Il nostro programma aprira' se stesso come file non tipato e record-size = 1
 [var f: file;]
 assign ( f, ParamStr(0) );
 reset ( f, 1 );
si posizionera' in fondo per leggere la dimensione dei dati
 [ var datasize: longint; ]
 seek ( f, filesize(f) - 4 );
 blockread ( f, datasize, 4 );
e a questo punto sapra' dove si trova l'inizio dei dati [e cioe' la
dimensione dell'eseguibile]
 [ var datastart: longint; ]
 datastart := filesize(f) - datasize - 4;
Cosi' risulta anche possibile lasciare i dati `fuori' dall'eseguibile mentre
si sta' lavorando su di esso semplicemente mettendo <nomefile> al
posto di `ParamStr(0)'.  Soltanto al momento della `distribuzione' del
programma lo si modifica in questo senso, poi si compila, si saldano i dati
e automaticamente il progr. si `riadatta' alla nuova dimensione del file
`ospite' senza ulteriori modifiche del codice.  Mettendo un header piu'
complesso in fondo al file (a.e. con una stringa di identificazione) si
potrebbe automatizzare la cosa:
 if <c'e' l'header in fondo all'exe>
  then <apri questo in lettura>
  else <apri un altro file esterno>
Poi si puo' ancora estendere in altri 200 modi: un finto filesystem dei
dati, crittazione, compressione... beh, tutto quel che si vuole :-)
[ un paio d'anni fa' ho sviluppato una libreria in C per questo formato che
  ho chiamato "backpak" (da buon informatico malato, un gioco di parole
  fra `zaino', `back' perche' parte dal fondo e i file `pak' di Quake da cui
  predevo spunto), se a qualcuno interessa non e' il miglior esempio di
  codice, pero' fa il suo dovere... ]
Topic nell'help del TP7
 RegisterBGIFont, RegisterBGIDriver, InitGraph,
 $L (Link Object File Directive),
 $X (Extended Syntax Switch - per chi non la usa gia')
Link & Search utili ( aka "Google e' tuo amico" )
 "exe file format"  (il `backpak' e il discorso del saldare dati in fondo
agli
  eseguibili valgono sia per eseguibili MZ che per PE)
 "Linkable Intel Object" (i files .OBJ)
-\eof\- 01/06/02 - (c) 2002, Dreadnaut production :-ţ
il contenuto di questo documento e da considerarsi esclusivamente
invenzione dell'autore, ogni riferimento a cose o persone realmente
esistenti e' puramente casuale e non voluto.

vero o no che Dreadnaut č meglio della guida in linea??
Cereal

pero' il giorno che premendo F1 mi teletrasportero' allora iniziero'
a preoccuparmi davvero :-)
--
Dreadnaut
(Life would be easier if I had the source code)


Consolati, io ho un prof che quando gli chiedi una cosa non la sa mai e
cerca sempre sull'help...
Alla fine ti aiuta ma ci mette mezzora per trovare la soluzione sull'help e
a memoria non la ricorda (anche se sono cacchiate).
Per questo lo chiamiamo F1 o help.
Quando premo F1 sulla tastiera a scuola me lo ritrovo sempre alle spalle ed
ho paura di premerlo quando sono a casa ancora arriva pure lě...
Pensa che il gattino di office quello della guida in linea l'ho sostituito
con una sua foto...
Cosě mi passa la voglia di premere F1...
Ciao
--
----------------------------------------
Carlo Camarda
chiamac...@tiscalinet.it
]@#[ Anna I Love You ]#@[

> Cosě mi passa la voglia di premere F1...
male male, l'help e' la base della conoscenza, penso si nato prima
della lingua parlata :-)
Pero' in effetti nel TP e' piu' utile premere Ctrl-F1 :-)


On Sat, 01 Jun 2002 17:14:10 GMT, "Dreadnaut"
<Drea...@liberoDALLASPAM.it> wrote:
e tu scrivi un post che non finisce + e poi dici che non hai tempo per
aprire ICQ?
Il Razziatore,
The Only Good Windows in an uninstalled Windows
-----------------------------------------------
E-MAILs : IlRazziat...@NOSPAMnetscape.net
WEB     : 
http://www.razziatore.dns2go.com/
ICQ     : 67552596

 con una sua foto...
come hai fatto a sostituire cn una foto???

 The Only Good Windows IS an uninstalled Windows
??
Ciao