diff options
author | Juan J. Martinez <jjm@usebox.net> | 2021-05-03 08:21:10 +0100 |
---|---|---|
committer | Juan J. Martinez <jjm@usebox.net> | 2021-05-03 10:00:00 +0100 |
commit | c3b0fa04a663fe233765b83d3be41a42aa08c25d (patch) | |
tree | 0befda349001ef6ce306b39378f9c70ad917363e /tools | |
download | return-of-traxtor-cpc-main.tar.gz return-of-traxtor-cpc-main.zip |
Diffstat (limited to 'tools')
79 files changed, 14033 insertions, 0 deletions
diff --git a/tools/2CDT/2cdt.cbp b/tools/2CDT/2cdt.cbp new file mode 100644 index 0000000..41deaf1 --- /dev/null +++ b/tools/2CDT/2cdt.cbp @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<CodeBlocks_project_file> + <FileVersion major="1" minor="4" /> + <Project> + <Option title="2cdt" /> + <Option makefile="makefile" /> + <Option pch_mode="0" /> + <Option compiler="gcc" /> + <Build> + <Target title="default"> + <Option output="C:\2cdt\2cdt.exe" /> + <Option type="1" /> + <Option compiler="gcc" /> + <Option parameters="-m 2 -r snake c:\blocks.bin c:\tester.cdt" /> + <Option includeInTargetAll="1" /> + <Option projectResourceIncludeDirsRelation="1" /> + </Target> + </Build> + <Compiler> + <Add option="-g" /> + </Compiler> + <Unit filename="src\2cdt.c"> + <Option compilerVar="CC" /> + <Option target="default" /> + </Unit> + <Unit filename="src\defs.h"> + <Option compilerVar="CC" /> + <Option compile="0" /> + <Option link="0" /> + <Option target="default" /> + </Unit> + <Unit filename="src\tzxfile.c"> + <Option compilerVar="CC" /> + <Option target="default" /> + </Unit> + <Unit filename="src\tzxfile.h"> + <Option compilerVar="CC" /> + <Option compile="0" /> + <Option link="0" /> + <Option target="default" /> + </Unit> + </Project> +</CodeBlocks_project_file>
\ No newline at end of file diff --git a/tools/2CDT/2cdt.depend b/tools/2CDT/2cdt.depend new file mode 100644 index 0000000..7427b7c --- /dev/null +++ b/tools/2CDT/2cdt.depend @@ -0,0 +1,22 @@ +# depslib dependency file v1.0
+1137940710 source:d:\www\download\2cdt\2cdt\src\tzxfile.c
+ <stdio.h>
+ <stdlib.h>
+ <memory.h>
+ "tzxfile.h"
+
+991048958 d:\www\download\2cdt\2cdt\src\tzxfile.h
+ "defs.h"
+
+1014464942 d:\www\download\2cdt\2cdt\src\defs.h
+
+1280219172 source:d:\www\download\2cdt\2cdt\src\2cdt.c
+ <stdio.h>
+ <stdlib.h>
+ <string.h>
+ <sys/io.h>
+ <io.h>
+ "defs.h"
+ "tzxfile.h"
+ "getopt.h"
+
diff --git a/tools/2CDT/2cdt.layout b/tools/2CDT/2cdt.layout new file mode 100644 index 0000000..b5fceb8 --- /dev/null +++ b/tools/2CDT/2cdt.layout @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<CodeBlocks_layout_file> + <ActiveTarget name="All" /> + <File name="src\2cdt.c" open="1" top="1" tabpos="1"> + <Cursor position="26859" topLine="1012" /> + </File> +</CodeBlocks_layout_file> diff --git a/tools/2CDT/COPYING b/tools/2CDT/COPYING new file mode 100644 index 0000000..196760e --- /dev/null +++ b/tools/2CDT/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/tools/2CDT/Makefile b/tools/2CDT/Makefile new file mode 100644 index 0000000..379c9c6 --- /dev/null +++ b/tools/2CDT/Makefile @@ -0,0 +1,24 @@ +# Makefile for 2cdt utility + +.PHONY: clean +CC = gcc +BIND = gcc +RM = rm + +# CFLAGS flags for C compile +# LFLAGS1 flags after output file spec, before obj file list +# LFLAGS2 flags after obj file list (libraries, etc) + +CFLAGS = -O2 -O3 -DUNIX +LFLAGS1 = +LFLAGS2 = -s + +CDT_O= src/2cdt.o src/tzxfile.o + +2cdt: $(CDT_O) + $(BIND) $(CDT_O) -o 2cdt $(LFLAGS1) $(LFLAGS2) $(LIBS) + +clean: + rm -rf src/*.o + rm -f 2cdt + rm -f 2cdt.exe diff --git a/tools/2CDT/Makefile.win b/tools/2CDT/Makefile.win new file mode 100644 index 0000000..39714b8 --- /dev/null +++ b/tools/2CDT/Makefile.win @@ -0,0 +1,33 @@ +# Project: 2cdt
+# Makefile created by Dev-C++ 4.9.9.2
+
+CPP = g++.exe
+CC = gcc.exe
+WINDRES = windres.exe
+RES =
+OBJ = src/2cdt.o src/tzxfile.o $(RES)
+LINKOBJ = src/2cdt.o src/tzxfile.o $(RES)
+LIBS = -L"C:/Dev-Cpp/lib"
+INCS = -I"C:/Dev-Cpp/include"
+CXXINCS = -I"C:/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"C:/Dev-Cpp/include/c++/3.4.2/backward" -I"C:/Dev-Cpp/include/c++/3.4.2/mingw32" -I"C:/Dev-Cpp/include/c++/3.4.2" -I"C:/Dev-Cpp/include"
+BIN = 2cdt.exe
+CXXFLAGS = $(CXXINCS)
+CFLAGS = $(INCS)
+RM = rm -f
+
+.PHONY: all all-before all-after clean clean-custom
+
+all: all-before 2cdt.exe all-after
+
+
+clean: clean-custom
+ ${RM} $(OBJ) $(BIN)
+
+$(BIN): $(OBJ)
+ $(CC) $(LINKOBJ) -o "2cdt.exe" $(LIBS)
+
+src/2cdt.o: src/2cdt.c
+ $(CC) -c src/2cdt.c -o src/2cdt.o $(CFLAGS)
+
+src/tzxfile.o: src/tzxfile.c
+ $(CC) -c src/tzxfile.c -o src/tzxfile.o $(CFLAGS)
diff --git a/tools/2CDT/file_id.diz b/tools/2CDT/file_id.diz new file mode 100644 index 0000000..e1ff8f5 --- /dev/null +++ b/tools/2CDT/file_id.diz @@ -0,0 +1,16 @@ +2CDT
+Copyright (C) Kevin Thacker, 2000-2002
+
+23-February-2002
+
+2CDT is a tool to create a ".CDT"
+tape image from a file in the Amstrad
+operating system cassette format.
+It can be used to test support
+for ".TZX" in Amstrad emulators
+and a starting point for a Amstrad
+".CDT" tool.
+
+Source included.
+
+makefile included for UNIX
\ No newline at end of file diff --git a/tools/2CDT/readme.txt b/tools/2CDT/readme.txt new file mode 100644 index 0000000..b10fcc2 --- /dev/null +++ b/tools/2CDT/readme.txt @@ -0,0 +1,135 @@ +2CDT
+====
+
+(c) Kevin Thacker
+
+(Original code written in May 2000, fixed and released in May 2001)
+
+2CDT is a utility to transfer files into a ".CDT" Tape-Image.
+
+A ".CDT" is a tape-image file which describes the data stored on a cassette tape.
+
+This file format is very powerful and can describe fast and custom loaders as well
+as standard operating system formats.
+
+The ".CDT" file format is identical to the ".TZX" format. The extension is used
+to differentiate between Spectrum and Amstrad Tape-Images.
+
+The ".TZX" file format was originally designed to store Spectrum tape programs,
+it's format can be found from various sources, one of these is "World Of Spectrum":
+http://www.void.jump.org/
+
+There are a number of tools which already create .TZX files, Taper, Voc2TZX and MakeTZX.
+However, these are designed to recognise Spectrum tape loaders, and so do not do well
+at creating a tape-image for Amstrad formats.
+
+This tool has been designed as a starting point for furthur Amstrad CDT tools,
+and as a program to generate reference tape-images which can be used by emulator
+authors to support this tape-image format in their programs.
+
+This tool is designed to "inject" one or more file into a ".CDT" in the format written
+by the Amstrad operating system. The tool allows the user to define the ".CDT" "recording"
+method and baud rate.
+
+2CDT [parameters] <source file> <output CDT filename>
+
+parameters:
+ -n
+ - Blank CDT file before use
+
+ Use this to create a new CDT, otherwise file
+ will be added to the end of an existing CDT.
+
+ -s <speed write>
+ - Write data with 'speed write' 0 or 1.
+
+ This is the same as typing "SPEED WRITE 0" or "SPEED WRITE 1"
+ in BASIC. Speed Write '0' is 1000 baud. Speed write '1' is
+ 2000 baud.
+
+ -b <baud rate>
+ - Specify Baud Rate.
+
+ Allows you to specify faster or slower loading.
+
+ -t <method>
+ - Method to write data into TZX (for Amstrad blocks)
+ 0 = Pure Data Block
+ 1 = Turbo Loading Data Block (default)
+
+ -m <method>
+ - Method to write CPC data
+ 0 = blocks (default)
+ 1 = headerless (Firmware function CAS READ for reading, CAS WRITE for writing )
+ To be loaded with firmware function CAS READ.
+ Not readable from BASIC. Allows entire program
+ to be stored as a single continuous block.
+ 2 = Spectrum ROM loader
+
+ -r <tape filename>
+ - Give the tape file a name. Up to 16 characters.
+
+ This allows you to give the file on tape a different
+ name to the name given on your local filesystem.
+
+ If no name is defined, the file will be unnamed.
+ This option applies to CPC 'blocks' methods only.
+
+ -X <address>
+ Define execution address (where file doesn't have header), or
+ override execution address (where file has a header)
+
+ -L <address>
+ Define load address (where file doesn't have header), or
+ override load address (where file has a header)
+
+ -T <address>
+ Define type (where file doesn't have header), or
+ override type address (where file has a header)
+ 0 = BASIC, 2 = BINARY
+
+ -p <number>
+ Set initial pause (default 3000ms)
+
+ -P
+ Add a small initial pause block for buggy emulators (e.g. old versions of Arnold)
+ Not recommended. Please use newer version of this emulator.
+
+Examples:
+
+The following in a bacth file will create the master tape for 'Stranded':
+
+REM create new CDT and put binary loader
+2cdt -n -r stranded strandlod.bin stranded.cdt
+REM add screen to existing CDT data
+2cdt -r screen loading.bin stranded.cdt
+REM add code to existing CDT data
+2cdt -r code stranded.bin stranded.cdt
+
+If you wanted to create a master tape for a game called 'Columns':
+
+REM create new CDT and put binary loader
+2cdt -n -r loader colload.bin columns.cdt
+REM put binary file as headerless
+2cdt -m 1 colcode.bin columns.cdt
+
+
+
+This archive contains a Windows command-line executable that will run under Win95, Win98,
+Win2000 and WinNT.
+
+License:
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
\ No newline at end of file diff --git a/tools/2CDT/src/2cdt.c b/tools/2CDT/src/2cdt.c new file mode 100644 index 0000000..c3fb520 --- /dev/null +++ b/tools/2CDT/src/2cdt.c @@ -0,0 +1,1290 @@ +/* + * 2CDT Copyright (c) Kevin Thacker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +/* The following program is designed to create a .tzx/.cdt from a tape-file stored +on the PC */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef UNIX +#include <sys/io.h> +#else +#include <io.h> +#endif +#include "defs.h" +#include "tzxfile.h" +#include "getopt.h"
+ +#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef unsigned __int64 ulong64;
+typedef signed __int64 long64;
+#else
+typedef unsigned long long ulong64;
+typedef signed long long long64;
+#endif
+ +enum +{ + CPC_METHOD_BLOCKS = 0, + CPC_METHOD_HEADERLESS, + CPC_METHOD_SPECTRUM, +}; + +static int ExecutionAddress; +static BOOL ExecutionAddressOverride; +static int LoadAddress; +static BOOL LoadAddressOverride; +static int Type; +static BOOL TypeOverride; +static int Pause; +static BOOL BuggyEmuExtraPause; + +#define MAXFILELEN 16 + +static int BaudRate; /* baud rate to write data */ +static int TZXWriteMethod; /* method to write data into TZX file */ +static BOOL BlankBeforeUse; /* blank existing CDT file before use */ +static int CPCMethod = CPC_METHOD_BLOCKS; + +/* I am using a enum, so that I can poke data into structures without +worrying how the compiler has aligned it */ +enum +{ + CPC_TAPE_HEADER_FILENAME_BYTE0 = 0, + CPC_TAPE_HEADER_FILENAME_BYTE1, + CPC_TAPE_HEADER_FILENAME_BYTE2, + CPC_TAPE_HEADER_FILENAME_BYTE3, + CPC_TAPE_HEADER_FILENAME_BYTE4, + CPC_TAPE_HEADER_FILENAME_BYTE5, + CPC_TAPE_HEADER_FILENAME_BYTE6, + CPC_TAPE_HEADER_FILENAME_BYTE7, + CPC_TAPE_HEADER_FILENAME_BYTE8, + CPC_TAPE_HEADER_FILENAME_BYTE9, + CPC_TAPE_HEADER_FILENAME_BYTE10, + CPC_TAPE_HEADER_FILENAME_BYTE11, + CPC_TAPE_HEADER_FILENAME_BYTE12, + CPC_TAPE_HEADER_FILENAME_BYTE13, + CPC_TAPE_HEADER_FILENAME_BYTE14, + CPC_TAPE_HEADER_FILENAME_BYTE15, + CPC_TAPE_HEADER_BLOCK_NUMBER, + CPC_TAPE_HEADER_LAST_BLOCK_FLAG, + CPC_TAPE_HEADER_FILE_TYPE, + CPC_TAPE_HEADER_DATA_LENGTH_LOW, + CPC_TAPE_HEADER_DATA_LENGTH_HIGH, + CPC_TAPE_HEADER_DATA_LOCATION_LOW, + CPC_TAPE_HEADER_DATA_LOCATION_HIGH, + CPC_TAPE_HEADER_FIRST_BLOCK_FLAG, + CPC_TAPE_HEADER_DATA_LOGICAL_LENGTH_LOW, + CPC_TAPE_HEADER_DATA_LOGICAL_LENGTH_HIGH, + CPC_TAPE_HEADER_DATA_EXECUTION_ADDRESS_LOW, + CPC_TAPE_HEADER_DATA_EXECUTION_ADDRESS_HIGH, +} CPC_TAPE_HEADER_ENUM; + +/* size of header */ +#define CPC_TAPE_HEADER_SIZE 64 + +/* load a file into memory */ +BOOL Host_LoadFile(const char *Filename, unsigned char **pLocation, unsigned long *pLength) +{ + FILE *fh; + unsigned char *pData; + + *pLocation = NULL; + *pLength = 0; + + if (Filename!=NULL) + { + if (strlen(Filename)!=0) + { + fh = fopen(Filename,"rb"); + + if (fh!=NULL) + { + int FileSize; + +#ifdef WIN32 + int FNo; + + FNo = _fileno(fh); + FileSize = _filelength(FNo); +#else + unsigned long CurrentPosition; + CurrentPosition = ftell(fh); + fseek(fh, 0, SEEK_END); + FileSize = ftell(fh); + fseek(fh, CurrentPosition, SEEK_SET); +#endif + if (FileSize!=0) + { + pData = (unsigned char *)malloc(FileSize); + + if (pData!=NULL) + { + if (fread(pData,1,FileSize,fh)==FileSize) + { + *pLocation = pData; + *pLength = FileSize; + fclose(fh); + return TRUE; + } + + free(pData); + } + } + + fclose(fh); + } + } + } + + return FALSE; +} + + +/* calculate checksum as AMSDOS would for the first 66 bytes of a datablock */ +/* this is used to determine if a file has a AMSDOS header */ +unsigned int AMSDOS_CalculateChecksum(unsigned char *pHeader) +{ + unsigned int Checksum; + int i; + + Checksum = 0; + + for (i=0; i<67; i++) + { + unsigned int CheckSumByte; + + CheckSumByte = pHeader[i] & 0x0ff; + + Checksum+=CheckSumByte; + } + + return Checksum; +} + +/* CRC code shamelessly taken from Pierre Guerrier's AIFF decoder! */ +#define kCRCpoly 4129 /* used for binary long division in CRC */ + +/* CRC polynomial: X^16+X^12+X^5+1 */ +unsigned int CRCupdate(unsigned int CRC, unsigned char new) +{ + unsigned int aux = CRC ^ (new << 8); + int i; + + for(i=0; i<8; i++) + if (aux & 0x8000) + aux = (aux <<= 1) ^ kCRCpoly; + else + aux <<= 1; + + return(aux); +} + +/* +ID : 11 - Turbo loading data block +------- + This block is very similar to the normal TAP block but with some + additional info on the timings and other important differences. + The same tape encoding is used as for the standard speed data block. + If a block should use some non-standard sync or pilot tones (for + example all sorts of protection schemes) then use the next three blocks + to describe it. + +00 2 Length of PILOT pulse [2168] +02 2 Length of SYNC First pulse [667] +04 2 Length of SYNC Second pulse [735] +06 2 Length of ZERO bit pulse [855] +08 2 Length of ONE bit pulse [1710] +0A 2 Length of PILOT tone (in PILOT pulses) [8064 Header, 3220 Data] +0C 1 Used bits in last byte (other bits should be 0) [8] + i.e. if this is 6 then the bits (x) used in last byte are: xxxxxx00 +0D 2 Pause After this block in milliseconds (ms) [1000] +0F 3 Length of following data +12 x Data; format is as for TAP (MSb first) + +- Length: [0F,10,11]+12 +*/ + +/* 2 pulses per bit, tone is composed of 1 bits */ +#define CPC_PILOT_TONE_NUM_WAVES (2048) +#define CPC_PILOT_TONE_NUM_PULSES (CPC_PILOT_TONE_NUM_WAVES*2) + +#define CPC_NOPS_PER_FRAME (19968) +#define CPC_NOPS_PER_SECOND (CPC_NOPS_PER_FRAME*50) +#define CPC_T_STATES (CPC_NOPS_PER_SECOND*4) + +#define T_STATE_CONVERSION_FACTOR (TZX_T_STATES<<8)/(CPC_T_STATES>>8) +/* pause between each block */ +#define CPC_PAUSE_AFTER_BLOCK_IN_MS 2500 +/* pause between tape header and data for block */ +#define CPC_PAUSE_AFTER_HEADER_IN_MS 14 + +void InitialiseStandardSpeedDataBlock(TZX_BLOCK *pBlock, int Pause) +{ + unsigned char *pHeader = TZX_GetBlockHeaderPtr(pBlock); + + if (pHeader!=NULL) + { + /* check it is a turbo-loading data block */ + if (pHeader[0] == TZX_STANDARD_SPEED_DATA_BLOCK) + { + pHeader++; + + pHeader[0x00] = (Pause & 0x0ff); + pHeader[0x01] = (Pause>>8); + + + } + } +} + +void CPC_InitialiseTurboLoadingDataBlock(TZX_BLOCK *pBlock, int BaudRate,int Pause) +{ + unsigned char *pHeader = TZX_GetBlockHeaderPtr(pBlock); + + if (pHeader!=NULL) + { + /* check it is a turbo-loading data block */ + if (pHeader[0] == TZX_TURBO_LOADING_DATA_BLOCK) + { + int ZeroPulseLengthInMicroseconds; + long64 ZeroPulseLengthInCPCTStates; + int OnePulseLength; + int ZeroPulseLength; + + pHeader++; + /* equation from CPC firmware guide: + Average baud rate: = 1 000 000/(3*half zero length) = 333 333/Half zero length + */ + + ZeroPulseLengthInMicroseconds = 333333/BaudRate; + ZeroPulseLengthInCPCTStates = ZeroPulseLengthInMicroseconds<<2; + + ZeroPulseLength = (ZeroPulseLengthInCPCTStates* + (T_STATE_CONVERSION_FACTOR>>8))>>8; + + /* one pulse is twice the size of a zero pulse */ + OnePulseLength = ZeroPulseLength<<1; + + /* PILOT pulse on CPC is a one bit */ + pHeader[0x00] = (unsigned char)OnePulseLength; + pHeader[0x01] = (unsigned char)(OnePulseLength>>8); + + /* SYNC on CPC is a zero bit, both sync pulses will be the same */ + pHeader[0x02] = pHeader[0x04] = (unsigned char)ZeroPulseLength; + pHeader[0x03] = pHeader[0x05] = (unsigned char)(ZeroPulseLength>>8); + + /* write zero pulse length */ + pHeader[0x06] = (unsigned char)ZeroPulseLength; + pHeader[0x07] = (unsigned char)(ZeroPulseLength>>8); + + /* write one pulse length */ + pHeader[0x08] = (unsigned char)OnePulseLength; + pHeader[0x09] = (unsigned char)(OnePulseLength>>8); + + /* PILOT pulse is same as 1 Pulse */ + /* pilot tone is 2048 bits long */ + pHeader[0x0a] = CPC_PILOT_TONE_NUM_PULSES & 0x0ff; + pHeader[0x0b] = (CPC_PILOT_TONE_NUM_PULSES>>8); + + /* the end of the block will be the trailer bytes. Say all bits are + used, although, because it doesn't contain useful data it doesn't matter */ + pHeader[0x0c] = 8; + + pHeader[0x0d] = (Pause & 0x0ff); + pHeader[0x0e] = (Pause>>8); + + + } + } +} + + + +void WriteStandardSpeedDataBlock(TZX_FILE *pFile, unsigned char SyncPattern, unsigned char *pData, int DataSize, int Pause) +{ + TZX_BLOCK *pBlock; + unsigned char *pBlockData; + + pBlock = TZX_CreateBlock(TZX_STANDARD_SPEED_DATA_BLOCK); + InitialiseStandardSpeedDataBlock(pBlock, Pause); + + if (pBlock!=NULL) + { + /* one byte for sync, one byte for checksum */ + int TZX_DataBlockSize = DataSize+2; + + /* add block to end of file */ + TZX_AddBlockToEndOfFile(pFile,pBlock); + + /* allocate data in block */ + TZX_AddDataToBlock(pBlock, TZX_DataBlockSize); + + pBlockData= TZX_GetBlockDataPtr(pBlock); + + if (pBlockData!=NULL) + { + char CheckSum = SyncPattern; + int i; + + /* write pattern */ + *pBlockData = SyncPattern; + ++pBlockData; + + for (i=0; i<DataSize; i++) + { + char ch = *pData; + ++pData; + CheckSum^=ch; + *pBlockData = ch; + ++pBlockData; + } + *pBlockData = CheckSum&0x0ff; + } + } +} + + +#define CPC_DATA_CHUNK_SIZE 256 +#define CPC_DATA_BLOCK_SIZE 2048 + +/* write a block of data to a file */ +void CPC_WriteTurboLoadingDataBlock(TZX_FILE *pFile, unsigned char SyncPattern, unsigned char *pData, int DataSize, int Pause) +{ + TZX_BLOCK *pBlock; + unsigned char *pBlockData; + + int NumChunks; + int TZX_DataBlockSize; + + /* divide into complete 256 byte blocks */ + NumChunks = (DataSize+255)>>8; + + /* each tape block is split into 256 chunks, each chunk has a CRC */ + + /* size of all chunks, plus CRC's for each block */ + TZX_DataBlockSize = + /* size of all chunks */ + (NumChunks<<8) + + /* size of CRC's for all chunks */ + (NumChunks<<1) + + /* size of trailer in bytes */ + 4 + + /* size of sync pattern */ + 1; + + + + pBlock = TZX_CreateBlock(TZX_TURBO_LOADING_DATA_BLOCK); + CPC_InitialiseTurboLoadingDataBlock(pBlock, BaudRate,Pause); + + + if (pBlock!=NULL) + { + /* add block to end of file */ + TZX_AddBlockToEndOfFile(pFile,pBlock); + + /* allocate data in block */ + TZX_AddDataToBlock(pBlock, TZX_DataBlockSize); + + pBlockData= TZX_GetBlockDataPtr(pBlock); + + if (pBlockData!=NULL) + { + int i,j; + unsigned char *pDataPtr; + int DataSizeRemaining; + unsigned char *pBlockPtr; + unsigned short CRC; + + pDataPtr = pData; + DataSizeRemaining = DataSize; + pBlockPtr = pBlockData; + + /* write pattern */ + pBlockPtr[0] = SyncPattern; + pBlockPtr++; + + /* write each chunk in turn and calculate CRC */ + for (i=0; i<NumChunks; i++) + { + /* copy data into block */ + if (DataSizeRemaining<CPC_DATA_CHUNK_SIZE) + { + /* less than CPC_DATA_CHUNK_SIZE */ + /* copy data, and fill rest with zeros */ + + /* copy less than 256 bytes */ + memcpy(pBlockPtr, pDataPtr, DataSizeRemaining); + /* fill reset of chunk with zero's */ + memset(pBlockPtr + DataSizeRemaining, 0, CPC_DATA_CHUNK_SIZE-DataSizeRemaining); + /* update source pointer */ + pDataPtr+=DataSizeRemaining; + /* update size remaining - nothing */ + DataSizeRemaining = 0; + } + else + { + /* greater or equal to CPC_DATA_CHUNK_SIZE */ + /* copy CPC_DATA_CHUNK_SIZE max */ + memcpy(pBlockPtr, pDataPtr, CPC_DATA_CHUNK_SIZE); + /* update source pointer */ + pDataPtr += CPC_DATA_CHUNK_SIZE; + /* update size remaining */ + DataSizeRemaining-=CPC_DATA_CHUNK_SIZE; + } + + /* reset CRC */ + CRC = 0x0ffff; + + /* calculate CRC for block */ + for (j=0; j<CPC_DATA_CHUNK_SIZE; j++) + { + char ch; + + ch = pBlockPtr[0]; + pBlockPtr++; + CRC = CRCupdate(CRC, ch); + } + + /* store CRC inverted */ + pBlockPtr[0] = (CRC>>8)^0x0ff; + pBlockPtr++; + pBlockPtr[0] = CRC^0x0ff; + pBlockPtr++; + } + + + /* write trailer */ + memset(pBlockPtr, 0x0ff, 4); + } + } +} + +/* +ID : 14 - Pure data block +------- + This is the same as in the turbo loading data block, except that it has + no pilot or sync pulses. + +00 2 Length of ZERO bit pulse +02 2 Length of ONE bit pulse +04 1 Used bits in LAST Byte +05 2 Pause after this block in milliseconds (ms) +07 3 Length of following data +0A x Data +*/ + +void CPC_InitialisePureDataBlock(TZX_BLOCK *pBlock, int BaudRate, int Pause) +{ + unsigned char *pHeader = TZX_GetBlockHeaderPtr(pBlock); + + if (pHeader!=NULL) + { + /* check it is a turbo-loading data block */ + if (pHeader[0] == TZX_PURE_DATA_BLOCK) + { + int ZeroPulseLengthInMicroseconds; + long64 ZeroPulseLengthInCPCTStates; + int OnePulseLength; + int ZeroPulseLength; + + pHeader++; + /* equation from CPC firmware guide: + Average baud rate: = 1 000 000/(3*half zero length) = 333 333/Half zero length + */ + + ZeroPulseLengthInMicroseconds = 333333/BaudRate; + ZeroPulseLengthInCPCTStates = ZeroPulseLengthInMicroseconds<<2; + + ZeroPulseLength = (ZeroPulseLengthInCPCTStates* + (T_STATE_CONVERSION_FACTOR>>8))>>8; + + /* one pulse is twice the size of a zero pulse */ + OnePulseLength = ZeroPulseLength<<1; + /* write zero pulse length */ + pHeader[0x00] = ZeroPulseLength; + pHeader[0x01] = ZeroPulseLength>>8; + + /* write one pulse length */ + pHeader[0x02] = OnePulseLength; + pHeader[0x03] = OnePulseLength>>8; + + /* the end of the block will be the trailer bytes. Say all bits are + used, although, because it doesn't contain useful data it doesn't matter */ + pHeader[0x04] = 8; + + /* write pause */ + pHeader[0x05] = (Pause & 0x0ff); + pHeader[0x06] = (Pause>>8) & 0x0ff; + + + } + } +} + + +/* the following is for a bitstream */ +unsigned char *pData; +unsigned long ByteCount; +unsigned long BitCount; + +/* initialise bit stream with buffer to write data to */ +void BitStream_Initialise(unsigned char *pBuffer) +{ + pData = pBuffer; + ByteCount = 0; + BitCount = 0; +} + +/* write bit to stream */ +void BitStream_WriteBit(int Bit) +{ + unsigned char Data; + + /* get current data written */ + Data = pData[ByteCount]; + Data &= ~(1<<(7-BitCount)); + Data |= (Bit<<(7-BitCount)); + pData[ByteCount] = Data; + + /* increment bit count */ + BitCount++; + /* if we overrun 8-bits, then bit 3 will be set, add this on */ + ByteCount += (BitCount>>3); + /* mask off bit count */ + BitCount &= 0x07; +} + +/* write byte to stream */ +void BitStream_WriteByte(unsigned char Byte) +{ + int b; + int Bit; + unsigned char LocalByte; + + LocalByte = Byte; + + for (b=0; b<8; b++) + { + Bit = LocalByte & 0x080; + Bit = Bit>>7; + BitStream_WriteBit(Bit); + LocalByte = LocalByte<<1; + } +} + + + +/* write a block of data to a file */ +void CPC_WritePureDataBlock(TZX_FILE *pFile, unsigned char SyncPattern, unsigned char *pData, int DataSize, int Pause) +{ + TZX_BLOCK *pBlock; + unsigned char *pBlockData; + + int NumChunks; + int TZX_DataBlockSize; + + /* divide into complete 256 byte blocks */ + NumChunks = (DataSize+255)>>8; + + /* each tape block is split into 256 chunks, each chunk has a CRC */ + + /* size of all chunks, plus CRC's for each block */ + TZX_DataBlockSize = + /* size of all chunks */ + (NumChunks<<8) + + /* size of CRC's for all chunks */ + (NumChunks<<1) + + /* size of trailer in bytes */ + 4 + + /* size of sync pattern */ + 1; + + TZX_DataBlockSize+= + /* pilot tone - CPC_PILOT_TONE_NUM_WAVES 1 bit's, a zero bit then data as before ... */ + ((CPC_PILOT_TONE_NUM_WAVES + 1)+7)>>3; + + pBlock = TZX_CreateBlock(TZX_PURE_DATA_BLOCK); + CPC_InitialisePureDataBlock(pBlock, BaudRate,Pause); + + + if (pBlock!=NULL) + { + /* add block to end of file */ + TZX_AddBlockToEndOfFile(pFile,pBlock); + + /* allocate data in block */ + TZX_AddDataToBlock(pBlock, TZX_DataBlockSize); + + pBlockData= TZX_GetBlockDataPtr(pBlock); + + if (pBlockData!=NULL) + { + int i,j; + unsigned char *pDataPtr; + int DataSizeRemaining; + unsigned char *pBlockPtr; + unsigned short CRC; + + pDataPtr = pData; + DataSizeRemaining = DataSize; + pBlockPtr = pBlockData; + + BitStream_Initialise(pBlockPtr); + + /* write leader */ + for (i=0; i<CPC_PILOT_TONE_NUM_WAVES; i++) + { + BitStream_WriteBit(1); + } + + BitStream_WriteBit(0); + + + BitStream_WriteByte(SyncPattern); + + /* write each chunk in turn and calculate CRC */ + for (i=0; i<NumChunks; i++) + { + int BlockSizeToWrite; + + /* copy data into block */ + if (DataSizeRemaining<CPC_DATA_CHUNK_SIZE) + { + BlockSizeToWrite = DataSizeRemaining; + } + else + { + BlockSizeToWrite = CPC_DATA_CHUNK_SIZE; + } + + CRC = 0x0ffff; + + for (j=0; j<BlockSizeToWrite; j++) + { + char ch; + + /* get byte */ + ch = pDataPtr[0]; + pDataPtr++; + /* update CRC */ + CRC = CRCupdate(CRC, ch); + /* write byte to stream */ + BitStream_WriteByte(ch); + } + + if (BlockSizeToWrite!=CPC_DATA_CHUNK_SIZE) + { + /* write padding zero's */ + for (j=0; j<(CPC_DATA_CHUNK_SIZE-BlockSizeToWrite); j++) + { + char ch; + + ch = 0; + /* update CRC */ + CRC = CRCupdate(CRC, ch); + /* write byte to stream */ + BitStream_WriteByte(ch); + } + } + + DataSizeRemaining-=BlockSizeToWrite; + + CRC = CRC^0x0ffff; + + BitStream_WriteByte((CRC>>8)); + BitStream_WriteByte(CRC); + } + + /* write trailer */ + for (i=0; i<32; i++) + { + BitStream_WriteBit(1); + } + } + } +} + +/* write a data block in format specified */ +void CPC_WriteDataBlock(TZX_FILE *pFile, unsigned char SyncByte, unsigned char *pData, unsigned long DataSize, int Pause) +{ + switch (TZXWriteMethod) + { + case TZX_TURBO_LOADING_DATA_BLOCK: + { + CPC_WriteTurboLoadingDataBlock(pFile, SyncByte, pData, DataSize,Pause); + } + break; + + case TZX_PURE_DATA_BLOCK: + { + /* write header */ + CPC_WritePureDataBlock(pFile, SyncByte, pData, DataSize,Pause); + } + break; + } +} + +#define UTILITY_NAME "2CDT" + +void DisplayInfo() +{ + printf("%s will transfer files into a .CDT/.TZX tape image, in Amstrad CPC/CPC+\r\n", UTILITY_NAME); + printf("KC Compact form.\r\n\r\n"); + printf("Usage: %s [arguments] <input filename> <.cdt image>\r\n\r\n", UTILITY_NAME); + printf("-n - Blank CDT file before use\n"); + printf("-b <number> - Specify Baud rate (default 2000)\n"); + printf("-s <0 or 1> - Specify 'Speed Write'.\n"); + printf(" 0 = 1000 baud, 1 = 2000 baud (default)\n"); + printf("-t <method> - TZX Block Write Method.\n"); + printf(" 0 = Pure Data, 1 = Turbo Loading (default)\n"); + printf("-m <method> - Data method\n"); + printf(" 0 = blocks (default)\n"); + printf(" 1 = headerless (Firmware function: CAS READ - &BCA1) \n"); + printf(" 2 = spectrum \n");
+ printf(" 3 = Two blocks. First block of 2K, second block has remainder\n"); + printf(" 4 = Two blocks. First block of 1 byte, second block has remainder\n");
+ printf("-X <number> = Define or override execution address (default is &1000 if no header)\r\n"); + printf("-L <number> = Define or override load address (default is &1000 if no header)\r\n"); + printf("-F <number> = Define or override file type (0=BASIC, 2=Binary (default if no header)) etc. Applies to Data method 0\r\n"); + printf("-p <number> = Set initial pause in milliseconds (default 3000ms)\r\n"); + printf("-P = Add a 1ms pause for buggy emulators that ignore first block\r\n"); + printf("-r <tape filename>\n"); + printf(" - Add <input filename> as <tape filename> to CDT (rename file)\n");
+} + +extern char *optarg; +
+int ReadNumberParameter(char *param)
+{
+ int Length = strlen(param);
+ BOOL bIsHex = FALSE;
+ int Offset = 0;
+ unsigned long Value = 0;
+ char ch;
+
+ if (Length==0)
+ return 0;
+
+ /* check for common prefixs for hex numbers */
+ if ((Length>1) && ((param[0]=='&') || (param[0]=='$')))
+ {
+ Offset = 1;
+ bIsHex = TRUE;
+ }
+ else if ((Length>2) && (param[0]=='0') && ((param[1]=='x') || (param[1]=='X')))
+ {
+ Offset = 2;
+ bIsHex = TRUE;
+ }
+
+ if (!bIsHex)
+ {
+ return atoi(param);
+ }
+
+ ch = param[Offset];
+ while (ch!='\0')
+ {
+ Value = Value<<4;
+ if ((ch>='0') && (ch<='9'))
+ {
+ Value = Value | (ch-'0');
+ }
+ else if ((ch>='a') && (ch<='f'))
+ {
+ Value = Value | ((ch-'a')+10);
+ }
+ else if ((ch>='A') && (ch<='F'))
+ {
+ Value = Value | ((ch-'A')+10);
+ }
+ Offset++;
+ ch = param[Offset];
+ }
+
+ return Value;
+}
+ +int main(int argc, char *argv[]) +{ + unsigned char *pTapeFilename = NULL; + + if (argc==1) + { + DisplayInfo(); + } + else + { + TZX_FILE *pTZXFile; + unsigned char *pSourceFilename; + unsigned char *pDestFilename; + unsigned char *pData; + unsigned long DataLength; + char c; + + /* initialise defaults */ + BaudRate = 2000; + Pause = 3000; + Type = 2; + TypeOverride = FALSE; + LoadAddressOverride = FALSE; + TZXWriteMethod = TZX_TURBO_LOADING_DATA_BLOCK; + BlankBeforeUse = FALSE; + ExecutionAddress = LoadAddress = 0x01000; + ExecutionAddressOverride = FALSE; + LoadAddressOverride = FALSE; +
+ printf("-n - Blank CDT file before use\n");
+ printf("-b <number> - Specify Baud rate (default 2000)\n");
+ printf("-s <0 or 1> - Specify 'Speed Write'.\n");
+ printf(" 0 = 1000 baud, 1 = 2000 baud (default)\n");
+ printf("-t <method> - TZX Block Write Method.\n");
+ printf(" 0 = Pure Data, 1 = Turbo Loading (default)\n");
+ printf("-m <method> - Data method\n");
+ printf(" 0 = blocks (default)\n");
+ printf(" 1 = headerless (Firmware function: CAS READ - &BCA1) \n");
+ printf(" 2 = spectrum \n");
+ printf(" 3 = Two blocks. First block of 2K, second block has remainder\n");
+ printf(" 4 = Two blocks. First block of 1 byte, second block has remainder\n");
+ printf("-X <number> = Define or override execution address (default is &1000 if no header)\r\n");
+ printf("-L <number> = Define or override load address (default is &1000 if no header)\r\n");
+ printf("-F <number> = Define or override file type (0=BASIC, 2=Binary (default if no header)) etc. Applies to Data method 0\r\n");
+ printf("-p <number> = Set initial pause in milliseconds (default 3000ms)\r\n");
+ printf("-P = Add a 1ms pause for buggy emulators that ignore first block\r\n");
+ printf("-r <tape filename>\n");
+ printf(" - Add <input filename> as <tape filename> to CDT (rename file)\n");
+
+ + do + { + c = getopt(argc, argv,"r:nb:p:m:t:F:L:s:X:p:P"); + + switch (c) + { + case 'm': + { + int nMethod = atoi(optarg); + CPCMethod = nMethod; + + } + break; + + case 'p': + { + Pause = atoi(optarg);
+ if (Pause<0)
+ {
+ Pause = 0;
+ } + } + break; + + case 'r': + { + pTapeFilename = optarg; + } + break; + + case 'n': + { + BlankBeforeUse = TRUE; + } + break; + + case 'b': + { + int Baud = atoi(optarg); + if ((Baud>0) && (Baud<6000)) + BaudRate = Baud; + } + break; + + case 'X': + { + ExecutionAddress = ReadNumberParameter(optarg) & 0x0ffff; + ExecutionAddressOverride = TRUE; + } + break;
+ + case 'L':
+ {
+ LoadAddress = ReadNumberParameter(optarg) & 0x0ffff;
+ LoadAddressOverride = TRUE;
+ }
+ break;
+ + case 's': + { + int SpeedWrite = atoi(optarg); + if (SpeedWrite==1) + { + BaudRate = 2000; + } + else + { + BaudRate = 1000; + } + } + break; + + case 'F': + { + Type = atoi(optarg) & 0x0ff; + TypeOverride = TRUE; + + + } + break; + +
+ case 'P': + { + BuggyEmuExtraPause = TRUE; + + } + break; + + case 't': + { + int nMethod = atoi(optarg); + if (nMethod==0) + { + TZXWriteMethod = TZX_PURE_DATA_BLOCK; + } + else if (nMethod==1) + { + TZXWriteMethod = TZX_TURBO_LOADING_DATA_BLOCK; + } + else if (nMethod==2) + { + TZXWriteMethod = TZX_STANDARD_SPEED_DATA_BLOCK; + } + } + break; + + default: + { + } + break; + } + + } + while (c!=-1); + + if ((argc-optind)==0) + { + printf("No source file or destination file have been specified!\n"); + exit(1); + } + + if ((argc-optind)==1) + { + printf("No destination file has been specified\n"); + exit(1); + } + + pSourceFilename = argv[optind]; + pDestFilename = argv[optind+1]; + + /* create TZX file */ + pTZXFile = TZX_CreateFile(TZX_VERSION_MAJOR,TZX_VERSION_MINOR); + + if (pTZXFile!=NULL) + { + int nFile; + + + if (BlankBeforeUse) + { + TZX_BLOCK *pBlock; + + /* if buggy emu, add an extra small pause */ + if (BuggyEmuExtraPause) + { + pBlock = TZX_CreateBlock(TZX_PAUSE_BLOCK); + + if (pBlock!=NULL) + { + /* add a 1ms initial pause for buggy emus */ + TZX_SetupPauseBlock(pBlock, 1); + TZX_AddBlockToEndOfFile(pTZXFile,pBlock); + } + } + + + /* correct pause */ + pBlock = TZX_CreateBlock(TZX_PAUSE_BLOCK); + + if (pBlock!=NULL) + { + TZX_SetupPauseBlock(pBlock, Pause); + TZX_AddBlockToEndOfFile(pTZXFile,pBlock); + } + } + + + if (Host_LoadFile(pSourceFilename, &pData, &DataLength)) + { + int FileOffset; + int FileLengthRemaining; + int TapeBlockSize; + BOOL FirstBlock,LastBlock; + int BlockIndex; + unsigned short BlockLocation; + + /* header for tape file */ + unsigned char TapeHeader[CPC_TAPE_HEADER_SIZE]; + + /* calculate checksum from loaded file */ + unsigned short CalculatedChecksum = (unsigned short)AMSDOS_CalculateChecksum(pData); + + /* get stored checksum */ + unsigned short StoredChecksum = + (pData[67] & 0x0ff) | + (pData[68] & 0x0ff)<<8; + + FileOffset = 0; + FileLengthRemaining = DataLength; + BlockIndex = 1; + FirstBlock =TRUE; + + /* insert a pause block - 1 second, this is added onto the end of the previous block */ + /* if (BlankBeforeUse == FALSE) + { + TZX_BLOCK *pBlock; + + pBlock = TZX_CreateBlock(TZX_PAUSE_BLOCK); + + if (pBlock!=NULL) + { + TZX_SetupPauseBlock(pBlock, 2000); + TZX_AddBlockToEndOfFile(pTZXFile,pBlock); + } + } +*/ + + + /* clear tape header */ + memset(TapeHeader, 0, CPC_TAPE_HEADER_SIZE); + + /* checksum's match? */ + if (CalculatedChecksum==StoredChecksum) + {
+ /* copy file type */ + TapeHeader[CPC_TAPE_HEADER_FILE_TYPE] = pData[CPC_TAPE_HEADER_FILE_TYPE]; + /* copy execution address */ + TapeHeader[CPC_TAPE_HEADER_DATA_EXECUTION_ADDRESS_LOW] = pData[CPC_TAPE_HEADER_DATA_EXECUTION_ADDRESS_LOW]; + TapeHeader[CPC_TAPE_HEADER_DATA_EXECUTION_ADDRESS_HIGH] = pData[CPC_TAPE_HEADER_DATA_EXECUTION_ADDRESS_HIGH]; + /* copy data location */ + TapeHeader[CPC_TAPE_HEADER_DATA_LOCATION_LOW] = pData[CPC_TAPE_HEADER_DATA_LOCATION_LOW]; + TapeHeader[CPC_TAPE_HEADER_DATA_LOCATION_HIGH] = pData[CPC_TAPE_HEADER_DATA_LOCATION_HIGH]; + + FileOffset+=128; + FileLengthRemaining-=128; + + /* override execution address? */ + if (ExecutionAddressOverride) + { + TapeHeader[CPC_TAPE_HEADER_DATA_EXECUTION_ADDRESS_LOW] = ExecutionAddress&0xFF; + TapeHeader[CPC_TAPE_HEADER_DATA_EXECUTION_ADDRESS_HIGH] = (ExecutionAddress>>8)&0xFF; + } + + /* override type? */ + if (TypeOverride) + { + TapeHeader[CPC_TAPE_HEADER_FILE_TYPE] = Type; + } + + /* override load address? */ + if (LoadAddressOverride) + { + TapeHeader[CPC_TAPE_HEADER_DATA_LOCATION_LOW] = LoadAddress&0xFF; + TapeHeader[CPC_TAPE_HEADER_DATA_LOCATION_HIGH] = (LoadAddress>>8)&0xFF; + } + + } + else + { + /* set type */ + TapeHeader[CPC_TAPE_HEADER_FILE_TYPE] = Type; + + /* set execution address */ + TapeHeader[CPC_TAPE_HEADER_DATA_EXECUTION_ADDRESS_LOW] = ExecutionAddress&0xFF; + TapeHeader[CPC_TAPE_HEADER_DATA_EXECUTION_ADDRESS_HIGH] = (ExecutionAddress>>8)&0xFF; + + /* set load address */ + TapeHeader[CPC_TAPE_HEADER_DATA_LOCATION_LOW] = LoadAddress&0xFF; + TapeHeader[CPC_TAPE_HEADER_DATA_LOCATION_HIGH] = (LoadAddress>>8)&0xFF; + } + + if (pTapeFilename!=NULL) + { + int i; + int nLength = strlen(pTapeFilename); + if (nLength>16) + nLength = 16; + for (i=0; i<nLength; i++) + { + TapeHeader[i] = toupper(pTapeFilename[i]); + } + } + TapeHeader[CPC_TAPE_HEADER_DATA_LOGICAL_LENGTH_LOW] = (FileLengthRemaining & 0x0ff); + TapeHeader[CPC_TAPE_HEADER_DATA_LOGICAL_LENGTH_HIGH] = (FileLengthRemaining>>8) & 0x0ff; + + + BlockLocation = TapeHeader[CPC_TAPE_HEADER_DATA_LOCATION_LOW] | + (TapeHeader[CPC_TAPE_HEADER_DATA_LOCATION_HIGH]<<8); + + if (CPCMethod == CPC_METHOD_SPECTRUM) + { + /* write data into block */ + WriteStandardSpeedDataBlock(pTZXFile, 0x0ff, &pData[FileOffset], FileLengthRemaining, 1000); + } + else + { + do + { + unsigned char Flag; + /* + CPC can't handle this one + if (CPCMethod == CPC_METHOD_2BLOCKS) + { + if (FirstBlock) + { + TapeBlockSize=CPC_DATA_BLOCK_SIZE; + LastBlock = FALSE; + } + else + { + TapeBlockSize = FileLengthRemaining; + LastBlock = TRUE; + } + } + else + */ + if (CPCMethod == CPC_METHOD_BLOCKS) + { + /* calc size of tape data block */ + if (FileLengthRemaining>CPC_DATA_BLOCK_SIZE) + { + TapeBlockSize = CPC_DATA_BLOCK_SIZE; + LastBlock = FALSE; + } + else + { + TapeBlockSize = FileLengthRemaining; + LastBlock = TRUE; + } + } + else + if (CPCMethod == CPC_METHOD_HEADERLESS) + { + TapeBlockSize = FileLengthRemaining; + } + + + + /**** HEADER ****/ + /* SETUP TAPE RELATED DATA */ + /* block index */ + TapeHeader[CPC_TAPE_HEADER_BLOCK_NUMBER] = BlockIndex; + + /* first block? */ + if (FirstBlock) + { + FirstBlock = FALSE; + + Flag = 0x0ff; + } + else + { + Flag = 0; + } + + TapeHeader[CPC_TAPE_HEADER_FIRST_BLOCK_FLAG] = Flag; + + /* last block? */ + if (LastBlock) + { + Flag = 0x0ff; + } + else + { + Flag = 0; + } + + TapeHeader[CPC_TAPE_HEADER_LAST_BLOCK_FLAG] = Flag; + + /* size of data following */ + TapeHeader[CPC_TAPE_HEADER_DATA_LENGTH_LOW] = (unsigned char)TapeBlockSize; + TapeHeader[CPC_TAPE_HEADER_DATA_LENGTH_HIGH] = (unsigned char)(TapeBlockSize>>8); + + /* location of block */ + TapeHeader[CPC_TAPE_HEADER_DATA_LOCATION_LOW] = (unsigned char)BlockLocation; + TapeHeader[CPC_TAPE_HEADER_DATA_LOCATION_HIGH] = (unsigned char)(BlockLocation>>8); + + /* don't write a header if headerless */ + if (CPCMethod!=CPC_METHOD_HEADERLESS) + { + /* write header */ + CPC_WriteDataBlock(pTZXFile, 0x02c, TapeHeader, CPC_TAPE_HEADER_SIZE,10); + } + + /* write data into block */ + CPC_WriteDataBlock(pTZXFile, 0x016, &pData[FileOffset], TapeBlockSize,CPC_PAUSE_AFTER_BLOCK_IN_MS); + + BlockLocation+=TapeBlockSize; + BlockIndex++; + FileOffset+=TapeBlockSize; + FileLengthRemaining -= TapeBlockSize; + } + while (FileLengthRemaining!=0); + } + + free(pData); + } + + /* write file */ + if (BlankBeforeUse) + { + TZX_WriteFile(pTZXFile, pDestFilename); + } + else + { + TZX_AppendFile(pTZXFile, pDestFilename); + } + + /* free it */ + TZX_FreeFile(pTZXFile); + } + else + { + printf("Failed to open output file!\r\n"); + exit(1); + } + + } + + exit(0); + + return 0; +} diff --git a/tools/2CDT/src/defs.h b/tools/2CDT/src/defs.h new file mode 100644 index 0000000..f042dde --- /dev/null +++ b/tools/2CDT/src/defs.h @@ -0,0 +1,36 @@ +/* + * 2CDT Copyright (c) Kevin Thacker + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __DEFS_HEADER_INCLUDED__ +#define __DEFS_HEADER_INCLUDED__ + + +typedef int BOOL; + +#ifndef TRUE +#define TRUE (1==1) +#endif + +#ifndef FALSE +#define FALSE (1==0) +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#endif diff --git a/tools/2CDT/src/tzxfile.c b/tools/2CDT/src/tzxfile.c new file mode 100644 index 0000000..3f550b0 --- /dev/null +++ b/tools/2CDT/src/tzxfile.c @@ -0,0 +1,445 @@ +/*
+ * 2CDT Copyright (c) Kevin Thacker
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+/* TZX file support */
+#include "tzxfile.h"
+/* header for TZX file */
+const unsigned char *TZX_FileHeader = (const unsigned char *)"ZXTape!\x1a";
+
+/* the internal format for the TZX is a link-list system.
+Blocks can be edited. A new file can be written with the new data */
+
+
+
+/**************************************/
+/* insert block after block specified */
+void TZX_InsertBlockAfter(TZX_FILE *pFile,TZX_BLOCK *pBlock, TZX_BLOCK *pPrev)
+{
+ /* setup block pointers */
+ pBlock->pPrev = pPrev;
+ pBlock->pNext = pPrev->pNext;
+
+ /* setup pointers for block before */
+ pPrev->pNext = pBlock;
+}
+
+/***************************************/
+/* insert block before block specified */
+void TZX_InsertBlockBefore(TZX_FILE *pFile, TZX_BLOCK *pBlock, TZX_BLOCK *pNext)
+{
+ /* setup block pointers */
+ pBlock->pNext = pNext;
+ pBlock->pPrev = pNext->pPrev;
+
+ /* setup pointers for block before */
+ pNext->pPrev = pBlock;
+
+ /* is block we are inserting after the first in the list? */
+ if (pFile->pFirstBlock == pNext)
+ {
+ /* yes. New block is now the start of the list */
+ pFile->pFirstBlock = pBlock;
+ }
+}
+
+
+/*****************************************/
+/* insert a block at the end of the file */
+void TZX_AddBlockToEndOfFile(TZX_FILE *pFile, TZX_BLOCK *pBlock)
+{
+ /* blocks in file? */
+ if (pFile->pFirstBlock==NULL)
+ {
+ /* no */
+ pFile->pFirstBlock = pBlock;
+ }
+ else
+ {
+ /* yes */
+ TZX_BLOCK *pCurrentBlock;
+
+ /* search for last block in list */
+ pCurrentBlock = pFile->pFirstBlock;
+
+ while (pCurrentBlock->pNext!=NULL)
+ pCurrentBlock = pCurrentBlock->pNext;
+
+ TZX_InsertBlockAfter(pFile,pBlock, pCurrentBlock);
+ }
+}
+
+/********************************/
+/* detach block from block list */
+void TZX_DetachBlock(TZX_FILE *pFile,TZX_BLOCK *pBlock)
+{
+ /* block before this block? */
+ if (pBlock->pPrev!=NULL)
+ {
+ /* yes */
+ pBlock->pPrev->pNext = pBlock->pNext;
+ }
+ else
+ {
+ /* no, this block is first in list */
+ pFile->pFirstBlock = pBlock->pNext;
+ }
+
+ /* block after this block? */
+ if (pBlock->pNext!=NULL)
+ {
+ /* yes */
+ pBlock->pNext->pPrev = pBlock->pPrev;
+ }
+}
+
+/************************/
+/* free data in a block */
+void TZX_FreeBlock(TZX_BLOCK *pBlock)
+{
+ /* free it */
+ free(pBlock);
+}
+
+
+
+/******************************/
+/* create a internal TZX file */
+
+TZX_FILE *TZX_CreateFile(unsigned char VersionMajor, unsigned char VersionMinor)
+{
+ TZX_FILE *pTZXFile;
+
+ /* alloc the header */
+ pTZXFile = malloc(sizeof(TZX_FILE));
+
+ if (pTZXFile!=NULL)
+ {
+ /* set version */
+ pTZXFile->VersionMajor = VersionMajor;
+ pTZXFile->VersionMinor = VersionMinor;
+
+ /* initialise block linked list */
+ pTZXFile->pFirstBlock = NULL;
+ }
+
+ return pTZXFile;
+}
+
+/*******************/
+/* free a TZX file */
+
+void TZX_FreeFile(TZX_FILE *pFile)
+{
+ TZX_BLOCK *pBlock;
+
+ pBlock = pFile->pFirstBlock;
+
+ while (pBlock!=NULL)
+ {
+ TZX_BLOCK *pNextBlock = pBlock->pNext;
+
+ /* remove block from list */
+ TZX_DetachBlock(pFile, pBlock);
+
+ /* free TZX block */
+ TZX_FreeBlock(pBlock);
+
+ pBlock = pNextBlock;
+ }
+
+ /* free TZX file header */
+ free(pFile);
+}
+
+/*****************************************************************************************************/
+/* write a TZX file */
+
+void TZX_WriteBlocks(TZX_FILE *pTZXFile, FILE *fh)
+{
+ TZX_BLOCK *pBlock;
+
+ /* get pointer to first block */
+ pBlock = pTZXFile->pFirstBlock;
+
+ /* write each block in turn to file */
+ while (pBlock!=NULL)
+ {
+ if (pBlock->pBlockHeader!=NULL)
+ {
+ BOOL BlockHasData;
+ int BlockHeaderSize;
+ unsigned char BlockID;
+
+ /* get block ID */
+ BlockID = pBlock->pBlockHeader[0];
+ /* get size of header */
+ BlockHeaderSize = TZX_GetBlockHeaderSize(BlockID);
+ /* does block have additional data ? */
+ BlockHasData = TZX_BlockHasData(BlockID);
+
+ if ((!BlockHasData) || ((BlockHasData) && (pBlock->pBlockData!=NULL)))
+ {
+ /* block requires data and has data, or block doesn't require data */
+
+ /* write the header */
+ fwrite(pBlock->pBlockHeader, BlockHeaderSize, sizeof(unsigned char), fh);
+
+ if (pBlock->pBlockData!=NULL)
+ {
+ /* write the data */
+
+ fwrite(pBlock->pBlockData, pBlock->DataBlockSize, sizeof(unsigned char), fh);
+ }
+ }
+ }
+
+ /* next block */
+ pBlock = pBlock->pNext;
+ }
+}
+
+
+void TZX_AppendFile(TZX_FILE *pTZXFile, unsigned char *pFilename)
+{
+ FILE *fh;
+
+ /* open TZX file */
+ fh = fopen((const char *)pFilename,"r+b");
+
+ if (fh!=NULL)
+ {
+ TZX_BLOCK *pBlock;
+
+ fseek(fh, 0, SEEK_END);
+
+ TZX_WriteBlocks(pTZXFile, fh);
+
+ /* close TZX file */
+ fclose(fh);
+ }
+}
+
+
+void TZX_WriteFile(TZX_FILE *pTZXFile, unsigned char *pFilename)
+{
+ FILE *fh;
+
+ /* open TZX file */
+ fh = fopen((const char *)pFilename,"wb");
+
+ if (fh!=NULL)
+ {
+ TZX_BLOCK *pBlock;
+
+ /* write header */
+ fwrite(TZX_FileHeader, 8, sizeof(unsigned char), fh);
+ /* write version numbers */
+ fwrite(&pTZXFile->VersionMajor, 1, sizeof(unsigned char), fh);
+ fwrite(&pTZXFile->VersionMinor, 1, sizeof(unsigned char), fh);
+
+ TZX_WriteBlocks(pTZXFile, fh);
+
+ /* close TZX file */
+ fclose(fh);
+ }
+}
+
+void TZX_SetupPauseBlock(TZX_BLOCK *pBlock,unsigned long PauseInMilliseconds)
+{
+ unsigned char *pHeader = TZX_GetBlockHeaderPtr(pBlock);
+
+ if (pHeader!=NULL)
+ {
+ if (pHeader[0] == TZX_PAUSE_BLOCK)
+ {
+ pHeader[1] = (unsigned char)PauseInMilliseconds;
+ pHeader[2] = (unsigned char)(PauseInMilliseconds>>8);
+ }
+ }
+}
+
+/*****************************************************************************************************/
+
+/* given a TZX block ID, this returns the size of the header */
+int TZX_GetBlockHeaderSize(unsigned char ID)
+{
+ switch (ID)
+ {
+ case TZX_STANDARD_SPEED_DATA_BLOCK:
+ return 4+1;
+ case TZX_TURBO_LOADING_DATA_BLOCK:
+ return 18+1;
+
+ case TZX_PAUSE_BLOCK:
+ return 2+1;
+ case TZX_PURE_DATA_BLOCK:
+ return 0x0a + 1;
+ case TZX_DIRECT_RECORDING_BLOCK:
+ return 0x08 + 1;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************************************/
+/* return TRUE if the block has additional data, false if not */
+BOOL TZX_BlockHasData(unsigned char ID)
+{
+ switch (ID)
+ {
+ case TZX_STANDARD_SPEED_DATA_BLOCK:
+ case TZX_TURBO_LOADING_DATA_BLOCK:
+ case TZX_PURE_DATA_BLOCK:
+ case TZX_DIRECT_RECORDING_BLOCK:
+ return TRUE;
+
+ case TZX_PAUSE_BLOCK:
+ return FALSE;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+
+}
+
+/*****************************************************************************************************/
+/* set block size */
+void TZX_SetBlockSizeInHeader(TZX_BLOCK *pBlock, unsigned long Size)
+{
+ unsigned char ID = pBlock->pBlockHeader[0];
+ unsigned char *pBlockData;
+
+ pBlockData = &pBlock->pBlockHeader[1];
+
+ switch (ID)
+ {
+ case TZX_STANDARD_SPEED_DATA_BLOCK:
+ {
+ pBlockData[2] = (unsigned char)Size;
+ pBlockData[3] = (unsigned char)(Size>>8);
+
+ }
+ break;
+
+ case TZX_TURBO_LOADING_DATA_BLOCK:
+ {
+ pBlockData[0x0f] = (unsigned char)Size;
+ pBlockData[0x010] = (unsigned char)(Size>>8);
+ pBlockData[0x011] = (unsigned char)(Size>>16);
+
+ }
+ break;
+
+ case TZX_PURE_DATA_BLOCK:
+ {
+ pBlockData[0x07] = (unsigned char)Size;
+ pBlockData[0x08] = (unsigned char)(Size>>8);
+ pBlockData[0x09] = (unsigned char)(Size>>16);
+ }
+ break;
+
+ case TZX_DIRECT_RECORDING_BLOCK:
+ {
+ pBlockData[0x05] = (unsigned char)Size;
+ pBlockData[0x06] = (unsigned char)(Size>>8);
+ pBlockData[0x07] = (unsigned char)(Size>>16);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/*****************************************************************************************************/
+/* create a block of the specified ID in the TZX image file */
+TZX_BLOCK *TZX_CreateBlock(unsigned char ID)
+{
+ TZX_BLOCK *pBlock;
+
+ pBlock = malloc(sizeof(TZX_BLOCK));
+
+ if (pBlock!=NULL)
+ {
+ int BlockHeaderSize;
+
+ /* reset block data */
+ memset(pBlock, 0, sizeof(TZX_BLOCK));
+
+ BlockHeaderSize = TZX_GetBlockHeaderSize(ID);
+
+ pBlock->pBlockHeader = malloc(BlockHeaderSize);
+
+ if (pBlock->pBlockHeader!=NULL)
+ {
+ pBlock->pBlockHeader[0] = ID;
+ }
+ }
+
+ return pBlock;
+}
+
+/*****************************************************************************************************/
+/* create a block of the specified ID in the TZX image file */
+void TZX_AddDataToBlock(TZX_BLOCK *pBlock, int DataSize)
+{
+ /* only add data if a header exists */
+ if (pBlock->pBlockHeader!=NULL)
+ {
+ /* get block id */
+ unsigned char BlockID = pBlock->pBlockHeader[0];
+
+ /* does this block ID have additional data? */
+ if (TZX_BlockHasData(BlockID))
+ {
+ /* allocate memory for the additional data */
+ pBlock->pBlockData = malloc(DataSize);
+
+ if (pBlock->pBlockData!=NULL)
+ {
+ pBlock->DataBlockSize = DataSize;
+
+ /* set size in TZX header */
+ TZX_SetBlockSizeInHeader(pBlock, DataSize);
+ }
+ }
+ }
+}
+
+/*****************************************************************************************************/
+/* get pointer to TZX data block */
+unsigned char *TZX_GetBlockDataPtr(TZX_BLOCK *pBlock)
+{
+ return pBlock->pBlockData;
+}
+
+/*****************************************************************************************************/
+/* get pointer to TZX data block */
+unsigned char *TZX_GetBlockHeaderPtr(TZX_BLOCK *pBlock)
+{
+ return pBlock->pBlockHeader;
+}
diff --git a/tools/2CDT/src/tzxfile.h b/tools/2CDT/src/tzxfile.h new file mode 100644 index 0000000..397f5d1 --- /dev/null +++ b/tools/2CDT/src/tzxfile.h @@ -0,0 +1,79 @@ +/*
+ * 2CDT Copyright (c) Kevin Thacker
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __TZX_FILE_HEADER__
+#define __TZX_FILE_HEADER__
+
+#include "defs.h"
+
+#define TZX_VERSION_MAJOR 1
+#define TZX_VERSION_MINOR 10
+
+#define TZX_STANDARD_SPEED_DATA_BLOCK 0x010
+#define TZX_TURBO_LOADING_DATA_BLOCK 0x011
+#define TZX_PAUSE_BLOCK 0x020
+#define TZX_PURE_DATA_BLOCK 0x014
+#define TZX_DIRECT_RECORDING_BLOCK 0x015
+
+#define TZX_T_STATES 3500000
+
+
+#define TZX_HARDWARE_COMPUTER_CPC464 0x015 /* Amstrad CPC 464 */
+#define TZX_HARDWARE_COMPUTER_CPC664 0x016 /* Amstrad CPC 664 */
+#define TZX_HARDWARE_COMPUTER_CPC6128 0x017 /* Amstrad CPC 6128 */
+#define TZX_HARDWARE_COMPUTER_CPC464PLUS 0x018 /* Amstrad CPC 464+ */
+#define TZX_HARDWARE_COMPUTER_CPC6128PLUS 0x019 /* Amstrad CPC 6128+ */
+
+typedef struct TZX_BLOCK
+{
+ /* previous TZX block */
+ struct TZX_BLOCK *pPrev;
+ /* next TZX block */
+ struct TZX_BLOCK *pNext;
+ /* pointer to header data allocated for this block */
+ unsigned char *pBlockHeader;
+ /* size of data block */
+ unsigned long DataBlockSize;
+ /* pointer to data added to this block */
+ unsigned char *pBlockData;
+} TZX_BLOCK;
+
+typedef struct TZX_FILE
+{
+ /* version of TZX file */
+ unsigned char VersionMajor;
+ unsigned char VersionMinor;
+ /* pointer to first block */
+ TZX_BLOCK *pFirstBlock;
+} TZX_FILE;
+
+void TZX_WriteFile(TZX_FILE *pTZXFile, unsigned char *pFilename);
+unsigned char *TZX_GetBlockDataPtr(TZX_BLOCK *);
+unsigned char *TZX_GetBlockHeaderPtr(TZX_BLOCK *);
+
+TZX_FILE *TZX_CreateFile(unsigned char VersionMajor, unsigned char VersionMinor);
+void TZX_FreeFile(TZX_FILE *pFile);
+void TZX_AddDataToBlock(TZX_BLOCK *pBlock, int DataSize);
+unsigned char *TZX_GetDataBlockPtr(TZX_BLOCK *pBlock);
+void TZX_AddBlockToEndOfFile(TZX_FILE *pFile, TZX_BLOCK *pBlock);
+int TZX_GetBlockHeaderSize(unsigned char ID);
+BOOL TZX_BlockHasData(unsigned char ID);
+TZX_BLOCK *TZX_CreateBlock(unsigned char ID);
+void TZX_SetupPauseBlock(TZX_BLOCK *pBlock,unsigned long PauseInMilliseconds);
+#endif
+
diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 0000000..fa59614 --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,38 @@ +BIN=idsk 2cdt ucl png2crtc hex2bin + +all: $(BIN) +CC=gcc +CFLAGS=-s -O3 -Wall + +idsk: + mkdir iDSK/build + cd iDSK/build && cmake ../ + make -C iDSK/build + cp iDSK/build/iDSK idsk + rm -rf iDSK/build + +2cdt: + make -C 2CDT + cp 2CDT/2cdt . + +png2crtc: + make -C gfx2crtc + cp gfx2crtc/png2crtc . + +%.o: %.c + $(CC) $(CFLAGS) $< -o $@ -c + +ucl: ucl.o + $(CC) -lucl $< -o $@ + +hex2bin: + make -C hex2bin-2.0 + cp hex2bin-2.0/bin/hex2bin . + +.PHONY: clean +clean: + make -C 2CDT clean + make -C gfx2crtc clean + make -C hex2bin-2.0 clean + rm -f $(BIN) *.o + diff --git a/tools/README.ucl b/tools/README.ucl new file mode 100644 index 0000000..ade95f9 --- /dev/null +++ b/tools/README.ucl @@ -0,0 +1,7 @@ +This is a simple compressor using the UCL library. + +It takes the data from stdin and writes to stdout. + +It is limited to MAX_MEM (64kb), but you should be compressing +way less than that anyway! + diff --git a/tools/bin2h.py b/tools/bin2h.py new file mode 100755 index 0000000..c430538 --- /dev/null +++ b/tools/bin2h.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +from argparse import ArgumentParser + +__version__ = "1.0" + +def main(): + + parser = ArgumentParser(description="Bin to H converter", + epilog="Copyright (C) 2014 Juan J Martinez <jjm@usebox.net>", + ) + + parser.add_argument("--version", action="version", version="%(prog)s " + __version__) + parser.add_argument("file", help="file to convert") + parser.add_argument("id", help="variable to use") + + args = parser.parse_args() + + with open(args.file, "rb") as fd: + data = bytearray(fd.read()) + + data_out = "" + for part in range(0, len(data), 8): + if data_out: + data_out += ",\n" + data_out += ', '.join(["0x%02x" % b for b in data[part: part + 8]]) + + print("/* file: %s */" % args.file) + print("#define %s_LEN %d\n" % (args.id.upper(), len(data))) + print("const unsigned char %s[] = {\n%s\n};\n" % (args.id, data_out)) + +if __name__ == "__main__": + main() + diff --git a/tools/chksize b/tools/chksize new file mode 100755 index 0000000..6f2c9b8 --- /dev/null +++ b/tools/chksize @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 + +import sys + +# video memory + back buffer (stack in 0x200) +TOP_MEM = 0xc000 + + +def main(): + if len(sys.argv) != 3: + sys.exit("usage: %s load_addr filename.map" % sys.argv[0]) + + load_addr = int(sys.argv[1]) + + with open(sys.argv[2], "r") as fd: + lines = fd.readlines() + # warnings + for line in lines: + if "l__INITIALIZED" in line: + init_size = int(line.split()[0], base=16) + if init_size != 0: + print("*WARNING* Initialized data found") + # search for HEAP + for line in lines: + if "s__HEAP" in line: + heap_addr = int(line.split()[0], base=16) + max_mem = TOP_MEM - load_addr + cur_mem = heap_addr - load_addr + left_mem = max_mem - cur_mem + print("""\ +*** + Max: {} bytes + Current: {} bytes ({} bytes left) +*** +""".format(max_mem, cur_mem, left_mem)) + sys.exit(0) + + sys.exit("HEAP size not found") + + +if __name__ == "__main__": + main() diff --git a/tools/dump-pal.py b/tools/dump-pal.py new file mode 100755 index 0000000..c87d7e7 --- /dev/null +++ b/tools/dump-pal.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python + +__version__ = "1.0" + +from argparse import ArgumentParser +from PIL import Image + +# firmware +CPC_PAL = ( + [0, 0, 0], + [0, 0, 128], + [0, 0, 255], + [128, 0, 0], + [128, 0, 128], + [128, 0, 255], + [255, 0, 0], + [255, 0, 128], + [255, 0, 255], + [0, 128, 0], + [0, 128, 128], + [0, 128, 255], + [128, 128, 0], + [128, 128, 128], + [128, 128, 255], + [255, 128, 0], + [255, 128, 128], + [255, 128, 255], + [0, 255, 0], + [0, 255, 128], + [0, 255, 255], + [128, 255, 0], + [128, 255, 128], + [128, 255, 255], + [255, 255, 0], + [255, 255, 128], + [255, 255, 255], + ) + +# hardware +CPC_PAL_HW = ( + 0x54, 0x44, 0x55, 0x5c, 0x58, 0x5d, 0x4c, 0x45, 0x4d, + 0x56, 0x46, 0x57, 0x5e, 0x40, 0x5f, 0x4e, 0x47, 0x4f, + 0x52, 0x42, 0x53, 0x5a, 0x59, 0x5b, 0x4a, 0x43, 0x4b, + ) + +def main(): + + parser = ArgumentParser(description="PNG to CPC palette (firmware)", + epilog="Copyright (C) 2015 Juan J Martinez <jjm@usebox.net>", + ) + + parser.add_argument("--version", action="version", version="%(prog)s " + __version__) + parser.add_argument("--hw", action="store_true", dest="hardware") + parser.add_argument("image", help="image to convert") + parser.add_argument("pal_dump", help="filename for the palette dump") + + args = parser.parse_args() + + try: + image = Image.open(args.image) + except IOError: + parser.error("failed to open the image") + + if image.mode != "P": + parser.error("not an indexed image (no palette)") + + palette = image.getpalette() + if not palette: + parser.error("failed to extract the palette (is this an indexed image?)") + + colors = image.getcolors(maxcolors=16) + if not colors: + parser.error("failed to extract the palette (color limit is 16)") + + rgb = [] + for _, i in colors: + c = palette[i * 3:i * 3 + 3] + if c not in CPC_PAL: + parser.error("%r not in the CPC palette" % c) + if c not in rgb: + rgb.append(c) + + out = [CPC_PAL.index(c) for c in rgb] + if len(out) < 16: + out.extend([i for i in range(16 - len(out))]) + + if args.hardware: + out = [CPC_PAL_HW[c] for c in out] + + with open(args.pal_dump, "wb") as fd: + fd.write(bytearray(out)) + +if __name__ == "__main__": + main() + diff --git a/tools/encrypt.py b/tools/encrypt.py new file mode 100644 index 0000000..6e03336 --- /dev/null +++ b/tools/encrypt.py @@ -0,0 +1,25 @@ + +def enc(key, text): + p = 0x59 + r = [] + for c in text: + new = ((ord(c) ^ p) ^ key) & 0xff + r.append(new) + p = new + return r + +def dec(key, text): + p = 0x59 + r = [] + for c in text: + new = ((c ^ key) ^ p) & 0xff + r.append(new) + p = c + return r + +res = enc(0xfe, "THE WAR IS OVER AND\nWE PREVAILED.\n\nFOR NOW...\n\nYOU ARE A LEGEND!\n\nTHANKS FOR PLAYING\nTHE GAME.\0") +print ", ".join("0x%02x" % r for r in res) + +res = dec(0xfe, res) +print "".join(chr(r) for r in res) + diff --git a/tools/gfx2crtc/AUTHORS b/tools/gfx2crtc/AUTHORS new file mode 100644 index 0000000..4cb7787 --- /dev/null +++ b/tools/gfx2crtc/AUTHORS @@ -0,0 +1,5 @@ +Logiciel Initial : +CloudStrife/Shinra (Quentin Carlier) <cloudstrife@cpcscene.com> + +Contributors: +PulkoMandy/Shinra (Adrien Destugues) <pulkomandy@gmail.com> diff --git a/tools/gfx2crtc/LICENCE b/tools/gfx2crtc/LICENCE new file mode 100644 index 0000000..1613fca --- /dev/null +++ b/tools/gfx2crtc/LICENCE @@ -0,0 +1,512 @@ + +CONTRAT DE LICENCE DE LOGICIEL LIBRE CeCILL + + + Avertissement + +Ce contrat est une licence de logiciel libre issue d'une concertation +entre ses auteurs afin que le respect de deux grands principes préside à +sa rédaction: + + * d'une part, le respect des principes de diffusion des logiciels + libres: accès au code source, droits étendus conférés aux + utilisateurs, + * d'autre part, la désignation d'un droit applicable, le droit + français, auquel elle est conforme, tant au regard du droit de la + responsabilité civile que du droit de la propriété intellectuelle + et de la protection qu'il offre aux auteurs et titulaires des + droits patrimoniaux sur un logiciel. + +Les auteurs de la licence CeCILL (pour Ce[a] C[nrs] I[nria] L[ogiciel] +L[ibre]) sont: + +Commissariat à l'Energie Atomique - CEA, établissement public de +recherche à caractère scientifique, technique et industriel, dont le +siège est situé 25 rue Leblanc, immeuble Le Ponant D, 75015 Paris. + +Centre National de la Recherche Scientifique - CNRS, établissement +public à caractère scientifique et technologique, dont le siège est +situé 3 rue Michel-Ange, 75794 Paris cedex 16. + +Institut National de Recherche en Informatique et en Automatique - +INRIA, établissement public à caractère scientifique et technologique, +dont le siège est situé Domaine de Voluceau, Rocquencourt, BP 105, 78153 +Le Chesnay cedex. + + + Préambule + +Ce contrat est une licence de logiciel libre dont l'objectif est de +conférer aux utilisateurs la liberté de modification et de +redistribution du logiciel régi par cette licence dans le cadre d'un +modèle de diffusion en logiciel libre. + +L'exercice de ces libertés est assorti de certains devoirs à la charge +des utilisateurs afin de préserver ce statut au cours des +redistributions ultérieures. + +L'accessibilité au code source et les droits de copie, de modification +et de redistribution qui en découlent ont pour contrepartie de n'offrir +aux utilisateurs qu'une garantie limitée et de ne faire peser sur +l'auteur du logiciel, le titulaire des droits patrimoniaux et les +concédants successifs qu'une responsabilité restreinte. + +A cet égard l'attention de l'utilisateur est attirée sur les risques +associés au chargement, à l'utilisation, à la modification et/ou au +développement et à la reproduction du logiciel par l'utilisateur étant +donné sa spécificité de logiciel libre, qui peut le rendre complexe à +manipuler et qui le réserve donc à des développeurs ou des +professionnels avertis possédant des connaissances informatiques +approfondies. Les utilisateurs sont donc invités à charger et tester +l'adéquation du logiciel à leurs besoins dans des conditions permettant +d'assurer la sécurité de leurs systèmes et/ou de leurs données et, plus +généralement, à l'utiliser et l'exploiter dans les mêmes conditions de +sécurité. Ce contrat peut être reproduit et diffusé librement, sous +réserve de le conserver en l'état, sans ajout ni suppression de clauses. + +Ce contrat est susceptible de s'appliquer à tout logiciel dont le +titulaire des droits patrimoniaux décide de soumettre l'exploitation aux +dispositions qu'il contient. + + + Article 1 - DEFINITIONS + +Dans ce contrat, les termes suivants, lorsqu'ils seront écrits avec une +lettre capitale, auront la signification suivante: + +Contrat: désigne le présent contrat de licence, ses éventuelles versions +postérieures et annexes. + +Logiciel: désigne le logiciel sous sa forme de Code Objet et/ou de Code +Source et le cas échéant sa documentation, dans leur état au moment de +l'acceptation du Contrat par le Licencié. + +Logiciel Initial: désigne le Logiciel sous sa forme de Code Source et +éventuellement de Code Objet et le cas échéant sa documentation, dans +leur état au moment de leur première diffusion sous les termes du Contrat. + +Logiciel Modifié: désigne le Logiciel modifié par au moins une +Contribution. + +Code Source: désigne l'ensemble des instructions et des lignes de +programme du Logiciel et auquel l'accès est nécessaire en vue de +modifier le Logiciel. + +Code Objet: désigne les fichiers binaires issus de la compilation du +Code Source. + +Titulaire: désigne le ou les détenteurs des droits patrimoniaux d'auteur +sur le Logiciel Initial. + +Licencié: désigne le ou les utilisateurs du Logiciel ayant accepté le +Contrat. + +Contributeur: désigne le Licencié auteur d'au moins une Contribution. + +Concédant: désigne le Titulaire ou toute personne physique ou morale +distribuant le Logiciel sous le Contrat. + +Contribution: désigne l'ensemble des modifications, corrections, +traductions, adaptations et/ou nouvelles fonctionnalités intégrées dans +le Logiciel par tout Contributeur, ainsi que tout Module Interne. + +Module: désigne un ensemble de fichiers sources y compris leur +documentation qui permet de réaliser des fonctionnalités ou services +supplémentaires à ceux fournis par le Logiciel. + +Module Externe: désigne tout Module, non dérivé du Logiciel, tel que ce +Module et le Logiciel s'exécutent dans des espaces d'adressage +différents, l'un appelant l'autre au moment de leur exécution. + +Module Interne: désigne tout Module lié au Logiciel de telle sorte +qu'ils s'exécutent dans le même espace d'adressage. + +GNU GPL: désigne la GNU General Public License dans sa version 2 ou +toute version ultérieure, telle que publiée par Free Software Foundation +Inc. + +Parties: désigne collectivement le Licencié et le Concédant. + +Ces termes s'entendent au singulier comme au pluriel. + + + Article 2 - OBJET + +Le Contrat a pour objet la concession par le Concédant au Licencié d'une +licence non exclusive, cessible et mondiale du Logiciel telle que +définie ci-après à l'article 5 pour toute la durée de protection des droits +portant sur ce Logiciel. + + + Article 3 - ACCEPTATION + +3.1 L'acceptation par le Licencié des termes du Contrat est réputée +acquise du fait du premier des faits suivants: + + * (i) le chargement du Logiciel par tout moyen notamment par + téléchargement à partir d'un serveur distant ou par chargement à + partir d'un support physique; + * (ii) le premier exercice par le Licencié de l'un quelconque des + droits concédés par le Contrat. + +3.2 Un exemplaire du Contrat, contenant notamment un avertissement +relatif aux spécificités du Logiciel, à la restriction de garantie et à +la limitation à un usage par des utilisateurs expérimentés a été mis à +disposition du Licencié préalablement à son acceptation telle que +définie à l'article 3.1 ci dessus et le Licencié reconnaît en avoir pris +connaissance. + + + Article 4 - ENTREE EN VIGUEUR ET DUREE + + + 4.1 ENTREE EN VIGUEUR + +Le Contrat entre en vigueur à la date de son acceptation par le Licencié +telle que définie en 3.1. + + + 4.2 DUREE + +Le Contrat produira ses effets pendant toute la durée légale de +protection des droits patrimoniaux portant sur le Logiciel. + + + Article 5 - ETENDUE DES DROITS CONCEDES + +Le Concédant concède au Licencié, qui accepte, les droits suivants sur +le Logiciel pour toutes destinations et pour la durée du Contrat dans +les conditions ci-après détaillées. + +Par ailleurs, si le Concédant détient ou venait à détenir un ou +plusieurs brevets d'invention protégeant tout ou partie des +fonctionnalités du Logiciel ou de ses composants, il s'engage à ne pas +opposer les éventuels droits conférés par ces brevets aux Licenciés +successifs qui utiliseraient, exploiteraient ou modifieraient le +Logiciel. En cas de cession de ces brevets, le Concédant s'engage à +faire reprendre les obligations du présent alinéa aux cessionnaires. + + + 5.1 DROIT D'UTILISATION + +Le Licencié est autorisé à utiliser le Logiciel, sans restriction quant +aux domaines d'application, étant ci-après précisé que cela comporte: + + 1. la reproduction permanente ou provisoire du Logiciel en tout ou + partie par tout moyen et sous toute forme. + + 2. le chargement, l'affichage, l'exécution, ou le stockage du + Logiciel sur tout support. + + 3. la possibilité d'en observer, d'en étudier, ou d'en tester le + fonctionnement afin de déterminer les idées et principes qui sont + à la base de n'importe quel élément de ce Logiciel; et ceci, + lorsque le Licencié effectue toute opération de chargement, + d'affichage, d'exécution, de transmission ou de stockage du + Logiciel qu'il est en droit d'effectuer en vertu du Contrat. + + + 5.2 DROIT D'APPORTER DES CONTRIBUTIONS + +Le droit d'apporter des Contributions comporte le droit de traduire, +d'adapter, d'arranger ou d'apporter toute autre modification au Logiciel +et le droit de reproduire le logiciel en résultant. + +Le Licencié est autorisé à apporter toute Contribution au Logiciel sous +réserve de mentionner, de façon explicite, son nom en tant qu'auteur de +cette Contribution et la date de création de celle-ci. + + + 5.3 DROIT DE DISTRIBUTION + +Le droit de distribution comporte notamment le droit de diffuser, de +transmettre et de communiquer le Logiciel au public sur tout support et +par tout moyen ainsi que le droit de mettre sur le marché à titre +onéreux ou gratuit, un ou des exemplaires du Logiciel par tout procédé. + +Le Licencié est autorisé à distribuer des copies du Logiciel, modifié ou +non, à des tiers dans les conditions ci-après détaillées. + + + 5.3.1 DISTRIBUTION DU LOGICIEL SANS MODIFICATION + +Le Licencié est autorisé à distribuer des copies conformes du Logiciel, +sous forme de Code Source ou de Code Objet, à condition que cette +distribution respecte les dispositions du Contrat dans leur totalité et +soit accompagnée: + + 1. d'un exemplaire du Contrat, + + 2. d'un avertissement relatif à la restriction de garantie et de + responsabilité du Concédant telle que prévue aux articles 8 + et 9, + +et que, dans le cas où seul le Code Objet du Logiciel est redistribué, +le Licencié permette aux futurs Licenciés d'accéder facilement au Code +Source complet du Logiciel en indiquant les modalités d'accès, étant +entendu que le coût additionnel d'acquisition du Code Source ne devra +pas excéder le simple coût de transfert des données. + + + 5.3.2 DISTRIBUTION DU LOGICIEL MODIFIE + +Lorsque le Licencié apporte une Contribution au Logiciel, les conditions +de distribution du Logiciel Modifié en résultant sont alors soumises à +l'intégralité des dispositions du Contrat. + +Le Licencié est autorisé à distribuer le Logiciel Modifié, sous forme de +code source ou de code objet, à condition que cette distribution +respecte les dispositions du Contrat dans leur totalité et soit +accompagnée: + + 1. d'un exemplaire du Contrat, + + 2. d'un avertissement relatif à la restriction de garantie et de + responsabilité du Concédant telle que prévue aux articles 8 + et 9, + +et que, dans le cas où seul le code objet du Logiciel Modifié est +redistribué, le Licencié permette aux futurs Licenciés d'accéder +facilement au code source complet du Logiciel Modifié en indiquant les +modalités d'accès, étant entendu que le coût additionnel d'acquisition +du code source ne devra pas excéder le simple coût de transfert des données. + + + 5.3.3 DISTRIBUTION DES MODULES EXTERNES + +Lorsque le Licencié a développé un Module Externe les conditions du +Contrat ne s'appliquent pas à ce Module Externe, qui peut être distribué +sous un contrat de licence différent. + + + 5.3.4 COMPATIBILITE AVEC LA LICENCE GNU GPL + +Le Licencié peut inclure un code soumis aux dispositions d'une des +versions de la licence GNU GPL dans le Logiciel modifié ou non et +distribuer l'ensemble sous les conditions de la même version de la +licence GNU GPL. + +Le Licencié peut inclure le Logiciel modifié ou non dans un code soumis +aux dispositions d'une des versions de la licence GNU GPL et distribuer +l'ensemble sous les conditions de la même version de la licence GNU GPL. + + + Article 6 - PROPRIETE INTELLECTUELLE + + + 6.1 SUR LE LOGICIEL INITIAL + +Le Titulaire est détenteur des droits patrimoniaux sur le Logiciel +Initial. Toute utilisation du Logiciel Initial est soumise au respect +des conditions dans lesquelles le Titulaire a choisi de diffuser son +oeuvre et nul autre n'a la faculté de modifier les conditions de +diffusion de ce Logiciel Initial. + +Le Titulaire s'engage à ce que le Logiciel Initial reste au moins régi +par le Contrat et ce, pour la durée visée à l'article 4.2. + + + 6.2 SUR LES CONTRIBUTIONS + +Le Licencié qui a développé une Contribution est titulaire sur celle-ci +des droits de propriété intellectuelle dans les conditions définies par +la législation applicable. + + + 6.3 SUR LES MODULES EXTERNES + +Le Licencié qui a développé un Module Externe est titulaire sur celui-ci +des droits de propriété intellectuelle dans les conditions définies par +la législation applicable et reste libre du choix du contrat régissant +sa diffusion. + + + 6.4 DISPOSITIONS COMMUNES + +Le Licencié s'engage expressément: + + 1. à ne pas supprimer ou modifier de quelque manière que ce soit les + mentions de propriété intellectuelle apposées sur le Logiciel; + + 2. à reproduire à l'identique lesdites mentions de propriété + intellectuelle sur les copies du Logiciel modifié ou non. + +Le Licencié s'engage à ne pas porter atteinte, directement ou +indirectement, aux droits de propriété intellectuelle du Titulaire et/ou +des Contributeurs sur le Logiciel et à prendre, le cas échéant, à +l'égard de son personnel toutes les mesures nécessaires pour assurer le +respect des dits droits de propriété intellectuelle du Titulaire et/ou +des Contributeurs. + + + Article 7 - SERVICES ASSOCIES + +7.1 Le Contrat n'oblige en aucun cas le Concédant à la réalisation de +prestations d'assistance technique ou de maintenance du Logiciel. + +Cependant le Concédant reste libre de proposer ce type de services. Les +termes et conditions d'une telle assistance technique et/ou d'une telle +maintenance seront alors déterminés dans un acte séparé. Ces actes de +maintenance et/ou assistance technique n'engageront que la seule +responsabilité du Concédant qui les propose. + +7.2 De même, tout Concédant est libre de proposer, sous sa seule +responsabilité, à ses licenciés une garantie, qui n'engagera que lui, +lors de la redistribution du Logiciel et/ou du Logiciel Modifié et ce, +dans les conditions qu'il souhaite. Cette garantie et les modalités +financières de son application feront l'objet d'un acte séparé entre le +Concédant et le Licencié. + + + Article 8 - RESPONSABILITE + +8.1 Sous réserve des dispositions de l'article 8.2, le Licencié a la +faculté, sous réserve de prouver la faute du Concédant concerné, de +solliciter la réparation du préjudice direct qu'il subirait du fait du +Logiciel et dont il apportera la preuve. + +8.2 La responsabilité du Concédant est limitée aux engagements pris en +application du Contrat et ne saurait être engagée en raison notamment: +(i) des dommages dus à l'inexécution, totale ou partielle, de ses +obligations par le Licencié, (ii) des dommages directs ou indirects +découlant de l'utilisation ou des performances du Logiciel subis par le +Licencié et (iii) plus généralement d'un quelconque dommage indirect. En +particulier, les Parties conviennent expressément que tout préjudice +financier ou commercial (par exemple perte de données, perte de +bénéfices, perte d'exploitation, perte de clientèle ou de commandes, +manque à gagner, trouble commercial quelconque) ou toute action dirigée +contre le Licencié par un tiers, constitue un dommage indirect et +n'ouvre pas droit à réparation par le Concédant. + + + Article 9 - GARANTIE + +9.1 Le Licencié reconnaît que l'état actuel des connaissances +scientifiques et techniques au moment de la mise en circulation du +Logiciel ne permet pas d'en tester et d'en vérifier toutes les +utilisations ni de détecter l'existence d'éventuels défauts. L'attention +du Licencié a été attirée sur ce point sur les risques associés au +chargement, à l'utilisation, la modification et/ou au développement et à +la reproduction du Logiciel qui sont réservés à des utilisateurs avertis. + +Il relève de la responsabilité du Licencié de contrôler, par tous +moyens, l'adéquation du produit à ses besoins, son bon fonctionnement et +de s'assurer qu'il ne causera pas de dommages aux personnes et aux biens. + +9.2 Le Concédant déclare de bonne foi être en droit de concéder +l'ensemble des droits attachés au Logiciel (comprenant notamment les +droits visés à l'article 5). + +9.3 Le Licencié reconnaît que le Logiciel est fourni "en l'état" par le +Concédant sans autre garantie, expresse ou tacite, que celle prévue à +l'article 9.2 et notamment sans aucune garantie sur sa valeur commerciale, +son caractère sécurisé, innovant ou pertinent. + +En particulier, le Concédant ne garantit pas que le Logiciel est exempt +d'erreur, qu'il fonctionnera sans interruption, qu'il sera compatible +avec l'équipement du Licencié et sa configuration logicielle ni qu'il +remplira les besoins du Licencié. + +9.4 Le Concédant ne garantit pas, de manière expresse ou tacite, que le +Logiciel ne porte pas atteinte à un quelconque droit de propriété +intellectuelle d'un tiers portant sur un brevet, un logiciel ou sur tout +autre droit de propriété. Ainsi, le Concédant exclut toute garantie au +profit du Licencié contre les actions en contrefaçon qui pourraient être +diligentées au titre de l'utilisation, de la modification, et de la +redistribution du Logiciel. Néanmoins, si de telles actions sont +exercées contre le Licencié, le Concédant lui apportera son aide +technique et juridique pour sa défense. Cette aide technique et +juridique est déterminée au cas par cas entre le Concédant concerné et +le Licencié dans le cadre d'un protocole d'accord. Le Concédant dégage +toute responsabilité quant à l'utilisation de la dénomination du +Logiciel par le Licencié. Aucune garantie n'est apportée quant à +l'existence de droits antérieurs sur le nom du Logiciel et sur +l'existence d'une marque. + + + Article 10 - RESILIATION + +10.1 En cas de manquement par le Licencié aux obligations mises à sa +charge par le Contrat, le Concédant pourra résilier de plein droit le +Contrat trente (30) jours après notification adressée au Licencié et +restée sans effet. + +10.2 Le Licencié dont le Contrat est résilié n'est plus autorisé à +utiliser, modifier ou distribuer le Logiciel. Cependant, toutes les +licences qu'il aura concédées antérieurement à la résiliation du Contrat +resteront valides sous réserve qu'elles aient été effectuées en +conformité avec le Contrat. + + + Article 11 - DISPOSITIONS DIVERSES + + + 11.1 CAUSE EXTERIEURE + +Aucune des Parties ne sera responsable d'un retard ou d'une défaillance +d'exécution du Contrat qui serait dû à un cas de force majeure, un cas +fortuit ou une cause extérieure, telle que, notamment, le mauvais +fonctionnement ou les interruptions du réseau électrique ou de +télécommunication, la paralysie du réseau liée à une attaque +informatique, l'intervention des autorités gouvernementales, les +catastrophes naturelles, les dégâts des eaux, les tremblements de terre, +le feu, les explosions, les grèves et les conflits sociaux, l'état de +guerre... + +11.2 Le fait, par l'une ou l'autre des Parties, d'omettre en une ou +plusieurs occasions de se prévaloir d'une ou plusieurs dispositions du +Contrat, ne pourra en aucun cas impliquer renonciation par la Partie +intéressée à s'en prévaloir ultérieurement. + +11.3 Le Contrat annule et remplace toute convention antérieure, écrite +ou orale, entre les Parties sur le même objet et constitue l'accord +entier entre les Parties sur cet objet. Aucune addition ou modification +aux termes du Contrat n'aura d'effet à l'égard des Parties à moins +d'être faite par écrit et signée par leurs représentants dûment habilités. + +11.4 Dans l'hypothèse où une ou plusieurs des dispositions du Contrat +s'avèrerait contraire à une loi ou à un texte applicable, existants ou +futurs, cette loi ou ce texte prévaudrait, et les Parties feraient les +amendements nécessaires pour se conformer à cette loi ou à ce texte. +Toutes les autres dispositions resteront en vigueur. De même, la +nullité, pour quelque raison que ce soit, d'une des dispositions du +Contrat ne saurait entraîner la nullité de l'ensemble du Contrat. + + + 11.5 LANGUE + +Le Contrat est rédigé en langue française et en langue anglaise, ces +deux versions faisant également foi. + + + Article 12 - NOUVELLES VERSIONS DU CONTRAT + +12.1 Toute personne est autorisée à copier et distribuer des copies de +ce Contrat. + +12.2 Afin d'en préserver la cohérence, le texte du Contrat est protégé +et ne peut être modifié que par les auteurs de la licence, lesquels se +réservent le droit de publier périodiquement des mises à jour ou de +nouvelles versions du Contrat, qui posséderont chacune un numéro +distinct. Ces versions ultérieures seront susceptibles de prendre en +compte de nouvelles problématiques rencontrées par les logiciels libres. + +12.3 Tout Logiciel diffusé sous une version donnée du Contrat ne pourra +faire l'objet d'une diffusion ultérieure que sous la même version du +Contrat ou une version postérieure, sous réserve des dispositions de +l'article 5.3.4. + + + Article 13 - LOI APPLICABLE ET COMPETENCE TERRITORIALE + +13.1 Le Contrat est régi par la loi française. Les Parties conviennent +de tenter de régler à l'amiable les différends ou litiges qui +viendraient à se produire par suite ou à l'occasion du Contrat. + +13.2 A défaut d'accord amiable dans un délai de deux (2) mois à compter +de leur survenance et sauf situation relevant d'une procédure d'urgence, +les différends ou litiges seront portés par la Partie la plus diligente +devant les Tribunaux compétents de Paris. + + +Version 2.0 du 2006-09-05. diff --git a/tools/gfx2crtc/LICENSE b/tools/gfx2crtc/LICENSE new file mode 100644 index 0000000..fcc8df2 --- /dev/null +++ b/tools/gfx2crtc/LICENSE @@ -0,0 +1,506 @@ + +CeCILL FREE SOFTWARE LICENSE AGREEMENT + + + Notice + +This Agreement is a Free Software license agreement that is the result +of discussions between its authors in order to ensure compliance with +the two main principles guiding its drafting: + + * firstly, compliance with the principles governing the distribution + of Free Software: access to source code, broad rights granted to + users, + * secondly, the election of a governing law, French law, with which + it is conformant, both as regards the law of torts and + intellectual property law, and the protection that it offers to + both authors and holders of the economic rights over software. + +The authors of the CeCILL (for Ce[a] C[nrs] I[nria] L[ogiciel] L[ibre]) +license are: + +Commissariat à l'Energie Atomique - CEA, a public scientific, technical +and industrial research establishment, having its principal place of +business at 25 rue Leblanc, immeuble Le Ponant D, 75015 Paris, France. + +Centre National de la Recherche Scientifique - CNRS, a public scientific +and technological establishment, having its principal place of business +at 3 rue Michel-Ange, 75794 Paris cedex 16, France. + +Institut National de Recherche en Informatique et en Automatique - +INRIA, a public scientific and technological establishment, having its +principal place of business at Domaine de Voluceau, Rocquencourt, BP +105, 78153 Le Chesnay cedex, France. + + + Preamble + +The purpose of this Free Software license agreement is to grant users +the right to modify and redistribute the software governed by this +license within the framework of an open source distribution model. + +The exercising of these rights is conditional upon certain obligations +for users so as to preserve this status for all subsequent redistributions. + +In consideration of access to the source code and the rights to copy, +modify and redistribute granted by the license, users are provided only +with a limited warranty and the software's author, the holder of the +economic rights, and the successive licensors only have limited liability. + +In this respect, the risks associated with loading, using, modifying +and/or developing or reproducing the software by the user are brought to +the user's attention, given its Free Software status, which may make it +complicated to use, with the result that its use is reserved for +developers and experienced professionals having in-depth computer +knowledge. Users are therefore encouraged to load and test the +suitability of the software as regards their requirements in conditions +enabling the security of their systems and/or data to be ensured and, +more generally, to use and operate it in the same conditions of +security. This Agreement may be freely reproduced and published, +provided it is not altered, and that no provisions are either added or +removed herefrom. + +This Agreement may apply to any or all software for which the holder of +the economic rights decides to submit the use thereof to its provisions. + + + Article 1 - DEFINITIONS + +For the purpose of this Agreement, when the following expressions +commence with a capital letter, they shall have the following meaning: + +Agreement: means this license agreement, and its possible subsequent +versions and annexes. + +Software: means the software in its Object Code and/or Source Code form +and, where applicable, its documentation, "as is" when the Licensee +accepts the Agreement. + +Initial Software: means the Software in its Source Code and possibly its +Object Code form and, where applicable, its documentation, "as is" when +it is first distributed under the terms and conditions of the Agreement. + +Modified Software: means the Software modified by at least one +Contribution. + +Source Code: means all the Software's instructions and program lines to +which access is required so as to modify the Software. + +Object Code: means the binary files originating from the compilation of +the Source Code. + +Holder: means the holder(s) of the economic rights over the Initial +Software. + +Licensee: means the Software user(s) having accepted the Agreement. + +Contributor: means a Licensee having made at least one Contribution. + +Licensor: means the Holder, or any other individual or legal entity, who +distributes the Software under the Agreement. + +Contribution: means any or all modifications, corrections, translations, +adaptations and/or new functions integrated into the Software by any or +all Contributors, as well as any or all Internal Modules. + +Module: means a set of sources files including their documentation that +enables supplementary functions or services in addition to those offered +by the Software. + +External Module: means any or all Modules, not derived from the +Software, so that this Module and the Software run in separate address +spaces, with one calling the other when they are run. + +Internal Module: means any or all Module, connected to the Software so +that they both execute in the same address space. + +GNU GPL: means the GNU General Public License version 2 or any +subsequent version, as published by the Free Software Foundation Inc. + +Parties: mean both the Licensee and the Licensor. + +These expressions may be used both in singular and plural form. + + + Article 2 - PURPOSE + +The purpose of the Agreement is the grant by the Licensor to the +Licensee of a non-exclusive, transferable and worldwide license for the +Software as set forth in Article 5 hereinafter for the whole term of the +protection granted by the rights over said Software. + + + Article 3 - ACCEPTANCE + +3.1 The Licensee shall be deemed as having accepted the terms and +conditions of this Agreement upon the occurrence of the first of the +following events: + + * (i) loading the Software by any or all means, notably, by + downloading from a remote server, or by loading from a physical + medium; + * (ii) the first time the Licensee exercises any of the rights + granted hereunder. + +3.2 One copy of the Agreement, containing a notice relating to the +characteristics of the Software, to the limited warranty, and to the +fact that its use is restricted to experienced users has been provided +to the Licensee prior to its acceptance as set forth in Article 3.1 +hereinabove, and the Licensee hereby acknowledges that it has read and +understood it. + + + Article 4 - EFFECTIVE DATE AND TERM + + + 4.1 EFFECTIVE DATE + +The Agreement shall become effective on the date when it is accepted by +the Licensee as set forth in Article 3.1. + + + 4.2 TERM + +The Agreement shall remain in force for the entire legal term of +protection of the economic rights over the Software. + + + Article 5 - SCOPE OF RIGHTS GRANTED + +The Licensor hereby grants to the Licensee, who accepts, the following +rights over the Software for any or all use, and for the term of the +Agreement, on the basis of the terms and conditions set forth hereinafter. + +Besides, if the Licensor owns or comes to own one or more patents +protecting all or part of the functions of the Software or of its +components, the Licensor undertakes not to enforce the rights granted by +these patents against successive Licensees using, exploiting or +modifying the Software. If these patents are transferred, the Licensor +undertakes to have the transferees subscribe to the obligations set +forth in this paragraph. + + + 5.1 RIGHT OF USE + +The Licensee is authorized to use the Software, without any limitation +as to its fields of application, with it being hereinafter specified +that this comprises: + + 1. permanent or temporary reproduction of all or part of the Software + by any or all means and in any or all form. + + 2. loading, displaying, running, or storing the Software on any or + all medium. + + 3. entitlement to observe, study or test its operation so as to + determine the ideas and principles behind any or all constituent + elements of said Software. This shall apply when the Licensee + carries out any or all loading, displaying, running, transmission + or storage operation as regards the Software, that it is entitled + to carry out hereunder. + + + 5.2 ENTITLEMENT TO MAKE CONTRIBUTIONS + +The right to make Contributions includes the right to translate, adapt, +arrange, or make any or all modifications to the Software, and the right +to reproduce the resulting software. + +The Licensee is authorized to make any or all Contributions to the +Software provided that it includes an explicit notice that it is the +author of said Contribution and indicates the date of the creation thereof. + + + 5.3 RIGHT OF DISTRIBUTION + +In particular, the right of distribution includes the right to publish, +transmit and communicate the Software to the general public on any or +all medium, and by any or all means, and the right to market, either in +consideration of a fee, or free of charge, one or more copies of the +Software by any means. + +The Licensee is further authorized to distribute copies of the modified +or unmodified Software to third parties according to the terms and +conditions set forth hereinafter. + + + 5.3.1 DISTRIBUTION OF SOFTWARE WITHOUT MODIFICATION + +The Licensee is authorized to distribute true copies of the Software in +Source Code or Object Code form, provided that said distribution +complies with all the provisions of the Agreement and is accompanied by: + + 1. a copy of the Agreement, + + 2. a notice relating to the limitation of both the Licensor's + warranty and liability as set forth in Articles 8 and 9, + +and that, in the event that only the Object Code of the Software is +redistributed, the Licensee allows future Licensees unhindered access to +the full Source Code of the Software by indicating how to access it, it +being understood that the additional cost of acquiring the Source Code +shall not exceed the cost of transferring the data. + + + 5.3.2 DISTRIBUTION OF MODIFIED SOFTWARE + +When the Licensee makes a Contribution to the Software, the terms and +conditions for the distribution of the resulting Modified Software +become subject to all the provisions of this Agreement. + +The Licensee is authorized to distribute the Modified Software, in +source code or object code form, provided that said distribution +complies with all the provisions of the Agreement and is accompanied by: + + 1. a copy of the Agreement, + + 2. a notice relating to the limitation of both the Licensor's + warranty and liability as set forth in Articles 8 and 9, + +and that, in the event that only the object code of the Modified +Software is redistributed, the Licensee allows future Licensees +unhindered access to the full source code of the Modified Software by +indicating how to access it, it being understood that the additional +cost of acquiring the source code shall not exceed the cost of +transferring the data. + + + 5.3.3 DISTRIBUTION OF EXTERNAL MODULES + +When the Licensee has developed an External Module, the terms and +conditions of this Agreement do not apply to said External Module, that +may be distributed under a separate license agreement. + + + 5.3.4 COMPATIBILITY WITH THE GNU GPL + +The Licensee can include a code that is subject to the provisions of one +of the versions of the GNU GPL in the Modified or unmodified Software, +and distribute that entire code under the terms of the same version of +the GNU GPL. + +The Licensee can include the Modified or unmodified Software in a code +that is subject to the provisions of one of the versions of the GNU GPL, +and distribute that entire code under the terms of the same version of +the GNU GPL. + + + Article 6 - INTELLECTUAL PROPERTY + + + 6.1 OVER THE INITIAL SOFTWARE + +The Holder owns the economic rights over the Initial Software. Any or +all use of the Initial Software is subject to compliance with the terms +and conditions under which the Holder has elected to distribute its work +and no one shall be entitled to modify the terms and conditions for the +distribution of said Initial Software. + +The Holder undertakes that the Initial Software will remain ruled at +least by this Agreement, for the duration set forth in Article 4.2. + + + 6.2 OVER THE CONTRIBUTIONS + +The Licensee who develops a Contribution is the owner of the +intellectual property rights over this Contribution as defined by +applicable law. + + + 6.3 OVER THE EXTERNAL MODULES + +The Licensee who develops an External Module is the owner of the +intellectual property rights over this External Module as defined by +applicable law and is free to choose the type of agreement that shall +govern its distribution. + + + 6.4 JOINT PROVISIONS + +The Licensee expressly undertakes: + + 1. not to remove, or modify, in any manner, the intellectual property + notices attached to the Software; + + 2. to reproduce said notices, in an identical manner, in the copies + of the Software modified or not. + +The Licensee undertakes not to directly or indirectly infringe the +intellectual property rights of the Holder and/or Contributors on the +Software and to take, where applicable, vis-à-vis its staff, any and all +measures required to ensure respect of said intellectual property rights +of the Holder and/or Contributors. + + + Article 7 - RELATED SERVICES + +7.1 Under no circumstances shall the Agreement oblige the Licensor to +provide technical assistance or maintenance services for the Software. + +However, the Licensor is entitled to offer this type of services. The +terms and conditions of such technical assistance, and/or such +maintenance, shall be set forth in a separate instrument. Only the +Licensor offering said maintenance and/or technical assistance services +shall incur liability therefor. + +7.2 Similarly, any Licensor is entitled to offer to its licensees, under +its sole responsibility, a warranty, that shall only be binding upon +itself, for the redistribution of the Software and/or the Modified +Software, under terms and conditions that it is free to decide. Said +warranty, and the financial terms and conditions of its application, +shall be subject of a separate instrument executed between the Licensor +and the Licensee. + + + Article 8 - LIABILITY + +8.1 Subject to the provisions of Article 8.2, the Licensee shall be +entitled to claim compensation for any direct loss it may have suffered +from the Software as a result of a fault on the part of the relevant +Licensor, subject to providing evidence thereof. + +8.2 The Licensor's liability is limited to the commitments made under +this Agreement and shall not be incurred as a result of in particular: +(i) loss due the Licensee's total or partial failure to fulfill its +obligations, (ii) direct or consequential loss that is suffered by the +Licensee due to the use or performance of the Software, and (iii) more +generally, any consequential loss. In particular the Parties expressly +agree that any or all pecuniary or business loss (i.e. loss of data, +loss of profits, operating loss, loss of customers or orders, +opportunity cost, any disturbance to business activities) or any or all +legal proceedings instituted against the Licensee by a third party, +shall constitute consequential loss and shall not provide entitlement to +any or all compensation from the Licensor. + + + Article 9 - WARRANTY + +9.1 The Licensee acknowledges that the scientific and technical +state-of-the-art when the Software was distributed did not enable all +possible uses to be tested and verified, nor for the presence of +possible defects to be detected. In this respect, the Licensee's +attention has been drawn to the risks associated with loading, using, +modifying and/or developing and reproducing the Software which are +reserved for experienced users. + +The Licensee shall be responsible for verifying, by any or all means, +the suitability of the product for its requirements, its good working +order, and for ensuring that it shall not cause damage to either persons +or properties. + +9.2 The Licensor hereby represents, in good faith, that it is entitled +to grant all the rights over the Software (including in particular the +rights set forth in Article 5). + +9.3 The Licensee acknowledges that the Software is supplied "as is" by +the Licensor without any other express or tacit warranty, other than +that provided for in Article 9.2 and, in particular, without any warranty +as to its commercial value, its secured, safe, innovative or relevant +nature. + +Specifically, the Licensor does not warrant that the Software is free +from any error, that it will operate without interruption, that it will +be compatible with the Licensee's own equipment and software +configuration, nor that it will meet the Licensee's requirements. + +9.4 The Licensor does not either expressly or tacitly warrant that the +Software does not infringe any third party intellectual property right +relating to a patent, software or any other property right. Therefore, +the Licensor disclaims any and all liability towards the Licensee +arising out of any or all proceedings for infringement that may be +instituted in respect of the use, modification and redistribution of the +Software. Nevertheless, should such proceedings be instituted against +the Licensee, the Licensor shall provide it with technical and legal +assistance for its defense. Such technical and legal assistance shall be +decided on a case-by-case basis between the relevant Licensor and the +Licensee pursuant to a memorandum of understanding. The Licensor +disclaims any and all liability as regards the Licensee's use of the +name of the Software. No warranty is given as regards the existence of +prior rights over the name of the Software or as regards the existence +of a trademark. + + + Article 10 - TERMINATION + +10.1 In the event of a breach by the Licensee of its obligations +hereunder, the Licensor may automatically terminate this Agreement +thirty (30) days after notice has been sent to the Licensee and has +remained ineffective. + +10.2 A Licensee whose Agreement is terminated shall no longer be +authorized to use, modify or distribute the Software. However, any +licenses that it may have granted prior to termination of the Agreement +shall remain valid subject to their having been granted in compliance +with the terms and conditions hereof. + + + Article 11 - MISCELLANEOUS + + + 11.1 EXCUSABLE EVENTS + +Neither Party shall be liable for any or all delay, or failure to +perform the Agreement, that may be attributable to an event of force +majeure, an act of God or an outside cause, such as defective +functioning or interruptions of the electricity or telecommunications +networks, network paralysis following a virus attack, intervention by +government authorities, natural disasters, water damage, earthquakes, +fire, explosions, strikes and labor unrest, war, etc. + +11.2 Any failure by either Party, on one or more occasions, to invoke +one or more of the provisions hereof, shall under no circumstances be +interpreted as being a waiver by the interested Party of its right to +invoke said provision(s) subsequently. + +11.3 The Agreement cancels and replaces any or all previous agreements, +whether written or oral, between the Parties and having the same +purpose, and constitutes the entirety of the agreement between said +Parties concerning said purpose. No supplement or modification to the +terms and conditions hereof shall be effective as between the Parties +unless it is made in writing and signed by their duly authorized +representatives. + +11.4 In the event that one or more of the provisions hereof were to +conflict with a current or future applicable act or legislative text, +said act or legislative text shall prevail, and the Parties shall make +the necessary amendments so as to comply with said act or legislative +text. All other provisions shall remain effective. Similarly, invalidity +of a provision of the Agreement, for any reason whatsoever, shall not +cause the Agreement as a whole to be invalid. + + + 11.5 LANGUAGE + +The Agreement is drafted in both French and English and both versions +are deemed authentic. + + + Article 12 - NEW VERSIONS OF THE AGREEMENT + +12.1 Any person is authorized to duplicate and distribute copies of this +Agreement. + +12.2 So as to ensure coherence, the wording of this Agreement is +protected and may only be modified by the authors of the License, who +reserve the right to periodically publish updates or new versions of the +Agreement, each with a separate number. These subsequent versions may +address new issues encountered by Free Software. + +12.3 Any Software distributed under a given version of the Agreement may +only be subsequently distributed under the same version of the Agreement +or a subsequent version, subject to the provisions of Article 5.3.4. + + + Article 13 - GOVERNING LAW AND JURISDICTION + +13.1 The Agreement is governed by French law. The Parties agree to +endeavor to seek an amicable solution to any disagreements or disputes +that may arise during the performance of the Agreement. + +13.2 Failing an amicable solution within two (2) months as from their +occurrence, and unless emergency proceedings are necessary, the +disagreements or disputes shall be referred to the Paris Courts having +jurisdiction, by the more diligent Party. + + +Version 2.0 dated 2006-09-05. diff --git a/tools/gfx2crtc/README b/tools/gfx2crtc/README new file mode 100644 index 0000000..596349d --- /dev/null +++ b/tools/gfx2crtc/README @@ -0,0 +1,36 @@ +English Version at the end. + +Version Française (French Version) +---------------------------------------------------------------------- + gfx2crtc - utilitaire de convertion d'image vers image au format cpc +---------------------------------------------------------------------- + +gfx2crtc est un utilitaire qui permet la convertion d'image (format brut +lineaire 8bits par pixel ou PNG 1,2 ou 4 bits) dans un format compatible avec +l'Amstrad CPC et Plus. + +Logiciel Initial écrit par : +CloudStrife/Shinra (Quentin Carlier) <cloudstrife@cpcscene.com>. +Il est diffusé sur la Licence de Logiciel Libre CeCILL version 2, +Voire LICENCE pour plus d'information. +Voire le fichier AUTHORS pour voire la liste des differents Contributeur. + +Utilisation : +------------- + +English Version +---------------------------------------------------- + gfx2crtc - gfx convert tools to amstrad cpc format +---------------------------------------------------- + +gfx2crtc is a tools program for convert gfx (linear raw 8bits per pixel or +PNG 1,2 ou 4 bits) in a compatible format for Amstrad CPC and Plus. + +Initial Software write by : +CloudStrife/Shinra (Quentin Carlier) <cloudstrife@cpcscene.com>. +It is diffused on the CeCILL Free Software License v2, +See LICENSE for more information. +See AUTHORS for the list of Contributor. + +Usage : +-------
\ No newline at end of file diff --git a/tools/gfx2crtc/TODO b/tools/gfx2crtc/TODO new file mode 100644 index 0000000..a394ead --- /dev/null +++ b/tools/gfx2crtc/TODO @@ -0,0 +1,9 @@ +- Ajouter un mode de convertion lineaire (équivalent à R9=0) +- Extraire la palette d'un png si palette CPC +- Gestion du registre 13 // Fait r47 +- Possibilité de ne garder qu'un pixel sur 2 (exemple pour Mode 0) +- Possibilité de ne garder qu'une ligne sur 2 (exemple pour Mode 2) +- Sprite plus (4bits/pixel, 1pixel/octets, 16x16, gauche a droite, haut en bas) +- Gestion mode entrelacé +- Visualisation ? +- Version Drag'n'drop pour windows ? diff --git a/tools/gfx2crtc/libraw2crtc.c b/tools/gfx2crtc/libraw2crtc.c new file mode 100644 index 0000000..b7d2f97 --- /dev/null +++ b/tools/gfx2crtc/libraw2crtc.c @@ -0,0 +1,186 @@ +/* GFX2CRTC - libraw2crtc.c + * CloudStrife - 20080921 + * Diffusé sous licence libre CeCILL v2 + * Voire LICENCE + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +unsigned short addrCalc(unsigned char vcc, unsigned char rcc, unsigned char hcc, unsigned char cclk, unsigned char r1, unsigned char r12, unsigned char r13) +{ + unsigned short MA; + unsigned short addr; + + //MA = vcc*r1 + hcc + (0x0C)*256; + MA = vcc*r1 + hcc + r12*256 + r13; + addr = cclk | ((MA & 0x03FF) << 1); + addr = addr | ((rcc & 0x07) << 11); + addr = addr | ((MA & 0x3000) << 2); + + return addr; +} + +unsigned char mode0interlace(unsigned char *x) +{ + unsigned char mode0pixel[] = {0, 64, 4, 68, 16, 80, 20, 84, 1, 65, 5, 69, 17, 81, 21, 85}; + return mode0pixel[x[0]] << 1 | mode0pixel[x[1]]; +} + +unsigned char mode1interlace(unsigned char *x) +{ + unsigned char mode1pixel[] = {0, 16, 1, 17}; + return mode1pixel[x[0]] << 3 | mode1pixel[x[1]] << 2 | mode1pixel[x[2]] << 1 | mode1pixel[x[3]]; +} + +unsigned char mode2interlace(unsigned char *x) +{ + unsigned char out = 0; + int i; + for(i = 0; i < 8; i++) out += ((x[7-i]&1) << i); + return out; +} + +unsigned char mode3interlace(unsigned char *x) +{ + unsigned char mode3pixel[] = {0, 16, 1, 17}; + return mode3pixel[x[0]] << 3 | mode3pixel[x[1]] << 2; +} + +unsigned char (*ptrMode)(unsigned char *x); + +unsigned char *raw2crtc(unsigned char *input, unsigned short width, unsigned short height, unsigned char mode, unsigned char r9, unsigned long *outSize, unsigned char *r1, unsigned char r12, unsigned char r13, unsigned char* reg6) +{ + unsigned char *outBuffer; + unsigned char *tmpBuffer; + unsigned char *allocationBuffer; + unsigned short minAddr = 0; + unsigned char minAddrIsDefined = 0; + unsigned short maxAddr; + + unsigned char nbPixPerByte; + int y,x; + + switch(mode) + { + case 0: + { + *r1 = (width+3)/4; + nbPixPerByte = 2; + ptrMode = mode0interlace; + break; + } + case 1: + { + *r1 = (width+7)/8; + nbPixPerByte = 4; + ptrMode = mode1interlace; + break; + } + case 2: + { + *r1 = (width+15)/16; + nbPixPerByte = 8; + ptrMode = mode2interlace; + break; + } + case 3: + { + *r1 = (width+3)/4; + nbPixPerByte = 2; + ptrMode = mode3interlace; + break; + } + default: + { + exit(4); + } + } + + tmpBuffer = (unsigned char*)malloc(0xFFFF); + if (tmpBuffer == NULL) + { + printf("Allocation tmpBuffer raté\n"); + exit(4); + } + + allocationBuffer = (unsigned char*)calloc(0xFFFF, 1); + if(allocationBuffer == NULL) + { + printf("Allocation allocationBuffer raté\n"); + exit(4); + } + + { + unsigned char r6; + unsigned char vcc,rcc,hcc,cclk; + r6 = (height+r9)/(r9+1); + *reg6 = r6; + + for(vcc = 0; vcc < r6; vcc++) + { + for(rcc = 0; rcc < (r9+1); rcc++) + { + for(hcc = 0; hcc < *r1; hcc++) + { + for(cclk = 0; cclk < 2; cclk++) + { + x = (hcc << 1 | cclk); + y = vcc*(r9+1) + rcc; + *(tmpBuffer + addrCalc(vcc, rcc, hcc, cclk, *r1, r12, r13)) = (*ptrMode)(input + y*width + x*nbPixPerByte); + *(allocationBuffer + addrCalc(vcc, rcc, hcc, cclk, *r1, r12, r13)) += 1; + } + } + } + } + } + + { + unsigned short i; + for(i = 0; i < 0xFFFF; i++) + { + if(*(allocationBuffer + i) > 1) + { + printf("Attention : Ecriture multiple a l'adresse mémoire %d\n",i); + } + if(*(allocationBuffer + i) > 0) + { + maxAddr = i; + } + if((*(allocationBuffer + i) == 1) && (minAddrIsDefined == 0)) + { + minAddr = i; + minAddrIsDefined = 1; + } + } + } + + *outSize = (maxAddr + 1) - minAddr; + + outBuffer = (unsigned char*)malloc((*outSize)); + if (outBuffer == NULL) + { + printf("Allocation outBuffer raté\n"); + exit(4); + } + + { + unsigned char *ptrTmp; + unsigned char *ptrOut; + unsigned short i; + ptrTmp = tmpBuffer + minAddr; + ptrOut = outBuffer; + + for(i = minAddr; i <= maxAddr; i++) + { + *(ptrOut++) = *(ptrTmp++); + } + } + free(tmpBuffer); + tmpBuffer = NULL; + free(allocationBuffer); + allocationBuffer = NULL; + + return outBuffer; +} diff --git a/tools/gfx2crtc/libraw2crtc.h b/tools/gfx2crtc/libraw2crtc.h new file mode 100644 index 0000000..8bab0e5 --- /dev/null +++ b/tools/gfx2crtc/libraw2crtc.h @@ -0,0 +1,12 @@ +/* GFX2CRTC - libraw2crtc.h + * CloudStrife - 20080921 + * Diffusé sous licence libre CeCILL v2 + * Voire LICENCE + */ + +#ifndef LIBRAW2CRTC_H +#define LIBRAW2CRTC_H 1 + +unsigned char * raw2crtc(unsigned char *input, unsigned short width, unsigned short height, unsigned char mode, unsigned char r9, unsigned long *outSize, unsigned char *r1, unsigned char r12, unsigned char r13, unsigned char* reg6); + +#endif diff --git a/tools/gfx2crtc/makefile b/tools/gfx2crtc/makefile new file mode 100644 index 0000000..8e4b2e2 --- /dev/null +++ b/tools/gfx2crtc/makefile @@ -0,0 +1,29 @@ +ALL= raw2crtc png2crtc + + +CC=gcc + +# Detect gcc2, if we're running it, use gnu9x standard instead of c99... +GCC_MAJOR = $(shell $(CC) -v 2>&1 |grep version |cut -d' ' -f3 |cut -d'.' -f1) + +ifeq ($(GCC_MAJOR),2) + CCFLAGS=-Os -W -Wall -std=gnu9x -g +else + CCFLAGS=-Os -W -Wall -std=c99 -g +endif + +#CCFLAGS=-O3 -W -Wall -pedantic -ansi + +all: $(ALL) + +clean : + rm -f a.out *.o core $(ALL) + +raw2crtc : raw2crtc.o libraw2crtc.o + $(CC) $(CCFLAGS) raw2crtc.o libraw2crtc.o -o raw2crtc + +png2crtc : png2crtc.o libraw2crtc.o + $(CC) $(CCFLAGS) png2crtc.o libraw2crtc.o -o png2crtc -lpng -lz + +.c.o : + $(CC) $(CCFLAGS) -c $< diff --git a/tools/gfx2crtc/png2crtc.c b/tools/gfx2crtc/png2crtc.c new file mode 100644 index 0000000..9742960 --- /dev/null +++ b/tools/gfx2crtc/png2crtc.c @@ -0,0 +1,204 @@ +/* GFX2CRTC - png2crtc.c + * CloudStrife - 20080921 + * Diffusé sous licence libre CeCILL v2 + * Voire LICENCE + */ + +#include <stdio.h> +#include <stdlib.h> +#include <png.h> +#include "libraw2crtc.h" + +#define ERROR 1 + +int main(int argc, char **argv) +{ + FILE *inFile, *outFile; + unsigned char *inBuffer, *outBuffer; + unsigned long outSize; + + unsigned char r1, r6, r9, r12, r13; + png_uint_32 width; + png_uint_32 height; + int bitdepth; + int colorType; + unsigned char mode; + unsigned char forcemode = 0; + unsigned char forcer12 = 0, forcer13 = 0; + + unsigned char header[8]; + unsigned char is_png; + + unsigned int y; + png_structp png_ptr; + png_infop info_ptr; + png_infop end_info; + + png_bytep * ptrRow; + + // We have to use this temporary variable insted of scanning directly into + // 8 bit integers using %hhu because mingW, relying on MSVCRT, is not C99 + // compliant and can't handle this "modern" stuff. + unsigned int stupid_mingw_isnt_c99; + + if((argc != 3) && (argc != 4) && (argc != 5) && (argc != 6) && (argc != 7)) + { + printf("Utilisation : %s input_filename output_filename [registre9] [mode] " + "[r12] [r13]\n",argv[0]); + exit(0); + } + + inFile = fopen(argv[1],"rb"); + + if(argc >= 4) + /*{sscanf(argv[3],"%hhu",&r9);}*/ + {sscanf(argv[3],"%u",&stupid_mingw_isnt_c99); r9=stupid_mingw_isnt_c99;} + else + {r9 = 7;} + if(argc >= 5) + { + // sscanf(argv[4],"%hhu",&mode); + sscanf(argv[4],"%u",&stupid_mingw_isnt_c99); mode = stupid_mingw_isnt_c99; + forcemode = 1; + if(mode > 3) puts("mode doit être compris entre 0 et 3"); + mode = mode & 3; + } + + // Registre r12 et r13 par défaut : + r12 = 0x0C; + r13 = 0x00; + + if(argc >= 6) + { + // sscanf(argv[5],"%hhu",&r12); + sscanf(argv[5],"%u",&stupid_mingw_isnt_c99); r12 = stupid_mingw_isnt_c99; + forcer12 = 1; + } + if(argc >= 7) + { + // sscanf(argv[6],"%hhu",&r13); + sscanf(argv[6],"%u",&stupid_mingw_isnt_c99); r13=stupid_mingw_isnt_c99; + forcer13 = 1; + } + + if (inFile == NULL) + { + printf("Fichier Inexistant\n"); + exit(1); + } + + fread(header, 1, 8, inFile); + is_png = !png_sig_cmp(header, 0, 8); + if (!is_png) + { + printf("Ce n'est pas un png\n"); + exit(2); + } + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, + NULL); + if (!png_ptr) return (ERROR); + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + return (ERROR); + } + + end_info = png_create_info_struct(png_ptr); + if (!end_info) + { + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + return (ERROR); + } + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + fclose(inFile); + return (ERROR); + } + + png_init_io(png_ptr, inFile); + png_set_sig_bytes(png_ptr, 8); + + png_read_info(png_ptr, info_ptr); + + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bitdepth, &colorType, NULL, + NULL, NULL); + + if(!((colorType == PNG_COLOR_TYPE_GRAY) + || (colorType == PNG_COLOR_TYPE_PALETTE))) + { + puts("Ce PNG n'est pas dans un format exploitable " + "(niveaux de gris ou palette)"); + return (ERROR); + } + + if(forcemode == 0) + { + switch(bitdepth) + { + case 1: + { + mode = 2; + break; + } + case 2: + { + mode = 1; + break; + } + case 4: + { + mode = 0; + break; + } + default: + { + puts("Ce PNG n'est pas dans un format exploitable" + "(bitdepth = 1, 2 ou 4)"); + return (ERROR); + } + } + } + + png_set_packing(png_ptr); /* Convertir en mode 1 pixel par octets */ + png_read_update_info(png_ptr, info_ptr); + + inBuffer = (unsigned char*)malloc(width*height); + if (inBuffer == NULL) + { + printf("Allocation inBuffer raté\n"); + exit(3); + } + + ptrRow = (png_bytep*)malloc(sizeof(png_bytep)*height); + for(y = 0; y < height; y++) + { + ptrRow[y] = (inBuffer + width*y); + } + + png_read_image(png_ptr, ptrRow); + + outBuffer = raw2crtc(inBuffer, width, height, mode, r9, &outSize, &r1, r12, r13, &r6); + + printf("Taille de l'écran de sortie : %lu\n",outSize); + printf("Mode = %d Largeur = %d Hauteur = %d R1 = %d R9 = %d R6 = %d\n",mode,(int)width,(int)height,r1,r9,r6); + + outFile = fopen(argv[2], "wb"); + fwrite(outBuffer, 1, outSize, outFile); + fclose(outFile); + + png_read_end(png_ptr, end_info); + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + + free(inBuffer); + inBuffer = NULL; + + free(outBuffer); + outBuffer = NULL; + + return 0; +} diff --git a/tools/gfx2crtc/raw2crtc.c b/tools/gfx2crtc/raw2crtc.c new file mode 100644 index 0000000..c8738dc --- /dev/null +++ b/tools/gfx2crtc/raw2crtc.c @@ -0,0 +1,86 @@ +/* GFX2CRTC - raw2crtc.c + * CloudStrife - 20080921 + * Diffusé sous licence libre CeCILL v2 + * Voire LICENCE + */ + +#include <stdio.h> +#include <stdlib.h> +#include "libraw2crtc.h" + +int main(int argc, char **argv) +{ + FILE *inFile, *outFile; + unsigned char *inBuffer, *outBuffer; + unsigned long inSize; + unsigned long outSize; + + unsigned char r1, r6, r9; + unsigned short width; + unsigned short height; + unsigned char mode; + + if((argc != 6) && (argc != 7)) + { + printf("Utilisation : %s input_filename output_filename width height mode [registre9]\n",argv[0]); + printf("Exemple : Convertir une image en 176 sur 224 en mode 0 :\n"); + printf("%s image.raw image.scr 176 224 0\n",argv[0]); + printf("Exemple : Convertir une image en 256 sur 128 en mode 1 avec R9 = 3 :\n"); + printf("%s image.raw image.scr 256 128 1 3\n",argv[0]); + exit(0); + } + + inFile = fopen(argv[1],"rb"); + + sscanf(argv[3],"%hud",&width); + sscanf(argv[4],"%hud",&height); + sscanf(argv[5],"%hhud",&mode); + if(mode > 3) printf("mode doit être compris entre 0 et 3"); + mode = mode & 3; + if(argc == 7) + {sscanf(argv[6],"%hhud",&r9);} + else + {r9 = 7;} + + if (inFile == NULL) + { + printf("Fichier Inexistant\n"); + exit(1); + } + + fseek(inFile, 0, SEEK_END); + inSize = ftell(inFile); + rewind(inFile); + + if (inSize != (unsigned long)(width*height)) + { + printf("Attention ! Mauvaise taille du fichier d'entré\n"); + } + + inBuffer = (unsigned char*)malloc(inSize); + if (inBuffer == NULL) + { + printf("Allocation inBuffer raté\n"); + exit(3); + } + + fread(inBuffer, 1, inSize, inFile); + fclose(inFile); + + outBuffer = raw2crtc(inBuffer, width, height, mode, r9, &outSize, &r1, 0, 0, &r6); + + printf("Taille de l'écran de sortie : %lu\n",outSize); + printf("Mode = %d Largeur = %d Hauteur = %d R1 = %d R9 = %d R6 = %d\n",mode,width,height,r1,r9,r6); + + outFile = fopen(argv[2], "wb"); + fwrite(outBuffer, 1, outSize, outFile); + fclose(outFile); + + free(inBuffer); + inBuffer = NULL; + + free(outBuffer); + outBuffer = NULL; + + return 0; +} diff --git a/tools/hex2bin-2.0/Makefile b/tools/hex2bin-2.0/Makefile new file mode 100755 index 0000000..c8ef10b --- /dev/null +++ b/tools/hex2bin-2.0/Makefile @@ -0,0 +1,42 @@ +# Makefile hex2bin/mot2bin +SRCDIR = src +BINDIR = bin +OBJDIR = obj +TGTDIR = $(BINDIR) +B_SRCFILES= $(foreach F, hex2bin.c common.c libcrc.c binary.c, $(SRCDIR)/$(F)) +B_OBJFILES= $(foreach F, hex2bin.o common.o libcrc.o binary.o, $(OBJDIR)/$(F)) +M_SRCFILES= $(foreach F, mot2bin.c common.c libcrc.c binary.c, $(SRCDIR)/$(F)) +M_OBJFILES= $(foreach F, mot2bin.o common.o libcrc.o binary.o, $(OBJDIR)/$(F)) + +# For generating documentation (hex2bin.1, select the second line) +# -- You will require pod2man installed for this to work +TGT_FILES = $(foreach F, hex2bin mot2bin, $(TGTDIR)/$(F)) +#TGT_FILES = $(foreach F, hex2bin mot2bin hex2bin.1, $(TGTDIR)/$(F)) + +CPFLAGS = -std=gnu99 -O3 -fsigned-char -Wall -pedantic +# Compile +all: objectdir $(TGT_FILES) + +$(OBJDIR)/%.o: $(SRCDIR)/%.c + gcc -c $(CPFLAGS) $< -o $@ + +objectdir: + @echo "Creating directory $(OBJDIR)..." + mkdir -p $(OBJDIR) + +$(TGTDIR)/hex2bin.1: $(SRCDIR)/hex2bin.pod + pod2man $(SRCDIR)/hex2bin.pod > $(TGTDIR)/hex2bin.1 + +$(TGTDIR)/hex2bin: $(B_OBJFILES) + gcc $(CPFLAGS) -o $(TGTDIR)/hex2bin $(B_OBJFILES) + +$(TGTDIR)/mot2bin: $(M_OBJFILES) + gcc $(CPFLAGS) -o $(TGTDIR)/mot2bin $(M_OBJFILES) + +clean: + @echo "Removing objects directory $(OBJDIR)/ ..." + @rm -rf $(OBJDIR) + +cleanall: clean + @echo "Removing binary files in $(BINDIR)/ ..." + @rm -f $(BINDIR)/* diff --git a/tools/hex2bin-2.0/bin/.deleteme b/tools/hex2bin-2.0/bin/.deleteme new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tools/hex2bin-2.0/bin/.deleteme diff --git a/tools/hex2bin-2.0/bin/hex2bin b/tools/hex2bin-2.0/bin/hex2bin Binary files differnew file mode 100755 index 0000000..c6967d7 --- /dev/null +++ b/tools/hex2bin-2.0/bin/hex2bin diff --git a/tools/hex2bin-2.0/bin/mot2bin b/tools/hex2bin-2.0/bin/mot2bin Binary files differnew file mode 100755 index 0000000..18400f4 --- /dev/null +++ b/tools/hex2bin-2.0/bin/mot2bin diff --git a/tools/hex2bin-2.0/doc/CRC list.txt b/tools/hex2bin-2.0/doc/CRC list.txt new file mode 100644 index 0000000..8549799 --- /dev/null +++ b/tools/hex2bin-2.0/doc/CRC list.txt @@ -0,0 +1,542 @@ +http://regregex.bbcmicro.net/crc-catalogue.htm + +CRC-8 +07 +<crc-8-atm> + Name : "CRC-8" + Width : 8 + Poly : 07 + Init : 00 + RefIn : False + RefOut : False + XorOut : 00 + Check : F4 + +<crc-8-itu> + Name : "CRC-8/ITU" + Width : 8 + Poly : 07 + Init : 00 + RefIn : False + RefOut : False + XorOut : 55 + Check : A1 + +<crc-8-rohc> + Name : "CRC-8/ROHC" + Width : 8 + Poly : 07 + Init : FF + RefIn : True + RefOut : True + XorOut : 0 + Check : D0 + +39 +<crc-8-darc> + Name : "CRC-8/DARC" + Width : 8 + Poly : 39 + Init : 00 + RefIn : True + RefOut : True + XorOut : 00 + Check : 15 + +1D +<crc-8-icode> + Name : "CRC-8/I-CODE" + Width : 8 + Poly : 1D + Init : FD + RefIn : False + RefOut : False + XorOut : 00 + Check : 7E + +<crc-8-j1850> + Name : "CRC-8/J1850" (new entry) + Width : 8 + Poly : 1D + Init : FF + RefIn : False + RefOut : False + XorOut : FF + Check : 4B + +31 +<crc-8-maxim> + Name : "CRC-8/MAXIM" + Alias : "DOW-CRC" + Width : 8 + Poly : 31 + Init : 00 + RefIn : True + RefOut : True + XorOut : 00 + Check : A1 + +9B +<crc-8-wcdma> + Name : "CRC-8/WCDMA" + Width : 8 + Poly : 9B + Init : 00 + RefIn : True + RefOut : True + XorOut : 00 + Check : 25 + +8D +<crc-8-ccitt> + Name : "CRC-8/CCITT" (new entry) 1-Wire? + Width : 8 + Poly : 8D + Init : 00? + RefIn : False? + RefOut : False? + XorOut : 00? + Check : D2 + +D5 +<crc-8> + Name : "CRC-8" (new entry) + Width : 8 + Poly : D5 + Init : 00? + RefIn : False? + RefOut : False? + XorOut : 00? + Check : BC + +CRC-16 +8005 +<crc-16> + Name : "ARC" + Alias : "CRC-16" + Alias : "CRC-IBM" + Alias : "CRC-16/ARC" + Alias : "CRC-16/LHA" + Width : 16 + Poly : 8005 + Init : 0000 + RefIn : True + RefOut : True + XorOut : 0000 + Check : BB3D + +<crc-16-buypass> + Name : "CRC-16/BUYPASS" + Alias : "CRC-16/VERIFONE" + Width : 16 + Poly : 8005 + Init : 0000 + RefIn : False + RefOut : False + XorOut : 0000 + Check : FEE8 + +<crc-dds-110> + Name : "CRC-16/DDS-110" + Width : 16 + Poly : 8005 + Init : 800D + RefIn : False + RefOut : False + XorOut : 0000 + Check : 9ECF + XCheck : CFE9 + +<crc-16-maxim> + Name : "CRC-16/MAXIM" + Width : 16 + Poly : 8005 + Init : 0000 + RefIn : True + RefOut : True + XorOut : FFFF + Check : 44C2 + +<crc-usb> + Name : "CRC-16/USB" + Width : 16 + Poly : 8005 + Init : FFFF + RefIn : True + RefOut : True + XorOut : FFFF + Check : B4C8 + +<crc-modbus> + Name : "MODBUS" + Width : 16 + Poly : 8005 + Init : FFFF + RefIn : True + RefOut : True + XorOut : 0000 + Check : 4B37 + +1021 +<crc-ccitt-1d0f> + Name : "CRC-16/AUG-CCITT" + Alias : "CRC-16/SPI-FUJITSU" + Width : 16 + Poly : 1021 + Init : 1D0F + RefIn : False + RefOut : False + XorOut : 0000 + Check : E5CC + +<crc-ccitt-ffff> + Name : "CRC-16/CCITT-FALSE" + Width : 16 + Poly : 1021 + Init : FFFF + RefIn : False + RefOut : False + XorOut : 0000 + Check : 29B1 + +<crc-genibus> + Name : "CRC-16/GENIBUS" + Alias : "CRC-16/I-CODE" + Alias : "CRC-16/DARC" + Width : 16 + Poly : 1021 + Init : FFFF + RefIn : False + RefOut : False + XorOut : FFFF + Check : D64E + +<crc-ccitt-xmodem> + Name : "XMODEM" + Alias : "ZMODEM" + Alias : "CRC-16/ACORN" + Width : 16 + Poly : 1021 + Init : 0000 + RefIn : False + RefOut : False + XorOut : 0000 + Check : 31C3 + +<crc-mcrf4xx> + Name : "CRC-16/MCRF4XX" + Width : 16 + Poly : 1021 + Init : FFFF + RefIn : True + RefOut : True + XorOut : 0000 + Check : 6F91 + +<crc-riello> + Name : "CRC-16/RIELLO" + Width : 16 + Poly : 1021 + Init : B2AA + RefIn : True + RefOut : True + XorOut : 0000 + Check : 63D0 + + <crc-ccitt-kermit> + Name : "KERMIT" + Alias : "CRC-16/CCITT" + Alias : "CRC-16/CCITT-TRUE" + Alias : "CRC-CCITT" + Width : 16 + Poly : 1021 + Init : 0000 + RefIn : True + RefOut : True + XorOut : 0000 + Check : 2189 + XCheck : 8921 + +<crc-x25> + Name : "X-25" + Alias : "CRC-16/IBM-SDLC" + Alias : "CRC-16/ISO-HDLC" + Width : 16 + Poly : 1021 + Init : FFFF + RefIn : True + RefOut : True + XorOut : FFFF + Check : 906E + XCheck : 6E90 + +0589 +<crc-dect-r> + Name : "CRC-16/DECT-R" + Alias : "R-CRC-16" + Width : 16 + Poly : 0589 + Init : 0000 + RefIn : False + RefOut : False + XorOut : 0001 + Check : 007E + +<crc-dect-x> + Name : "CRC-16/DECT-X" + Alias : "X-CRC-16" + Width : 16 + Poly : 0589 + Init : 0000 + RefIn : False + RefOut : False + XorOut : 0000 + Check : 007F + +3D65 +<crc-dnp> + Name : "CRC-16/DNP" + Width : 16 + Poly : 3D65 + Init : 0000 + RefIn : True + RefOut : True + XorOut : FFFF + Check : EA82 + XCheck : 82EA + +<crc-en-13757> + Name : "CRC-16/EN-13757" + Width : 16 + Poly : 3D65 + Init : 0000 + RefIn : False + RefOut : False + XorOut : FFFF + Check : C2B7 + +8BB7 +<crc-t10-dif> + Name : "CRC-16/T10-DIF" + Width : 16 + Poly : 8BB7 + Init : 0000 + RefIn : False + RefOut : False + XorOut : 0000 + Check : D0DB + +A097 +<crc-teledisk> + Name : "CRC-16/TELEDISK" + Width : 16 + Poly : A097 + Init : 0000 + RefIn : False + RefOut : False + XorOut : 0000 + Check : 0FB3 + +CRC-24 +864CFB +<crc-24> + Name : "CRC-24" + Alias : "CRC-24/OPENPGP" + Width : 24 + Poly : 864CFB + Init : B704CE + RefIn : False + RefOut : False + XorOut : 000000 + Check : 21CF02 + +5D6DCB +<crc-24-flexray-a> + Name : "CRC-24/FLEXRAY-A" + Width : 24 + Poly : 5D6DCB + Init : FEDCBA + RefIn : False + RefOut : False + XorOut : 000000 + Check : 7979BD + +<crc-24-flexray-b> + Name : "CRC-24/FLEXRAY-B" + Width : 24 + Poly : 5D6DCB + Init : ABCDEF + RefIn : False + RefOut : False + XorOut : 000000 + Check : 1F23B8 + +CRC-32 +04C11DB7 +<crc-32> + Name : "CRC-32" + Alias : "CRC-32/ADCCP" + Alias : "PKZIP" + Width : 32 + Poly : 04C11DB7 + Init : FFFFFFFF + RefIn : True + RefOut : True + XorOut : FFFFFFFF + Check : CBF43926 + +<crc-32-bzip2> + Name : "CRC-32/BZIP2" + Alias : "B-CRC-32" + Width : 32 + Poly : 04C11DB7 + Init : FFFFFFFF + RefIn : False + RefOut : False + XorOut : FFFFFFFF + Check : FC891918 + +<crc-32-mpeg-2> + Name : "CRC-32/MPEG-2" + Width : 32 + Poly : 04C11DB7 + Init : FFFFFFFF + RefIn : False + RefOut : False + XorOut : 00000000 + Check : 0376E6E7 + +<crc-32-posix> + Name : "CRC-32/POSIX" + Alias : "CKSUM" + Width : 32 + Poly : 04C11DB7 + Init : 00000000 + RefIn : False + RefOut : False + XorOut : FFFFFFFF + Check : 765E7680 + LCheck : 377A6011 + +<crc-32-jamcrc> + Name : "JAMCRC" + Width : 32 + Poly : 04C11DB7 + Init : FFFFFFFF + RefIn : True + RefOut : True + XorOut : 00000000 + Check : 340BC6D9 + +1EDC6F41 +<crc-32-C> + Name : "CRC-32C" + Alias : "CRC-32/ISCSI" + Alias : "CRC-32/CASTAGNOLI" + Width : 32 + Poly : 1EDC6F41 + Init : FFFFFFFF + RefIn : True + RefOut : True + XorOut : FFFFFFFF + Check : E3069283 + +A833982B +<crc-32-D> + Name : "CRC-32D" + Width : 32 + Poly : A833982B + Init : FFFFFFFF + RefIn : True + RefOut : True + XorOut : FFFFFFFF + Check : 87315576 + +741B8CD7 +<crc-32-K> (new entry) + Name : "CRC-32K" + Alias : "CRC-32/KOOPMAN" + Width : 32 + Poly : 741B8CD7 + Init : 00000000? + RefIn : False? + RefOut : False? + XorOut : 00000000? + Check : 085A3197 ? + +814141AB +<crc-32-Q> + Name : "CRC-32Q" + Width : 32 + Poly : 814141AB + Init : 00000000 + RefIn : False + RefOut : False + XorOut : 00000000 + Check : 3010BF7F + +000000AF +<crc-32-xfer> + Name : "XFER" + Width : 32 + Poly : 000000AF + Init : 00000000 + RefIn : False + RefOut : False + XorOut : 00000000 + Check : BD0BE338 + +CRC-40 +<crc-40-gsm> + Name : "CRC-40/GSM" + Width : 40 + Poly : 0004820009 + Init : 0000000000 + RefIn : False + RefOut : False + XorOut : 0000000000 + Check : 2BE9B039B9 + +CRC-64 +42F0E1EBA9EA3693 +<crc-64> + Name : "CRC-64" + Width : 64 + Poly : 42F0E1EBA9EA3693 + Init : 0000000000000000 + RefIn : False + RefOut : False + XorOut : 0000000000000000 + Check : 6C40DF5F0B497347 + +<crc-64-we> + Name : "CRC-64/WE" + Width : 64 + Poly : 42F0E1EBA9EA3693 + Init : FFFFFFFFFFFFFFFF + RefIn : False + RefOut : False + XorOut : FFFFFFFFFFFFFFFF + Check : 62EC59E3F1A4F00A + +000000000000001B +<crc-64-1b> + Name : "CRC-64/1B" (New entry) + Width : 64 + Poly : 000000000000001B + Init : 0000000000000000 + RefIn : True + RefOut : True + XorOut : 0000000000000000 + Check : 46A5A9388A5BEFFE + +AD93D23594C935A9 +<crc-64-jones> + Name : "CRC-64/Jones" (New entry) + Width : 64 + Poly : AD93D23594C935A9 + Init : FFFFFFFFFFFFFFFF + RefIn : True + RefOut : True + XorOut : 0000000000000000 + Check : CAA717168609F281 diff --git a/tools/hex2bin-2.0/doc/ChangeLog_hex2bin b/tools/hex2bin-2.0/doc/ChangeLog_hex2bin new file mode 100644 index 0000000..3339250 --- /dev/null +++ b/tools/hex2bin-2.0/doc/ChangeLog_hex2bin @@ -0,0 +1,57 @@ +(UTF8 encoding) + +- hex2bin 1.0.12 - 20141122 Simone Fratini + small feature added + 20141121 Slucx + added line for removing extra CR when entering file name at run time. + 20141008 JP + removed junk code + +- hex2bin 1.0.11 - 20141005 Jacques Pelletier + added option to support byte-swapped hex used by Microchip's MPLAB IDE + corrected bug caused by extra LF at end or within file + +- hex2bin 1.0.10 - 20120509 Yoshimasa Nakane + modified error checking (also for output file, JP) + modified option parser (JP) + +- hex2bin 1.0.9 - 20120125 - Danny Schneider + Added code for filling a binary file to a given Max_Length relative to + Starting Address if Max-Address is larger than Highest-Address + +- hex2bin 1.0.8 - 20100402 - Jacques Pelletier + Fixed a bug with physical address calculation with extended linear address records + ADDRESS_MASK is now calculated from MEMORY_SIZE + +- hex2bin 1.0.7 - 20091212 - Jacques Pelletier + Fixed the crash on 0 byte length data records + +- hex2bin 1.0.6 - 20080103 - Jacques Pelletier + Fixed a bug when generating binary files near the end of the buffer + +- hex2bin 1.0.5 - 20071005 - PaweÅ‚ Grabski - + Improved parsing of options. + +- hex2bin 1.0.4 - 20050126 - Jacques Pelletier - + Corrected the conversion LF -> CR+LF bug + applied patch for correcting the incorrect handling of + extended segment address record + added the Rockwell checksum extensions, and modified them a bit to allow + other types later. + +- hex2bin 1.0.3 - 20040617 - Alf Lacis - + Added pad byte (may not always want FF). + Added 'break;' to remove GNU compiler warning about label at + end of compound statement + Added PROGRAM & VERSION strings. + +- hex2bin 1.0.2 - + Corrected Bug in checksum verification + +- hex2bin 1.0.1 - + Added checking for memory indexing out of bound. + Added segmented and linear extended addressing in hex2bin. + Corrected an error: & were interverted with && (and bitwise, logical and). + +- hex2bin 1.0.0 - + Initial release diff --git a/tools/hex2bin-2.0/doc/ChangeLog_mot2bin b/tools/hex2bin-2.0/doc/ChangeLog_mot2bin new file mode 100644 index 0000000..4e3c7b3 --- /dev/null +++ b/tools/hex2bin-2.0/doc/ChangeLog_mot2bin @@ -0,0 +1,49 @@ +(UTF8 encoding tab = 4) +- mot2bin 1.0.12 - 20141122 Simone Fratini + small feature added + 20141121 Slucx + added line for removing extra CR when entering file name at run time. + +- mot2bin 1.0.11 - 20141005 Jacques Pelletier + added option to support byte-swapped hex used by Microchip's MPLAB IDE + corrected bug caused by extra LF at end or within file + +- mot2bin 1.0.10 - 20120509 Yoshimasa Nakane + modified error checking (also for output file, JP) + +- mot2bin 1.0.9 - 20120125 - Danny Schneider + Added code for filling a binary file to a given Max_Length relative to + Starting Address if Max-Address is larger than Highest-Address + (JP) corrected a bug in the checksum checking + (JP) added code for record types 0,5,7,8,9 + +- mot2bin 1.0.8 - 20100402 - Jacques Pelletier + ADDRESS_MASK is now calculated from MEMORY_SIZE + +- mot2bin 1.0.7 - 20091212 - Jacques Pelletier + Fixed the crash on 0 byte length data records + +- mot2bin 1.0.6 - 20080103 - Jacques Pelletier + Corrected a bug when generating a binary file near the end of the buffer. + +- mot2bin 1.0.5 - 20071005 - PaweÅ‚ Grabski - + Improved parsing of options (same code as hex2bin). + +- mot2bin 1.0.4 - 20050128 - Jacques Pelletier - + Modified the checksum code to be able to generate other checksum types + later (ex. CRC). + +- mot2bin 1.0.3 - 20041026 - Scott A. Mintz - + Modified the MOT2BIN file to compute a checksum over a range using + 8bit, 16bit little endian, or 16bit big endian and optionally forcing + the checksum to a specific value by modifying a memory location. + +- mot2bin 1.0.2 - 20040617 - Alf Lacis - + Added pad byte (may not always want FF). + Added initialisation to Checksum to remove GNU + compiler warning about possible uninitialised usage + Added 2x'break;' to remove GNU compiler warning about label at + end of compound statement + Added PROGRAM & VERSION strings. + +- no previous ChangeLog - diff --git a/tools/hex2bin-2.0/doc/README b/tools/hex2bin-2.0/doc/README new file mode 100644 index 0000000..78ee7e7 --- /dev/null +++ b/tools/hex2bin-2.0/doc/README @@ -0,0 +1,225 @@ +Yet Another Hex to bin converter + +It can handle the extended Intel hex format in segmented and linear address +modes. Records need not be sorted and there can be gaps between records. + +Some hex files are produced by compilers. They generate objects files for each +module in a project, and when the linker generates the final hex file, the +object files are stored within the hex files, but modules can appear not +necessary in order of address. + +How does it work? + +Hex2bin/mot2bin allocates a 4 MBytes buffer and just place the converted bytes +in its buffer. At the end, the buffer is written to disk. Using a buffer elimi- +nates the need to sort records. If the option l is used (3), the buffer will be +allocated with the maximum size specified if over 4Mbytes. + +Before reading the hex file, the buffer is filled with a default value. These +padding bytes are all FF by default so an EPROM programmer can skip these bytes +when programming. The padding value can be changed with the -p option. + +1. Compiling on Linux or other unix platforms + + make + + then + + make install + + This will install the program to /usr/local/bin. + +1a. Compiling for Windows on Msys, Cygwin or DOS prompt + + The programs can be compiled as follows: + gcc -O2 -Wall -o hex2bin.exe hex2bin.c common.c libcrc.c binary.c + gcc -O2 -Wall -o mot2bin.exe mot2bin.c common.c libcrc.c binary.c + +2. Using hex2bin + + hex2bin example.hex + + hex2bin will generate a binary file example.bin starting at the + lowest address in the hex file. + +3. Binary file starting address and length + + If the lowest address isn't 0000, + ex: 0100: (the first record begins with :nn010000xxx ) + + there will be problems when using the binary file to program a EPROM + since the first byte supposed to be at 0100 is stored in the binary file + at 0000. + + you can specify a starting address for the binary file on the command line: + + hex2bin -s 0000 start_at_0100.hex + + This start address is not the same thing as the start address record in + the hex file. The start address record is used to specify the starting + address for execution of the binary code. + + The bytes will be stored in the binary file with a padding from 0000 + to the lowest address minus 1 (00FF in this case). + + Similarly, the binary file can be padded up to Length -1 with FF or another byte. + + Here, the space between the last byte and 07FF will be filled with FF. + hex2bin -l 0800 ends_before_07FF.hex + + EPROM, EEPROM and Flash memories contain all FF when erased. + + This program does minimal error checking since many hex files are + generated by known good assemblers. + + When the source file name is + for-example.test.hex + the binary created will have the name + for-example.bin + the ".test" part will be dropped. + + Hex2bin/mot2bin assume the source file doesn't contain overlapping records, + if so, overlaps will be reported. + +4. Checksum of source file + + By default, it ignores record checksum errors, so that someone can change + by hand some bytes allowing quick and dirty changes. + If you want checksum error reporting, specify the option -c. + + hex2bin -c example.hex + + If there is a record checksum error somewhere, the program will continue the + conversion anyway. + + The example file example.hex contains some records with checksum errors. + +5. Check value inserted inside binary file + + A check value can be inserted in the resulting binary file. + + hex2bin -k [0-4] -r [start] [end] -f [address] -C [Poly] [Init] [RefIn] [RefOut] [XorOut] + + -k Select the check method: + 0: Checksum 8-bit + 1: Checksum 16-bit + 2: CRC8 + 3: CRC16 + 4: CRC32 + + -r Range to compute checksum over (default is min and max addresses) + + -f Address of the result to write + + -C Parameters for CRC + Parameters for common CRCs are listed in doc/CRC list.txt. They appear in + the same order. Feed them as is and use t for TRUE, f for FALSE. + + See also the test/Makefile for these common CRCs; since they're tested, + you'll have the command line figured out. + + -E Endian for storing the check result or forcing it + 0: little + 1: big + + Change from previous versions of hex2bin/mot2bin: + Replace former options to this version + -k 1 -> -k 1 -E 0 + -k 2 -> -k 1 -E 1 + +6. Value inserted directly inside binary file + Instead of calculating a value, it can be inserted directly into the file at a specified address. + + hex2bin -k [0|1|2] -F [address] [value] + + -k Select the value format: + + 0 = 8-bit + 1 = 16-bit + 2 = 32-bit + + -F Address and value of checksum to force + + -E Endian for storing the check result or forcing it + 0: little + 1: big + +7. Motorola S files + + mot2bin example.s19 + + Options for mot2bin are the same as hex2bin. Executing the program + without argument will display available options. Some are specific to + Motorola files. + + This program will handle S19 files generated for Motorola micropro- + cessors. Since I use this program for an EPROM programmer, I will + rarely need to have more than 4M, I limited the source program for + 24 bits or 16 bits address records. + + 32 bits records are now supported, but obviously I can't allocate all + the memory for the binary target. What I did is simply assume that the + binary file will occupy less than 4M. For binary files greater than 4M, + see length option (section 3). + +8. Support for byte-swapped hex/S19 files + + -w Wordwise swap: for each pair of bytes, exchange the low and high part. + If a checksum needs to be generated to insert in the binary file, select + one of the 16-bit checksums. + + hex2bin -w test-byte-swap.hex + +9. Goodies + + Description of the file formats is included. + Added examples files for extended addressing. + + Check for overlapping records. The check is rather basic: supposing + that the buffer is filled with pad bytes, when a record overlaps a + previous one, value in the buffer will be different from the pad bytes. + This will not detect the case when the previous value equals the pad byte, + but it's more likely that more than one byte will be overlapped. + + +10. Error messages + + "Can't allocate memory." + + Can't do anything in this case, so the program simply exits. + + "Error occurred while reading from file" + + Problem with fgets. + + "Input/Output file %s cannot be opened. Enter new filename: " + + The user may not have permissions to open the file. + + "0 byte length data record ignored" + + This means that an empty data record was read. Since it's empty, it's simply + ignored and should have no impact on the binary file. + + "Data record skipped at ..." + + This means that the records are falling outside the memory buffer. + + "Overlapped record detected" + + A record is overwritten by a subsequent record. If you're using SDCC, check + if more than one area is specified with a starting address. Checking the map + file generated by the linker can help. + + "Some error occurred when parsing options." + + + +11. History + + See ChangeLog + +12. Other hex tool + + There is a program that supports more formats and has more features. + See SRecord at http://srecord.sourceforge.net/ diff --git a/tools/hex2bin-2.0/doc/S-record.txt b/tools/hex2bin-2.0/doc/S-record.txt new file mode 100644 index 0000000..ba4abc1 --- /dev/null +++ b/tools/hex2bin-2.0/doc/S-record.txt @@ -0,0 +1,361 @@ +S-Record Format
+
+ A file in Motorola S-record format is an ASCII file. There are three different
+ formats:
+
+ S19 for 16-bit address
+ S2 for 24-bit address
+ S3 for 32-bit address
+
+
+ The files consist of optional symbol table information, data specifications
+ for loading memory, and a terminator record.
+
+ [ $$ {module_record}
+ symbol records
+ $$ [ module_record ]
+ symbol_records
+ $$]
+ header_record
+ data_records
+ record_count_record
+ terminator_record
+
+
+Module Record (Optional)
+
+ Each object file contains one record for each module that is a component of it. This
+ record contains the name of the module. There is one module record for each relocatable
+ object created by the assembler. The name of the relocatable object module
+ contained in the record comes from the IDNT directive. For absolute objects created
+ by the linker, there is one module record for each relocatable object file linked,
+ plus an additional record whose name comes from the NAME command for the
+ linker.
+
+ Example:
+
+ $$ MODNAME
+
+
+Symbol Record (Optional)
+
+ As many symbol records as needed can be contained in the object module. Up to 4
+ symbols per line can be used, but it is not mandatory that each line contain 4
+ symbols. A module can contain only symbol records.
+
+ Example:
+
+ APPLE $00000 LABEL1 $ODOC3
+ MEM $OFFFF ZEEK $01947
+
+ The module name associated with the symbols can be specified in the
+ module_record preceding the symbol records.
+
+ Example:
+
+ $$MAIN
+
+ Symbols are assumed to be in the module named in the preceding module_record
+ until another module is specified with another module_record. Symbols defined by
+ the linker's PUBLIC command appear following the first module record, which
+ indicates the name of the output object module specified by the linker's NAME
+ command.
+
+
+*****************************************************************************************
+
+Header Record (SO)
+
+ Each object module has exactly one header record with the following format:
+
+ S00600004844521B
+
+ Description:
+
+ S0 Identifies the record as a header record
+ 06 The number of bytes following this one
+ 0000 The address field, which is ignored
+ 484452 The string HDR in ASCII
+ 1B The checksum
+
+
+
+*****************************************************************************************
+
+Data Record (S1)
+
+ A data record specifies data bytes that are to be loaded into memory. Figure 1
+ shows the format for such a record. The columns shown in the figure represent half
+ of a byte (4 bits).
+
+ ---------------------------------------------
+ | 1 2 3 4 5 6 7 8 9 ... 40 41 42 |
+ | |
+ | S ID byte load data...data checksum |
+ | count address 1 n |
+ ---------------------------------------------
+ Figure 1: Data Record Formatter 16-Bit Load Address
+
+
+ Column Description
+
+ 1 Contains the ASCII character S, which indicates the start of
+ a record in Motorola S-record format.
+
+ 2 Contains the ASCII character identifying the record type.
+ For data records, this character is 1.
+
+ 3 to 4 Contain the count of the number of bytes following this one
+ within the record. The count includes the checksum and the
+ load address bytes but not the byte count itself.
+
+ 5 to 8 Contain the load address. The first data byte is to be loaded
+ into this address and subsequent bytes into the next sequential
+ address. Columns 5 and 6 contain the high-order address
+ byte, and columns 7 and 8 contain the low-order address byte.
+
+ 9 to 40 Contain the specifications for up to 16 bytes of data.
+
+ 41 to 42 Contain a checksum for the record. To calculate this, take the
+ sum of the values of all bytes from the byte count up to the
+ last data byte, inclusive, modulo 256. Subtract this result
+ from 255.
+
+
+*****************************************************************************************
+
+Data Record (S2)
+
+
+ A data record specifies data bytes that are to be loaded into memory. Figure 2
+ shows the format for such a record. The columns shown in the figure represent half
+ of a byte (4 bits).
+
+
+ ----------------------------------------------------
+ | 1 2 3 4 5 6 7 8 9 10 11 ... 42 43 44 |
+ | |
+ | S ID byte load data...data checksum |
+ | count address 1 n |
+ ----------------------------------------------------
+ Figure 2: Data Record Format for 24-Bit Load Address
+
+ Column Description
+
+ 1 Contains the ASCII character S, which indicates the start of
+ a record in Motorola S-record format.
+
+ 2 Contains the ASCII character identifying the record type.
+ For data records, this character is 2.
+
+ 3 to 4 Contain the count of the number of bytes following this one
+ within the record. The count includes the checksum and the
+ load address bytes but not the byte count itself.
+
+ 5 to 10 Contain the load address. The first data byte is to be loaded
+ into this address and subsequent bytes into the next sequential
+ address. Columns 5 and 6 contain the high-order address
+ byte, and columns 9 and 10 contain the low-order address byte.
+
+ 11 to 42 Contain the specifications for up to 16 bytes of data.
+
+ 43 to 44 Contain a checksum for the record. To calculate this, take the
+ sum of the values of all bytes from the byte count up to the
+ last data byte, inclusive, modulo 256. Subtract this result
+ from 255.
+
+
+*****************************************************************************************
+
+Data Record (S3)
+
+
+ A data record specifies data bytes that are to be loaded into memory. Figure 3
+ shows the format for such a record. The columns shown in the figure represent half
+ of a byte (4 bits).
+
+ ----------------------------------------------------------
+ | 1 2 3 4 5 6 7 8 9 10 11 12 13 ... 44 45 46 |
+ | |
+ | S ID byte load data...data checksum |
+ | count address 1 n |
+ ----------------------------------------------------------
+ Figure 3: Data Record Format for 32-Bit Load Address
+
+ Column Description
+
+ 1 Contains the ASCII character S, which indicates the start of
+ a record in Motorola S-record format.
+
+ 2 Contains the ASCII character identifying the record type.
+ For data records, this digit is 3 for 32-bit addresses.
+
+ 3 to 4 Contain the count of the number of bytes following this one
+ within the record. The count includes the checksum and the
+ load address bytes but not the byte count itself.
+
+ 5 to 12 Contain the load address. The first data byte is to be loaded
+ into this address and subsequent bytes into the next sequential
+ address. Columns 5 and 6 contain the high-order address
+ byte, and columns 11 and 12 contain the low-order address byte.
+
+ 13 to 44 Contain the specifications for up to 15 bytes of data.
+
+ 45 to 46 Contain a checksum for the record. To calculate this, take the
+ sum of the values of all bytes from the byte count up to the
+ last data byte, inclusive, modulo 256. Subtract this result
+ from 255.
+
+
+*****************************************************************************************
+
+Record Count Record (S5)
+
+
+ The record count record verifies the number of data records preceding it. Figure 4
+ shows the format for such a record. The columns shown in the figure represent half
+ of a byte (4 bits).
+
+ --------------------------------------
+ | 1 2 3 4 5 6 7 8 9 10 |
+ | |
+ | S ID byte # of data checksum |
+ | count records |
+ --------------------------------------
+ Figure 4: Record Count Record Format
+
+ Column Description
+
+ 1 Contains the ASCII character S, which indicates the start of
+ a record in Motorola S-record format.
+
+ 2 Contains the ASCII character 5, which indicates a record
+ count record.
+
+ 3 to 4 Contain the byte count, ASCII string 03.
+
+ 5 to 8 Contain the number of data records in this file. The high-
+ order byte is in columns 5 and 6.
+
+ 9 to 10 Contain the checksum for the record.
+
+ Example:
+
+ S503010DEE
+
+ The example above shows a record count record indicating a total of 269 records
+ (0x010D) and a checksum of 0xEE.
+
+
+
+*****************************************************************************************
+
+Terminator Record for 32-bit address (S7)
+
+ A terminator record specifies the end of the data records. Figure 5 shows the
+ format for such a record. The columns shown in the figure represent half of a byte
+ (4 bits).
+
+ -------------------------------------
+ | 1 2 3 4 5...12 13 14 |
+ | |
+ | S ID byte load checksum |
+ | count address |
+ -------------------------------------
+ Figure5: Terminator Record Format for 32-Bit Load Address
+
+ Column Description
+
+ 1 Contains the ASCII character S, which indicates the start of
+ a record in Motorola S-record format.
+
+ 2 Contains the ASCII character 7, which indicates a 32-bit
+ load address.
+
+ 3 to 4 Contain the byte count, ASCII string 04.
+
+ 5 to 12 Contain the load address that is either set to zero or to the
+ starting address specified in the END directive or START
+ command (there are no data bytes).
+
+ 13 to 14 Contain the checksum for the record.
+
+*****************************************************************************************
+
+Terminator Record for 24-bit address (S8)
+
+
+ A terminator record specifies the end of the data records. Figure 6 shows the
+ format for such a record. The columns shown in the figure represent half of a byte
+ (4 bits).
+
+ ----------------------------------------
+ | 1 2 3 4 5 6 7 8 9 10 11 12 |
+ | |
+ | S ID byte load checksum |
+ | count address |
+ ----------------------------------------
+ Figure 6: Terminator Record Format for 24-Bit Load Address
+
+ Column Description
+
+ 1 Contains the ASCII character S, which indicates the start of
+ a record in Motorola S-record format.
+
+ 2 Contains the ASCII character 8, which indicates a 24-bit
+ load address.
+
+ 3 to 4 Contain the byte count, ASCII string 04.
+
+ 5 to 10 Contain the load address, which is either set to zero or to the
+ starting address specified in the END directive or START
+ command. There are no data bytes.
+
+ 11 to 12 Contain the checksum for the record.
+
+ Example:
+
+ S804000AF0001
+
+ The previous example shows a terminator record with a 24-bit load address of
+ 0x000AF0 and a checksum of 0x01.
+
+
+*****************************************************************************************
+
+Terminator Record for 16-bit address (S9)
+
+
+ A terminator record specifies the end of the data records. Figure 7 shows the
+ format for such a record. The columns shown in the figure represent half of a byte
+ (4 bits).
+
+ -------------------------------------
+ | 1 2 3 4 5 6 7 8 9 10 |
+ | |
+ | S ID byte load checksum |
+ | count address |
+ -------------------------------------
+ Figure 7: Terminator Record Format for 16-Bit Load Address
+
+
+ Column Description
+
+ 1 Contains the ASCII character S, which indicates the start of
+ a record in Motorola S-record format.
+
+ 2 Contains the ASCII character 9, which indicates a 16-bit
+ load address.
+
+ 3 to 4 Contain the byte count, ASCII string 04.
+
+ 5 to 8 Contain the load address, which is either set to zero or to the
+ starting address specified in the END directive or START
+ command (there are no data bytes).
+
+ 9 to 10 Contain the checksum for the record.
+
+
+
+*****************************************************************************************
+ hagen.v.tronje@on-line.de
diff --git a/tools/hex2bin-2.0/doc/formats.txt b/tools/hex2bin-2.0/doc/formats.txt new file mode 100644 index 0000000..25e5e37 --- /dev/null +++ b/tools/hex2bin-2.0/doc/formats.txt @@ -0,0 +1,72 @@ +Hex formats + +Intel +===== + +Hexadecimal values are always in uppercase. Each line is a record. +The sum of all the bytes in each record should be 00 (modulo 256). + +Record types: + +00: data records +01: end-of-file record +02: extended address record + +Data record +----------- + + :0D011C0000000000C3E0FF0000000000C30F + +: 0D 011C 00 00000000C3E0FF0000000000C3 0F +| | | | -------------+------------ | +| | | | | +--- Checksum +| | | | +------------------ Data bytes +| | | +--------------------------------- Record type +| | +------------------------------------- Address +| +----------------------------------------- Number of data bytes ++-------------------------------------------- Start of record + + +End of file record +------------------ + + :00000001FE + +: 00 0000 01 FE +| | | | | +| | | | +--- Checksum +| | | +------ Record type +| | +---------- Address +| +-------------- Number of data bytes ++----------------- Start of record + + + +Extended address record +----------------------- + + :02010002E0001B + +: 02 0100 02 E000 1B +| | | | | | +| | | | | +--- Checksum +| | | | +-------- Segment address +| | | +----------- Record type +| | +--------------- Address +| +------------------- Number of data bytes ++---------------------- Start of record + +Following data records will start at E000:0100 or E0100 + + + + + + + + + + + + + diff --git a/tools/hex2bin-2.0/doc/intelhex.spc b/tools/hex2bin-2.0/doc/intelhex.spc new file mode 100644 index 0000000..946d586 --- /dev/null +++ b/tools/hex2bin-2.0/doc/intelhex.spc @@ -0,0 +1,409 @@ + +====================================================================== + +Intel +Hexadecimal Object File +Format Specification +Revision A, 1/6/88 + + + +DISCLAIMER + +Intel makes no representation or warranties with respect to the contents +hereof and specifically disclaims any implied warranties of +merchantability or fitness for any particular purpose. Further, Intel +reserves the right to revise this publication from time to time in the +content hereof without obligation of Intel to notify any person of such +revision or changes. The publication of this specification should not +be construed as a commitment on Intel's part to implement any product. + + +1. Introduction +This document describes the hexadecimal object file format for the Intel +8- bit, 16-bit, and 32-bit microprocessors. The hexadecimal format is +suitable as input to PROM programmers or hardware emulators. +Hexadecimal object file format is a way of representing an absolute +binary object file in ASCII. Because the file is in ASCII instead of +binary, it is possible to store the file is non-binary medium such as +paper-tape, punch cards, etc.; and the file can also be displayed on CRT +terminals, line printers, etc.. The 8-bit hexadecimal object file +format allows for the placement of code and data within the 16-bit +linear address space of the Intel 8-bit processors. The 16-bit +hexadecimal format allows for the 20-bit segmented address space of the +Intel 16-bit processors. And the 32-bit format allows for the 32-bit +linear address space of the Intel 32-bit processors. +The hexadecimal representation of binary is coded in ASCII alphanumeric +characters. For example, the 8-bit binary value 0011-1111 is 3F in +hexadecimal. To code this in ASCII, one 8-bit byte containing the ASCII +code for the character '3' (0011-0011 or 033H) and one 8-bit byte +containing the ASCII code for the character 'F' (0100-0110 or 046H) are +required. For each byte value, the high-order hexadecimal digit is +always the first digit of the pair of hexadecimal digits. This +representation (ASCII hexadecimal) requires twice as ma ny bytes as the +binary representation. +A hexadecimal object file is blocked into records, each of which +contains the record type, length, memory load address and checksum in +addition to the data. There are currently six (6) different types of +records that are defined, not all combinations of these records are +meaningful, however. The records are: + +Data Record (8-, 16-, or 32-bit formats) +End of File Record (8-, 16-, or 32-bit formats) +Extended Segment Address Record (16- or 32-bit formats) +Start Segment Address Record (16- or 32-bit formats) +Extended Linear Address Record (32-bit format only) +Start Linear Address Record (32-bit format only) + + +2. General Record Format +| RECORD | LOAD | | | INFO | | +| MARK | RECLEN | OFFSET | RECTYP | or | CHKSUM | +| ':' | | | | DATA | | + 1-byte 1-byte 2-bytes 1-byte n-bytes 1-byte + +Each record begins with a RECORD MARK field containing 03AH, the ASCII +code for the colon (':') character. +Each record has a RECLEN field which specifies the number of bytes of +information or data which follows the RECTYP field of the record. Note +that one data byte is represented by two ASCII characters. The maximum +value of the RECLEN field is hexadecimal 'FF' or 255. +Each record has a LOAD OFFSET field which specifies the 16-bit starting +load offset of the data bytes, therefore this field is only used for +Data Records. In other records where this field is not used, it should +be coded as four ASCII zero characters ('0000' or 030303030H). +Each record has a RECTYP field which specifies the record type of this +record. The RECTYP field is used to interpret the remaining information +within the record. The encoding for all the current record types are: + +'00' Data Record +'01' End of File Record +'02' Extended Segment Address Record +'03' Start Segment Address Record +'04' Extended Linear Address Record +'05' Start Linear Address Record + +Each record has a variable length INFO/DATA field, it consists of zero +or more bytes encoded as pairs of hexadecimal digits. The +interpretation of this field depends on the RECTYP field. +Each record ends with a CHKSUM field that contains the ASCII hexadecimal +representation of the two's complement of the 8-bit bytes that result +from converting each pair of ASCII hexadecimal digits to one byte of +binary, from and including the RECLEN field to and including the last +byte of the INFO/DATA field. Therefore, the sum of all the ASCII pairs +in a record after converting to binary, from the RECLEN field to and +including the CHKSUM field, is zero. + + +3. Extended Linear Address Record (32-bit format only) +| RECORD | LOAD | | | | | +| MARK | RECLEN | OFFSET | RECTYP | ULBA | CHKSUM | +| ':' | '02' | '0000' | '04' | | | + 1-byte 1-byte 2-bytes 1-byte 2-bytes 1-byte + +The 32-bit Extended Linear Address Record is used to specify bits 16-31 +of the Linear Base Address (LBA), where bits 0-15 of the LBA are zero. +Bits 16-31 of the LBA are referred to as the Upper Linear Base Address +(ULBA). The absolute memory address of a content byte in a subsequent +Data Record is obtained by adding the LBA to an offset calculated by +adding the LOAD OFFSET field of the containing Data Record to the index +of the byte in the Data Record (0, 1, 2, ... n). This offset addition +is done modulo 4G (i.e., 32-bits), ignoring any carry, so that offset +wrap-around loading (from OFFFFFFFFH to OOOOOOOOOH) results in wrapping +around from the end to the beginning of the 4G linear address defined by +the LBA. The linear address at which a particular byte is loaded is +calculated as: +(LBA + DRLO + DRI) MOD 4G +where: +DRLO is the LOAD OFFSET field of a Data Record. +DRI is the data byte index within the Data Record. + +When an Extended Linear Address Record defines the value of LBA, it may +appear anywhere within a 32-bit hexadecimal object file. This value +remains in effect until another Extended Linear Address Record is +encountered. The LBA defaults to zero until an Extended Linear Address +Record is encountered. +The contents of the individual fields within the record are: + +RECORD MARK +This field contains 03AH, the hexadecimal encoding of the ASCII colon +(':') character. + +RECLEN +The field contains 03032H, the hexadecimal encoding of the ASCII +characters '02', which is the length, in bytes, of the ULBA data +information within this record. + +LOAD OFFSET +This field contains 030303030H, the hexadecimal encoding of the ASCII +characters '0000', since this field is not used for this record. + +RECTYP +This field contains 03034H, the hexadecimal encoding of the ASCII +character '04', which specifies the record type to be an Extended Linear +Address Record. + +ULBA +This field contains four ASCII hexadecimal digits that specify the +16-bit Upper Linear Base Address value. The high-order byte is the +10th/llth character pair of the record. The low-order byte is the +12th/13th character pair of the record. + +CHKSUM +This field contains the check sum on the RECLEN, LOAD OFFSET, RECTYP, +and ULBA fields. + + +4. Extended Segment Address Record (16- or 32-bit formats) +| RECORD | LOAD | | | | | +| MARK | RECLEN | OFFSET | RECTYP | USBA | CHKSUM | +| ':' | '02' | '0000' | '02' | | | + 1-byte 1-byte 2-bytes 1-byte 2-bytes 1-byte + +The 16-bit Extended Segment Address Record is used to specify bits 4-19 +of the Segment Base Address (SBA), where bits 0-3 of the SBA are zero. +Bits 4-19 of the SBA are referred to as the Upper Segment Base Address +(USBA). The absolute memory address of a content byte in a subsequent +Data Record is obtained by adding the SBA to an offset calculated by +adding the LOAD OFFSET field of the containing Data Record to the index +of the byte in the Data Record (0, 1, 2, ... n). This offset addition +is done modulo 64K (i.e., 16-bits), ignoring any carry, so that offset +wraparound loading (from OFFFFH to OOOOOH) results in wrapping around +from the end to the beginning of the 64K segment defined by the SBA. +The address at which a particular byte is loaded is calculated as: + + SBA + ([DRLO + DRI] MOD 64K) + +where: + DRLO is the LOAD OFFSET field of a Data Record. + DRI is the data byte index within the Data Record. + +When an Extended Segment Address Record defines the value of SBA, it +may appear anywhere within a 16-bit hexadecimal object file. This +value remains in effect until another Extended Segment Address +Record is encountered. The SBA defaults to zero until an Extended +Segment Address Record is encountered. + +The contents of the individual fields within the record are: + +RECORD MARK +This field contains 03AH, the hexadecimal encoding of the ASCII +colon (':') character. + +RECLEN +The field contains 03032H, the hexadecimal encoding of the ASCII +characters '02', which is the length, in bytes, of the USBA data +information within this record. + +LOAD OFFSET +This field contains 030303030H, the hexadecimal encoding of the +ASCII characters '0000', since this field is not used for this +record. + +RECTYP +This field contains 03032H, the hexadecimal encoding of the ASCII +character '02', which specifies the record type to be an Extended +Segment Address Record. + +USBA +This field contains four ASCII hexadecimal digits that specify the +16-bit Upper Segment Base Address value. The high-order byte is the +10th/1lth character pair of the record. The low-order byte is the +12th/13th character pair of the record. + +CHKSUM +This field contains the check sum on the RECLEN, LOAD OFFSET, +RECTYP, and USBA fields. + +5. Data Record (8-, 16-, or 32-bit formats) + +| RECORD | LOAD | | | | | +| MARK | RECLEN | OFFSET | RECTYP | DATA | CHKSUM | +| ':' | | | '00' | | | + 1-byte 1-byte 2-bytes 1-byte n-bytes 1-byte + + +The Data Record provides a set of hexadecimal digits that represent +the ASCII code for data bytes that make up a portion of a memory +image. The method for calculating the absolute address (linear in +the 8-bit and 32-bit case and segmented in the 16-bit case) for each +byte of data is described in the discussions of the Extended Linear +Address Record and the Extended Segment Address Record. + +The contents of the individual fields within the record are: + +RECORD MARK +This field contains 03AH, the hexadecimal encoding of the ASCII +colon (':') character. + +RECLEN +The field contains two ASCII hexadecimal digits that specify the +number of data bytes in the record. The maximum value is 'FF' or +04646H (255 decimal). + +LOAD OFFSET +This field contains four ASCII hexadecimal digits representing the +offset from the LBA (see Extended Linear Address Record) or SBA (see +Extended Segment Address Record) defining the address which the +first byte of the data is to be placed. + +RECTYP +This field contains 03030H, the hexadecimal encoding of the ASCII +character '00', which specifies the record type to be a Data Record. + +DATA +This field contains pairs of ASCII hexadecimal digits, one pair for +each data byte. + +CHKSUM +This field contains the check sum on the RECLEN, LOAD OFFSET, +RECTYP, and DATA fields. + + +6. Start Linear Address Record (32-bit format only) + +| RECORD | LOAD | | | | | +| MARK | RECLEN | OFFSET | RECTYP | EIP | CHKSUM | +| ':' | '04' | '0000' | '05' | | | + 1-byte 1-byte 2-bytes 1-byte 4-bytes 1-byte + + +The Start Linear Address Record is used to specify the execution +start address for the object file. The value given is the 32-bit +linear address for the EIP register. Note that this record only +specifies the code address within the 32-bit linear address space of +the 80386. If the code is to start execution in the real mode of +the 80386, then the Start Segment Address Record should be used +instead, since that record specifies both the CS and IP register +contents necessary for real mode. + +The Start Linear Address Record can appear anywhere in a 32-bit +hexadecimal object file. If such a record is not present in a +hexadecimal object file, a loader is free to assign a default start +address. + +The contents of the individual fields within the record are: + +RECORD MARK +This field contains 03AH, the hexadecimal encoding of the ASCII +colon (':') character. + +RECLEN +The field contains 03034H, the hexadecimal encoding of the ASCII +characters '04', which is the length, in bytes, of the EIP register +content within this record. + +LOAD OFFSET +This field contains 030303030H, the hexadecimal encoding of the +ASCII characters '0000', since this field is not used for this +record. + +RECTYP +This field contains 03035H, the hexadecimal encoding of the ASCII +character '05', which specifies the record type to be a Start Linear +Address Record. + +EIP +This field contains eight ASCII hexadecimal digits that specify the +32-bit EIP register contents. The high-order byte is the 10th/1lth +character pair. + +CHKSUM +This field contains the check sum on the RECLEN, LOAD OFFSET, +RECTYP, and EIP fields. + + +7. Start Segment Address Record (16- or 32-bit formats) + +| RECORD | LOAD | | | | | +| MARK | RECLEN | OFFSET | RECTYP | CS/IP | CHKSUM | +| ':' | '04' | '0000' | '03' | | | + 1-byte 1-byte 2-bytes 1-byte 4-bytes 1-byte + + +The Start Segment Address Record is used to specify the execution +start address for the object file. The value given is the 20-bit +segment address for the CS and IP registers. Note that this record +only specifies the code address within the 20-bit segmented address +space of the 8086/80186. + +The Start Segment Address Record can appear anywhere in a 16-bit +hexadecimal object file. If such a record is not present in a +hexadecimal object file, a loader is free to assign a default start +address. + +The contents of the individual fields within the record are: + +RECORD MARK +This field contains 03AH, the hexadecimal encoding of the ASCII +colon (':') character. + +RECLEN +The field contains 03034H, the hexadecimal encoding of the ASCII +characters '04', which is the length, in bytes, of the CS/IP +register contents within this record. + +LOAD OFFSET +This field contains 030303030H, the hexadecimal encoding of the +ASCII characters '0000', since this field is not used for this +record. + +RECTYP +This field contains 03033H, the hexadecimal encoding of the ASCII +character '03', which specifies the record type to be a Start +Segment Address Record. + +CS/IP +This field contains eight ASCII hexadecimal digits that specify the +16-bit CS register and 16-bit IP register contents. The high-order +byte of the CS register content is the 10th/llth character pair, the +low-order byte is the 12th/13th character pair of the record. The +high-order byte of the IP register content is the 14th/15th +character pair, the low-order byte is the 16th/17th character pair +of the record. + +CHKSUM +This field contains the check sum on the RECLEN, LOAD OFFSET, +RECTYP, and CS/IP fields. + + + +8. End of File Record (8-, 16-, or 32-bit formats) + +| RECORD | LOAD | | | | +| MARK | RECLEN | OFFSET | RECTYP | CHKSUM | +| ':' | '00' | '0000' | '01' | | + 1-byte 1-byte 2-bytes 1-byte 1-byte + +The End of File Record specifies the end of the hexadecimal object +file. + +The contents of the individual fields within the record are: + +RECORD MARK +This field contains 03AH, the hexadecimal encoding of the ASCII +colon (':') character. + +RECLEN +The field contains 03030H, the hexadecimal encoding of the ASCII +characters '00'. Since this record does not contain any INFO/DATA +bytes, the length is zero. + +LOAD OFFSET +This field contains 030303030H, the hexadecimal encoding of the +ASCII characters '0000', since this field is not used for this +record. + +RECTYP +This field contains 03031H, the hexadecimal encoding of the ASCII +character '01', which specifies the record type to be an End of File +Record. + +CHKSUM +This field contains the check sum an the RECLEN, LOAD OFFSET, and +RECTYP fields. Since all the fields are static, the check sum can +also be calculated statically, and the value is 04646H, the +hexadecimal encoding of the ASCII characters 'FF'. + +======================================================================== +END diff --git a/tools/hex2bin-2.0/doc/srec.txt b/tools/hex2bin-2.0/doc/srec.txt new file mode 100644 index 0000000..ea63d31 --- /dev/null +++ b/tools/hex2bin-2.0/doc/srec.txt @@ -0,0 +1,447 @@ +S-Records
+
+
+ -S-Record Format-
+
+ Chaplin@keinstr.uucp (Roger Chaplin) reposted an article written
+ by mcdchg!motmpl!ron (Ron Widell) that explained how Motorola
+ S-Records are formatted. This comes from a unix man page. No
+ mention of which version of Unix is specified. This section
+ of the FAQ is a bit long. An anonymous ftp archive is currently
+ being sought. When one is found, the section will be placed in
+ the archive.
+
+
+ SREC(4) UNIX 5.0 (03/21/84) SREC(4)
+
+
+ An S-record file consists of a sequence of specially formatted
+ ASCII character strings. An S-record will be less than or equal to
+ 78 bytes in length.
+
+ The order of S-records within a file is of no significance and no
+ particular order may be assumed.
+
+ The general format of an S-record follow:
+
+ +------------------//-------------------//-----------------------+
+ | type | count | address | data | checksum |
+ +------------------//-------------------//-----------------------+
+
+ type A char-2- field. These characters describe the
+ type of record (S0, S1, S2, S3, S5, S7, S8, or
+ S9).
+ count A char-2- field. These characters when paired and
+ interpreted as a hexadecimal value, display the
+ count of remaining character pairs in the record.
+
+ address A char-4,6, or 8- field. These characters grouped
+ and interpreted as a hexadecimal value, display
+ the address at which the data field is to be
+ loaded into memory. The length of the field
+ depends on the number of bytes necessary to hold
+ the address. A 2-byte address uses 4 characters,
+ a 3-byte address uses 6 characters, and a 4-byte
+ address uses 8 characters.
+ data A char -0-64- field. These characters when paired
+ and interpreted as hexadecimal values represent
+ the memory loadable data or descriptive
+ information.
+
+ checksum A char-2- field. These characters when paired and
+ interpreted as a hexadecimal value display the
+ least significant byte of the ones complement of
+ the sum of the byte values represented by the
+ pairs of characters making up the count, the
+ address, and the data fields.
+
+ Each record is terminated with a line feed. If any
+ additional or different record terminator(s) or delay
+ characters are needed during transmission to the target
+ system it is the responsibility of the transmitting program
+ to provide them.
+
+ S0 Record The type of record is 'S0' (0x5330). The address
+
+
+ field is unused and will be filled with zeros
+ (0x0000). The header information within the data
+ field is divided into the following subfields.
+
+ mname is char-20- and is the
+ module name.
+ ver is char-2- and is the
+ version number.
+
+ rev is char-2- and is the
+ revision number.
+ description is char-0-36- and is a
+ text comment.
+
+ Each of the subfields is composed of ASCII bytes
+ whose associated characters, when paired,
+ represent one byte hexadecimal values in the case
+ of the version and revision numbers, or represent
+ the hexadecimal values of the ASCII characters
+ comprising the module name and description.
+
+ S1 Record The type of record field is 'S1' (0x5331). The
+ address field is interpreted as a 2-byte address.
+ The data field is composed of memory loadable
+ data.
+ S2 Record The type of record field is 'S2' (0x5332). The
+ address field is interpreted as a 3-byte address.
+ The data field is composed of memory loadable
+ data.
+
+ S3 Record The type of record field is 'S3' (0x5333). The
+ address field is interpreted as a 4-byte address.
+ The data field is composed of memory loadable
+ data.
+ S5 Record The type of record field is 'S5' (0x5335). The
+ address field is interpreted as a 2-byte value
+ and contains the count of S1, S2, and S3 records
+ previously transmitted. There is no data field.
+
+ S7 Record The type of record field is 'S7' (0x5337). The
+ address field contains the starting execution
+ address and is interpreted as 4-byte address.
+ There is no data field.
+ S8 Record The type of record field is 'S8' (0x5338). The
+ address field contains the starting execution
+ address and is interpreted as 3-byte address.
+ There is no data field.
+
+ S9 Record The type of record field is 'S9' (0x5339). The
+ address field contains the starting execution
+ address and is interpreted as 2-byte address.
+ There is no data field.
+
+ EXAMPLE
+
+ Shown below is a typical S-record format file.
+
+ S00600004844521B
+ S1130000285F245F2212226A000424290008237C2A
+ S11300100002000800082629001853812341001813
+ S113002041E900084E42234300182342000824A952
+ S107003000144ED492
+ S5030004F8
+ S9030000FC
+
+ The file consists of one S0 record, four S1 records, one S5
+ record and an S9 record.
+
+ The S0 record is comprised as follows:
+
+ S0 S-record type S0, indicating it is a header
+ record.
+ 06 Hexadecimal 06 (decimal 6), indicating that six
+ character pairs (or ASCII bytes) follow.
+
+ 00 00 Four character 2-byte address field, zeroes in
+ this example.
+ 48 ASCII H, D, and R - "HDR".
+
+ 1B The checksum.
+
+ The first S1 record is comprised as follows:
+ S1 S-record type S1, indicating it is a data record
+ to be loaded at a 2-byte address.
+
+ 13 Hexadecimal 13 (decimal 19), indicating that
+ nineteen character pairs, representing a 2 byte
+ address, 16 bytes of binary data, and a 1 byte
+ checksum, follow.
+ 00 00 Four character 2-byte address field; hexadecimal
+ address 0x0000, where the data which follows is to
+ be loaded.
+
+ 28 5F 24 5F 22 12 22 6A 00 04 24 29 00 08 23 7C Sixteen
+ character pairs representing the actual binary
+ data.
+ 2A The checksum.
+
+ The second and third S1 records each contain 0x13 (19)
+ character pairs and are ended with checksums of 13 and 52,
+ respectively. The fourth S1 record contains 07 character
+ pairs and has a checksum of 92.
+
+ The S5 record is comprised as follows:
+
+ S5 S-record type S5, indicating it is a count record
+ indicating the number of S1 records.
+
+
+
+ 03 Hexadecimal 03 (decimal 3), indicating that three
+ character pairs follow.
+
+ 00 04 Hexadecimal 0004 (decimal 4), indicating that
+ there are four data records previous to this
+ record.
+ F8 The checksum.
+
+ The S9 record is comprised as follows:
+
+ S9 S-record type S9, indicating it is a termination
+ record.
+ 03 Hexadecimal 03 (decimal 3), indicating that three
+ character pairs follow.
+
+ 00 00 The address field, hexadecimal 0 (decimal 0)
+ indicating the starting execution address.
+ FC The checksum.
+
+
+ -Intel Hex ASCII Format-
+
+ Intel HEX-ASCII format takes the form:
+
+ +----------------------------------- Start Character
+ |
+ | +-------------------------------- Byte Count
+ | | (# of data bytes)
+ | |
+ | | +-------------------------- Address of first data.
+ | | |
+ | | | +-------------------- Record Type (00 data,
+ | | | | 01 end of record)
+ | | | |
+ | | | | +------------ Data Bytes
+ | | | | |
+ | | | | | +---- Checksum
+ | | | | | |
+ | / \ / \ / \ / \ / \
+ : B C A A A A T T H H ... H H C C
+
+ An examples:
+
+ :10000000DB00E60F5F1600211100197ED300C3004C
+ :1000100000000101030307070F0F1F1F3F3F7F7FF2
+ :01002000FFE0
+ :00000001FF
+
+ This information comes from _Microprocessors and Programmed
+ Logic_, Second Edition, Kenneth L. Short, 1987, Prentice-Hall,
+ ISBN 0-13-580606-2.
+
+ Provisions have been made for data spaces larger than 64 kBytes.
+ The above reference does not discuss them. I suspect there is
+ a start of segment type record, but I do not know how it is
+ implemented.
+
+----------------------------------------------------------------------------
+
+/* This file contains source code to read a Motorola S-record file into
+** a memory image. The size of the file cannot exceed BUFSIZE of data.
+** The image is then written to disk either as binary data starting at
+** address 0 with no data gaps, or as a C array of unsigned longs.
+** Input lines must be no longer than MAXLINE. No check is made!
+**
+** Author: Eric McRae, Electro-Logic Machines, Inc.
+** Date: Copyright 1994
+**
+** This source code is made available to the public "as is". No
+** warranty is given or implied for it's proper operation. This source
+** code may be used in whole or in part as long as this copyright is
+** included.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Comment the following line for non PC applications */
+#define PCDOS
+
+/* Uncomment the following line if you want a binary output instead of
+** a structure
+*/
+/* #define BINARY */
+
+#ifdef PCDOS /* Intel x86 architecture */
+#define BUFSIZE 49152 /* 48K to avoid segment hopping */
+#else /* Any reasonable (non-segmented) arch... */
+#define BUFSIZE 65536 /* As big as you want */
+#endif
+
+#define MAXLINE 256 /* Length of longest input line + 1 */
+/* Globals */
+FILE *infilePH, *outfilePH; /* Handles for input and output files */
+unsigned char *bufAC, /* Allocated image buffer */
+ *highestPC = NULL; /* Highest buffer address written */
+
+/* Change this string to reflect the name of the output array */
+char headerAC[] = "unsigned long sRec[] =\n{\n";
+
+/* Predeclarations */
+int parsebufN( char * ); /* Does the actual parsing */
+
+void main(int argc, const char * argv[])
+{
+ int c, /* Temp char storage */
+ resN; /* result status */
+ char *lbufPC, lbufAC[MAXLINE];
+ int linectrN = 0; /* Used to correlate parse fail to input line */
+
+#ifndef BINARY
+ int i;
+ unsigned long *codePL;
+ unsigned char *codePC;
+#endif
+
+ /* Check the argument count */
+ if( argc != 3 ) /* If didn't specify input and output files */
+ {
+ printf("Usage: %s: infile outfile\n", argv[0] );
+ exit(1);
+ }
+
+ /* OK, let's open some files */
+ if( ( infilePH = fopen( argv[1], "r" ) )== NULL )
+ {
+ printf("%s: Couldn't open input file %s\n", argv[0], argv[1] );
+ exit(2);
+ }
+
+ if( ( outfilePH = fopen( argv[2], "w" ) ) == NULL )
+ {
+ printf("%s: Couldn't open output file %s\n", argv[0], argv[3] );
+ exit(3);
+ }
+
+ /* OK, get a buffer and clear it. */
+ if( (bufAC = calloc( (size_t)BUFSIZE, (size_t)1 )) == NULL )
+ {
+ printf("%s: Couldn't malloc memory for buffer\n", argv[0] );
+ exit(4);
+ }
+
+ lbufPC = lbufAC; /* Point at beginning of line buffer */
+ while( c = fgetc( infilePH ))
+ {
+ if( (c == '\n') || (c == EOF) ) /* If found end of line or file */
+ { /* Parse the Line */
+ if( ( c == EOF ) && ( ferror( infilePH ) ) )
+ {
+ printf("%s: Error reading input file\n", argv[0] );
+ exit(5);
+ }
+ else
+ { /* OK, have a complete line in buffer */
+ linectrN++; /* Increment line counter */
+ if( lbufPC == lbufAC )
+ break; /* ignore blank lines */
+ *lbufPC = 0; /* Terminate the line string */
+ if( resN = parsebufN( lbufAC ) ) /* Parse data record to mem */
+ {
+ printf("%s: Error reading input file at line %d, return code = %d\n",
+ argv[0], linectrN, resN );
+ exit( resN );
+ }
+ lbufPC = lbufAC; /* Repoint line buffer pointer */
+ } /* End of have a complete line */
+ }
+ else
+ *lbufPC++ = c; /* Place char into line buffer */
+ }
+
+ /* At this point, the input file has been emptied. Now dispose of the
+ ** output data according to compilation mode.
+ */
+
+#ifdef BINARY
+
+ /* Write the buffer back to disk as a binary image */
+ resN = fwrite( bufAC, 1, (size_t)((highestPC - bufAC) + 1), outfilePH );
+ if( resN != (int)( (highestPC - bufAC) + 1) )
+ {
+ printf("%s: Error writing output file\n", argv[0] );
+ exit( 6 );
+ }
+
+#else
+ /* Produce a file that can be included in a C program. Data is read
+ ** from buffer as bytes to avoid portability/endian problems with
+ ** this program.
+ */
+ /* Output header first, then 1 long per line */
+ fwrite( (void *)headerAC, 1, (size_t)(sizeof( headerAC )-1), outfilePH );
+
+ codePL = (unsigned long *)bufAC;
+ for( i = (highestPC - bufAC + 1) / 4; i; i-- ) /* for each long */
+ {
+ codePC = (unsigned char *)codePL++;
+ sprintf(lbufAC, "0x%02x%02x%02x%02x%s",
+ *codePC, *(codePC + 1), *(codePC + 2), *(codePC + 3),
+ i == 1 ? "\n" : ",\n" ); /* No comma after final long */
+ fwrite( lbufAC, 1, (size_t)(strlen( lbufAC )), outfilePH );
+ }
+ /* OK, data has been written out, close end of array */
+ fwrite( "};\n", 1, (size_t)3, outfilePH );
+#endif
+}
+
+/* Function: parsebufV
+** Parses an S-record in the buffer and writes it into the buffer
+** if it is has a valid checksum.
+**
+** Args: pointer to character buffer for null terminated line
+** Returns: int result code: 0 = success, else failure
+*/
+int parsebufN( char *lbufPC )
+{
+ unsigned long addrL;
+ unsigned char cksmB, /* checksum of addr, count, & data length */
+ *bufPC; /* Pointer into memory array */
+ int i, countN, /* Number of bytes represented in record */
+ oheadN, /* Number of overhead (addr + chksum) bytes */
+ tvalN; /* Temp for check checksum */
+
+ switch( *(lbufPC+1) ) /* examine 2nd character on the line */
+ {
+ case '1': /* 16 bit address field */
+ if( sscanf(lbufPC, "S1%2x%4lx", &countN, &addrL ) != 2 )
+ return( 10 ); /* Flag error in S1 record */
+ oheadN = 3; /* 2 address + 1 checksum */
+ break;
+
+ case '2': /* 24 bit address field */
+ if( sscanf(lbufPC, "S2%2x%6lx", &countN, &addrL ) != 2 )
+ return( 11 ); /* Flag error in S2 record */
+ oheadN = 4; /* 3 address + 1 checksum */
+ break;
+
+ case '3': /* 32 bit address field */
+ if( sscanf(lbufPC, "S3%2x%8lx", &countN, &addrL ) != 2 )
+ return( 12 ); /* Flag error in S3 record */
+ oheadN = 5; /* 4 address + 1 checksum */
+ break;
+
+ default: /* ignore all but S1,2,3 records. */
+ return( 0 );
+ }
+
+ if( addrL > BUFSIZE ) return( 13 ); /* if address exceeds buffer size */
+ bufPC = bufAC + addrL; /* otherwise, point to right spot in buffer */
+
+ /* OK now see if checksum is OK, while reading data to buffer */
+ cksmB = 0;
+ countN++; /* Bump counter to read final checksum too */
+ for( i = 1; i <= countN; i++ )
+ {
+ sscanf( lbufPC + i*2, "%2x", &tvalN ); /* Scan a 2 hex digit byte */
+ cksmB += (unsigned char)tvalN;
+ if( ( i > oheadN ) && ( i < countN ) ) /* If scanned a data byte */
+ *bufPC++ = (unsigned char) tvalN; /* write it to the buffer */
+ }
+ if( cksmB += 1 ) return( 14 ); /* flag checksum error */
+
+ if( (bufPC - 1) > highestPC )
+ highestPC = bufPC - 1; /* track highest address loaded */
+
+ return( 0 ); /* Successful return */
+}
+
+
+
diff --git a/tools/hex2bin-2.0/src/binary.c b/tools/hex2bin-2.0/src/binary.c new file mode 100644 index 0000000..63ead0d --- /dev/null +++ b/tools/hex2bin-2.0/src/binary.c @@ -0,0 +1,196 @@ +/*---------------------------------------------------------------------------* + * binary.c * + * Copyright (C) 2014 Jacques Pelletier * + * * + * This program is free software; you can redistribute it and *or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation, * + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + *---------------------------------------------------------------------------*/ + +#include <stdint.h> + +#include "binary.h" + +const uint8_t Reflect8[256] = { + 0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0, + 0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8, + 0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4, + 0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC, + 0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2, + 0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA, + 0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6, + 0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE, + 0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1, + 0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9, + 0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5, + 0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD, + 0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3, + 0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB, + 0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7, + 0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF, +}; + +uint16_t Reflect16(uint16_t Value16) +{ + return (((uint16_t) Reflect8[u16_lo(Value16)]) << 8) | ((uint16_t) Reflect8[u16_hi(Value16)]); +} + +uint32_t Reflect24(uint32_t Value24) +{ + return ( + (((uint32_t) Reflect8[u32_b0(Value24)]) << 16) | + (((uint32_t) Reflect8[u32_b1(Value24)]) << 8) | + ((uint32_t) Reflect8[u32_b2(Value24)]) + ); +} + +uint32_t Reflect32(uint32_t Value32) +{ + return ( + (((uint32_t) Reflect8[u32_b0(Value32)]) << 24) | + (((uint32_t) Reflect8[u32_b1(Value32)]) << 16) | + (((uint32_t) Reflect8[u32_b2(Value32)]) << 8) | + ((uint32_t) Reflect8[u32_b3(Value32)]) + ); +} + +uint64_t Reflect40(uint64_t Value40) +{ + return ( + (((uint64_t) Reflect8[u64_b0(Value40)]) << 32) | + (((uint64_t) Reflect8[u64_b1(Value40)]) << 24) | + (((uint64_t) Reflect8[u64_b2(Value40)]) << 16) | + (((uint64_t) Reflect8[u64_b3(Value40)]) << 8) | + ((uint64_t) Reflect8[u64_b4(Value40)]) + ); +} + +uint64_t Reflect64(uint64_t Value64) +{ + return ( + (((uint64_t) Reflect8[u64_b0(Value64)]) << 56) | + (((uint64_t) Reflect8[u64_b1(Value64)]) << 48) | + (((uint64_t) Reflect8[u64_b2(Value64)]) << 40) | + (((uint64_t) Reflect8[u64_b3(Value64)]) << 32) | + (((uint64_t) Reflect8[u64_b4(Value64)]) << 24) | + (((uint64_t) Reflect8[u64_b5(Value64)]) << 16) | + (((uint64_t) Reflect8[u64_b6(Value64)]) << 8) | + ((uint64_t) Reflect8[u64_b7(Value64)]) + ); +} + +uint8_t u16_hi(uint16_t value) +{ + return (uint8_t)((value & 0xFF00) >> 8); +} + +uint8_t u16_lo(uint16_t value) +{ + return (uint8_t)(value & 0x00FF); +} + +uint8_t u32_b3(uint32_t value) +{ + return (uint8_t)((value & 0xFF000000) >> 24); +} + +uint8_t u32_b2(uint32_t value) +{ + return (uint8_t)((value & 0x00FF0000) >> 16); +} + +uint8_t u32_b1(uint32_t value) +{ + return (uint8_t)((value & 0x0000FF00) >> 8); +} + +uint8_t u32_b0(uint32_t value) +{ + return (uint8_t)(value & 0x000000FF); +} + +uint8_t u64_b7(uint64_t value) +{ + return (uint8_t)((value & 0xFF00000000000000) >> 56); +} + +uint8_t u64_b6(uint64_t value) +{ + return (uint8_t)((value & 0x00FF000000000000) >> 48); +} + +uint8_t u64_b5(uint64_t value) +{ + return (uint8_t)((value & 0x0000FF0000000000) >> 40); +} + +uint8_t u64_b4(uint64_t value) +{ + return (uint8_t)((value & 0x000000FF00000000) >> 32); +} + +uint8_t u64_b3(uint64_t value) +{ + return (uint8_t)((value & 0x00000000FF000000) >> 24); +} + +uint8_t u64_b2(uint64_t value) +{ + return (uint8_t)((value & 0x0000000000FF0000) >> 16); +} + +uint8_t u64_b1(uint64_t value) +{ + return (uint8_t)((value & 0x000000000000FF00) >> 8); +} + +uint8_t u64_b0(uint64_t value) +{ + return (uint8_t)(value & 0x00000000000000FF); +} + +/* Checksum/CRC conversion to ASCII */ +uint8_t nibble2ascii(uint8_t value) +{ + uint8_t result = value & 0x0f; + + if (result > 9) return result + 0x41-0x0A; + else return result + 0x30; +} + +bool cs_isdecdigit(char c) +{ + return (c >= 0x30) && (c < 0x3A); +} + +unsigned char tohex(unsigned char c) +{ + if ((c >= '0') && (c < '9'+1)) + return (c - '0'); + if ((c >= 'A') && (c < 'F'+1)) + return (c - 'A' + 0x0A); + if ((c >= 'a') && (c < 'f'+1)) + return (c - 'a' + 0x0A); + + return 0; +} + +unsigned char todecimal(unsigned char c) +{ + if ((c >= '0') && (c < '9'+1)) + return (c - '0'); + + return 0; +} + + diff --git a/tools/hex2bin-2.0/src/binary.h b/tools/hex2bin-2.0/src/binary.h new file mode 100644 index 0000000..198589b --- /dev/null +++ b/tools/hex2bin-2.0/src/binary.h @@ -0,0 +1,36 @@ +#ifndef _BINARY_H_ +#define _BINARY_H_ + +typedef enum {false, true} bool; + +extern const unsigned char Reflect8[256]; + +uint16_t Reflect16(uint16_t Value16); +uint32_t Reflect24(uint32_t Value24); +uint32_t Reflect32(uint32_t Value32); +uint64_t Reflect40(uint64_t Value40); +uint64_t Reflect64(uint64_t Value64); + +uint8_t u16_hi(uint16_t value); +uint8_t u16_lo(uint16_t value); + +uint8_t u32_b3(uint32_t value); +uint8_t u32_b2(uint32_t value); +uint8_t u32_b1(uint32_t value); +uint8_t u32_b0(uint32_t value); + +uint8_t u64_b7(uint64_t value); +uint8_t u64_b6(uint64_t value); +uint8_t u64_b5(uint64_t value); +uint8_t u64_b4(uint64_t value); +uint8_t u64_b3(uint64_t value); +uint8_t u64_b2(uint64_t value); +uint8_t u64_b1(uint64_t value); +uint8_t u64_b0(uint64_t value); + +uint8_t nibble2ascii(uint8_t value); +bool cs_isdecdigit(char c); +unsigned char tohex(unsigned char c); +unsigned char todecimal(unsigned char c); + +#endif /* _BINARY_H_ */ diff --git a/tools/hex2bin-2.0/src/common.c b/tools/hex2bin-2.0/src/common.c new file mode 100644 index 0000000..f453dc4 --- /dev/null +++ b/tools/hex2bin-2.0/src/common.c @@ -0,0 +1,527 @@ +#include "common.h" + +filetype Filename; /* string for opening files */ +char Extension[MAX_EXTENSION_SIZE]; /* filename extension for output files */ + +FILE *Filin, /* input files */ + *Filout; /* output files */ + +#ifdef USE_FILE_BUFFERS +char *FilinBuf, /* text buffer for file input */ + *FiloutBuf; /* text buffer for file output */ +#endif + +int Pad_Byte = 0xFF; +bool Enable_Checksum_Error = false; +bool Status_Checksum_Error = false; +byte Checksum; +unsigned int Record_Nb; + +/* This will hold binary codes translated from hex file. */ +byte *Memory_Block; +unsigned int Lowest_Address, Highest_Address; +unsigned int Starting_Address; +unsigned int Max_Length = 0; +unsigned int Minimum_Block_Size = 0x1000; // 4096 byte +int Module; +bool Minimum_Block_Size_Setted = false; +bool Starting_Address_Setted = false; +bool Max_Length_Setted = false; +bool Swap_Wordwise = false; + +int Endian = 0; + +t_CRC Cks_Type = CHK8_SUM; +unsigned int Cks_Start = 0, Cks_End = 0, Cks_Addr = 0, Cks_Value = 0; +bool Cks_range_set = false; +bool Cks_Addr_set = false; +bool Force_Value = false; + +unsigned int Crc_Poly = 0x07, Crc_Init = 0, Crc_XorOut = 0; +bool Crc_RefIn = false; +bool Crc_RefOut = false; + +void usage(void) +{ + fprintf (stderr, + "\n" + "usage: %s [OPTIONS] filename\n" + "Options:\n" + " -c Enable record checksum verification\n" + " -C [Poly][Init][RefIn][RefOut][XorOut]\n CRC parameters" + " -e [ext] Output filename extension (without the dot)\n" + " -E [0|1] Endian for checksum/CRC, 0: little, 1: big\n" + " -f [address] Address of check result to write\n" + " -F [address] [value]\n Address and value to force\n" + " -k [0-4] Select check method (checksum or CRC) and size\n" + " -d display list of check methods/value size\n" + " -l [length] Maximal Length (Starting address + Length -1 is Max Address)\n" + " File will be filled with Pattern until Max Address is reached\n" + " -m [size] Minimum Block Size\n" + " File Size Dimension will be a multiple of Minimum block size\n" + " File will be filled with Pattern\n" + " Length must be a power of 2 in hexadecimal [see -l option]\n" + " Attention this option is STRONGER than Maximal Length \n" + " -p [value] Pad-byte value in hex (default: %x)\n" + " -r [start] [end]\n" + " Range to compute checksum over (default is min and max addresses)\n" + " -s [address] Starting address in hex (default: 0)\n" + " -w Swap wordwise (low <-> high)\n\n", + Pgm_Name,Pad_Byte); + exit(1); +} /* procedure USAGE */ + +void DisplayCheckMethods(void) +{ + fprintf (stderr, + "Check methods/value size:\n" + "0: Checksum 8-bit\n" + "1: Checksum 16-bit\n" + "2: CRC8\n" + "3: CRC16\n" + "4: CRC32\n"); + exit(1); +} + +#define LAST_CHECK_METHOD 4 + +void *NoFailMalloc (size_t size) +{ + void *result; + + if ((result = malloc (size)) == NULL) + { + fprintf (stderr,"Can't allocate memory.\n"); + exit(1); + } + return (result); +} + +/* Open the input file, with error checking */ +void NoFailOpenInputFile (char *Flnm) +{ + while ((Filin = fopen(Flnm,"r")) == NULL) + { + fprintf (stderr,"Input file %s cannot be opened. Enter new filename: ",Flnm); + if (fgets (Flnm,MAX_FILE_NAME_SIZE,stdin) == NULL) exit(1); /* modified error checking */ + + if (Flnm[strlen(Flnm) - 1] == '\n') Flnm[strlen(Flnm) - 1] = '\0'; + } + +#ifdef USE_FILE_BUFFERS + FilinBuf = (char *) NoFailMalloc (BUFFSZ); + setvbuf(Filin, FilinBuf, _IOFBF, BUFFSZ); +#endif +} /* procedure OPENFILIN */ + +/* Open the output file, with error checking */ +void NoFailOpenOutputFile (char *Flnm) +{ + while ((Filout = fopen(Flnm,"wb")) == NULL) + { + /* Failure to open the output file may be + simply due to an insufficiant permission setting. */ + fprintf(stderr,"Output file %s cannot be opened. Enter new file name: ", Flnm); + if (fgets(Flnm,MAX_FILE_NAME_SIZE,stdin) == NULL) exit(1); + + if (Flnm[strlen(Flnm) - 1] == '\n') Flnm[strlen(Flnm) - 1] = '\0'; + } + +#ifdef USE_FILE_BUFFERS + FiloutBuf = (char *) NoFailMalloc (BUFFSZ); + setvbuf(Filout, FiloutBuf, _IOFBF, BUFFSZ); +#endif + +} /* procedure OPENFILOUT */ + +void GetLine(char* str,FILE *in) +{ + char *result; + + result = fgets(str,MAX_LINE_SIZE,in); + if ((result == NULL) && !feof (in)) fprintf(stderr,"Error occurred while reading from file\n"); +} + +// 0 or 1 +int GetBin(const char *str) +{ + int result; + unsigned int value; + + result = sscanf(str,"%u",&value); + + if (result == 1) return value & 1; + else + { + fprintf(stderr,"GetBin: some error occurred when parsing options.\n"); + exit (1); + } +} + +int GetDec(const char *str) +{ + int result; + unsigned int value; + + result = sscanf(str,"%u",&value); + + if (result == 1) return value; + else + { + fprintf(stderr,"GetDec: some error occurred when parsing options.\n"); + exit (1); + } +} + +int GetHex(const char *str) +{ + int result; + unsigned int value; + + result = sscanf(str,"%x",&value); + + if (result == 1) return value; + else + { + fprintf(stderr,"GetHex: some error occurred when parsing options.\n"); + exit (1); + } +} + +// Char t/T: true f/F: false +bool GetBoolean(const char *str) +{ + int result; + unsigned char value, temp; + + result = sscanf(str,"%c",&value); + temp = tolower(value); + + if ((result == 1) && ((temp == 't') || (temp == 'f'))) + { + return (temp == 't'); + } + else + { + fprintf(stderr,"GetBoolean: some error occurred when parsing options.\n"); + exit (1); + } +} + +void GetExtension(const char *str,char *ext) +{ + if (strlen(str) > MAX_EXTENSION_SIZE) + usage(); + + strcpy(ext, str); +} + +/* Adds an extension to a file name */ +void PutExtension(char *Flnm, char *Extension) +{ + char *Period; /* location of period in file name */ + bool Samename; + + /* This assumes DOS like file names */ + /* Don't use strchr(): consider the following filename: + ../my.dir/file.hex + */ + if ((Period = strrchr(Flnm,'.')) != NULL) + *(Period) = '\0'; + + Samename = false; + if (strcmp(Extension, Period+1) == 0) + Samename = true; + + strcat(Flnm,"."); + strcat(Flnm, Extension); + if (Samename) + { + fprintf (stderr,"Input and output filenames (%s) are the same.", Flnm); + exit(1); + } +} + +void VerifyChecksumValue(void) +{ + if ((Checksum != 0) && Enable_Checksum_Error) + { + fprintf(stderr,"Checksum error in record %d: should be %02X\n", + Record_Nb, (256 - Checksum) & 0xFF); + Status_Checksum_Error = true; + } +} + +void CrcParamsCheck(void) +{ + switch (Cks_Type) + { + case CRC8: + Crc_Poly &= 0xFF; + Crc_Init &= 0xFF; + Crc_XorOut &= 0xFF; + break; + case CRC16: + Crc_Poly &= 0xFFFF; + Crc_Init &= 0xFFFF; + Crc_XorOut &= 0xFFFF; + break; + case CRC32: + break; + default: + fprintf (stderr,"See file CRC list.txt for parameters\n"); + exit(1); + } +} + +void WriteMemBlock16(uint16_t Value) +{ + if (Endian == 1) + { + Memory_Block[Cks_Addr - Lowest_Address] = u16_hi(Value); + Memory_Block[Cks_Addr - Lowest_Address +1] = u16_lo(Value); + } + else + { + Memory_Block[Cks_Addr - Lowest_Address +1] = u16_hi(Value); + Memory_Block[Cks_Addr - Lowest_Address] = u16_lo(Value); + } +} + +void WriteMemBlock32(uint32_t Value) +{ + if (Endian == 1) + { + Memory_Block[Cks_Addr - Lowest_Address] = u32_b3(Value); + Memory_Block[Cks_Addr - Lowest_Address +1] = u32_b2(Value); + Memory_Block[Cks_Addr - Lowest_Address +2] = u32_b1(Value); + Memory_Block[Cks_Addr - Lowest_Address +3] = u32_b0(Value); + } + else + { + Memory_Block[Cks_Addr - Lowest_Address +3] = u32_b3(Value); + Memory_Block[Cks_Addr - Lowest_Address +2] = u32_b2(Value); + Memory_Block[Cks_Addr - Lowest_Address +1] = u32_b1(Value); + Memory_Block[Cks_Addr - Lowest_Address] = u32_b0(Value); + } +} + +void WriteMemory(void) +{ + if ((Cks_Addr >= Lowest_Address) || (Cks_Addr < Highest_Address)) + { + if(Force_Value) + { + switch (Cks_Type) + { + case 0: + Memory_Block[Cks_Addr - Lowest_Address] = Cks_Value; + fprintf(stdout,"Addr %08X set to %02X\n",Cks_Addr, Cks_Value); + break; + case 1: + WriteMemBlock16(Cks_Value); + fprintf(stdout,"Addr %08X set to %04X\n",Cks_Addr, Cks_Value); + break; + case 2: + WriteMemBlock32(Cks_Value); + fprintf(stdout,"Addr %08X set to %08X\n",Cks_Addr, Cks_Value); + break; + default:; + } + } + else if (Cks_Addr_set) + { + /* Add a checksum to the binary file */ + if (!Cks_range_set) + { + Cks_Start = Lowest_Address; + Cks_End = Highest_Address; + } + /* checksum range MUST BE in the array bounds */ + + if (Cks_Start < Lowest_Address) + { + fprintf(stdout,"Modifying range start from %X to %X\n",Cks_Start,Lowest_Address); + Cks_Start = Lowest_Address; + } + if (Cks_End > Highest_Address) + { + fprintf(stdout,"Modifying range end from %X to %X\n",Cks_End,Highest_Address); + Cks_End = Highest_Address; + } + + switch (Cks_Type) + { + case CHK8_SUM: + { + uint8_t wCKS = 0; + + for (unsigned int i=Cks_Start; i<=Cks_End; i++) + { + wCKS += Memory_Block[i - Lowest_Address]; + } + + fprintf(stdout,"8-bit Checksum = %02X\n",wCKS & 0xff); + Memory_Block[Cks_Addr - Lowest_Address] = wCKS; + fprintf(stdout,"Addr %08X set to %02X\n",Cks_Addr, wCKS); + } + break; + + case CHK16: + { + uint16_t wCKS, w; + + wCKS = 0; + + if (Endian == 1) + { + for (unsigned int i=Cks_Start; i<=Cks_End; i+=2) + { + w = Memory_Block[i - Lowest_Address +1] | ((word)Memory_Block[i - Lowest_Address] << 8); + wCKS += w; + } + } + else + { + for (unsigned int i=Cks_Start; i<=Cks_End; i+=2) + { + w = Memory_Block[i - Lowest_Address] | ((word)Memory_Block[i - Lowest_Address +1] << 8); + wCKS += w; + } + } + fprintf(stdout,"16-bit Checksum = %04X\n",wCKS); + WriteMemBlock16(wCKS); + fprintf(stdout,"Addr %08X set to %04X\n",Cks_Addr, wCKS); + } + break; + + case CRC8: + { + uint8_t CRC8; + crc_table = NoFailMalloc(256); + + if (Crc_RefIn) + { + init_crc8_reflected_tab(Reflect8[Crc_Poly]); + CRC8 = Reflect8[Crc_Init]; + } + else + { + init_crc8_normal_tab(Crc_Poly); + CRC8 = Crc_Init; + } + + for (unsigned int i=Cks_Start; i<=Cks_End; i++) + { + CRC8 = update_crc8(CRC8,Memory_Block[i - Lowest_Address]); + } + + CRC8 = (CRC8 ^ Crc_XorOut) & 0xff; + Memory_Block[Cks_Addr - Lowest_Address] = CRC8; + fprintf(stdout,"Addr %08X set to %02X\n",Cks_Addr, CRC8); + } + break; + + case CRC16: + { + uint16_t CRC16; + crc_table = NoFailMalloc(256 * 2); + + if (Crc_RefIn) + { + init_crc16_reflected_tab(Reflect16(Crc_Poly)); + CRC16 = Reflect16(Crc_Init); + + for (unsigned int i=Cks_Start; i<=Cks_End; i++) + { + CRC16 = update_crc16_reflected(CRC16,Memory_Block[i - Lowest_Address]); + } + } + else + { + init_crc16_normal_tab(Crc_Poly); + CRC16 = Crc_Init; + + + for (unsigned int i=Cks_Start; i<=Cks_End; i++) + { + CRC16 = update_crc16_normal(CRC16,Memory_Block[i - Lowest_Address]); + } + } + + CRC16 = (CRC16 ^ Crc_XorOut) & 0xffff; + WriteMemBlock16(CRC16); + fprintf(stdout,"Addr %08X set to %04X\n",Cks_Addr, CRC16); + } + break; + + case CRC32: + { + uint32_t CRC32; + + crc_table = NoFailMalloc(256 * 4); + if (Crc_RefIn) + { + init_crc32_reflected_tab(Reflect32(Crc_Poly)); + CRC32 = Reflect32(Crc_Init); + + for (unsigned int i=Cks_Start; i<=Cks_End; i++) + { + CRC32 = update_crc32_reflected(CRC32,Memory_Block[i - Lowest_Address]); + } + } + else + { + init_crc32_normal_tab(Crc_Poly); + CRC32 = Crc_Init; + + for (unsigned int i=Cks_Start; i<=Cks_End; i++) + { + CRC32 = update_crc32_normal(CRC32,Memory_Block[i - Lowest_Address]); + } + } + + CRC32 ^= Crc_XorOut; + WriteMemBlock32(CRC32); + fprintf(stdout,"Addr %08X set to %08X\n",Cks_Addr, CRC32); + } + break; + + default: + ; + } + + free(crc_table); + } + } + else + { + fprintf (stderr,"Force/Check address outside of memory range\n"); + } + + /* write binary file */ + fwrite (Memory_Block, + Max_Length, + 1, + Filout); + + free (Memory_Block); + + // Minimum_Block_Size is set; the memory buffer is multiple of this? + if (Minimum_Block_Size_Setted==true) + { + Module = Max_Length % Minimum_Block_Size; + if (Module) + { + Memory_Block = (byte *) NoFailMalloc(Module); + memset (Memory_Block,Pad_Byte,Module); + fwrite (Memory_Block, + Module, + 1, + Filout); + free (Memory_Block); + if (Max_Length_Setted==true) + fprintf(stdout,"Attention Max Length changed by Minimum Block Size\n"); + } + } +} diff --git a/tools/hex2bin-2.0/src/common.h b/tools/hex2bin-2.0/src/common.h new file mode 100644 index 0000000..64caff5 --- /dev/null +++ b/tools/hex2bin-2.0/src/common.h @@ -0,0 +1,116 @@ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "binary.h" +#include "libcrc.h" + +/* To compile with Microsoft Visual Studio */ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif + +#if defined(MSDOS) || defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) +#define _IS_OPTION_(x) (((x) == '-') || ((x) == '/')) +#else +/* Assume unix and similar */ +/* We don't accept an option beginning with a '/' because it could be a file name. */ +#define _IS_OPTION_(x) ((x) == '-') +#endif + +/* We use buffer to speed disk access. */ +#ifdef USE_FILE_BUFFERS +#define BUFFSZ 4096 +#endif + +/* FIXME how to get it from the system/OS? */ +#define MAX_FILE_NAME_SIZE 81 + +#ifdef DOS +#define MAX_EXTENSION_SIZE 4 +#else +#define MAX_EXTENSION_SIZE 16 +#endif + +/* The data records can contain 255 bytes: this means 512 characters. */ +#define MAX_LINE_SIZE 1024 + +typedef char filetype[MAX_FILE_NAME_SIZE]; +typedef unsigned char byte; +typedef unsigned short word; + +#define LAST_CHECK_METHOD 4 + +typedef enum Crc +{ + CHK8_SUM =0, + CHK16, + CRC8, + CRC16, + CRC32 +} t_CRC; + +extern const char *Pgm_Name; +void usage(void); +void DisplayCheckMethods(void); + +void *NoFailMalloc (size_t size); +void NoFailOpenInputFile (char *Flnm); +void NoFailOpenOutputFile (char *Flnm); +void GetLine(char* str,FILE *in); +int GetBin(const char *str); +int GetDec(const char *str); +int GetHex(const char *str); +bool GetBoolean(const char *str); +void GetExtension(const char *str,char *ext); +void PutExtension(char *Flnm, char *Extension); + +filetype Filename; /* string for opening files */ +char Extension[MAX_EXTENSION_SIZE]; /* filename extension for output files */ + +FILE *Filin, /* input files */ + *Filout; /* output files */ + +#ifdef USE_FILE_BUFFERS +char *FilinBuf, /* text buffer for file input */ + *FiloutBuf; /* text buffer for file output */ +#endif + +int Pad_Byte; +bool Enable_Checksum_Error; +bool Status_Checksum_Error; +byte Checksum; +unsigned int Record_Nb; + +/* This will hold binary codes translated from hex file. */ +byte *Memory_Block; +unsigned int Lowest_Address, Highest_Address; +unsigned int Starting_Address; +unsigned int Max_Length; +unsigned int Minimum_Block_Size; +int Module; +bool Minimum_Block_Size_Setted; +bool Starting_Address_Setted; +bool Max_Length_Setted; +bool Swap_Wordwise; + +int Endian; + +t_CRC Cks_Type; +unsigned int Cks_Start, Cks_End, Cks_Addr, Cks_Value; +bool Cks_range_set; +bool Cks_Addr_set; +bool Force_Value; + +unsigned int Crc_Poly, Crc_Init, Crc_XorOut; +bool Crc_RefIn; +bool Crc_RefOut; + +void VerifyChecksumValue(void); +void CrcParamsCheck(void); +void WriteMemBlock16(uint16_t Value); +void WriteMemBlock32(uint32_t Value); +void WriteMemory(void); + diff --git a/tools/hex2bin-2.0/src/hex2bin.1 b/tools/hex2bin-2.0/src/hex2bin.1 new file mode 100644 index 0000000..c2e5e89 --- /dev/null +++ b/tools/hex2bin-2.0/src/hex2bin.1 @@ -0,0 +1,294 @@ +.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +. ds C` +. ds C' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.\" +.\" Avoid warning from groff about undefined register 'F'. +.de IX +.. +.nr rF 0 +.if \n(.g .if rF .nr rF 1 +.if (\n(rF:(\n(.g==0)) \{ +. if \nF \{ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. if !\nF==2 \{ +. nr % 0 +. nr F 2 +. \} +. \} +.\} +.rr rF +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "HEX2BIN 1" +.TH HEX2BIN 1 "2015-02-28" "perl v5.18.2" "User Contributed Perl Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +hex2bin/mot2bin \e\- converts Intel/Motorola hex files into binary +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +hex2bin [options] file +.PP +Option list: + [\-c] + [\-C Poly Init RefIn RefOut XorOut] + [\-e extension] + [\-E 0|1] + [\-f address] + [\-F address value] + [\-k checksum type] + [\-l length] + [\-m minimum block size] + [\-p pad byte] + [\-r start end] + [\-s address] + [\-w] +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\fBHex2bin\fR +is a program that converts an Intel hex format into binary. +It can handle the extended Intel hex format. Both the segmented +and linear address records are supported. +Records need not be sorted and there can be gaps between records. +Records are assumed to be non-overlapping. +Padding bytes may be specified and a checksum may be inserted in the +binary file. +.PP +\&\fBMot2bin\fR +does the same with Motorola hex files. It has the same features and command line +options. 24 bit and 32 bit records are supported. +.SH "OPTIONS" +.IX Header "OPTIONS" +Options can be specified in any order, with the file name at the end. Options are +now case sensitive. All option values are specified in hexadecimal. +.PP +\&\fB\-c\fR +.PP +Enables checksum verification. +.PP +By default, it ignores checksum errors in the hex file, so that someone can change +by hand some bytes with a text editor, allowing quick fixes without recompiling a source +code all over again. This is useful when tweaking constants directly in the code or +something similar. If you want checksum error reporting, specify the option \-c. +.PP +\&\fBEx.: hex2bin \-c example.hex\fR +.PP +If there is a checksum error somewhere, the program will continue the +conversion anyway. +.PP +\&\fB\-C Poly Init RefIn RefOut XorOut\fR +.PP +\&\s-1CRC\s0 parameters. See the doc/CRC list.txt file for a description of common CRCs. See also +the test/Makefile for examples of command lines. Needs \fB\-k\fR and \fB\-f\fR option. +RefIn and RefOut parameters are specified by \fBt\fR or \fBf\fR for true or false. +.PP +\&\fB\-d\fR +.PP +Display the list of available check methods and sizes. +.PP +\&\fB\-e extension\fR +.PP +By default, the output file will have an extension \fBfilename.bin\fR. +Another extension may be specified with this command: +.PP +\&\fBEx.: hex2bin \-e com example.hex\fR +.PP +The output file will be example.com +.PP +\&\fB\-E 0|1\fR +.PP +Endianness for writing the check result or forcing a 16\-bit value. + \fB0\fR: little, \fB1\fR: big. +.PP +By default, little endian is used. +.PP +\&\fB\-f address\fR +.PP +Address in hexadecimal for inserting the check value in the binary file. Needs \fB\-k\fR +option to specify the check method. A range can be specified with option \fB\-r\fR. +.PP +\&\fB\-F address value\fR +.PP +Address and value of checksum to insert (force) in the binary file. Needs \fB\-k\fR +option to specify the size. The value is written as is. +.PP +\&\fB\-k 0\-4\fR +.PP +In many cases, someone needs to insert a check value in the binary file. For example, +a boot rom is programmed with a checksum which is verified at power-up. This feature +uses also options \fB\-r\fR, \fB\-C\fR and \fB\-f\fR. Display the list with \fB\-d\fR. +.PP +Select the checksum type to insert into the binary file + 0: Checksum 8\-bit + 1: Checksum 16\-bit + 2: \s-1CRC8 + 3: CRC16 + 4: CRC32\s0 +.PP +\&\fB\-l length\fR +.PP +The binary file will be padded with \s-1FF\s0 or pad bytes as specified by the option +below, up to a maximal Length (Starting address + Length \-1 is Max Address) +.PP +\&\fB\-m minimum_block_size\fR +.PP +File Size Dimension will be a multiple of Minimum block size. +File will be filled with Pattern. +Length must be a power of 2 in hexadecimal [see \fB\-l\fR option] +Attention this option is \s-1STRONGER\s0 than Maximal Length +.PP +\&\fB\-p pad_byte\fR +.PP +Pads unused locations with the specified byte. +.PP +By default, this byte is \s-1FF,\s0 which is the unprogrammed value for most EPROM/EEPROM/Flash. +.PP +\&\fBEx.: hex2bin \-p 3E example.hex\fR +.PP +\&\fB\-r [start] [end]\fR +.PP +Range to compute binary checksum over (default is min and max addresses) +.PP +\&\fB\-s address\fR +.PP +Specify the starting address of the binary file. +.PP +Normally, hex2bin will generate a binary file starting at the lowest address in +the hex file. If the lowest address isn't 0000, ex: 0100, the first byte that +should be at 0100 will be stored at address 0000 in the binary file. This may +cause problems when using the binary file to program an \s-1EPROM.\s0 +.PP +If you can't specify the starting address (or offset) to your \s-1EPROM\s0 programmer, +you can specify a starting address on the command line: +.PP +\&\fBEx.: hex2bin \-s 0000 records_start_at_0100.hex\fR +.PP +The bytes will be stored in the binary file with a padding from 0000 to the +lowest address (00FF in this case). Padding bytes are all \s-1FF\s0 by default so an \s-1EPROM\s0 +programmer can skip these bytes when programming. The padding value can be changed +with the \-p option. +.PP +\&\fB\-w\fR +.PP +Swap wordwise (low <\-> high). Used by Microchip's \s-1MPLAB IDE\s0 +.SH "NOTES" +.IX Header "NOTES" +This program does minimal error checking since many hex files are +generated by known good assemblers. +.SH "AUTHOR Jacques Pelletier (jpelletier@ieee.org) \- version 2.0" +.IX Header "AUTHOR Jacques Pelletier (jpelletier@ieee.org) - version 2.0" diff --git a/tools/hex2bin-2.0/src/hex2bin.c b/tools/hex2bin-2.0/src/hex2bin.c new file mode 100644 index 0000000..7537d8c --- /dev/null +++ b/tools/hex2bin-2.0/src/hex2bin.c @@ -0,0 +1,587 @@ +/* + hex2bin converts an Intel hex file to binary. + + Copyright (C) 2015, Jacques Pelletier + checksum extensions Copyright (C) 2004 Rockwell Automation + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + 20040617 Alf Lacis: Added pad byte (may not always want FF). + Added 'break;' to remove GNU compiler warning about label at + end of compound statement + Added PROGRAM & VERSION strings. + + 20071005 PG: Improvements on options parsing + 20091212 JP: Corrected crash on 0 byte length data records + 20100402 JP: Corrected bug on physical address calculation for extended + linear address record. + ADDRESS_MASK is now calculated from MEMORY_SIZE + + 20120125 Danny Schneider: + Added code for filling a binary file to a given Max_Length relative to + Starting Address if Max-Address is larger than Highest-Address + 20120509 Yoshimasa Nakane: + modified error checking (also for output file, JP) + 20141005 JP: added support for byte swapped hex files + corrected bug caused by extra LF at end or within file + 20141008 JP: removed junk code + 20141121 Slucx: added line for removing extra CR when entering file name at run time. + 20141122 Simone Fratini: small feature added + 20150116 Richard Genoud (Paratronic): correct buffer overflows/wrong results with the -l flag + 20150122 JP: added support for different check methods + 20150221 JP: rewrite of the checksum write/force value +*/ + +#define PROGRAM "hex2bin" +#define VERSION "2.0" + +#include "common.h" + +#define NO_ADDRESS_TYPE_SELECTED 0 +#define LINEAR_ADDRESS 1 +#define SEGMENTED_ADDRESS 2 + +const char *Pgm_Name = PROGRAM; + +int main (int argc, char *argv[]) +{ + /* line inputted from file */ + char Line[MAX_LINE_SIZE]; + + /* flag that a file was read */ + bool Fileread; + + /* cmd-line parameter # */ + char *p; + + int Param,result; + + /* Application specific */ + + unsigned int Nb_Bytes; + unsigned int First_Word, Address, Segment, Upper_Address; + unsigned int Phys_Addr, Type; + unsigned int temp; + unsigned int Records_Start; // Lowest address of the records + + /* We will assume that when one type of addressing is selected, it will be valid for all the + current file. Records for the other type will be ignored. */ + unsigned int Seg_Lin_Select = NO_ADDRESS_TYPE_SELECTED; + + unsigned int temp2; + + byte Data_Str[MAX_LINE_SIZE]; + + fprintf (stdout,PROGRAM" v"VERSION", Copyright (C) 2015 Jacques Pelletier & contributors\n\n"); + + if (argc == 1) + usage(); + + strcpy(Extension, "bin"); /* default is for binary file extension */ + + /* read file */ + Starting_Address = 0; + + /* + use p for parsing arguments + use i for number of parameters to skip + use c for the current option + */ + for (Param = 1; Param < argc; Param++) + { + int i = 0; + char c; + + p = argv[Param]; + c = *(p+1); /* Get option character */ + + if ( _IS_OPTION_(*p) ) + { + // test for no space between option and parameter + if (strlen(p) != 2) usage(); + + switch(c) + { + /* file extension */ + case 'c': + Enable_Checksum_Error = true; + i = 0; + break; + case 'd': + DisplayCheckMethods(); + case 'e': + GetExtension(argv[Param + 1],Extension); + i = 1; /* add 1 to Param */ + break; + case 'E': + Endian = GetBin(argv[Param + 1]); + i = 1; /* add 1 to Param */ + break; + case 'f': + Cks_Addr = GetHex(argv[Param + 1]); + Cks_Addr_set = true; + i = 1; /* add 1 to Param */ + break; + case 'F': + Cks_Addr = GetHex(argv[Param + 1]); + Cks_Value = GetHex(argv[Param + 2]); + Force_Value = true; + i = 2; /* add 2 to Param */ + break; + case 'k': + Cks_Type = GetHex(argv[Param + 1]); + { + if (Cks_Type > LAST_CHECK_METHOD) usage(); + } + i = 1; /* add 1 to Param */ + break; + case 'l': + Max_Length = GetHex(argv[Param + 1]); + if (Max_Length > 0x800000) + { + fprintf(stderr,"Max_Length = %u\n", Max_Length); + exit(1); + } + Max_Length_Setted = true; + i = 1; /* add 1 to Param */ + break; + case 'm': + Minimum_Block_Size = GetHex(argv[Param + 1]); + Minimum_Block_Size_Setted = true; + i = 1; /* add 1 to Param */ + break; + case 'p': + Pad_Byte = GetHex(argv[Param + 1]); + i = 1; /* add 1 to Param */ + break; + case 'r': + Cks_Start = GetHex(argv[Param + 1]); + Cks_End = GetHex(argv[Param + 2]); + Cks_range_set = true; + i = 2; /* add 2 to Param */ + break; + case 's': + Starting_Address = GetHex(argv[Param + 1]); + Starting_Address_Setted = true; + i = 1; /* add 1 to Param */ + break; + case 'w': + Swap_Wordwise = true; + i = 0; + break; + case 'C': + Crc_Poly = GetHex(argv[Param + 1]); + Crc_Init = GetHex(argv[Param + 2]); + Crc_RefIn = GetBoolean(argv[Param + 3]); + Crc_RefOut = GetBoolean(argv[Param + 4]); + Crc_XorOut = GetHex(argv[Param + 5]); + CrcParamsCheck(); + i = 5; /* add 5 to Param */ + break; + + case '?': + case 'h': + default: + usage(); + } /* switch */ + + /* Last parameter is not a filename */ + if (Param == argc-1) usage(); + + /* if (Param + i) < (argc -1) */ + if (Param < argc -1 -i) Param += i; + else usage(); + + } + else + break; + /* if option */ + } /* for Param */ + + /* when user enters input file name */ + + /* Assume last parameter is filename */ + strcpy(Filename,argv[argc -1]); + + /* Just a normal file name */ + NoFailOpenInputFile (Filename); + PutExtension(Filename, Extension); + NoFailOpenOutputFile(Filename); + Fileread = true; + + /* To begin, assume the lowest address is at the end of the memory. + While reading each records, subsequent addresses will lower this number. + At the end of the input file, this value will be the lowest address. + + A similar assumption is made for highest address. It starts at the + beginning of memory. While reading each records, subsequent addresses will raise this number. + At the end of the input file, this value will be the highest address. */ + Lowest_Address = (unsigned int)-1; + Highest_Address = 0; + Records_Start = 0; + Segment = 0; + Upper_Address = 0; + Record_Nb = 0; // Used for reporting errors + + /* get highest and lowest addresses so that we can allocate the right size */ + do + { + unsigned int i; + + /* Read a line from input file. */ + GetLine(Line,Filin); + Record_Nb++; + + /* Remove carriage return/line feed at the end of line. */ + i = strlen(Line); + + if (--i != 0) + { + if (Line[i] == '\n') Line[i] = '\0'; + + /* Scan the first two bytes and nb of bytes. + The two bytes are read in First_Word since its use depend on the + record type: if it's an extended address record or a data record. + */ + result = sscanf (Line, ":%2x%4x%2x%s",&Nb_Bytes,&First_Word,&Type,Data_Str); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + p = (char *) Data_Str; + + /* If we're reading the last record, ignore it. */ + switch (Type) + { + /* Data record */ + case 0: + if (Nb_Bytes == 0) + break; + + Address = First_Word; + + if (Seg_Lin_Select == SEGMENTED_ADDRESS) + { + Phys_Addr = (Segment << 4) + Address; + } + else + { + /* LINEAR_ADDRESS or NO_ADDRESS_TYPE_SELECTED + Upper_Address = 0 as specified in the Intel spec. until an extended address + record is read. */ + Phys_Addr = ((Upper_Address << 16) + Address); + } + + /* Set the lowest address as base pointer. */ + if (Phys_Addr < Lowest_Address) + Lowest_Address = Phys_Addr; + + /* Same for the top address. */ + temp = Phys_Addr + Nb_Bytes -1; + + if (temp > Highest_Address) + Highest_Address = temp; + + break; + + case 2: + /* First_Word contains the offset. It's supposed to be 0000 so + we ignore it. */ + + /* First extended segment address record ? */ + if (Seg_Lin_Select == NO_ADDRESS_TYPE_SELECTED) + Seg_Lin_Select = SEGMENTED_ADDRESS; + + /* Then ignore subsequent extended linear address records */ + if (Seg_Lin_Select == SEGMENTED_ADDRESS) + { + result = sscanf (p, "%4x%2x",&Segment,&temp2); + if (result != 2) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Update the current address. */ + Phys_Addr = (Segment << 4); + } + else + { + fprintf(stderr,"Ignored extended linear address record %d\n", Record_Nb); + } + break; + + case 4: + /* First_Word contains the offset. It's supposed to be 0000 so + we ignore it. */ + + /* First extended linear address record ? */ + if (Seg_Lin_Select == NO_ADDRESS_TYPE_SELECTED) + Seg_Lin_Select = LINEAR_ADDRESS; + + /* Then ignore subsequent extended segment address records */ + if (Seg_Lin_Select == LINEAR_ADDRESS) + { + result = sscanf (p, "%4x%2x",&Upper_Address,&temp2); + if (result != 2) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Update the current address. */ + Phys_Addr = (Upper_Address << 16); + } + else + { + fprintf(stderr,"Ignored extended segment address record %d\n", Record_Nb); + } + break; + + default: + break; + } + } + } + while (!feof (Filin)); + + rewind(Filin); + Segment = 0; + Upper_Address = 0; + Record_Nb = 0; + + if (Starting_Address_Setted == true) + { + Records_Start = Lowest_Address; + Lowest_Address = Starting_Address; + } + else + { + Records_Start = Lowest_Address; + Starting_Address = Lowest_Address; + } + + if (Max_Length_Setted == false) + Max_Length = Highest_Address - Lowest_Address + 1; + else + Highest_Address = Lowest_Address + Max_Length - 1; + + /* Now, that we know the buffer size, we can allocate it. */ + /* allocate a buffer */ + Memory_Block = (byte *) NoFailMalloc(Max_Length); + + /* For EPROM or FLASH memory types, fill unused bytes with FF or the value specified by the p option */ + memset (Memory_Block,Pad_Byte,Max_Length); + + /* Read the file & process the lines. */ + do /* repeat until EOF(Filin) */ + { + unsigned int i; + + /* Read a line from input file. */ + GetLine(Line,Filin); + Record_Nb++; + + /* Remove carriage return/line feed at the end of line. */ + i = strlen(Line); + + //fprintf(stderr,"Record: %d; length: %d\n", Record_Nb, i); + + if (--i != 0) + { + if (Line[i] == '\n') Line[i] = '\0'; + + /* Scan the first two bytes and nb of bytes. + The two bytes are read in First_Word since its use depend on the + record type: if it's an extended address record or a data record. + */ + result = sscanf (Line, ":%2x%4x%2x%s",&Nb_Bytes,&First_Word,&Type,Data_Str); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + Checksum = Nb_Bytes + (First_Word >> 8) + (First_Word & 0xFF) + Type; + + p = (char *) Data_Str; + + /* If we're reading the last record, ignore it. */ + switch (Type) + { + /* Data record */ + case 0: + if (Nb_Bytes == 0) + { + fprintf(stderr,"0 byte length Data record ignored\n"); + break; + } + + Address = First_Word; + + if (Seg_Lin_Select == SEGMENTED_ADDRESS) + Phys_Addr = (Segment << 4) + Address; + else + /* LINEAR_ADDRESS or NO_ADDRESS_TYPE_SELECTED + Upper_Address = 0 as specified in the Intel spec. until an extended address + record is read. */ + Phys_Addr = ((Upper_Address << 16) + Address); + + /* Check that the physical address stays in the buffer's range. */ + if ((Phys_Addr >= Lowest_Address) && (Phys_Addr <= Highest_Address)) + { + /* The memory block begins at Lowest_Address */ + Phys_Addr -= Lowest_Address; + + /* Read the Data bytes. */ + /* Bytes are written in the Memory block even if checksum is wrong. */ + i = Nb_Bytes; + + do + { + result = sscanf (p, "%2x",&temp2); + if (result != 1) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + p += 2; + + /* Check that the physical address stays in the buffer's range. */ + if (Phys_Addr < Max_Length) + { + /* Overlapping record will erase the pad bytes */ + if (Swap_Wordwise) + { + if (Memory_Block[Phys_Addr ^ 1] != Pad_Byte) fprintf(stderr,"Overlapped record detected\n"); + Memory_Block[Phys_Addr++ ^ 1] = temp2; + } + else + { + if (Memory_Block[Phys_Addr] != Pad_Byte) fprintf(stderr,"Overlapped record detected\n"); + Memory_Block[Phys_Addr++] = temp2; + } + + Checksum = (Checksum + temp2) & 0xFF; + } + } + while (--i != 0); + + /* Read the Checksum value. */ + result = sscanf (p, "%2x",&temp2); + if (result != 1) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Verify Checksum value. */ + Checksum = (Checksum + temp2) & 0xFF; + VerifyChecksumValue(); + } + else + { + if (Seg_Lin_Select == SEGMENTED_ADDRESS) + fprintf(stderr,"Data record skipped at %4X:%4X\n",Segment,Address); + else + fprintf(stderr,"Data record skipped at %8X\n",Phys_Addr); + } + + break; + + /* End of file record */ + case 1: + /* Simply ignore checksum errors in this line. */ + break; + + /* Extended segment address record */ + case 2: + /* First_Word contains the offset. It's supposed to be 0000 so + we ignore it. */ + + /* First extended segment address record ? */ + if (Seg_Lin_Select == NO_ADDRESS_TYPE_SELECTED) + Seg_Lin_Select = SEGMENTED_ADDRESS; + + /* Then ignore subsequent extended linear address records */ + if (Seg_Lin_Select == SEGMENTED_ADDRESS) + { + result = sscanf (p, "%4x%2x",&Segment,&temp2); + if (result != 2) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Update the current address. */ + Phys_Addr = (Segment << 4); + + /* Verify Checksum value. */ + Checksum = (Checksum + (Segment >> 8) + (Segment & 0xFF) + temp2) & 0xFF; + VerifyChecksumValue(); + } + break; + + /* Start segment address record */ + case 3: + /* Nothing to be done since it's for specifying the starting address for + execution of the binary code */ + break; + + /* Extended linear address record */ + case 4: + /* First_Word contains the offset. It's supposed to be 0000 so + we ignore it. */ + + /* First extended linear address record ? */ + if (Seg_Lin_Select == NO_ADDRESS_TYPE_SELECTED) + Seg_Lin_Select = LINEAR_ADDRESS; + + /* Then ignore subsequent extended segment address records */ + if (Seg_Lin_Select == LINEAR_ADDRESS) + { + result = sscanf (p, "%4x%2x",&Upper_Address,&temp2); + if (result != 2) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Update the current address. */ + Phys_Addr = (Upper_Address << 16); + + /* Verify Checksum value. */ + Checksum = (Checksum + (Upper_Address >> 8) + (Upper_Address & 0xFF) + temp2) + & 0xFF; + VerifyChecksumValue(); + } + break; + + /* Start linear address record */ + case 5: + /* Nothing to be done since it's for specifying the starting address for + execution of the binary code */ + break; + default: + fprintf(stderr,"Unknown record type\n"); + break; + } + } + } + while (!feof (Filin)); + /*-----------------------------------------------------------------------------*/ + + fprintf(stdout,"Binary file start = %08X\n",Lowest_Address); + fprintf(stdout,"Records start = %08X\n",Records_Start); + fprintf(stdout,"Highest address = %08X\n",Highest_Address); + fprintf(stdout,"Pad Byte = %X\n", Pad_Byte); + + WriteMemory(); + +#ifdef USE_FILE_BUFFERS + free (FilinBuf); + free (FiloutBuf); +#endif + + fclose (Filin); + fclose (Filout); + + if (Status_Checksum_Error && Enable_Checksum_Error) + { + fprintf(stderr,"Checksum error detected.\n"); + return 1; + } + + if (!Fileread) + usage(); + return 0; +} diff --git a/tools/hex2bin-2.0/src/hex2bin.pod b/tools/hex2bin-2.0/src/hex2bin.pod new file mode 100644 index 0000000..a8eb238 --- /dev/null +++ b/tools/hex2bin-2.0/src/hex2bin.pod @@ -0,0 +1,161 @@ +HEX2BIN 1 "2015 february 22nd" "Hex2bin Version 2.0" +=head1 NAME + +hex2bin/mot2bin \- converts Intel/Motorola hex files into binary + +=head1 SYNOPSIS + +hex2bin [options] file + +Option list: + [-c] + [-C Poly Init RefIn RefOut XorOut] + [-e extension] + [-E 0|1] + [-f address] + [-F address value] + [-k checksum type] + [-l length] + [-m minimum block size] + [-p pad byte] + [-r start end] + [-s address] + [-w] + +=head1 DESCRIPTION + +B<Hex2bin> +is a program that converts an Intel hex format into binary. +It can handle the extended Intel hex format. Both the segmented +and linear address records are supported. +Records need not be sorted and there can be gaps between records. +Records are assumed to be non-overlapping. +Padding bytes may be specified and a checksum may be inserted in the +binary file. + +B<Mot2bin> +does the same with Motorola hex files. It has the same features and command line +options. 24 bit and 32 bit records are supported. + +=head1 OPTIONS + +Options can be specified in any order, with the file name at the end. Options are +now case sensitive. All option values are specified in hexadecimal. + +B<-c> + +Enables checksum verification. + +By default, it ignores checksum errors in the hex file, so that someone can change +by hand some bytes with a text editor, allowing quick fixes without recompiling a source +code all over again. This is useful when tweaking constants directly in the code or +something similar. If you want checksum error reporting, specify the option -c. + +B<Ex.: hex2bin -c example.hex> + +If there is a checksum error somewhere, the program will continue the +conversion anyway. + +B<-C Poly Init RefIn RefOut XorOut> + +CRC parameters. See the doc/CRC list.txt file for a description of common CRCs. See also +the test/Makefile for examples of command lines. Needs B<-k> and B<-f> option. +RefIn and RefOut parameters are specified by B<t> or B<f> for true or false. + +B<-d> + +Display the list of available check methods and sizes. + +B<-e extension> + +By default, the output file will have an extension B<filename.bin>. +Another extension may be specified with this command: + +B<Ex.: hex2bin -e com example.hex> + +The output file will be example.com + +B<-E 0|1> + +Endianness for writing the check result or forcing a 16-bit value. + B<0>: little, B<1>: big. + +By default, little endian is used. + +B<-f address> + +Address in hexadecimal for inserting the check value in the binary file. Needs B<-k> +option to specify the check method. A range can be specified with option B<-r>. + +B<-F address value> + +Address and value of checksum to insert (force) in the binary file. Needs B<-k> +option to specify the size. The value is written as is. + +B<-k 0-4> + +In many cases, someone needs to insert a check value in the binary file. For example, +a boot rom is programmed with a checksum which is verified at power-up. This feature +uses also options B<-r>, B<-C> and B<-f>. Display the list with B<-d>. + +Select the checksum type to insert into the binary file + 0: Checksum 8-bit + 1: Checksum 16-bit + 2: CRC8 + 3: CRC16 + 4: CRC32 + +B<-l length> + +The binary file will be padded with FF or pad bytes as specified by the option +below, up to a maximal Length (Starting address + Length -1 is Max Address) + +B<-m minimum_block_size> + +File Size Dimension will be a multiple of Minimum block size. +File will be filled with Pattern. +Length must be a power of 2 in hexadecimal [see B<-l> option] +Attention this option is STRONGER than Maximal Length + +B<-p pad_byte> + +Pads unused locations with the specified byte. + +By default, this byte is FF, which is the unprogrammed value for most EPROM/EEPROM/Flash. + +B<Ex.: hex2bin -p 3E example.hex> + +B<-r [start] [end]> + +Range to compute binary checksum over (default is min and max addresses) + +B<-s address> + +Specify the starting address of the binary file. + +Normally, hex2bin will generate a binary file starting at the lowest address in +the hex file. If the lowest address isn't 0000, ex: 0100, the first byte that +should be at 0100 will be stored at address 0000 in the binary file. This may +cause problems when using the binary file to program an EPROM. + +If you can't specify the starting address (or offset) to your EPROM programmer, +you can specify a starting address on the command line: + +B<Ex.: hex2bin -s 0000 records_start_at_0100.hex> + +The bytes will be stored in the binary file with a padding from 0000 to the +lowest address (00FF in this case). Padding bytes are all FF by default so an EPROM +programmer can skip these bytes when programming. The padding value can be changed +with the -p option. + +B<-w> + +Swap wordwise (low <-> high). Used by Microchip's MPLAB IDE + +=head1 NOTES + +This program does minimal error checking since many hex files are +generated by known good assemblers. + +=head1 AUTHOR +Jacques Pelletier (jpelletier@ieee.org) - version 2.0 diff --git a/tools/hex2bin-2.0/src/libcrc.c b/tools/hex2bin-2.0/src/libcrc.c new file mode 100644 index 0000000..02bcd4b --- /dev/null +++ b/tools/hex2bin-2.0/src/libcrc.c @@ -0,0 +1,204 @@ +/********************************************************************* + * * + * Library : lib_crc * + * File : lib_crc.c * + * Author : Lammert Bies 1999-2008 * + * E-mail : info@lammertbies.nl * + * Language : ANSI C * + * * + * * + * Description * + * =========== * + * * + * The file lib_crc.c contains the private and public func- * + * tions used for the calculation of CRC-16, CRC-CCITT and * + * CRC-32 cyclic redundancy values. * + * * + * * + * Dependencies * + * ============ * + * * + * libcrc.h CRC definitions and prototypes * + * * + ********************************************************************/ +#include <stdint.h> + +#ifndef G_GUINT64_CONSTANT +#define G_GUINT64_CONSTANT(val) (val##UL) +#endif + +void *crc_table; + +/* private */ + +void init_crc8_normal_tab(uint8_t polynom) +{ + int i, j; + uint8_t crc; + uint8_t *p; + + p = (uint8_t *) crc_table; + + for (i=0; i<256; i++) + { + crc = (uint8_t) i; + + for (j=0; j<8; j++) + { + if (crc & 0x80) crc = (crc << 1) ^ polynom; + else crc <<= 1; + } + *p++ = crc; + } +} + +void init_crc8_reflected_tab(uint8_t polynom) +{ + int i, j; + uint8_t crc; + uint8_t *p; + + p = (uint8_t *) crc_table; + + for (i=0; i<256; i++) + { + crc = (uint8_t) i; + + for (j=0; j<8; j++) + { + if (crc & 0x01) crc = (crc >> 1) ^ polynom; + else crc >>= 1; + } + *p++ = crc; + } +} + +/* Common routines for calculations */ +void init_crc16_normal_tab(uint16_t polynom) +{ + int i, j; + uint16_t crc; + uint16_t *p; + + p = (uint16_t *) crc_table; + + for (i=0; i<256; i++) + { + crc = ((uint16_t) i) << 8; + + for (j=0; j<8; j++) + { + if ( crc & 0x8000 ) crc = ( crc << 1 ) ^ polynom; + else crc <<= 1; + } + *p++ = crc; + } +} + +void init_crc16_reflected_tab(uint16_t polynom) +{ + int i, j; + uint16_t crc; + uint16_t *p; + + p = (uint16_t *) crc_table; + + for (i=0; i<256; i++) + { + crc = (uint16_t) i; + + for (j=0; j<8; j++) + { + if ( crc & 0x0001 ) crc = ( crc >> 1 ) ^ polynom; + else crc >>= 1; + } + *p++ = crc; + } +} + +void init_crc32_normal_tab(uint32_t polynom) +{ + int i, j; + uint32_t crc; + uint32_t *p; + + p = (uint32_t *) crc_table; + + for (i=0; i<256; i++) + { + crc = ((uint32_t) i) << 24; + + for (j=0; j<8; j++) + { + if ( crc & 0x80000000L ) crc = ( crc << 1 ) ^ polynom; + else crc <<= 1; + } + *p++ = crc; + } +} + +void init_crc32_reflected_tab(uint32_t polynom) +{ + int i, j; + uint32_t crc; + uint32_t *p; + + p = (uint32_t *) crc_table; + + for (i=0; i<256; i++) + { + crc = (uint32_t) i; + + for (j=0; j<8; j++) + { + if ( crc & 0x00000001L ) crc = ( crc >> 1 ) ^ polynom; + else crc >>= 1; + } + *p++ = crc; + } +} + +/* Common routines for calculations */ + +uint8_t update_crc8(uint8_t crc, uint8_t c) +{ + return (((uint8_t *) crc_table)[crc ^ c]); +} + +uint16_t update_crc16_normal(uint16_t crc, char c ) +{ + uint16_t short_c; + + short_c = 0x00ff & (uint16_t) c; + + /* Normal form */ + return (crc << 8) ^ ((uint16_t *) crc_table)[(crc >> 8) ^ short_c]; +} + +uint16_t update_crc16_reflected(uint16_t crc, char c ) +{ + uint16_t short_c; + + short_c = 0x00ff & (uint16_t) c; + + /* Reflected form */ + return (crc >> 8) ^ ((uint16_t *) crc_table)[(crc ^ short_c) & 0xff]; +} + +uint32_t update_crc32_normal(uint32_t crc, char c ) +{ + uint32_t long_c; + + long_c = 0x000000ffL & (uint32_t) c; + + return (crc << 8) ^ ((uint32_t *) crc_table)[((crc >> 24) ^ long_c) & 0xff]; +} + +uint32_t update_crc32_reflected(uint32_t crc, char c ) +{ + uint32_t long_c; + + long_c = 0x000000ffL & (uint32_t) c; + + return (crc >> 8) ^ ((uint32_t *) crc_table)[(crc ^ long_c) & 0xff]; +} diff --git a/tools/hex2bin-2.0/src/libcrc.h b/tools/hex2bin-2.0/src/libcrc.h new file mode 100644 index 0000000..39f20d0 --- /dev/null +++ b/tools/hex2bin-2.0/src/libcrc.h @@ -0,0 +1,44 @@ + /******************************************************************** + * * + * Library : lib_crc * + * File : lib_crc.h * + * Author : Lammert Bies 1999-2008 * + * E-mail : info@lammertbies.nl * + * Language : ANSI C * + * * + * * + * Description * + * =========== * + * * + * The file lib_crc.h contains public definitions and proto- * + * types for the CRC functions present in lib_crc.c. * + * * + * * + * Dependencies * + * ============ * + * * + * none * + * * + * * + ********************************************************************/ +#ifndef _LIBCRC_H_ +#define _LIBCRC_H_ + +void *crc_table; + +void init_crc8_normal_tab(uint8_t polynom); +void init_crc8_reflected_tab(uint8_t polynom); + +void init_crc16_normal_tab(uint16_t polynom); +void init_crc16_reflected_tab(uint16_t polynom); +void init_crc32_normal_tab(uint32_t polynom); +void init_crc32_reflected_tab(uint32_t polynom); + +uint8_t update_crc8(uint8_t crc, uint8_t c); + +uint16_t update_crc16_normal(uint16_t crc, char c ); +uint16_t update_crc16_reflected(uint16_t crc, char c ); +uint32_t update_crc32_normal(uint32_t crc, char c ); +uint32_t update_crc32_reflected(uint32_t crc, char c ); + +#endif /* _LIBCRC_H_ */ diff --git a/tools/hex2bin-2.0/src/mot2bin.c b/tools/hex2bin-2.0/src/mot2bin.c new file mode 100644 index 0000000..9e0e23c --- /dev/null +++ b/tools/hex2bin-2.0/src/mot2bin.c @@ -0,0 +1,518 @@ +/* +mot2bin converts a Motorola hex file to binary. + +Copyright (C) 2015, Jacques Pelletier +checksum extensions Copyright (C) 2004 Rockwell Automation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +20040617 Alf Lacis: Added pad byte (may not always want FF). + Added initialisation to Checksum to remove GNU + compiler warning about possible uninitialised usage + Added 2x'break;' to remove GNU compiler warning about label at + end of compound statement + Added PROGRAM & VERSION strings. + +20071005 PG: Improvements on options parsing +20091212 JP: Corrected crash on 0 byte length data records +20100402 JP: ADDRESS_MASK is now calculated from MEMORY_SIZE + +20120125 Danny Schneider: + Added code for filling a binary file to a given Max_Length relative to + Starting Address if Max-Address is larger than Highest-Address +20120509 Yoshimasa Nakane: + modified error checking (also for output file, JP) +20141005 JP: added support for byte swapped hex files + corrected bug caused by extra LF at end or within file +20141121 Slucx: added line for removing extra CR when entering file name at run time. +20150116 Richard Genoud (Paratronic): correct buffer overflows/wrong results with the -l flag +20150122 JP: added support for different check methods +20150221 JP: rewrite of the checksum write/force value +*/ + +#define PROGRAM "mot2bin" +#define VERSION "2.0" + +#include "common.h" + +const char *Pgm_Name = PROGRAM; + +int main (int argc, char *argv[]) +{ + /* line inputted from file */ + char Line[MAX_LINE_SIZE]; + + /* flag that a file was read */ + bool Fileread; + + /* cmd-line parameter # */ + char *p; + + int Param, result; + + /* Application specific */ + + unsigned int Nb_Bytes; + unsigned int First_Word, Address; + + unsigned int Phys_Addr, Type; + unsigned int Exec_Address; + unsigned int temp; + unsigned int Record_Count, Record_Checksum; + unsigned int Records_Start; // Lowest address of the records + + unsigned int temp2; + + byte Data_Str[MAX_LINE_SIZE]; + + fprintf (stdout,PROGRAM" v"VERSION", Copyright (C) 2015 Jacques Pelletier & contributors\n\n"); + + if (argc == 1) + usage(); + + strcpy(Extension, "bin"); /* default is for binary file extension */ + + /* read file */ + Starting_Address = 0; + + /* + use p for parsing arguments + use i for number of parameters to skip + use c for the current option + */ + for (Param = 1; Param < argc; Param++) + { + int i = 0; + char c; + + p = argv[Param]; + c = *(p+1); /* Get option character */ + + if ( _IS_OPTION_(*p) ) + { + // test for no space between option and parameter + if (strlen(p) != 2) usage(); + + switch(c) + { + /* file extension */ + case 'c': + Enable_Checksum_Error = true; + i = 0; + break; + case 'd': + DisplayCheckMethods(); + case 'e': + GetExtension(argv[Param + 1],Extension); + i = 1; /* add 1 to Param */ + break; + case 'f': + Cks_Addr = GetHex(argv[Param + 1]); + Cks_Addr_set = true; + i = 1; /* add 1 to Param */ + break; + case 'F': + Cks_Addr = GetHex(argv[Param + 1]); + Cks_Value = GetHex(argv[Param + 2]); + Force_Value = true; + i = 2; /* add 2 to Param */ + break; + case 'k': + Cks_Type = GetHex(argv[Param + 1]); + { + if (Cks_Type > LAST_CHECK_METHOD) usage(); + } + i = 1; /* add 1 to Param */ + break; + case 'l': + Max_Length = GetHex(argv[Param + 1]); + Max_Length_Setted = true; + i = 1; /* add 1 to Param */ + break; + case 'm': + Minimum_Block_Size = GetHex(argv[Param + 1]); + Minimum_Block_Size_Setted = true; + i = 1; /* add 1 to Param */ + break; + case 'p': + Pad_Byte = GetHex(argv[Param + 1]); + i = 1; /* add 1 to Param */ + break; + case 'r': + Cks_Start = GetHex(argv[Param + 1]); + Cks_End = GetHex(argv[Param + 2]); + Cks_range_set = true; + i = 2; /* add 2 to Param */ + break; + case 's': + Starting_Address = GetHex(argv[Param + 1]); + Starting_Address_Setted = true; + i = 1; /* add 1 to Param */ + break; + case 'w': + Swap_Wordwise = true; + i = 0; + break; + case 'C': + Crc_Poly = GetHex(argv[Param + 1]); + Crc_Init = GetHex(argv[Param + 2]); + Crc_RefIn = GetBoolean(argv[Param + 3]); + Crc_RefOut = GetBoolean(argv[Param + 4]); + Crc_XorOut = GetHex(argv[Param + 5]); + CrcParamsCheck(); + i = 5; /* add 5 to Param */ + break; + + case '?': + case 'h': + default: + usage(); + } /* switch */ + + /* Last parameter is not a filename */ + if (Param == argc-1) usage(); + + // fprintf(stderr,"Param: %d, option: %c\n",Param,c); + + /* if (Param + i) < (argc -1) */ + if (Param < argc -1 -i) Param += i; + else usage(); + + } + else + break; + /* if option */ + } /* for Param */ + + /* when user enters input file name */ + + /* Assume last parameter is filename */ + strcpy(Filename,argv[argc -1]); + + /* Just a normal file name */ + NoFailOpenInputFile (Filename); + PutExtension(Filename, Extension); + NoFailOpenOutputFile(Filename); + Fileread = true; + + /* To begin, assume the lowest address is at the end of the memory. + While reading each records, subsequent addresses will lower this number. + At the end of the input file, this value will be the lowest address. + + A similar assumption is made for highest address. It starts at the + beginning of memory. While reading each records, subsequent addresses will raise this number. + At the end of the input file, this value will be the highest address. */ + Lowest_Address = (unsigned int)-1; + Highest_Address = 0; + Records_Start = 0; + Record_Nb = 0; + + /* get highest and lowest addresses so that we can allocate the right size */ + do + { + unsigned int i; + + /* Read a line from input file. */ + GetLine(Line,Filin); + Record_Nb++; + + /* Remove carriage return/line feed at the end of line. */ + i = strlen(Line); + + if (--i != 0) + { + if (Line[i] == '\n') Line[i] = '\0'; + + p = (char *) Data_Str; + + switch(Line[1]) + { + case '0': + break; + + /* 16 bits address */ + case '1': + result = sscanf (Line,"S%1x%2x%4x",&Type,&Nb_Bytes,&First_Word); + if (result != 3) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = Nb_Bytes - 3; + break; + + /* 24 bits address */ + case '2': + result = sscanf (Line,"S%1x%2x%6x",&Type,&Nb_Bytes,&First_Word); + if (result != 3) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = Nb_Bytes - 4; + break; + + /* 32 bits address */ + case '3': + result = sscanf (Line,"S%1x%2x%8x",&Type,&Nb_Bytes,&First_Word); + if (result != 3) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = Nb_Bytes - 5; + break; + } + + Phys_Addr = First_Word; + + /* Set the lowest address as base pointer. */ + if (Phys_Addr < Lowest_Address) + Lowest_Address = Phys_Addr; + + /* Same for the top address. */ + temp = Phys_Addr + Nb_Bytes -1; + + if (temp > Highest_Address) + Highest_Address = temp; + } + } + while (!feof (Filin)); + + if (Starting_Address_Setted == true) + { + Records_Start = Lowest_Address; + Lowest_Address = Starting_Address; + } + else + { + Records_Start = Lowest_Address; + Starting_Address = Lowest_Address; + } + + if (Max_Length_Setted == false) + Max_Length = Highest_Address - Lowest_Address + 1; + else + Highest_Address = Lowest_Address + Max_Length - 1; + + /* Now, that we know the buffer size, we can allocate it. */ + /* allocate a buffer */ + Memory_Block = (byte *) NoFailMalloc(Max_Length); + + /* For EPROM or FLASH memory types, fill unused bytes with FF or the value specified by the p option */ + memset (Memory_Block,Pad_Byte,Max_Length); + + rewind(Filin); + Record_Nb = 0; + + /* Read the file & process the lines. */ + do /* repeat until EOF(Filin) */ + { + int i; + + Checksum = 0; + + /* Read a line from input file. */ + GetLine(Line,Filin); + Record_Nb++; + + /* Remove carriage return/line feed at the end of line. */ + i = strlen(Line); + + if (--i != 0) + { + if (Line[i] == '\n') Line[i] = '\0'; + + /* Scan starting address and nb of bytes. */ + /* Look at the record type after the 'S' */ + Type = 0; + + switch(Line[1]) + { + case '0': + result = sscanf (Line,"S0%2x0000484452%2x",&Nb_Bytes,&Record_Checksum); + if (result != 2) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + 0x48 + 0x44 + 0x52; + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = 0; + break; + + /* 16 bits address */ + case '1': + result = sscanf (Line,"S%1x%2x%4x%s",&Type,&Nb_Bytes,&Address,Data_Str); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Address >> 8) + (Address & 0xFF); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = Nb_Bytes - 3; + break; + + /* 24 bits address */ + case '2': + result = sscanf (Line,"S%1x%2x%6x%s",&Type,&Nb_Bytes,&Address,Data_Str); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Address >> 16) + (Address >> 8) + (Address & 0xFF); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = Nb_Bytes - 4; + break; + + /* 32 bits address */ + case '3': + result = sscanf (Line,"S%1x%2x%8x%s",&Type,&Nb_Bytes,&Address,Data_Str); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Address >> 24) + (Address >> 16) + (Address >> 8) + (Address & 0xFF); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = Nb_Bytes - 5; + break; + + case '5': + result = sscanf (Line,"S%1x%2x%4x%2x",&Type,&Nb_Bytes,&Record_Count,&Record_Checksum); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Record_Count >> 8) + (Record_Count & 0xFF); + + /* Adjust Nb_Bytes for the number of data bytes */ + Nb_Bytes = 0; + break; + + case '7': + result = sscanf (Line,"S%1x%2x%8x%2x",&Type,&Nb_Bytes,&Exec_Address,&Record_Checksum); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Exec_Address >> 24) + (Exec_Address >> 16) + (Exec_Address >> 8) + (Exec_Address & 0xFF); + Nb_Bytes = 0; + break; + + case '8': + result = sscanf (Line,"S%1x%2x%6x%2x",&Type,&Nb_Bytes,&Exec_Address,&Record_Checksum); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Exec_Address >> 16) + (Exec_Address >> 8) + (Exec_Address & 0xFF); + Nb_Bytes = 0; + break; + case '9': + result = sscanf (Line,"S%1x%2x%4x%2x",&Type,&Nb_Bytes,&Exec_Address,&Record_Checksum); + if (result != 4) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + Checksum = Nb_Bytes + (Exec_Address >> 8) + (Exec_Address & 0xFF); + Nb_Bytes = 0; + break; + } + + p = (char *) Data_Str; + + /* If we're reading the last record, ignore it. */ + switch (Type) + { + /* Data record */ + case 1: + case 2: + case 3: + if (Nb_Bytes == 0) + { + fprintf(stderr,"0 byte length Data record ignored\n"); + break; + } + + Phys_Addr = Address; + + /* Read the Data bytes. */ + i = Nb_Bytes; + + do + { + result = sscanf (p, "%2x",&temp2); + if (result != 1) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + p += 2; + + /* Overlapping record will erase the pad bytes */ + if (Swap_Wordwise) + { + if (Memory_Block[Phys_Addr ^ 1] != Pad_Byte) fprintf(stderr,"Overlapped record detected\n"); + Memory_Block[Phys_Addr++ ^ 1] = temp2; + } + else + { + if (Memory_Block[Phys_Addr] != Pad_Byte) fprintf(stderr,"Overlapped record detected\n"); + Memory_Block[Phys_Addr++] = temp2; + } + + Checksum = (Checksum + temp2) & 0xFF; + } + while (--i != 0); + + /* Read the Checksum value. */ + result = sscanf (p, "%2x",&Record_Checksum); + if (result != 1) fprintf(stderr,"Error in line %d of hex file\n", Record_Nb); + break; + + case 5: + fprintf(stderr,"Record total: %d\n",Record_Count); + break; + + case 7: + fprintf(stderr,"Execution Address (unused): %08X\n",Exec_Address); + break; + + case 8: + fprintf(stderr,"Execution Address (unused): %06X\n",Exec_Address); + break; + + case 9: + fprintf(stderr,"Execution Address (unused): %04X\n",Exec_Address); + break; + + /* Ignore all other records */ + default:; + } + + Record_Checksum &= 0xFF; + + /* Verify Checksum value. */ + if (((Record_Checksum + Checksum) != 0xFF) && Enable_Checksum_Error) + { + fprintf(stderr,"Checksum error in record %d: should be %02X\n",Record_Nb, 255-Checksum); + Status_Checksum_Error = true; + } + } + } + while (!feof (Filin)); + /*-----------------------------------------------------------------------------*/ + + fprintf(stdout,"Binary file start = %08X\n",Lowest_Address); + fprintf(stdout,"Records start = %08X\n",Records_Start); + fprintf(stdout,"Highest address = %08X\n",Highest_Address); + fprintf(stdout,"Pad Byte = %X\n", Pad_Byte); + + WriteMemory(); + +#ifdef USE_FILE_BUFFERS + free (FilinBuf); + free (FiloutBuf); +#endif + + fclose (Filin); + fclose (Filout); + + if (Status_Checksum_Error && Enable_Checksum_Error) + { + fprintf(stderr,"Checksum error detected.\n"); + return 1; + } + + if (!Fileread) + usage(); + return 0; +} diff --git a/tools/iDSK/.gitignore b/tools/iDSK/.gitignore new file mode 100644 index 0000000..4d731b8 --- /dev/null +++ b/tools/iDSK/.gitignore @@ -0,0 +1,7 @@ +CMakeFiles +CMakeCache.txt +*.cmake +iDSK.* +Makefile +*.swp +*.dsk diff --git a/tools/iDSK/AUTHORS b/tools/iDSK/AUTHORS new file mode 100644 index 0000000..0c18ff6 --- /dev/null +++ b/tools/iDSK/AUTHORS @@ -0,0 +1,3 @@ +cpcemu - Marco Vieth +manageDSK - Ludovic Deplanque +iDSK - Sid from IMPACT / PulkoMandy from the Shinra Team diff --git a/tools/iDSK/CMakeLists.txt b/tools/iDSK/CMakeLists.txt new file mode 100644 index 0000000..b15c716 --- /dev/null +++ b/tools/iDSK/CMakeLists.txt @@ -0,0 +1,14 @@ +PROJECT(iDSK) + +add_executable(iDSK + src/Basic.cpp + src/BitmapCPC.cpp + src/Dams.cpp + src/Desass.cpp + src/endianPPC.cpp + src/GestDsk.cpp + src/getopt_pp.cpp + src/Main.cpp + src/Outils.cpp + src/ViewFile.cpp +) diff --git a/tools/iDSK/COPYING b/tools/iDSK/COPYING new file mode 100644 index 0000000..b515066 --- /dev/null +++ b/tools/iDSK/COPYING @@ -0,0 +1 @@ +Well, ask Sid before doing anything... diff --git a/tools/iDSK/src/Basic.cpp b/tools/iDSK/src/Basic.cpp new file mode 100644 index 0000000..4aeb314 --- /dev/null +++ b/tools/iDSK/src/Basic.cpp @@ -0,0 +1,350 @@ +#include <iostream> +using namespace std; +#include <cmath> +#include <cstring> +#include <cstdio> +#include <ctype.h> + +#include "MyType.h" +#include "Basic.h" + + +//static char ConvCpcFr[ 128 ] = " !\"#$%&'()*+,-./0123456789:;<=>?à ABCDEFGHIJKLMNOPQRSTUVWXYZ[ç]^_`abcdefghijklmnopqrstuvwxyzéùè~"; + + +// +// Tableau de décryptage d'un programme en basic protégé +// +static BYTE DproBasic[ 128 ] = + { + 0xAB, 0x2C, 0xED, 0xEA, 0x6C, 0x37, 0x3F, 0xEC, + 0x9B, 0xDF, 0x7A, 0x0C, 0x3B, 0xD4, 0x6D, 0xF5, + 0x04, 0x44, 0x03, 0x11, 0xDF, 0x59, 0x8F, 0x21, + 0x73, 0x7A, 0xCC, 0x83, 0xDD, 0x30, 0x6A, 0x30, + 0xD3, 0x8F, 0x02, 0xF0, 0x60, 0x6B, 0x94, 0xE4, + 0xB7, 0xF3, 0x03, 0xA8, 0x60, 0x88, 0xF0, 0x43, + 0xE8, 0x8E, 0x43, 0xA0, 0xCA, 0x84, 0x31, 0x53, + 0xF3, 0x1F, 0xC9, 0xE8, 0xAD, 0xC0, 0xBA, 0x6D, + 0x93, 0x08, 0xD4, 0x6A, 0x2C, 0xB2, 0x07, 0x27, + 0xC0, 0x99, 0xEE, 0x89, 0xAF, 0xC3, 0x53, 0xAB, + 0x2B, 0x34, 0x5C, 0x2F, 0x13, 0xEE, 0xAA, 0x2C, + 0xD9, 0xF4, 0xBC, 0x12, 0xB3, 0xC5, 0x1C, 0x68, + 0x01, 0x20, 0x2C, 0xFA, 0x77, 0xA6, 0xB5, 0xA4, + 0xFC, 0x9B, 0xF1, 0x32, 0x5B, 0xC3, 0x70, 0x77, + 0x85, 0x36, 0xBE, 0x5B, 0x8C, 0xC8, 0xB5, 0xC2, + 0xF0, 0x0B, 0x98, 0x0F, 0x36, 0x9D, 0xD8, 0x96 + }; + + +BYTE GetByte( BYTE * BufFile, int Pos, int Deprotect ) +{ + //BYTE b = ( BYTE )( BufFile[ Pos ] ^ ( DproBasic[ Pos & 0x7F ] * Deprotect ) ); + //cout << "GetByte:"<<hex<<b<<endl; + return( BYTE )( BufFile[ Pos ] ^ ( DproBasic[ Pos & 0x7F ] * Deprotect ) ); +} + + +int GetWord( BYTE * BufFile, int Pos, int Deprotect ) +{ + int Ret = BufFile[ Pos ] ^ ( DproBasic[ Pos & 0x7F ] * Deprotect ); + Pos++; + Ret += ( ( BufFile[ Pos ] ^ ( DproBasic[ Pos & 0x7F ] * Deprotect ) ) << 8 ); + return( Ret ); +} + + +// +// Ajoute un "mot" (nom d'une variable, RSX...) dans la chaine "Listing" +// +int AddWord( BYTE * BufFile, int Pos, char * Listing, int Deprotect ) +{ + int LenVar = 0, l = strlen( Listing ); + BYTE b; + + do + { + b = GetByte( BufFile, Pos++, Deprotect ); + Listing[ l++ ] = ( char )( b & 0x7F ); + } + while( ! ( b & 0x80 ) && LenVar++ < 0xFF ); + Listing[ l ] = 0; + return( Pos ); +} + + +// +// Convertir le buffer en listing basic +// +void Basic( BYTE * BufFile, char * Listing, bool IsBasic, bool CrLf ) +{ + static char Tmp[ 32 ]; + int Pos = 0, Token = 0; + int StartLigne = 0, EndLigne; + char * p; + double f; + int exp; + int Deprotect=0; + //cout << BufFile <<endl; + static const char * Nbre[ 11 ] = + { + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" + }; + static const char * MotsClefs[ 0x80 ] = + { + "AFTER", "AUTO", "BORDER", "CALL", "CAT", "CHAIN", "CLEAR", "CLG", + "CLOSEIN", "CLOSEOUT", "CLS", "CONT", "DATA", "DEF", "DEFINT", + "DEFREAL", "DEFSTR", "DEG", "DELETE", "DIM", "DRAW", "DRAWR", "EDIT", + "ELSE", "END", "ENT", "ENV", "ERASE", "ERROR", "EVERY", "FOR", + "GOSUB", "GOTO", "IF", "INK", "INPUT", "KEY", "LET", "LINE", "LIST", + "LOAD", "LOCATE", "MEMORY", "MERGE", "MID$", "MODE", "MOVE", "MOVER", + "NEXT", "NEW", "ON", "ON BREAK", "ON ERROR GOTO", "SQ", "OPENIN", + "OPENOUT", "ORIGIN", "OUT", "PAPER", "PEN", "PLOT", "PLOTR", "POKE", + "PRINT", "'", "RAD", "RANDOMIZE", "READ", "RELEASE", "REM", "RENUM", + "RESTORE", "RESUME", "RETURN", "RUN", "SAVE", "SOUND", "SPEED", "STOP", + "SYMBOL", "TAG", "TAGOFF", "TROFF", "TRON", "WAIT", "WEND", "WHILE", + "WIDTH", "WINDOW", "WRITE", "ZONE", "DI", "EI", "FILL", "GRAPHICS", + "MASK", "FRAME", "CURSOR", "#E2", "ERL", "FN", "SPC", "STEP", "SWAP", + "#E8", "#E9", "TAB", "THEN", "TO", "USING", ">", "=", ">=", "<", "<>", + "<=", "+", "-", "*", "/", "^", "\\ ", "AND", "MOD", "OR", "XOR", "NOT", + "#FF" + }; + + static const char * Fcts[ 0x80 ] = + { + "ABS", "ASC", "ATN", "CHR$", "CINT", "COS", "CREAL", "EXP", "FIX", + "FRE", "INKEY", "INP", "INT", "JOY", "LEN", "LOG", "LOG10", "LOWER$", + "PEEK", "REMAIN", "SGN", "SIN", "SPACE$", "SQ", "SQR", "STR$", "TAN", + "UNT", "UPPER$", "VAL", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "EOF", "ERR", "HIMEM", "INKEY$", "PI", "RND", + "TIME", "XPOS", "YPOS", "DERR", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "BIN$", "DEC$", "HEX$", + "INSTR", "LEFT$", "MAX", "MIN", "POS", "RIGHT$", "ROUND", "STRING$", + "TEST", "TESTR", "COPYCHR$", "VPOS" + }; + + + * Listing = 0; + Token = GetByte( BufFile, 0, Deprotect ); + for ( ;; ) + { + //cout << "Listing : " <<Listing << endl; + if ( IsBasic ) + { + int lg = GetWord( BufFile, Pos, Deprotect ); + Pos += 2; + if ( ! lg ) + break; + + int NumLigne = GetWord( BufFile, Pos, Deprotect ); + Pos += 2; + sprintf( Tmp, "%d ", NumLigne ); + strcat( Listing, Tmp ); + } + else + if ( ! Token || Token == 0x1A ) + break; + + int DansChaine = 0; // #### Hum, plus compliqué que ça je pense... + do + { + //cout << "Tmp:"<<Tmp<<endl; + Token = GetByte( BufFile, Pos++, Deprotect ); + if ( ! IsBasic && Token == 0x1A ) + break; + + if ( DansChaine || ! IsBasic ) + { + Tmp[ 0 ] = ( char )Token; + Tmp[ 1 ] = 0; + strcat( Listing, Tmp ); + if ( Token == '"' ) + DansChaine ^= 1; + // cout << " DansChaine Tmp:"<<Tmp<<endl; + } + else + if ( Token > 0x7F && Token < 0xFF ) + { + // #### Traitement particulier du ':' avant le ELSE + if ( Listing[ strlen( Listing ) - 1 ] == ':' + && Token == 0x97 + ) + Listing[ strlen( Listing ) - 1 ] = 0; + + strcat( Listing + , MotsClefs[ Token & 0x7F ] + ); + } + else + if ( Token >= 0x0E && Token <= 0x18 ) + strcat( Listing + , Nbre[ Token - 0x0E ] + ); + else + if ( Token >= 0x20 && Token < 0x7C ) + { + Tmp[ 0 ] = ( char )Token; + Tmp[ 1 ] = 0; + strcat( Listing, Tmp ); + if ( Token == '"' ) + DansChaine ^= 1; + } + else + { + //cout << "Token:" << Token <<endl; + switch( Token ) + { + case 0x01 : + Tmp[ 0 ] = ':'; + Tmp[ 1 ] = 0; + strcat( Listing, Tmp ); + break; + + case 0x02 : // Variable entière (type %) + Pos = AddWord( BufFile + , 2 + Pos + , Listing + , Deprotect + ); + strcat( Listing, "%" ); + break; + + + case 0x03 : // Variable chaine (type $) + Pos = AddWord( BufFile + , 2 + Pos + , Listing + , Deprotect + ); + strcat( Listing, "$" ); + break; + + case 0x0B : + case 0x0C : + case 0x0D : // Variable "standard" + Pos = AddWord( BufFile + , 2 + Pos + , Listing + , Deprotect + ); + break; + + case 0x19 : // Constante entière 8 bits + sprintf(Listing+strlen(Listing),"%d",(BYTE)GetByte( BufFile, Pos, Deprotect)); + Pos++; + break; + + case 0x1A : + case 0x1E : // Constante entière 16 bits + sprintf(Listing+strlen(Listing),"%d",GetWord( BufFile, Pos, Deprotect)); + Pos += 2; + break; + + case 0x1B : + sprintf( Tmp + , "&X%X" + , GetWord( BufFile, Pos, Deprotect ) + ); + strcat( Listing, Tmp ); + Pos += 2; + break; + + case 0x1C : + sprintf( Tmp + , "&%X" + , GetWord( BufFile, Pos, Deprotect ) + ); + strcat( Listing, Tmp ); + Pos += 2; + break; + + case 0x1F : // Constante flottante + f = ( GetByte( BufFile, Pos + 2, Deprotect ) << 16 ) + + ( GetByte( BufFile, Pos + 1, Deprotect ) << 8 ) + + GetByte( BufFile, Pos, Deprotect ) + + ( ( GetByte( BufFile, Pos + 3, Deprotect ) & 0x7F ) << 24 ); + f = 1 + ( f / 0x80000000 ); + + if ( GetByte( BufFile, Pos + 3, Deprotect ) & 0x80 ) + f = -f; + + exp = GetByte( BufFile, Pos + 4, Deprotect ) - 129; + Pos += 5; + sprintf( Tmp, "%f", f * pow( (double) 2, exp ) ); + // Suppression des '0' inutiles + p = &Tmp[ strlen( Tmp ) - 1 ]; + while( * p == '0' ) + * p-- = 0; + + if ( * p == '.' ) + * p = 0; + + strcat( Listing, Tmp ); + break; + + case 0x7C : + strcat( Listing, "|" ); + Pos = AddWord( BufFile + , 1 + Pos + , Listing + , Deprotect + ); + break; + + case 0xFF : + if ( GetByte( BufFile, Pos, Deprotect ) < 0x80 ) + strcat( Listing + , Fcts[ GetByte( BufFile + , Pos++ + , Deprotect + ) + ] + ); + else + { + Tmp[ 1 ] = 0; + Tmp[ 0 ] = ( char )( GetByte( BufFile + , Pos++ + , Deprotect + ) & 0x7F + ); + strcat( Listing, Tmp ); + } + break; + + default : + Token = Token; + } + } + } + while( Token ); + if ( CrLf ) + { + // + // Retour à la ligne si > 80 caractères + // + EndLigne = strlen( &Listing[ StartLigne ] ); + while( EndLigne > 80 ) + { + memmove( &Listing[ StartLigne + 82 ] + , &Listing[ StartLigne + 80 ] + , EndLigne + ); + memcpy( &Listing[ StartLigne + 80 ], "\r\n", 2 ); + StartLigne += 82; + EndLigne -= 80; + } + } + strcat( Listing, "\r\n" ); + StartLigne = strlen( Listing ); + } + // Conversion des caractères accentués si nécessaire + + for ( int i = strlen( Listing); i--; ) + { + //cout << i << " "; + + if ( ! isprint(Listing[ i ]) && Listing[ i ] != '\n' && Listing[ i ] != '\r' ) Listing[ i ] = '?'; + } +} diff --git a/tools/iDSK/src/Basic.h b/tools/iDSK/src/Basic.h new file mode 100644 index 0000000..bb99181 --- /dev/null +++ b/tools/iDSK/src/Basic.h @@ -0,0 +1,8 @@ +#ifndef BASIC_H
+#define BASIC_H
+
+
+void Basic( unsigned char * BufFile, char * Listing, bool IsBasic, bool CrLf );
+
+
+#endif
diff --git a/tools/iDSK/src/BitmapCPC.cpp b/tools/iDSK/src/BitmapCPC.cpp new file mode 100644 index 0000000..19b39a6 --- /dev/null +++ b/tools/iDSK/src/BitmapCPC.cpp @@ -0,0 +1,264 @@ +#include <iostream>
+#include <cstdio>
+#include "MyType.h"
+#include "BitmapCPC.h"
+#include "GestDsk.h"
+#include <string>
+#include <cstring>
+using namespace std;
+
+
+//
+// Couleurs du CPC converties en composantes r, v, b
+//
+static StRVB RgbCPC[ 27 ] =
+ {
+ { 0x00, 0x00, 0x00, 0x00 },
+ { 0x7F, 0x00, 0x00, 0x00 },
+ { 0xFF, 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x7F, 0x00 },
+ { 0x7F, 0x00, 0x7F, 0x00 },
+ { 0xFF, 0x00, 0x7F, 0x00 },
+ { 0x00, 0x00, 0xFF, 0x00 },
+ { 0x7F, 0x00, 0xFF, 0x00 },
+ { 0xFF, 0x00, 0xFF, 0x00 },
+ { 0x00, 0x7F, 0x00, 0x00 },
+ { 0x7F, 0x7F, 0x00, 0x00 },
+ { 0xFF, 0x7F, 0x00, 0x00 },
+ { 0x00, 0x7F, 0x7F, 0x00 },
+ { 0x7F, 0x7F, 0x7F, 0x00 },
+ { 0xFF, 0x7F, 0x7F, 0x00 },
+ { 0x00, 0x7F, 0xFF, 0x00 },
+ { 0x7F, 0x7F, 0xFF, 0x00 },
+ { 0xFF, 0x7F, 0xFF, 0x00 },
+ { 0x00, 0xFF, 0x00, 0x00 },
+ { 0x7F, 0xFF, 0x00, 0x00 },
+ { 0xFF, 0xFF, 0x00, 0x00 },
+ { 0x00, 0xFF, 0x7F, 0x00 },
+ { 0x7F, 0xFF, 0x7F, 0x00 },
+ { 0xFF, 0xFF, 0x7F, 0x00 },
+ { 0x00, 0xFF, 0xFF, 0x00 },
+ { 0x7F, 0xFF, 0xFF, 0x00 },
+ { 0xFF, 0xFF, 0xFF, 0x00 }
+ };
+
+
+int GetRgbCPC( int Coul )
+{
+ if ( Coul >= 0 && Coul < 27 )
+ {
+ StRVB i = RgbCPC[ Coul ];
+ return( ( i.b << 16 ) + ( i.v << 8 ) + i.r );
+ }
+ return( -1 );
+}
+
+
+StRVB GetPalCPC( int Coul )
+{
+ if ( Coul >= 0 && Coul < 27 )
+ return( RgbCPC[ Coul ] );
+
+ return( RgbCPC[ 0 ] );
+}
+
+
+void InitPalette( unsigned char NewPal[ 16 ], bool SetNewPal )
+{
+ /*
+ Si sauvegard� avec ConvImgCpc, alors la palette se trouve
+ dans l'image...
+ */
+ int i;
+ if ( BitmapCPC[ 0x7D0 ] == 0x3A
+ && BitmapCPC[ 0x7D1 ] == 0xD0
+ && BitmapCPC[ 0x7D2 ] == 0xD7
+ && BitmapCPC[ 0x7D3 ] == 0xCD
+ )
+ {
+ Mode = BitmapCPC[ 0x17D0 ];
+ for ( i = 0; i < 16; i++ )
+ Palette[ i ] = BitmapCPC[ 0x17D1 + i ];
+ }
+ if ( SetNewPal )
+ for ( i = 0; i < 16; i++ )
+ Palette[ i ] = NewPal[ i ];
+}
+
+
+//
+// D�compacter une image au format OCP
+//
+void DepactOCP( void )
+{
+ static unsigned char BufTmp[ 0x4000 ];
+ int PosIn = 0, PosOut = 0;
+ int LgOut, CntBlock = 0;
+ int c,i;
+ unsigned char a;
+ memcpy( BufTmp, BitmapCPC, sizeof( BufTmp ) );
+ memset( BitmapCPC, 0, 0x4000 );
+ while( PosOut < 0x4000 )
+ {
+ if ( ! strncmp( ( char * )&BufTmp[ PosIn ], "MJH", 3 ) )
+ {
+ PosIn += 3;
+ LgOut = BufTmp[ PosIn++ ];
+ LgOut += ( BufTmp[ PosIn++ ] << 8 );
+ CntBlock = 0;
+ while( CntBlock < LgOut )
+ {
+ if ( ! strncmp( ( char * )&BufTmp[ PosIn ], "MJH", 3 ) )
+ break;
+
+ a = BufTmp[ PosIn++ ];
+ if ( a == MARKER_OCP )
+ {
+ c = BufTmp[ PosIn++ ];
+ a = BufTmp[ PosIn++ ];
+ if ( ! c )
+ c = 0x100;
+
+ for ( i = 0; i < c && CntBlock < LgOut; i++ )
+ {
+ BitmapCPC[ PosOut++ ] = a;
+ CntBlock++;
+ }
+ }
+ else
+ {
+ BitmapCPC[ PosOut++ ] = a;
+ CntBlock++;
+ }
+ }
+ }
+ else
+ PosOut = 0x4000;
+ }
+}
+
+
+bool LireImage( char * Nom, StRVB * Bitmap )
+{
+ static unsigned char Entete[ 0x80 ];
+ bool Ret = FALSE;
+ //DWORD Nb;
+ FILE* hFile;
+
+
+ if ( (hFile=fopen(Nom,"rb"))!=NULL )
+ {
+ fread(Entete,sizeof(Entete),1,hFile);
+ // ReadFile( hFile, Entete, sizeof( Entete ), &Nb, NULL );
+ if ( CheckAmsdos( Entete ) )
+ {
+ fread(BitmapCPC,sizeof( BitmapCPC ),1,hFile);
+ // ReadFile( hFile, BitmapCPC, sizeof( BitmapCPC ), &Nb, NULL );
+ if ( ! strncmp( ( char * )BitmapCPC, "MJH", 3 ) )
+ DepactOCP();
+
+ InitPalette( NULL, FALSE );
+ Ret = TRUE;
+ }
+ // CloseHandle( hFile );
+ fclose(hFile);
+ if ( Ret )
+ Render( Bitmap, 1 );
+ }
+ return( Ret );
+
+}
+
+
+//
+// Affiche l'image � l'�cran
+//
+void Render( StRVB * Bitmap, bool Flat )
+{
+ int AdrCPC = 0, i, p0, p1, p2, p3;
+ int y,x,AdrBitmap;
+ unsigned char Octet;
+ for ( y = 0; y < NbLignes; y++ )
+ {
+ AdrBitmap = TAILLE_CPC_X * ( y + ( ( 200 - NbLignes ) >> 1 ) )
+ + ( ( ( 80 - NbCol ) >> 1 ) << 3 );
+ for ( x = 0; x < NbCol; x++ )
+ {
+ Octet = BitmapCPC[ AdrCPC + x ];
+ switch( Mode )
+ {
+ case 0 :
+ case 3 : // Mode 3 = Mode 0
+ p0 = ( Octet >> 7 )
+ + ( ( Octet & 0x20 ) >> 3 )
+ + ( ( Octet & 0x08 ) >> 2 )
+ + ( ( Octet & 0x02 ) << 2 );
+ p1 = ( ( Octet & 0x40 ) >> 6 )
+ + ( ( Octet & 0x10 ) >> 2 )
+ + ( ( Octet & 0x04 ) >> 1 )
+ + ( ( Octet & 0x01 ) << 3 );
+ Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p0 ] );
+ Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p0 ] );
+ Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p0 ] );
+ Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p0 ] );
+ Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p1 ] );
+ Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p1 ] );
+ Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p1 ] );
+ Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p1 ] );
+ break;
+
+ case 1 :
+ p0 = ( ( Octet >> 7 ) & 1 ) + ( ( Octet >> 2 ) & 2 );
+ p1 = ( ( Octet >> 6 ) & 1 ) + ( ( Octet >> 1 ) & 2 );
+ p2 = ( ( Octet >> 5 ) & 1 ) + ( ( Octet >> 0 ) & 2 );
+ p3 = ( ( Octet >> 4 ) & 1 ) + ( ( Octet << 1 ) & 2 );
+ Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p0 ] );
+ Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p0 ] );
+ Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p1 ] );
+ Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p1 ] );
+ Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p2 ] );
+ Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p2 ] );
+ Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p3 ] );
+ Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ p3 ] );
+ break;
+
+ case 2 :
+ for ( i = 8; i--; )
+ Bitmap[ AdrBitmap++ ] = GetPalCPC( Palette[ ( Octet >> i ) & 1 ] );
+ break;
+ }
+ }
+ if ( Flat )
+ AdrCPC += NbCol;
+ else
+ {
+ AdrCPC += 0x800;
+ if ( AdrCPC > 0x3FFF )
+ AdrCPC -= 0x3FB0;
+ }
+ }
+}
+
+
+void SetBitmapCPC( unsigned char * BitmapSource )
+{
+ memcpy( BitmapCPC, BitmapSource, 0x4000 );
+ if ( ! strncmp( ( char * )BitmapCPC, "MJH", 3 ) )
+ DepactOCP();
+
+ InitPalette( NULL, FALSE );
+}
+
+
+void SetNbCol( int n )
+{
+ if ( n > 0 && n <= 80 )
+ NbCol = n;
+}
+
+
+void SetNbLignes( int n )
+{
+ if ( n > 0 && n <= 200 )
+ NbLignes = n;
+}
diff --git a/tools/iDSK/src/BitmapCPC.h b/tools/iDSK/src/BitmapCPC.h new file mode 100644 index 0000000..2af2bab --- /dev/null +++ b/tools/iDSK/src/BitmapCPC.h @@ -0,0 +1,46 @@ +#ifndef BITMAPCPC_H
+#define BITMAPCPC_H
+
+
+#define TAILLE_CPC_X 640
+
+#define TAILLE_CPC_Y 200
+
+#define MARKER_OCP 1 // Marker pour compression RLE
+int Mode, NbCol, NbLignes;
+unsigned char BitmapCPC[ 0x4000 ];
+unsigned char Palette[ 16 ];
+typedef struct
+ {
+ unsigned char b, v, r, a;
+ } StRVB;
+
+
+
+void CBitmapCPC( void ) { NbCol = 80; NbLignes = 200; }
+bool LireImage( char * Nom, StRVB * Bitmap );
+void Render( StRVB * Bitmap, bool Flat );
+void SetBitmapCPC( unsigned char * BitmapSource );
+unsigned char * GetBitmapCPC( void ) { return( BitmapCPC ); }
+void SetMode( int m ) { Mode = m; }
+void InitPalette( unsigned char Pal[ 16 ], bool SetPal );
+unsigned char * GetPalette( void ) { return( Palette ); }
+int GetMode( void ) { return( Mode ); }
+void SetNbCol( int n );
+void SetNbLignes( int n );
+
+
+void DepactOCP( void );
+void LisseBitmap( StRVB * Bitmap );
+
+
+
+
+
+
+StRVB GetPalCPC( int Coul );
+
+int GetRgbCPC( int Coul );
+
+
+#endif
diff --git a/tools/iDSK/src/Dams.cpp b/tools/iDSK/src/Dams.cpp new file mode 100644 index 0000000..9b24813 --- /dev/null +++ b/tools/iDSK/src/Dams.cpp @@ -0,0 +1,184 @@ +#include <iostream>
+#include <cstdio>
+#include <cstring>
+using namespace std;
+
+
+//
+// Convertir le buffer en listing au format Dams
+// Adaptation des sources de Thierry JOUIN ( Ramlaid )
+//
+void Dams( unsigned char * BufFile, int TailleFic, char * Listing )
+{
+ const char * MotCleDams[ 0x80 ] =
+ {
+ "LD","INC","DEC","ADD","ADC","SUB","SBC","AND","XOR","OR","CP",
+ "PUSH","POP","BIT","RES","SET","RLC","RRC","RL","RR","SLA","SRA",
+ "SRL","IN","OUT","RST","DJNZ","EX","IM","JR","CALL","RET","JP",
+ "NOP","RLCA","RRCA","RLA","RRA","DAA","CPL","SCF","CCF","HALT",
+ "EXX","DI","EI","NEG","RETN","RETI","RRD","RLD","LDI","CPI","INI",
+ "OUTI","LDD","CPD","IND","OUTD","LDIR","CPIR","INIR","OTIR","LDDR",
+ "CPDR","INDR","OTDR","DB","DW","DM","DS","EQU","ORG","ENT",
+ "IF","ELSE","END"
+ };
+ char Tmp[ 32 ];
+ int PosFile = 0;
+ int PosDest = 0;
+ unsigned char c;
+
+ * Listing = 0;
+ c = BufFile[ PosFile++ ];
+ while( c )
+ {
+ if ( c == 0xFF )
+ {
+ // Commentaire ligne
+ Listing[ PosDest++ ] = ';';
+ c = BufFile[ PosFile++ ];
+ while( c != 0x0D && PosFile < TailleFic )
+ {
+ Listing[ PosDest++ ] = c;
+ c = BufFile[ PosFile++ ];
+ }
+ Listing[ PosDest++ ] = '\r';
+ Listing[ PosDest++ ] = '\n';
+ }
+ else
+ {
+ if ( c >= 0x80 && c != 0x0D )
+ {
+ // Mnemonique sans label
+ // ENT
+ if ( c == 0xC9 )
+ Listing[ PosDest++ ] = ';';
+
+ sprintf( Tmp, "\t%s\t", MotCleDams[ c & 0x7F ] );
+ int l = strlen( Tmp );
+ memcpy( &Listing[ PosDest ], Tmp, l );
+ PosDest += l;
+ // DS ?,?
+ if ( c == 0xC6 )
+ {
+ c = BufFile[ PosFile++ ];
+ // Fin de ligne
+ while( c != 0x0D && PosFile < TailleFic )
+ {
+ if ( c == ',' )
+ {
+ while( c != 0x0D && c != 0xFF && PosFile < TailleFic )
+ c = BufFile[ PosFile++ ];
+ }
+ if ( c != 0x0D )
+ {
+ if ( c == 0xFF )
+ Listing[ PosDest++ ] = '\t';
+ else
+ Listing[ PosDest++ ] = c;
+
+ c = BufFile[ PosFile++ ];
+ }
+ }
+ }
+ else
+ {
+ c = BufFile[ PosFile++ ];
+ // Fin de ligne
+ while( c != 0x0D && PosFile < TailleFic )
+ {
+ if ( c == 0xFF )
+ Listing[ PosDest++ ] = '\t';
+ else
+ Listing[ PosDest++ ] = c;
+
+ c = BufFile[ PosFile++ ];
+ }
+ }
+ Listing[ PosDest++ ] = '\r';
+ Listing[ PosDest++ ] = '\n';
+ }
+ else
+ {
+ // Label
+ while( c < 0x80 && c != 0x0D && PosFile < TailleFic )
+ {
+ Listing[ PosDest++ ] = c;
+ c = BufFile[ PosFile++ ];
+ }
+ if ( c != 0x0D )
+ {
+ // Mnemonique apres label
+ // ENT
+ if ( c == 0xC9 )
+ Listing[ PosDest++ ] = ';';
+
+ if ( c != 0xFF )
+ {
+ sprintf( Tmp, "\t%s\t", MotCleDams[ c & 0x7F ] );
+ int l = strlen( Tmp );
+ memcpy( &Listing[ PosDest ], Tmp, l );
+ PosDest += l;
+ }
+ else
+ {
+ Listing[ PosDest++ ] = '\t';
+ Listing[ PosDest++ ] = '\t';
+ Listing[ PosDest++ ] = '\t';
+ }
+ // DS ?,?
+ if ( c == 0xC6 )
+ {
+ c = BufFile[ PosFile++ ];
+ // Fin de ligne
+ while( c != 0x0D && PosFile < TailleFic )
+ {
+ if ( c == ',' )
+ {
+ while( c != 0x0D && c != 0xFF && PosFile < TailleFic )
+ c = BufFile[ PosFile++ ];
+ }
+ if ( c != 0x0D )
+ {
+ if ( c == 0xFF )
+ {
+ Listing[ PosDest++ ] = '\t';
+ Listing[ PosDest++ ] = ';';
+ }
+ else
+ Listing[ PosDest++ ] = c;
+
+ c = BufFile[ PosFile++ ];
+ }
+ }
+ }
+ else
+ {
+ c = BufFile[ PosFile++ ];
+ // Fin de ligne
+ while( c != 0x0D && PosFile < TailleFic )
+ {
+ if ( c == 0xFF )
+ {
+ Listing[ PosDest++ ] = '\t';
+ Listing[ PosDest++ ] = ';';
+ }
+ else
+ Listing[ PosDest++ ] = c;
+
+ c = BufFile[ PosFile++ ];
+ }
+ }
+ Listing[ PosDest++ ] = '\r';
+ Listing[ PosDest++ ] = '\n';
+ }
+ else
+ {
+ Listing[ PosDest++ ] = '\r';
+ Listing[ PosDest++ ] = '\n';
+ }
+ }
+ }
+ c = BufFile[ PosFile++ ];
+ if ( PosFile > TailleFic )
+ break;
+ }
+}
diff --git a/tools/iDSK/src/Dams.h b/tools/iDSK/src/Dams.h new file mode 100644 index 0000000..6610ef7 --- /dev/null +++ b/tools/iDSK/src/Dams.h @@ -0,0 +1,8 @@ +#ifndef DAMS_H
+#define DAMS_H
+
+
+void Dams( unsigned char * BufFile, int TailleFic, char * Listing );
+
+
+#endif
diff --git a/tools/iDSK/src/Desass.cpp b/tools/iDSK/src/Desass.cpp new file mode 100644 index 0000000..a2030a0 --- /dev/null +++ b/tools/iDSK/src/Desass.cpp @@ -0,0 +1,532 @@ +#include <iostream>
+#include <cstdio>
+#include <cstring>
+
+#include "Outils.h"
+using namespace std;
+
+
+//
+// Tableau des OP-Codes Z80...
+//
+const char * TabInstrCB[ 256 ] =
+ {
+ "RLC B","RLC C","RLC D","RLC E",
+ "RLC H","RLC L","RLC (HL)","RLC A",
+ "RRC B","RRC C","RRC D","RRC E",
+ "RRC H","RRC L","RRC (HL)","RRC A",
+ "RL B","RL C","RL D","RL E",
+ "RL H","RL L","RL (HL)","RL A",
+ "RR B","RR C","RR D","RR E",
+ "RR H","RR L","RR (HL)","RR A",
+ "SLA B","SLA C","SLA D","SLA E",
+ "SLA H","SLA L","SLA (HL)","SLA A",
+ "SRA B","SRA C","SRA D","SRA E",
+ "SRA H","SRA L","SRA (HL)","SRA A",
+ "SLL B","SLL C","SLL D","SLL E",
+ "SLL H","SLL L","SLL (HL)","SLL A",
+ "SRL B","SRL C","SRL D","SRL E",
+ "SRL H","SRL L","SRL (HL)","SRL A",
+ "BIT 0,B","BIT 0,C","BIT 0,D","BIT 0,E",
+ "BIT 0,H","BIT 0,L","BIT 0,(HL)","BIT 0,A",
+ "BIT 1,B","BIT 1,C","BIT 1,D","BIT 1,E",
+ "BIT 1,H","BIT 1,L","BIT 1,(HL)","BIT 1,A",
+ "BIT 2,B","BIT 2,C","BIT 2,D","BIT 2,E",
+ "BIT 2,H","BIT 2,L","BIT 2,(HL)","BIT 2,A",
+ "BIT 3,B","BIT 3,C","BIT 3,D","BIT 3,E",
+ "BIT 3,H","BIT 3,L","BIT 3,(HL)","BIT 3,A",
+ "BIT 4,B","BIT 4,C","BIT 4,D","BIT 4,E",
+ "BIT 4,H","BIT 4,L","BIT 4,(HL)","BIT 4,A",
+ "BIT 5,B","BIT 5,C","BIT 5,D","BIT 5,E",
+ "BIT 5,H","BIT 5,L","BIT 5,(HL)","BIT 5,A",
+ "BIT 6,B","BIT 6,C","BIT 6,D","BIT 6,E",
+ "BIT 6,H","BIT 6,L","BIT 6,(HL)","BIT 6,A",
+ "BIT 7,B","BIT 7,C","BIT 7,D","BIT 7,E",
+ "BIT 7,H","BIT 7,L","BIT 7,(HL)","BIT 7,A",
+ "RES 0,B","RES 0,C","RES 0,D","RES 0,E",
+ "RES 0,H","RES 0,L","RES 0,(HL)","RES 0,A",
+ "RES 1,B","RES 1,C","RES 1,D","RES 1,E",
+ "RES 1,H","RES 1,L","RES 1,(HL)","RES 1,A",
+ "RES 2,B","RES 2,C","RES 2,D","RES 2,E",
+ "RES 2,H","RES 2,L","RES 2,(HL)","RES 2,A",
+ "RES 3,B","RES 3,C","RES 3,D","RES 3,E",
+ "RES 3,H","RES 3,L","RES 3,(HL)","RES 3,A",
+ "RES 4,B","RES 4,C","RES 4,D","RES 4,E",
+ "RES 4,H","RES 4,L","RES 4,(HL)","RES 4,A",
+ "RES 5,B","RES 5,C","RES 5,D","RES 5,E",
+ "RES 5,H","RES 5,L","RES 5,(HL)","RES 5,A",
+ "RES 6,B","RES 6,C","RES 6,D","RES 6,E",
+ "RES 6,H","RES 6,L","RES 6,(HL)","RES 6,A",
+ "RES 7,B","RES 7,C","RES 7,D","RES 7,E",
+ "RES 7,H","RES 7,L","RES 7,(HL)","RES 7,A",
+ "SET 0,B","SET 0,C","SET 0,D","SET 0,E",
+ "SET 0,H","SET 0,L","SET 0,(HL)","SET 0,A",
+ "SET 1,B","SET 1,C","SET 1,D","SET 1,E",
+ "SET 1,H","SET 1,L","SET 1,(HL)","SET 1,A",
+ "SET 2,B","SET 2,C","SET 2,D","SET 2,E",
+ "SET 2,H","SET 2,L","SET 2,(HL)","SET 2,A",
+ "SET 3,B","SET 3,C","SET 3,D","SET 3,E",
+ "SET 3,H","SET 3,L","SET 3,(HL)","SET 3,A",
+ "SET 4,B","SET 4,C","SET 4,D","SET 4,E",
+ "SET 4,H","SET 4,L","SET 4,(HL)","SET 4,A",
+ "SET 5,B","SET 5,C","SET 5,D","SET 5,E",
+ "SET 5,H","SET 5,L","SET 5,(HL)","SET 5,A",
+ "SET 6,B","SET 6,C","SET 6,D","SET 6,E",
+ "SET 6,H","SET 6,L","SET 6,(HL)","SET 6,A",
+ "SET 7,B","SET 7,C","SET 7,D","SET 7,E",
+ "SET 7,H","SET 7,L","SET 7,(HL)","SET 7,A"
+ };
+
+
+const char * TabInstrED[ 256 ] =
+ {
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ "IN B,(C)","OUT (C),B","SBC HL,BC","LD (nnnn),BC",
+ "NEG","RETN","IM 0","LD I,A",
+ "IN C,(C)","OUT (C),C","ADC HL,BC","LD BC,(nnnn)",
+ 0,"RETI",0,"LD R,A",
+ "IN D,(C)","OUT (C),D","SBC HL,DE","LD (nnnn),DE",
+ 0,0,"IM 1","LD A,I",
+ "IN E,(C)","OUT (C),E","ADC HL,DE","LD DE,(nnnn)",
+ 0,0,"IM 2","LD A,R",
+ "IN H,(C)","OUT (C),H","SBC HL,HL",0,
+ 0,0,0,"RRD",
+ "IN L,(C)","OUT (C),L","ADC HL,HL",0,
+ 0,0,0,"RLD",
+ 0,"OUT (C),0","SBC HL,SP","LD (nnnn),SP",
+ 0,0,0,0,
+ "IN A,(C)","OUT (C),A","ADC HL,SP","LD SP,(nnnn)",
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ "LDI","CPI","INI","OUTI",
+ 0,0,0,0,
+ "LDD","CPD","IND","OUTD",
+ 0,0,0,0,
+ "LDIR","CPIR","INIR","OTIR",
+ 0,0,0,0,
+ "LDDR","CPDR","INDR","OTDR",
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0
+ };
+
+
+const char * TabInstrDD[ 256 ] =
+ {
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,"ADD IX,BC",0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,"ADD IX,DE",0,0,
+ 0,0,0,0,
+ 0,"LD IX,nnnn","LD (nnnn),IX","INC IX",
+ "INC IXh","DEC IXh","LD IXh,nn",0,
+ 0,"ADD IX,HL","LD IX,(nnnn)","DEC IX",
+ "INC IXl","DEC IXl","LD IXl,nn",0,
+ 0,0,0,0,
+ "INC (IX+nn)","DEC (IX+nn)","LD (IX+nn),nn",0,
+ 0,"ADD IX,SP",0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ "LD B,IXh","LD B,IXl","LD B,(IX+nn)",0,
+ 0,0,0,0,
+ "LD C,IXh","LD C,IXl","LD C,(IX+nn)",0,
+ 0,0,0,0,
+ "LD D,IXh","LD D,IXl","LD D,(IX+nn)",0,
+ 0,0,0,0,
+ "LD E,IXh","LD E,IXl","LD E,(IX+nn)",0,
+ "LD IXh,B","LD IXh,C","LD IXh,D","LD IXh,E",
+ "LD IXh,IXh","LD IXh,IXl","LD H,(IX+nn)","LD IXh,A",
+ "LD IXl,B","LD IXl,C","LD IXl,D","LD IXl,E",
+ "LD IXl,IXh","LD IXl,IXl","LD L,(IX+nn)","LD IXl,A",
+ "LD (IX+nn),B","LD (IX+nn),C","LD (IX+nn),D","LD (IX+nn),E",
+ "LD (IX+nn),H","LD (IX+nn),L",0,"LD (IX+nn),A",
+ 0,0,0,0,
+ "LD A,IXh","LD A,IXl","LD A,(IX+nn)",0,
+ 0,0,0,0,
+ "ADD A,IXh","ADD A,IXl","ADD A,(IX+nn)",0,
+ 0,0,0,0,
+ "ADC A,IXh","ADC A,IXl","ADC A,(IX+nn)",0,
+ 0,0,0,0,
+ "SUB IXh","SUB IXl","SUB (IX+nn)",0,
+ 0,0,0,0,
+ "SBC A,IXh","SBC A,IXl","SBC A,(IX+nn)",0,
+ 0,0,0,0,
+ "AND IXh","AND IXl","AND (IX+nn)",0,
+ 0,0,0,0,
+ "XOR IXh","XOR IXl","XOR (IX+nn)",0,
+ 0,0,0,0,
+ "OR IXh","OR IXl","OR (IX+nn)",0,
+ 0,0,0,0,
+ "CP IXh","CP IXl","CP (IX+nn)",0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,"POP IX",0,"EX (SP),IX",
+ 0,"PUSH IX",0,0,
+ 0,"JP (IX)",0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,
+ 0,"LD SP,IX",0,0,
+ 0,0,0,0
+ };
+
+
+const char * TabInstrDDCB[ 256 ] =
+ {
+ 0,0,0,0,0,0,"RLC (IX+nn)",0,
+ 0,0,0,0,0,0,"RRC (IX+nn)",0,
+ 0,0,0,0,0,0,"RL (IX+nn)",0,
+ 0,0,0,0,0,0,"RR (IX+nn)",0,
+ 0,0,0,0,0,0,"SLA (IX+nn)",0,
+ 0,0,0,0,0,0,"SRA (IX+nn)",0,
+ 0,0,0,0,0,0,"SLL (IX+nn)",0,
+ 0,0,0,0,0,0,"SRL (IX+nn)",0,
+ 0,0,0,0,0,0,"BIT 0,(IX+nn)",0,
+ 0,0,0,0,0,0,"BIT 1,(IX+nn)",0,
+ 0,0,0,0,0,0,"BIT 2,(IX+nn)",0,
+ 0,0,0,0,0,0,"BIT 3,(IX+nn)",0,
+ 0,0,0,0,0,0,"BIT 4,(IX+nn)",0,
+ 0,0,0,0,0,0,"BIT 5,(IX+nn)",0,
+ 0,0,0,0,0,0,"BIT 6,(IX+nn)",0,
+ 0,0,0,0,0,0,"BIT 7,(IX+nn)",0,
+ 0,0,0,0,0,0,"RES 0,(IX+nn)",0,
+ 0,0,0,0,0,0,"RES 1,(IX+nn)",0,
+ 0,0,0,0,0,0,"RES 2,(IX+nn)",0,
+ 0,0,0,0,0,0,"RES 3,(IX+nn)",0,
+ 0,0,0,0,0,0,"RES 4,(IX+nn)",0,
+ 0,0,0,0,0,0,"RES 5,(IX+nn)",0,
+ 0,0,0,0,0,0,"RES 6,(IX+nn)",0,
+ 0,0,0,0,0,0,"RES 7,(IX+nn)",0,
+ 0,0,0,0,0,0,"SET 0,(IX+nn)",0,
+ 0,0,0,0,0,0,"SET 1,(IX+nn)",0,
+ 0,0,0,0,0,0,"SET 2,(IX+nn)",0,
+ 0,0,0,0,0,0,"SET 3,(IX+nn)",0,
+ 0,0,0,0,0,0,"SET 4,(IX+nn)",0,
+ 0,0,0,0,0,0,"SET 5,(IX+nn)",0,
+ 0,0,0,0,0,0,"SET 6,(IX+nn)",0,
+ 0,0,0,0,0,0,"SET 7,(IX+nn)",0
+ };
+
+
+const char * TabInstrFD[ 256 ] =
+ {
+ 0,0,0,0,0,0,0,0,
+ 0,"ADD IY,BC",0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,"ADD IY,DE",0,0,0,0,0,0,
+ 0,"LD IY,nnnn","LD (nnnn),IY","INC IY","INC IYh","DEC IYh","LD IYh,nn",0,
+ 0,"ADD IY,HL","LD IY,(nnnn)","DEC IY","INC IYl","DEC IYl","LD IYl,nn",0,
+ 0,0,0,0,"INC (IY+nn)","DEC (IY+nn)","LD (IY+nn),nn",0,
+ 0,"ADD IY,SP",0,0,0,0,0,0,
+ 0,0,0,0,"LD B,IYh","LD B,IYl","LD B,(IY+nn)",0,
+ 0,0,0,0,"LD C,IYh","LD C,IYl","LD C,(IY+nn)",0,
+ 0,0,0,0,"LD D,IYh","LD D,IYl","LD D,(IY+nn)",0,
+ 0,0,0,0,"LD E,IYh","LD E,IYl","LD E,(IY+nn)",0,
+ "LD IYh,B","LD IYh,C","LD IYh,D","LD IYh,E","LD IYh,IYh","LD IYh,IYl","LD H,(IY+nn)","LD IYh,A",
+ "LD IYl,B","LD IYl,C","LD IYl,D","LD IYl,E","LD IYl,IYh","LD IYl,IYl","LD L,(IY+nn)","LD IYl,A",
+ "LD (IY+nn),B","LD (IY+nn),C","LD (IY+nn),D","LD (IY+nn),E","LD (IY+nn),H","LD (IY+nn),L",0,"LD (IY+nn),A",
+ 0,0,0,0,"LD A,IYh","LD A,IYl","LD A,(IY+nn)",0,
+ 0,0,0,0,"ADD A,IYh","ADD A,IYl","ADD A,(IY+nn)",0,
+ 0,0,0,0,"ADC A,IYh","ADC A,IYl","ADC A,(IY+nn)",0,
+ 0,0,0,0,"SUB IYh","SUB IYl","SUB (IY+nn)",0,
+ 0,0,0,0,"SBC A,IYh","SBC A,IYl","SBC A,(IY+nn)",0,
+ 0,0,0,0,"AND IYh","AND IYl","AND (IY+nn)",0,
+ 0,0,0,0,"XOR IYh","XOR IYl","XOR (IY+nn)",0,
+ 0,0,0,0,"OR IYh","OR IYl","OR (IY+nn)",0,
+ 0,0,0,0,"CP IYh","CP IYl","CP (IY+nn)",0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,"POP IY",0,"EX (SP),IY",0,"PUSH IY",0,0,
+ 0,"JP (IY)",0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,
+ 0,"LD SP,IY",0,0,0,0,0,0
+ };
+
+
+const char * TabInstrFDCB[ 256 ] =
+ {
+ 0,0,0,0,0,0,"RLC (IY+nn)",0,
+ 0,0,0,0,0,0,"RRC (IY+nn)",0,
+ 0,0,0,0,0,0,"RL (IY+nn)",0,
+ 0,0,0,0,0,0,"RR (IY+nn)",0,
+ 0,0,0,0,0,0,"SLA (IY+nn)",0,
+ 0,0,0,0,0,0,"SRA (IY+nn)",0,
+ 0,0,0,0,0,0,"SLL (IY+nn)",0,
+ 0,0,0,0,0,0,"SRL (IY+nn)",0,
+ 0,0,0,0,0,0,"BIT 0,(IY+nn)",0,
+ 0,0,0,0,0,0,"BIT 1,(IY+nn)",0,
+ 0,0,0,0,0,0,"BIT 2,(IY+nn)",0,
+ 0,0,0,0,0,0,"BIT 3,(IY+nn)",0,
+ 0,0,0,0,0,0,"BIT 4,(IY+nn)",0,
+ 0,0,0,0,0,0,"BIT 5,(IY+nn)",0,
+ 0,0,0,0,0,0,"BIT 6,(IY+nn)",0,
+ 0,0,0,0,0,0,"BIT 7,(IY+nn)",0,
+ 0,0,0,0,0,0,"RES 0,(IY+nn)",0,
+ 0,0,0,0,0,0,"RES 1,(IY+nn)",0,
+ 0,0,0,0,0,0,"RES 2,(IY+nn)",0,
+ 0,0,0,0,0,0,"RES 3,(IY+nn)",0,
+ 0,0,0,0,0,0,"RES 4,(IY+nn)",0,
+ 0,0,0,0,0,0,"RES 5,(IY+nn)",0,
+ 0,0,0,0,0,0,"RES 6,(IY+nn)",0,
+ 0,0,0,0,0,0,"RES 7,(IY+nn)",0,
+ 0,0,0,0,0,0,"SET 0,(IY+nn)",0,
+ 0,0,0,0,0,0,"SET 1,(IY+nn)",0,
+ 0,0,0,0,0,0,"SET 2,(IY+nn)",0,
+ 0,0,0,0,0,0,"SET 3,(IY+nn)",0,
+ 0,0,0,0,0,0,"SET 4,(IY+nn)",0,
+ 0,0,0,0,0,0,"SET 5,(IY+nn)",0,
+ 0,0,0,0,0,0,"SET 6,(IY+nn)",0,
+ 0,0,0,0,0,0,"SET 7,(IY+nn)",0
+ };
+
+
+const char * TabInstr[ 256 ] =
+ {
+ "NOP","LD BC,nnnn","LD (BC),A","INC BC",
+ "INC B","DEC B","LD B,nn","RLCA",
+ "EX AF,AF","ADD HL,BC","LD A,(BC)","DEC BC",
+ "INC C","DEC C","LD C,nn","RRCA",
+ "DJNZ eeee","LD DE,nnnn","LD (DE),A","INC DE",
+ "INC D","DEC D","LD D,nn","RLA",
+ "JR eeee","ADD HL,DE","LD A,(DE)","DEC DE",
+ "INC E","DEC E","LD E,nn","RRA",
+ "JR NZ,eeee","LD HL,nnnn","LD (nnnn),HL","INC HL",
+ "INC H","DEC H","LD H,nn","DAA",
+ "JR Z,eeee","ADD HL,HL","LD HL,(nnnn)","DEC HL",
+ "INC L","DEC L","LD L,nn","CPL",
+ "JR NC,eeee","LD SP,nnnn","LD (nnnn),A","INC SP",
+ "INC (HL)","DEC (HL)","LD (HL),nn","SCF",
+ "JR C,eeee","ADD HL,SP","LD A,(nnnn)","DEC SP",
+ "INC A","DEC A","LD A,nn","CCF",
+ "LD B,B","LD B,C","LD B,D","LD B,E",
+ "LD B,H","LD B,L","LD B,(HL)","LD B,A",
+ "LD C,B","LD C,C","LD C,D","LD C,E",
+ "LD C,H","LD C,L","LD C,(HL)","LD C,A",
+ "LD D,B","LD D,C","LD D,D","LD D,E",
+ "LD D,H","LD D,L","LD D,(HL)","LD D,A",
+ "LD E,B","LD E,C","LD E,D","LD E,E",
+ "LD E,H","LD E,L","LD E,(HL)","LD E,A",
+ "LD H,B","LD H,C","LD H,D","LD H,E",
+ "LD H,H","LD H,L","LD H,(HL)","LD H,A",
+ "LD L,B","LD L,C","LD L,D","LD L,E",
+ "LD L,H","LD L,L","LD L,(HL)","LD L,A",
+ "LD (HL),B","LD (HL),C","LD (HL),D","LD (HL),E",
+ "LD (HL),H","LD (HL),L","HALT","LD (HL),A",
+ "LD A,B","LD A,C","LD A,D","LD A,E",
+ "LD A,H","LD A,L","LD A,(HL)","LD A,A",
+ "ADD A,B","ADD A,C","ADD A,D","ADD A,E",
+ "ADD A,H","ADD A,L","ADD A,(HL)","ADD A,A",
+ "ADC A,B","ADC A,C","ADC A,D","ADC A,E",
+ "ADC A,H","ADC A,L","ADC A,(HL)","ADC A,A",
+ "SUB B","SUB C","SUB D","SUB E",
+ "SUB H","SUB L","SUB (HL)","SUB A",
+ "SBC A,B","SBC A,C","SBC A,D","SBC A,E",
+ "SBC A,H","SBC A,L","SBC A,(HL)","SBC A,A",
+ "AND B","AND C","AND D","AND E",
+ "AND H","AND L","AND (HL)","AND A",
+ "XOR B","XOR C","XOR D","XOR E",
+ "XOR H","XOR L","XOR (HL)","XOR A",
+ "OR B","OR C","OR D","OR E",
+ "OR H","OR L","OR (HL)","OR A",
+ "CP B","CP C","CP D","CP E",
+ "CP H","CP L","CP (HL)","CP A",
+ "RET NZ","POP BC","JP NZ,nnnn","JP nnnn",
+ "CALL NZ,nnnn","PUSH BC","ADD A,nn","RST 00",
+ "RET Z","RET","JP Z,nnnn",0,
+ "CALL Z,nnnn","CALL nnnn","ADC A,nn","RST 08",
+ "RET NC","POP DE","JP NC,nnnn","OUT (nn),A",
+ "CALL NC,nnnn","PUSH DE","SUB nn","RST 10",
+ "RET C","EXX","JP C,nnnn","IN A,(nn)",
+ "CALL C,nnnn",0,"SBC A,nn","RST 18",
+ "RET PE","POP HL","JP PE,nnnn","EX (SP),HL",
+ "CALL PE,nnnn","PUSH HL","AND nn","RST 20",
+ "RET PO","JP (HL)","JP PO,nnnn","EX DE,HL",
+ "CALL PO,nnnn",0,"XOR nn","RST 28",
+ "RET P","POP AF","JP P,nnnn","DI",
+ "CALL P,nnnn","PUSH AF","OR nn","RST 30",
+ "RET M","LD SP,HL","JP M,nnnn","EI",
+ "CALL M,nnnn",0,"CP nn","RST 38"
+ };
+
+
+//
+// Convertir le buffer en listing d�sassembl�
+//
+void Desass( unsigned char * Prg, char * Listing, int Longueur )
+{
+ int i, Instr, Inst2 = 0, Inst3 = 0, Inst4 = 0, Ad16;
+ const char * Chaine;
+ char *p;
+ char Inst[ 1024 ];
+
+ int Adr, OldAdr, PosD = 0;
+ char Ad8;
+
+ * Listing = 0;
+ for ( Adr = 0; Adr < Longueur; )
+ {
+ OldAdr = Adr;
+ Instr = Prg[ Adr++ ];
+ Chaine = TabInstr[ Instr ];
+ if ( Instr == 0xCB )
+ {
+ Inst2 = Prg[ Adr++ ];
+ Chaine = TabInstrCB[ Inst2 ];
+ }
+ else
+ if ( Instr == 0xDD )
+ {
+ Inst2 = Prg[ Adr++ ];
+ if ( Inst2 == 0xCB )
+ {
+ Inst3 = Prg[ Adr++ ];
+ Inst4 = Prg[ Adr++ ];
+ Chaine = TabInstrDDCB[ Inst4 ];
+ strcpy( Inst, Chaine );
+ p = strstr( Inst, "nn" );
+ if ( p )
+ {
+ if ( Inst3 < 0x80 )
+ Hex( p, Inst3, 2 );
+ else
+ {
+ Hex( p, -Inst3, 2 );
+ p[ -1 ] = '-';
+ }
+ }
+ Chaine = Inst;
+ }
+ else
+ Chaine = TabInstrDD[ Inst2 ];
+ }
+ else
+ if ( Instr == 0xED )
+ {
+ Inst2 = Prg[ Adr++ ];
+ Chaine = TabInstrED[ Inst2 ];
+ }
+ else
+ if ( Instr == 0xFD )
+ {
+ Inst2 = Prg[ Adr++ ];
+ if ( Inst2 == 0xCB )
+ {
+ Ad8 = Prg[ Adr++ ];
+ Inst3 = Prg[ Adr++ ];
+ Chaine = TabInstrFDCB[ Inst3 ];
+ if ( Chaine )
+ {
+ strcpy( Inst, Chaine );
+ Chaine = Inst;
+ p = strstr( Inst, "nn" );
+ if ( p )
+ Hex( p, Ad8, 2 );
+ }
+ }
+ else
+ Chaine = TabInstrFD[ Inst2 ];
+ }
+ if ( Chaine )
+ {
+ strcpy( Inst, Chaine );
+ p = strstr( Inst, "nnnn" );
+ Ad16 = Prg[ Adr++ ];
+ Ad16 += Prg[ Adr ] << 8;
+ Ad8 = ( char ) Ad16;
+ if ( p )
+ {
+ Hex( p, Ad16, 4 );
+ Adr++;
+ }
+ else
+ {
+ p = strstr( Inst, "nn" );
+ if ( p )
+ {
+ Hex( p, Ad16, 2 );
+ p = strstr( Inst, "nn" );
+ if ( p )
+ Hex( p, Ad16 >> 8, 2 );
+ }
+ else
+ {
+ p = strstr( Inst, "eeee" );
+ if ( p )
+ Hex( p, Adr + Ad8, 4 );
+ else
+ Adr--;
+ }
+ }
+ }
+ else
+ sprintf( Inst, "%02X %02X %02X ????", Instr, Inst2, Inst3 );
+
+ Hex( &Listing[ PosD ], OldAdr, 4 );
+ Listing[ PosD + 4 ] = ' ';
+ PosD += 5;
+ for ( i = OldAdr; i < Adr; i++ )
+ {
+ Hex( &Listing[ PosD ], Prg[ i ], 2 );
+ Listing[ PosD + 2 ] = ' ';
+ PosD += 3;
+ }
+ for ( i = 0; i < 5 - Adr + OldAdr; i++ )
+ {
+ Listing[ PosD ] = Listing[ PosD + 1 ] = Listing[ PosD + 2 ] = ' ';
+ PosD += 3;
+ }
+ char * p = Inst;
+ while( * p )
+ Listing[ PosD++ ] = * p++;
+
+ Listing[ PosD++ ] = '\r';
+ Listing[ PosD++ ] = '\n';
+ }
+}
diff --git a/tools/iDSK/src/Desass.h b/tools/iDSK/src/Desass.h new file mode 100644 index 0000000..647f535 --- /dev/null +++ b/tools/iDSK/src/Desass.h @@ -0,0 +1,8 @@ +#ifndef DESASS_H
+#define DESASS_H
+
+
+void Desass( unsigned char * Prg, char * Desass, int Longueur );
+
+
+#endif
diff --git a/tools/iDSK/src/GestDsk.cpp b/tools/iDSK/src/GestDsk.cpp new file mode 100644 index 0000000..f1063cd --- /dev/null +++ b/tools/iDSK/src/GestDsk.cpp @@ -0,0 +1,1183 @@ +#include <iostream> +#include <string.h> +#include <cstdlib> +#include <cstdio> +#include <algorithm> +#include <sstream> + +#include "MyType.h" +#include "GestDsk.h" +#include "endianPPC.h" +#include "Outils.h" +#include <cerrno> + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif + +using namespace std; + +char Listing[ 0x280000 ]; +unsigned char BufFile[ 0x10000 ]; +int TailleFic, CurLigne; + + +// +// Verifie si en-tete AMSDOS est valide +// +bool CheckAmsdos( unsigned char * Buf ) { + int i, Checksum = 0; + bool ModeAmsdos = false; + unsigned short CheckSumFile; + CheckSumFile = Buf[ 0x43 ] + Buf[ 0x43 +1 ] *256; + for ( i = 0; i < 67; i++ ) + Checksum += Buf[ i ]; + + if ( ( CheckSumFile == ( unsigned short )Checksum ) && Checksum ) + ModeAmsdos = true; + + return( ModeAmsdos ); +} + + + +// +// CrŽe une en-tte AMSDOS par dŽfaut +// +StAmsdos * CreeEnteteAmsdos( char * NomFic, unsigned short Longueur ) { + static char NomReel[ 256 ]; + static StAmsdos Entete; + static char Nom[ 12 ]; + int i; + + strcpy( NomReel, NomFic ); + memset( &Entete, 0, sizeof( Entete ) ); + memset( Nom, ' ', sizeof( Nom ) ); + char * p = NULL; + do { + p = strchr( NomReel, '/' ); //Sous linux c'est le / qu'il faut enlever ... + if ( p ) + strcpy( NomReel, ++p ); + } while( p ); + p = strchr( NomReel, '.' ); + if ( p ) + * p++ = 0; + + int l = strlen( NomReel ); + if ( l > 8 ) + l = 8; + + for ( int i = 0; i < l; i++ ) + Nom[ i ] = ( char )toupper( NomReel[ i ] ); + + if ( p ) + for ( i = 0; i < 3; i++ ) + Nom[ i + 8 ] = ( char )toupper( p[ i ] ); + + memcpy( Entete.FileName, Nom, 11 ); + Entete.Length = 0; //Non renseigné par AMSDos !! + Entete.RealLength = Entete.LogicalLength = Longueur; + Entete.FileType = 2; //Fichier binaire + + SetChecksum(&Entete); + + return( &Entete ); +} + + +// +// Calcule et positionne le checksum AMSDOS +// +void SetChecksum( StAmsdos * pEntete ) { + int i, Checksum = 0; + unsigned char * p = ( unsigned char * )pEntete; + for ( i = 0; i < 67; i++ ) + Checksum += * (p+i); + + pEntete->CheckSum = ( unsigned short )Checksum; +} + + +// +// Effectue un "nettoyage" de l'en-tete Amsdos : +// remet a zero les octets inutilises +// +void ClearAmsdos( unsigned char * Buf ) { + if ( CheckAmsdos( Buf ) ) { + int i, Checksum = 0; + StAmsdos * pEntete = ( StAmsdos * )Buf; + memset( pEntete->Unused, 0, sizeof( pEntete->Unused ) ); + memset( pEntete->Unused2, 0, sizeof( pEntete->Unused2 ) ); + for ( i = 0; i < 67; i++ ) + Checksum += Buf[ i ]; + + Buf[ 0x43 ] = ( unsigned short )Checksum; + } +} + +// +// Recherche le plus petit secteur d'une piste +// +int DSK::GetMinSect( void ) { + int Sect = 0x100; + CPCEMUTrack * tr = ( CPCEMUTrack * )&ImgDsk[ sizeof( CPCEMUEnt ) ]; + for ( int s = 0; s < tr->NbSect; s++ ) + if ( Sect > tr->Sect[ s ].R ) + Sect = tr->Sect[ s ].R; + + return( Sect ); +} + + +// +// Retourne la position d'un secteur dans le fichier DSK +// +int DSK::GetPosData( int track, int sect, bool SectPhysique ) { + // Recherche position secteur + int Pos = sizeof( CPCEMUEnt ); + CPCEMUTrack * tr = ( CPCEMUTrack * )&ImgDsk[ Pos ]; + short SizeByte; + for ( int t = 0; t <= track; t++ ) { + Pos += sizeof( CPCEMUTrack ); + for ( int s = 0; s < tr->NbSect; s++ ) { + if ( t == track ) { + if ( ( ( tr->Sect[ s ].R == sect ) && SectPhysique ) + || ( ( s == sect ) && ! SectPhysique ) + ) + break; + } + SizeByte = tr->Sect[ s ].SizeByte ; + if (SizeByte) + Pos += SizeByte; + else + Pos += ( 128 << tr->Sect[ s ].N ); + } + } + return( Pos ); +} + + +// +// Recherche un bloc libre et le remplit +// +int DSK::RechercheBlocLibre( int MaxBloc ) { + for ( int i = 2; i < MaxBloc; i++ ) + if ( ! Bitmap[ i ] ) { + Bitmap[ i ] = 1; + return( i ); + } + return( 0 ); +} + + +// +// Recherche une entrŽe de rŽpertoire libre +// +int DSK::RechercheDirLibre( void ) { + for ( int i = 0; i < 64; i++ ) { + StDirEntry * Dir = GetInfoDirEntry( i ); + if ( Dir->User == USER_DELETED ) + return( i ); + } + return( -1 ); +} + + +// +// Retourne les donnŽes "brutes" de l'image disquette +// +unsigned char * DSK::GetRawData( int Pos ) { + return( &ImgDsk[ Pos ] ); +} + + +// +// Ecriture de donnŽes "brutes" dans l'image disquette +// +void DSK::WriteRawData( int Pos, unsigned char * Data, int Longueur ) { + memcpy( &ImgDsk[ Pos ], Data, Longueur ); +} + + +// +// Retourne la taille du fichier image +// +int DSK::GetTailleDsk( void ) { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + int NbTracks = Infos->NbTracks; + int Pos = sizeof( CPCEMUEnt ); + CPCEMUTrack * tr = ( CPCEMUTrack * )&ImgDsk[ Pos ]; + for ( int t = 0; t < NbTracks; t++ ) { + Pos += sizeof( CPCEMUTrack ); + for ( int s = 0; s < tr->NbSect; s++ ) { + if ( tr->Sect[ s ].SizeByte ) + Pos += tr->Sect[ s ].SizeByte; + else + Pos += ( 128 << tr->Sect[ s ].N ); + } + } + return( Pos ); +} + + +// +// Retourne le nombre de pistes de la disquette +// +int DSK::GetNbTracks( void ) { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + return( Infos->NbTracks ); +} + + +// +// Lecture d'un bloc AMSDOS (1 block = 2 secteurs) +// +unsigned char * DSK::ReadBloc( int bloc ) { + static unsigned char BufBloc[ SECTSIZE * 2 ]; + int track = ( bloc << 1 ) / 9; + int sect = ( bloc << 1 ) % 9; + int MinSect = GetMinSect(); + if ( MinSect == 0x41 ) + track += 2; + else + if ( MinSect == 0x01 ) + track++; + + int Pos = GetPosData( track, sect + MinSect, true ); + memcpy( BufBloc, &ImgDsk[ Pos ], SECTSIZE ); + if ( ++sect > 8 ) { + track++; + sect = 0; + } + + Pos = GetPosData( track, sect + MinSect, true ); + memcpy( &BufBloc[ SECTSIZE ], &ImgDsk[ Pos ], SECTSIZE ); + return( BufBloc ); +} + + +// +// Formatter une piste +// +void DSK::FormatTrack( CPCEMUEnt * Infos, int t, int MinSect, int NbSect ) { + CPCEMUTrack * tr = ( CPCEMUTrack * )&ImgDsk[ sizeof( CPCEMUEnt ) + t * Infos->DataSize ]; + memset( &ImgDsk[ sizeof( CPCEMUEnt ) + + sizeof( CPCEMUTrack ) + + ( t * Infos->DataSize ) + ] + , 0xE5 + , 0x200 * NbSect + ); + strcpy( tr->ID, "Track-Info\r\n" ); + tr->Track = ( unsigned char )t; + tr->Head = 0; + tr->SectSize = 2; + tr->NbSect = ( unsigned char )NbSect; + tr->Gap3 = 0x4E; + tr->OctRemp = 0xE5; + int ss = 0; + // + // Gestion "entrelacement" des secteurs + // + for ( int s = 0; s < NbSect; ) { + tr->Sect[ s ].C = ( unsigned char )t; + tr->Sect[ s ].H = 0; + tr->Sect[ s ].R = ( unsigned char )( ss + MinSect ); + tr->Sect[ s ].N = 2; + tr->Sect[ s ].SizeByte = 0x200; + ss++; + if ( ++s < NbSect ) { + tr->Sect[ s ].C = ( unsigned char )t; + tr->Sect[ s ].H = 0; + tr->Sect[ s ].R = ( unsigned char )( ss + MinSect + 4 ); + tr->Sect[ s ].N = 2; + tr->Sect[ s ].SizeByte = 0x200; + s++; + } + } +} + + +// +// Ecriture d'un bloc AMSDOS (1 block = 2 secteurs) +// +void DSK::WriteBloc( int bloc, unsigned char BufBloc[ SECTSIZE * 2 ] ) { + int track = ( bloc << 1 ) / 9; + int sect = ( bloc << 1 ) % 9; + int MinSect = GetMinSect(); + if ( MinSect == 0x41 ) + track += 2; + else + if ( MinSect == 0x01 ) + track++; + + // + // Ajuste le nombre de pistes si dŽpassement capacitŽ + // + CPCEMUEnt * Entete = ( CPCEMUEnt * )ImgDsk; + if ( track > Entete->NbTracks - 1 ) { + Entete->NbTracks = ( unsigned char )( track + 1 ); + FormatTrack( Entete, track, MinSect, 9 ); + } + + int Pos = GetPosData( track, sect + MinSect, true ); + memcpy( &ImgDsk[ Pos ], BufBloc, SECTSIZE ); + if ( ++sect > 8 ) { + track++; + sect = 0; + } + Pos = GetPosData( track, sect + MinSect, true ); + memcpy( &ImgDsk[ Pos ], &BufBloc[ SECTSIZE ], SECTSIZE ); +} + + +// +// Ecriture d'un secteur +// +void DSK::WriteSect( int Track, int Sect, unsigned char * Buff, int AmsdosMode ) { + int MinSect = AmsdosMode ? GetMinSect() : 0; + if ( ( MinSect == 0x41 ) && AmsdosMode ) + Track += 2; + else + if ( ( MinSect == 0x01 ) && AmsdosMode ) + Track++; + + int Pos = GetPosData( Track, Sect + MinSect, AmsdosMode ); + memcpy( &ImgDsk[ Pos ], Buff, SECTSIZE ); +} + + +// +// Lecture d'un secteur +// +unsigned char * DSK::ReadSect( int Track, int Sect, int AmsdosMode ) { + int MinSect = AmsdosMode ? GetMinSect() : 0; + if ( ( MinSect == 0x41 ) && AmsdosMode ) + Track += 2; + else + if ( ( MinSect == 0x01 ) && AmsdosMode ) + Track++; + + int Pos = GetPosData( Track, Sect + MinSect, AmsdosMode ); + return( &ImgDsk[ Pos ] ); +} + + +// +// Retourne les informations d'une piste +// +CPCEMUTrack * DSK::GetInfoTrack( int Track ) { + int Pos = sizeof( CPCEMUEnt ); + CPCEMUTrack * tr = ( CPCEMUTrack * )&ImgDsk[ Pos ]; + for ( int t = 0; t < Track; t++ ) { + Pos += sizeof( CPCEMUTrack ); + + for ( int s = 0; s < tr->NbSect; s++ ) { + if ( tr->Sect[ s ].SizeByte ) + Pos += tr->Sect[ s ].SizeByte; + else + Pos += ( 128 << tr->Sect[ s ].N ); + } + } + return( ( CPCEMUTrack * )&ImgDsk[ Pos ] ); +} + +// +// Remplit un "bitmap" pour savoir o il y a des fichiers sur la disquette +// Retourne Žgalement le nombre de Ko utilisŽs sur la disquette +// +int DSK::FillBitmap( void ) { + int NbKo = 0; + + memset( Bitmap, 0, sizeof( Bitmap ) ); + Bitmap[ 0 ] = Bitmap[ 1 ] = 1; + for ( int i = 0; i < 64; i++ ) { + StDirEntry * Dir = GetInfoDirEntry( i ); + if ( Dir->User != USER_DELETED ) { + for ( int j = 0; j < 16; j++ ) { + int b = Dir->Blocks[ j ]; + if ( b > 1 && ( ! Bitmap[ b ] ) ) { + Bitmap[ b ] = 1; + NbKo++; + } + } + } + } + return( NbKo ); +} + + +// +// Positionne une entrŽe dans le rŽpertoire +// +void DSK::SetInfoDirEntry( int NumDir, StDirEntry * Dir ) { + int MinSect = GetMinSect(); + int s = ( NumDir >> 4 ) + MinSect; + int t = ( MinSect == 0x41 ? 2 : 0 ); + if ( MinSect == 1 ) + t = 1; + + for (int i =0; i<16; i++) + memcpy( &ImgDsk[ ( ( NumDir & 15 ) << 5 ) + GetPosData( t, s, true ) ] + , Dir + , sizeof( StDirEntry ) + ); +} + + +// +// VŽrifie l'existente d'un fichier, retourne l'indice du fichier si existe, +// -1 sinon +// +int DSK::FileExist( char * Nom ) { + int i; + for ( i = 0; i < 64; i++ ) { + StDirEntry * Dir = GetInfoDirEntry( i ); + for(int q=0;q<12;q++) + Dir->Nom[q]=Dir->Nom[q]&127; // Avoid missing hidden files + if ( Dir->User != USER_DELETED + && ! strncmp( Nom, ( char * )Dir->Nom, 11 ) // 11 = 8+3 car le point est enlevé + ) + return( i ); + } + return( -1 ); +} + + +StDirEntry * DSK::GetNomDir( string NomFic ) { + static StDirEntry DirLoc; + int i; + + memset( &DirLoc, 0, sizeof( DirLoc ) ); + memset( DirLoc.Nom, ' ', 8 ); + memset( DirLoc.Ext, ' ', 3 ); + size_t p = NomFic.find('.'); + if ( p!=std::string::npos ) + { + NomFic.copy( DirLoc.Nom, std::min((int)p,8), 0); + p++; + NomFic.copy( DirLoc.Ext, std::min( (int)(NomFic.size()-p), 3 ), p ); + } + else + NomFic.copy( DirLoc.Nom, std::min((int)NomFic.size(), 8 ),0); + + for ( i = 0; i < 11; i++ ) + DirLoc.Nom[ i ] = ( unsigned char )toupper( DirLoc.Nom[ i ] ); + + return( &DirLoc ); +} + + +int DSK::FileIsIn( string FileName ) { + StDirEntry * DirLoc = GetNomDir( FileName ); + return FileExist( ( char*) DirLoc->Nom ); +} + +// +// Copie un fichier sur le DSK +// +// la taille est determine par le nombre de NbPages +// regarder pourquoi different d'une autre DSK +int DSK::CopieFichier( unsigned char * BufFile, char * NomFic, int TailleFic, int MaxBloc, int UserNumber, bool System_file, bool Read_only ) { + int j, l, Bloc, PosFile, NbPages = 0, PosDir, TaillePage; + FillBitmap(); + StDirEntry * DirLoc = GetNomDir( NomFic ); //Construit l'entrée pour mettre dans le catalogue + for ( PosFile = 0; PosFile < TailleFic; ) { //Pour chaque bloc du fichier + PosDir = RechercheDirLibre(); //Trouve une entrée libre dans le CAT + if ( PosDir != -1 ) { + DirLoc->User = UserNumber; //Remplit l'entrée : User 0 + if(System_file) DirLoc->Nom[9]|=0x80; + if(Read_only) DirLoc->Nom[8]|=0x80; + DirLoc->NumPage = ( unsigned char )NbPages++; // Numéro de l'entrée dans le fichier + TaillePage = (TailleFic - PosFile + 127) >> 7 ; // Taille de la page (on arrondit par le haut) + if ( TaillePage > 128 ) // Si y'a plus de 16k il faut plusieurs pages + TaillePage = 128; + + DirLoc->NbPages = ( unsigned char )TaillePage; + l = ( DirLoc->NbPages + 7 ) >> 3; //Nombre de blocs=TaillePage/8 arrondi par le haut + memset( DirLoc->Blocks, 0, 16 ); + for ( j = 0; j < l; j++ ) { //Pour chaque bloc de la page + Bloc = RechercheBlocLibre( MaxBloc ); //Met le fichier sur la disquette + if ( Bloc ) { + DirLoc->Blocks[ j ] = ( unsigned char )Bloc; + WriteBloc( Bloc, &BufFile[ PosFile ] ); + PosFile += 1024; // Passe au bloc suivant + } + else + return( ERR_NO_BLOCK ); + + } + SetInfoDirEntry( PosDir, DirLoc ); + } + else + return( ERR_NO_DIRENTRY ); + } + return( ERR_NO_ERR ); +} + + +// +// Retourne une entrŽe du rŽpertoire +// +StDirEntry * DSK::GetInfoDirEntry( int NumDir ) { + static StDirEntry Dir; + int MinSect = GetMinSect(); + int s = ( NumDir >> 4 ) + MinSect; + int t = ( MinSect == 0x41 ? 2 : 0 ); + if ( MinSect == 1 ) + t = 1; + + memcpy( &Dir + , &ImgDsk[ ( ( NumDir & 15 ) << 5 ) + GetPosData( t, s, true ) ] + , sizeof( StDirEntry ) + ); + return( &Dir ); +} + + +// +// VŽrifier si DSK est "standard" (DATA ou VENDOR) +// +bool DSK::CheckDsk( void ) { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + if ( Infos->NbHeads == 1 ) { + int MinSectFirst = GetMinSect(); + if ( MinSectFirst != 0x41 && MinSectFirst != 0xC1 && MinSectFirst != 0x01 ) + { + cout << "DSK has wrong sector number!" << endl; + return( false ); + } + + + if ( Infos->NbTracks > 42 ) + Infos->NbTracks = 42; + + for ( int track = 0; track < Infos->NbTracks; track++ ) { + // Recherche position secteur + int Pos = sizeof( CPCEMUEnt ) + ( 0x1200 + sizeof( CPCEMUTrack ) ) * track; + CPCEMUTrack * tr = ( CPCEMUTrack * )&ImgDsk[ Pos ]; + + int MinSect = 0xFF, MaxSect = 0; + if ( tr->NbSect != 9 ) + { + cout << "Warning : track " << track <<" has "<<tr->NbSect<<" sectors ! (wanted 9)" << endl; + // return( false ); + } + for ( int s = 0; s < (int)tr->NbSect; s++ ) { + if ( MinSect > tr->Sect[ s ].R ) + MinSect = tr->Sect[ s ].R; + + if ( MaxSect < tr->Sect[ s ].R ) + MaxSect = tr->Sect[ s ].R; + } + if ( MaxSect - MinSect != 8 ) + { + cout << "Warning : trange sector numbering in track "<<track<<"!" << endl; + // return( false ); + } + if ( MinSect != MinSectFirst ) + { + cout << "Warning : track "<<track<<" start at sector"<<MinSect<<" while track 0 starts at "<<MinSectFirst << endl; + //return( false ); + } + } + return( true ); + } + cout << "Multi-side dsk ! Expected 1 head, got " << (int)Infos->NbHeads << endl; + return( false ); +} + + +// +// Lire un fichier DSK +// +bool DSK::ReadDsk( std::string NomFic ) { + bool Ret = false; + CPCEMUEnt * Infos; + if(sizeof(CPCEMUEnt) != 0x100) cout << "INVALID DSK BUILD" << endl; + FILE* fp ; + + if ( (fp=fopen(NomFic.c_str(),"rb"))!=NULL ) { + fread(ImgDsk,sizeof(ImgDsk),1,fp); + Infos = ( CPCEMUEnt * )ImgDsk; + if ( isBigEndian( ) ) FixEndianDsk( false ); // fix endian for Big endianness machines (PPC) + if ( ! strncmp( Infos->debut, "MV -", 4 ) + || ! strncmp( Infos->debut, "EXTENDED CPC DSK", 16 ) + ) + Ret = true; + fclose(fp); + } + return( Ret ); +} + + +// +// Formatter une disquette +// +void DSK::FormatDsk( int NbSect, int NbTrack ) { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + + strcpy( Infos->debut, "MV - CPCEMU Disk-File\r\nDisk-Info\r\n" ); + Infos->DataSize = ( short )( sizeof( CPCEMUTrack ) + (0x200 * NbSect) ); + Infos->NbTracks = ( unsigned char ) NbTrack; + Infos->NbHeads = 1; + for ( int t = 0; t < NbTrack; t++ ) + FormatTrack( Infos, t, 0xC1, NbSect ); + + + FillBitmap(); +} + + + +// +// Modifie le endianness de la disquette +// +void DSK::FixEndianDsk( bool littleToBig) { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + //std::cerr<< "FixEndianDsk() Infos->DataSize : " << Infos->DataSize <<std::endl; + + if ( ! littleToBig ) + Infos->DataSize = FIX_SHORT( Infos->DataSize ); + for ( int t = 0; t < Infos->NbTracks; t++ ) + FixEndianTrack( Infos, t, 9 ); + if ( littleToBig ) + Infos->DataSize = FIX_SHORT( Infos->DataSize ); + FillBitmap(); +} + +// +// Modifie le endianness de la piste +// +void DSK::FixEndianTrack( CPCEMUEnt * Infos, int t, int NbSect ) { + CPCEMUTrack *tr; + if ( Infos->DataSize != 0 ) + tr = ( CPCEMUTrack * )&ImgDsk[ sizeof( CPCEMUEnt ) + t * Infos->DataSize ]; + else { + int ExtendedDataSize = ImgDsk[ 0x34 + t ] *256; //case of a extended dsk image + tr = ( CPCEMUTrack * )&ImgDsk[ sizeof( CPCEMUEnt ) + t * ExtendedDataSize ]; + } + int ss = 0; + + // + // Gestion "entrelacement" des secteurs + // + for ( int s = 0; s < NbSect; ) { + tr->Sect[ s ].SizeByte = FIX_SHORT( tr->Sect[ s ].SizeByte ); + tr->Sect[ s ].Un1 = FIX_SHORT( tr->Sect[ s ].Un1 ); + ss++; + if ( ++s < NbSect ) { + tr->Sect[ s ].SizeByte = FIX_SHORT( tr->Sect[ s ].SizeByte ); + tr->Sect[ s ].Un1 = FIX_SHORT( tr->Sect[ s ].Un1 ); + s++; + } + } + tr->Unused = FIX_SHORT( tr->Unused ); +} + + +// +// Ecriture du fichier DSK +// +bool DSK::WriteDsk( string NomDsk ) { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + FILE* fp; + int Taille,Copie; + + + if ( (fp=fopen(NomDsk.c_str(),"wb+")) != NULL) { + if ( ! Infos->DataSize ) Infos->DataSize = 0x100 + SECTSIZE * 9; + Taille = Infos->NbTracks * Infos->DataSize + sizeof( * Infos ); + if ( isBigEndian() ) FixEndianDsk( true ) ; // Fix endianness for Big endian machines (PPC) + + if ( (Copie=(fwrite(ImgDsk,1,Taille,fp))) !=Taille ) ; + fclose(fp); + // in case of the same DSK image stay in memory + if ( isBigEndian() ) FixEndianDsk( false ) ; // unFix endianness for Big endian machines (PPC) + + return( true ); + } + return( false ); +} + + +void DSK::DskEndian() { + CPCEMUEnt * Infos = ( CPCEMUEnt * )ImgDsk; + for ( int i=1 ; i<(int)Infos->NbTracks ; i++) { + CPCEMUTrack * TrackData = GetInfoTrack( i ); + TrackData = CPCEMUTrackEndian ( TrackData ) ; + } + Infos = CPCEMUEntEndian ( Infos ) ; +} + + +StAmsdos* DSK::StAmsdosEndian ( StAmsdos * pEntete ){ + pEntete->Length = FIX_SHORT( pEntete->Length ); + pEntete->Adress = FIX_SHORT( pEntete->Adress ); + pEntete->LogicalLength = FIX_SHORT( pEntete->LogicalLength); + pEntete->EntryAdress = FIX_SHORT( pEntete->EntryAdress ); + pEntete->RealLength = FIX_SHORT( pEntete->RealLength ); + pEntete->CheckSum = FIX_SHORT( pEntete->CheckSum ) ; + return ( pEntete ); +} + + +CPCEMUEnt* DSK::CPCEMUEntEndian ( CPCEMUEnt* Infos ) { + Infos->DataSize = FIX_SHORT( Infos->DataSize ); + return (Infos); +} + + +CPCEMUTrack* DSK::CPCEMUTrackEndian ( CPCEMUTrack* tr ) { + for ( int i=0;i < (int)tr->NbSect ; i++) { + tr->Sect[i] = CPCEMUSectEndian( tr->Sect[i] ); + } + + return ( tr); + +} + + +CPCEMUSect DSK::CPCEMUSectEndian ( CPCEMUSect Sect) { + Sect.Un1 = FIX_SHORT( Sect.Un1 ); + Sect.SizeByte = FIX_SHORT( Sect.SizeByte ); + return (Sect); +} + +// Retourne le type de fichier sous forme de chaine +// +const char * DSK::GetType( int Langue, StAmsdos * Ams ) { + if ( CheckAmsdos( ( unsigned char * )Ams ) ) { + switch( Ams->FileType ) { + case 0 : // BASIC + return( "BASIC"); //GetTexteLoc( 22, Langue ) ); + + case 1 : // BASIC (P) + return( "BASIC(P)"); // GetTexteLoc( 23, Langue ) ); + + case 2 : // BINAIRE + return("BINAIRE"); // GetTexteLoc( 24, Langue ) ); + + case 3 : // BINAIRE (P) + return( "BINAIRE(P)"); //GetTexteLoc( 25, Langue ) ); + + default : + return( "INCONNU"); // GetTexteLoc( 26, Langue ) ); + } + } + return("ASCII"); // GetTexteLoc( 27, Langue ) ); +} + +char * DSK::GetEntryNameInCatalogue ( int num , char* Nom ) { + int PosItem[ 64 ]; + StDirEntry TabDir[ 64 ]; + + memset( PosItem, 0, sizeof( PosItem ) ); + + for ( int i = 0; i < 64; i++ ) + memcpy( &TabDir[ i ], GetInfoDirEntry( i ), sizeof( StDirEntry )); + + for ( int i = 0; i < 64; i++ ) { + SetInfoDirEntry( i, &TabDir[ i ] ); + + if ( TabDir[ i ].User != USER_DELETED && ! TabDir[ i ].NumPage && num == i) { + memcpy( Nom, TabDir[ i ].Nom, 8 ); + memcpy( &Nom[ 9 ], TabDir[ i ].Ext, 3 ); + Nom[ 8 ] = '.'; + Nom[ 12 ] = 0; + for ( int j = 0; j < 12; j++ ) + Nom[ j ] &= 0x7F; + for ( int j = 0; j < 12; j++ ) + if ( ! isprint( Nom[ j ] ) ) + Nom[ j ] = '?' ; + return Nom; + } + } + return Nom; +} + +char * DSK::GetEntrySizeInCatalogue ( int num , char* Size ) { + int PosItem[ 64 ]; + StDirEntry TabDir[ 64 ]; + + + memset( PosItem, 0, sizeof( PosItem ) ); + + for ( int i = 0; i < 64; i++ ) + memcpy( &TabDir[ i ], GetInfoDirEntry( i ), sizeof( StDirEntry )); + + for ( int i = 0; i < 64; i++ ) { + SetInfoDirEntry( i, &TabDir[ i ] ); + + if ( TabDir[ i ].User != USER_DELETED && ! TabDir[ i ].NumPage && num == i) { + int p = 0, t = 0; + do { + if ( TabDir[ p + i ].User == TabDir[ i ].User ) { + t += TabDir[ p + i ].NbPages; + } + p++; + } + while( TabDir[ p + i ].NumPage && ( p + i ) < 64 ); + sprintf( Size, "%d Ko", ( t + 7 ) >>3 ); + return Size; + } + } + return Size; +} + + +bool DSK::GetFileInDsk( char* path, int Indice ){ + int i = Indice; + char current[ 16 ]; + char NomIndice[ 16 ]; + int lMax = 0x1000000; + int cumul=0; + FILE* f; + StDirEntry TabDir[ 64 ]; + + if ( (f=fopen(path,"wb"))==NULL ) + return false; + + for ( int i = 0; i < 64; i++ ) + memcpy( &TabDir[ i ], GetInfoDirEntry( i ), sizeof( StDirEntry )); + + + memset( NomIndice, 0 , sizeof( NomIndice ) ); + strncpy( NomIndice, GetNomAmsdos( TabDir[ i ].Nom ), 16); + strncat( NomIndice, GetNomAmsdos( TabDir[ i ].Ext), 3); + + do + { + // Longueur du fichier + int l = ( TabDir[ i ].NbPages + 7 ) >> 3; + for ( int j = 0; j < l; j++ ) { + int TailleBloc = 1024; + unsigned char * p = ReadBloc( TabDir[ i ].Blocks[ j ] ); + int NbOctets = min( lMax, TailleBloc ); + if ( NbOctets > 0 ) { + fwrite(p,1,NbOctets,f); + cumul+=NbOctets; + } + lMax -= 1024; + } + memset( current , 0, sizeof( current ) ); + i++; + strncpy(current, GetNomAmsdos( TabDir[ i ].Nom ), 16 ); + strncat(current, GetNomAmsdos( TabDir[ i ].Ext ), 3); + + if ( i > 64 ) return false; + }while (! strncmp( NomIndice, current , max( strlen( NomIndice ), strlen( current ) ))); + + fclose (f); + return true; +} + + +bool DSK::PutFileInDsk( string Masque ,int TypeModeImport ,int loadAdress, int exeAdress, int UserNumber, bool System_file, bool Read_only ) { + static unsigned char Buff[ 0x20000 ]; + static char *cFileName; + unsigned long Lg; + bool ret; + FILE* Hfile; + if ( NULL==(cFileName = (char*)malloc(16*sizeof(char))) ) + return false; + + cFileName = GetNomAmsdos((char *)Masque.c_str()); + if (( Hfile = fopen(Masque.c_str(),"rb")) == NULL ) return false; + Lg=fread(Buff,1, 0x20000 ,Hfile); + fclose( Hfile ); + bool AjouteEntete = false; + StAmsdos * e = ( StAmsdos * )Buff; + // Attention : longueur > 64Ko ! + if ( Lg > 0x10080 ) { + free(cFileName); + return false; + } + + // + // Regarde si le fichier contient une en-tete ou non + // + bool IsAmsdos = CheckAmsdos( Buff ); + + if ( ! IsAmsdos ) { + // Creer une en-tete amsdos par defaut + cout << "Création automatique d'une en-tête pour le fichier ...\n"; + e = CreeEnteteAmsdos( cFileName, ( unsigned short )Lg ); + if ( loadAdress != 0) + { + e->Adress = (unsigned short)loadAdress; + TypeModeImport = MODE_BINAIRE; + } + if ( exeAdress != 0 ) + { + e->EntryAdress = (unsigned short)exeAdress; + TypeModeImport = MODE_BINAIRE; + } + // Il faut recalculer le checksum en comptant es adresses ! + SetChecksum(e); + // fix the endianness of the input file + if ( isBigEndian() ) e = StAmsdosEndian(e); + } + else + cout << "Le fichier a déjà une en-tête\n"; + // + // En fonction du mode d'importation... + // + switch( TypeModeImport ) { + case MODE_ASCII : + // + // Importation en mode ASCII + // + if ( IsAmsdos ) { + // Supprmier en-tete si elle existe + memcpy( Buff, &Buff[ sizeof( StAmsdos ) ], Lg - sizeof( StAmsdos )); + Lg -= sizeof( StAmsdos ); + } + break; + + case MODE_BINAIRE : + // + // Importation en mode BINAIRE + // + + if ( ! IsAmsdos ) + // + // Indique qu'il faudra ajouter une en-tete + // + AjouteEntete = true; + break; + + } + + // + // Si fichier ok pour etre import + // + if ( AjouteEntete ) { + // Ajoute l'en-tete amsdos si necessaire + + memmove( &Buff[ sizeof( StAmsdos ) ], Buff, Lg ); + memcpy( Buff, e, sizeof( StAmsdos ) ); + Lg += sizeof( StAmsdos ); + } + + //if (MODE_BINAIRE) ClearAmsdos(Buff); //Remplace les octets inutilisés par des 0 dans l'en-tête + + if ( CopieFichier( Buff,cFileName,Lg,256, UserNumber, System_file, Read_only) != ERR_NO_ERR ) + ret = false; + else + ret = true; + + return ret; +} + + +bool DSK::OnViewFic(int nItem) { + int LongFic = 0; + memset( BufFile, 0, sizeof( BufFile ) ); + memset( Listing, 0, sizeof( Listing ) ); + char NomFic[ 16 ]; + char current[ 16 ]; + int i = nItem; + bool FirstBlock = true; + StDirEntry TabDir[ 64 ]; + + for ( int j = 0; j < 64; j++ ) + memcpy( &TabDir[ j ], GetInfoDirEntry( j ), sizeof( StDirEntry )); + + memset( NomFic, 0 , sizeof( NomFic ) ); + strncpy( NomFic, GetNomAmsdos( TabDir[ i ].Nom ), 16); + strncat( NomFic, GetNomAmsdos( TabDir[ i ].Ext), 3); + + int lMax = sizeof( BufFile ); + + TailleFic = 0; + + + do + { + // Longueur du fichier + int l = ( TabDir[ i ].NbPages + 7 ) >> 3; + for ( int j = 0; j < l; j++ ) { + int TailleBloc = 1024; + unsigned char * p = ReadBloc( TabDir[ i ].Blocks[ j ] ); + if ( FirstBlock ) { + if ( CheckAmsdos( p ) ) { + TailleFic = p[ 0x18 +1 ] *256 + p[ 0x18 ]; + TailleBloc -= sizeof( StAmsdos ); + memcpy( p , &p[ 0x80 ] , TailleBloc ); + } + FirstBlock = false; + + } + int NbOctets = min( lMax, TailleBloc ); + if ( NbOctets > 0 ) { + memcpy( &BufFile[ LongFic ], p, NbOctets ); + LongFic += NbOctets; + } + lMax -= 1024; + } + memset( current , 0, sizeof( current ) ); + i++; + strncpy(current, GetNomAmsdos( TabDir[ i ].Nom ), 16 ); + strncat(current, GetNomAmsdos( TabDir[ i ].Ext ), 3); + if ( i > 64 ) return false; + }while( ! strncmp( NomFic, current, max( strlen( current ), strlen( NomFic ) ) ) ); + + if ( TailleFic == 0 ) + TailleFic = LongFic; + return true; +} + + +bool DSK::Hexdecimal() { + + int TailleCourante=0; + char OffSet[ 7 ]; + const char * CodeHexa = "0123456789ABCDEF"; + + while (TailleCourante <= TailleFic ) { + // display the offset + memset( OffSet, 0 , 7 ); + snprintf( OffSet,6,"#%.4X:", TailleCourante ); + strcat( Listing, OffSet ); + strcat( Listing, " "); + char Ascii[ 18 ]; + char Hex[ 16 *3 +1 ]; + memset( Ascii, 0 , 18 ); + memset( Hex , 0 , ( 16*3 +1) ); + for ( int i=0; i<16 ; ++i ) { + unsigned char cur = BufFile[ TailleCourante + i ]; + // manage the ascii display + if ( cur > 32 && cur < 125 ) + Ascii[ i ] = cur; + else + Ascii[ i ] = '.'; + char Val[ 4 ]; + // manage the hexadeciaml display + Val[ 0 ] = CodeHexa[ cur >> 4 ]; + Val[ 1 ] = CodeHexa[ cur & 0x0F ]; + Val[ 2 ] = ' '; + Val[ 3 ] ='\0'; + strcat( Hex, Val ); + } + Ascii[ 16 ] = '\n'; + strcat( Listing, Hex ); + strcat( Listing, "| "); + strcat( Listing, Ascii ); + TailleCourante += 16; + } + + return true; +} + + +void DSK::RemoveFile ( int item ) { + char NomFic[ 16 ]; + int i = item; + StDirEntry TabDir[ 64 ]; + + for ( int j = 0; j < 64; j++ ) + memcpy( &TabDir[ j ], GetInfoDirEntry( j ), sizeof( StDirEntry )); + + strcpy( NomFic, GetNomAmsdos( TabDir[ i ].Nom ) ); + char *p ; + + do { + TabDir[ i ].User = USER_DELETED; + SetInfoDirEntry( i, &TabDir[ i ]); + p = GetNomAmsdos( TabDir[ ++i ].Nom) ; + } while ( ! strncmp( NomFic, p , max(strlen( p ), strlen( NomFic ) )) ); + + + return ; +} + + + +void DSK::RenameFile( int item , char *NewName) { + char NomFic[ 16 ]; + StDirEntry TabDir[ 64 ]; + StDirEntry DirLoc; + int c = item; + for ( int j = 0; j < 64; j++ ) + memcpy( &TabDir[ j ], GetInfoDirEntry( j ), sizeof( StDirEntry )); + + memset( DirLoc.Nom, ' ', 8); + memset( DirLoc.Ext, ' ', 3); + for ( int i=0; i<(int) strlen( NewName ) ; ++i) + NewName[ i ] = toupper( NewName[ i ] ); + + char *p = strchr( NewName, '.'); + + if ( p ) { + p++; + memcpy( DirLoc.Nom, NewName, p - NewName -1); + memcpy( DirLoc.Ext, p, std::min((int)strlen(p),3) ); + } + else { + memcpy( DirLoc.Nom, NewName, min( (int)strlen( NewName) , 8 ) ); + } + strcpy( NomFic, GetNomAmsdos( TabDir[ c ].Nom )); + + do { + memcpy( TabDir[ c ].Nom , DirLoc.Nom , 8 ); + memcpy( TabDir[ c ].Ext , DirLoc.Ext, 3 ); + SetInfoDirEntry( c, &TabDir[ c ]); + p = GetNomAmsdos( TabDir[ ++c ].Nom ); + }while (!strncmp( NomFic, p , max(strlen(p),strlen(NomFic)))); +} + + +std::string DSK::ReadDskDir( void ) { + StDirEntry TabDir[ 64 ]; + string catalogue; + for ( int i = 0; i < 64; i++ ) { + memcpy( &TabDir[ i ] + , GetInfoDirEntry( i ) + , sizeof( StDirEntry ) + ); + } + // Trier les fichiers + for ( int i = 0; i < 64; i++ ) { + // + // Afficher les fichiers non effacés + // + if ( TabDir[ i ].User != USER_DELETED && ! TabDir[ i ].NumPage ) { + char Nom[ 13 ]; + memcpy( Nom, TabDir[ i ].Nom, 8 ); + memcpy( &Nom[ 9 ], TabDir[ i ].Ext, 3 ); + Nom[ 8 ] = '.'; + Nom[ 12 ] = 0; + // + // Masquer les bits d'attributs + // + for ( int j = 0; j < 12; j++ ) + { + Nom[ j ] &= 0x7F; + + if ( ! isprint( Nom[ j ] ) ) + Nom[ j ] = '?' ; + } + + catalogue += Nom; + catalogue += " "; + ostringstream c; + c << (int)TabDir[i].User; + catalogue += c.str(); + // + // Calcule la taille du fichier en fonction du nombre de blocs + // + int p = 0, t = 0; + do { + if ( TabDir[ p + i ].User == TabDir[ i ].User ) + t += TabDir[ p + i ].NbPages; + p++; + } while( TabDir[ p + i ].NumPage && ( p + i ) < 64 ); + //string size = GetTaille( ( t + 7 ) >> 3 ); + //catalogue+= " : " + size + "\n"; + catalogue += "\n"; + + } + } + return catalogue; +} diff --git a/tools/iDSK/src/GestDsk.h b/tools/iDSK/src/GestDsk.h new file mode 100644 index 0000000..b825ab4 --- /dev/null +++ b/tools/iDSK/src/GestDsk.h @@ -0,0 +1,168 @@ +#ifndef GESTDSK_H +#define GESTDSK_H + +#include <string> + +#define USER_DELETED 0xE5 + + +extern char Listing[ 0x280000 ]; +extern unsigned char BufFile[ 0x10000 ]; + + +extern int TailleFic, CurLigne; + +#pragma pack(1) //evite le padding des structures qui sont utilisées dans des memcpy par la suite + +// +// Structure d'une entree AMSDOS +// +typedef struct +{ + unsigned char UserNumber; // 00 User + unsigned char FileName[15]; // 01-0F Nom + extension + unsigned char BlockNum; // 10 Numéro du bloc (disquette) + unsigned char LastBlock; // 11 Flag "dernier bloc" bloc (disquette) + unsigned char FileType; // 12 Type de fichier + unsigned short Length; // 13-14 Longueur + unsigned short Adress; // 15-16 Adresse + unsigned char FirstBlock; // 17 Flag premier bloc de fichier (disquette) + unsigned short LogicalLength; // 18-19 Longueur logique + unsigned short EntryAdress; // 1A-1B Point d'entree + unsigned char Unused[0x24]; + unsigned short RealLength; // 40-42 Longueur reelle + unsigned char BigLength; // Longueur reelle (3 octets) + unsigned short CheckSum; // 43-44 CheckSum Amsdos + unsigned char Unused2[0x3B]; +} StAmsdos; + + +#define SECTSIZE 512 + + +typedef struct +{ + char debut[0x30]; // "MV - CPCEMU Disk-File\r\nDisk-Info\r\n" + unsigned char NbTracks; + unsigned char NbHeads; + unsigned short DataSize; // 0x1300 = 256 + ( 512 * nbsecteurs ) + unsigned char Unused[0xCC]; +} CPCEMUEnt; + + +typedef struct +{ + unsigned char C; // track + unsigned char H; // head + unsigned char R; // sect + unsigned char N; // size + short Un1; + short SizeByte; // Taille secteur en octets +} CPCEMUSect; + + +typedef struct +{ + char ID[0x10]; // "Track-Info\r\n" + unsigned char Track; + unsigned char Head; + short Unused; + unsigned char SectSize; // 2 + unsigned char NbSect; // 9 + unsigned char Gap3; // 0x4E + unsigned char OctRemp; // 0xE5 + CPCEMUSect Sect[29]; +} CPCEMUTrack; + +#ifdef __GNUC__ +#define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__)) +#else +#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop) ) +#endif + +PACK(typedef struct +{ + unsigned char User; + char Nom[8]; + char Ext[3]; + unsigned char NumPage; + unsigned char Unused[2]; + unsigned char NbPages; + unsigned char Blocks[16]; +}) StDirEntry; + +#pragma pack() + +enum { ERR_NO_ERR = 0, ERR_NO_DIRENTRY, ERR_NO_BLOCK, ERR_FILE_EXIST }; + +bool CheckAmsdos( unsigned char * Buf ); +StAmsdos * CreeEnteteAmsdos( char * NomFic, unsigned short Length ); +void ClearAmsdos( unsigned char * Buf ); +void SetChecksum( StAmsdos * pEntete ); +bool CheckAmsdos( unsigned char * Buf ); + + +class DSK +{ + unsigned char ImgDsk[ 0x80000 ]; + unsigned char Bitmap[ 256 ]; + + unsigned char * GetRawData( int Pos ); + void WriteRawData( int Pos, unsigned char * Data, int Longueur ); + int GetNbTracks( void ); + void WriteBloc( int bloc, unsigned char * BufBloc ); + void WriteSect( int Track, int Sect, unsigned char * Buff, int AmsdosMode ); + unsigned char * ReadSect( int Track, int Sect, int AmsdosMode ); + CPCEMUTrack * GetInfoTrack( int Track ); + int FillBitmap( void ); + void DskEndian(); + CPCEMUEnt* CPCEMUEntEndian ( CPCEMUEnt* Infos ); + CPCEMUTrack* CPCEMUTrackEndian ( CPCEMUTrack* tr ); + CPCEMUSect CPCEMUSectEndian ( CPCEMUSect Sect); + const char * GetType( int Langue, StAmsdos * Ams ); + int GetMinSect( void ); + int GetPosData( int track, int sect, bool SectPhysique ); + int RechercheBlocLibre( int MaxBloc ); + void FormatTrack( CPCEMUEnt * Infos, int t, int MinSect, int NbSect ); + +public: + DSK(){} + DSK(const DSK& d) + { + for (int i=0; i< 0x80000; i++) + ImgDsk[i]=d.ImgDsk[i]; + for (int j=0; j< 256 ; j++ ) + Bitmap[j]=d.Bitmap[j]; + } + + ~DSK(){} + + int GetTailleDsk(); + StDirEntry * GetNomDir(std::string Nom ); + int CopieFichier( unsigned char * BufFile, char * NomFic, int TailleFic, int MaxBloc, int, bool,bool ); + bool WriteDsk( std::string NomDsk ); + unsigned char * ReadBloc( int bloc ); + bool ReadDsk( std::string NomFic ); + bool CheckDsk( void ); + int FileExist( char * Nom ); + StDirEntry * GetInfoDirEntry( int NumDir ); + int FileIsIn( std::string FileName ); + int RechercheDirLibre( void ); + void FormatDsk( int NbSect, int NbTrack ); + StAmsdos* StAmsdosEndian ( StAmsdos * pEntete ); + void SetInfoDirEntry( int NumDir, StDirEntry * Dir ); + char * GetEntryNameInCatalogue ( int num , char* Nom ); + char * GetEntrySizeInCatalogue ( int num , char* Size ); + bool GetFileInDsk( char* path, int Indice ); + bool PutFileInDsk( std::string Masque ,int TypeModeImport ,int loadAdress, int exeAdress, int,bool,bool ); + bool OnViewFic(int nItem); + bool Hexdecimal(); + void RemoveFile ( int item ); + void FixEndianDsk( bool LittleToBig ); + void FixEndianTrack( CPCEMUEnt * Infos, int t, int NbSect ); + void RenameFile( int item , char *NewName); + std::string ReadDskDir(void); + +}; + +#endif diff --git a/tools/iDSK/src/Main.cpp b/tools/iDSK/src/Main.cpp new file mode 100644 index 0000000..f8bcdce --- /dev/null +++ b/tools/iDSK/src/Main.cpp @@ -0,0 +1,284 @@ +#include <iostream> +#include <cstdlib> +#include <cstring> +#include <algorithm> // pour contourner un bug de std::vector ... + +#include "getopt_pp.h" /* Command line handling */ + +using namespace std; + +#include "MyType.h" +#include "GestDsk.h" +#include "Outils.h" +#include "Main.h" +#include "endianPPC.h" +#include "ViewFile.h" + +int main(int argc, char** argv) { + bool IsDskLoc, IsDskSet, + ModeListDsk, ModeImportFile, + ModeRemoveFile, + ModeDisaFile, ModeListBasic, + ModeListDams,ModeListHex, + ModeGetFile, ModeNewDsk, Force_Overwrite, + Read_only, System_file; + + ModeListDsk = ModeImportFile = + ModeRemoveFile = ModeDisaFile = + ModeListBasic = ModeListDams = ModeListHex = ModeNewDsk = + ModeGetFile = IsDskLoc = IsDskSet = Force_Overwrite = Read_only = System_file = false ; + + string DskFile, AmsdosFile; + vector<string> AmsdosFileList; + + int exeAdress=0,loadAdress=0,AmsdosType=1, UserNumber=0; + + DSK MyDsk; + + IsDsk = IsDskValid = false; + IsDskSaved = true; + + // Récupération des arguments avec getopt_pp +{using namespace GetOpt; + GetOpt_pp opts(argc,argv); + + opts >> GlobalOption(DskFile); + if (DskFile != "") + IsDskSet = true; + + opts >> OptionPresent('l',"list",ModeListDsk) + + >> OptionPresent('i',"import",ModeImportFile) + >> Option('i',"import",AmsdosFileList) + + >> OptionPresent('r',"remove",ModeRemoveFile) + >> Option('r',"remove",AmsdosFileList) + + >> OptionPresent('n',"new",ModeNewDsk) + + >> OptionPresent('z',"disassemble",ModeDisaFile) + >> Option('z',"disassemble",AmsdosFileList) + + >> OptionPresent('b',"basic",ModeListBasic) + >> Option('b',"basic",AmsdosFileList) + + >> OptionPresent('d',"dams",ModeListDams) + >> Option('d',"dams",AmsdosFileList) + + >> OptionPresent('h',"hex",ModeListHex) + >> Option('h',"hex",AmsdosFileList) + + >> std::hex >> Option('e',"exec",exeAdress) + >> Option('c',"load",loadAdress) + >> std::dec >> Option('t',"type",AmsdosType) + + >> OptionPresent('g',"get",ModeGetFile) + >> Option('g',"get",AmsdosFileList) + + >> OptionPresent('f',"force",Force_Overwrite) + >> OptionPresent('o',"write-protect",Read_only) + >> OptionPresent('s',"system",System_file) + >> Option('u',"user",UserNumber) + ; + + if(opts.options_remain()) + { + cout << "Unhandled option ! Check the syntax." << endl; + exit(EXIT_FAILURE); + } + +}//namespace getopt + + if ( ! IsDskSet ) { + cerr << "You did not select a DSK file to work with !" << endl; + help(); + } + else cerr << "DSK : " << DskFile << endl; + + if ( ModeListBasic || ModeListHex || ModeListDams || ModeDisaFile ) + { + if ( ! MyDsk.ReadDsk(DskFile)) + { + cerr<< "Error reading file ("<< DskFile << ")."<<endl; + exit(EXIT_FAILURE); + } + if ( ! MyDsk.CheckDsk() ) { + cerr <<"Fichier image non supporté ("<< DskFile << ")."<<endl; + exit(EXIT_FAILURE); + } + int Indice; + for(vector<string>::iterator iter=AmsdosFileList.begin(); iter!=AmsdosFileList.end(); iter++) + { + char* amsdosF = GetNomAmsdos(iter->c_str()); + cerr << "Amsdos file : " << amsdosF << endl; + if ( (Indice= MyDsk.FileIsIn( amsdosF ))<0) { + cerr << "Error: File "<< amsdosF << " not found."<< endl; + exit(EXIT_FAILURE); + } + MyDsk.OnViewFic(Indice); + + if ( ModeListBasic ) + cout << ViewBasic( ) << endl; + else if ( ModeListDams ) + cout << "Not yet coded ! Please try a newer version of iDSK ! Sorry !"<<endl; + else if ( ModeListHex ) { + MyDsk.Hexdecimal(); + cout << Listing << endl; + } + else if ( ModeDisaFile ) + cout << ViewDesass( )<<endl; + } + } + + if(ModeNewDsk) + { + MyDsk.FormatDsk( 9, 42 ); + if (! MyDsk.WriteDsk(DskFile)) + { + cerr << "Error writing file " << DskFile << endl; + exit(EXIT_FAILURE); + } + } + + if ( ModeListDsk ) { // lire Dsk + if ( ! MyDsk.ReadDsk(DskFile) ) { + cerr<< "Error reading file ("<< DskFile << ")."<<endl; + exit(EXIT_FAILURE); + } + if ( ! MyDsk.CheckDsk() ) { + cerr <<"Unsupported dsk file ("<< DskFile << ")."<<endl; + exit(EXIT_FAILURE); + } + cout << MyDsk.ReadDskDir(); + } + + if ( ModeImportFile ) { // Ajouter fichiers sur dsk + if ( ! MyDsk.ReadDsk(DskFile) ) { + cerr<< "Error reading file ("<< DskFile << ")."<<endl; + exit(EXIT_FAILURE); + } + + if ( ! MyDsk.CheckDsk() ) { + cerr <<"Unsupported dsk file ("<< DskFile << ")."<<endl; + exit(EXIT_FAILURE); + } + + for(vector<string>::iterator iter=AmsdosFileList.begin(); iter!=AmsdosFileList.end(); iter++) + { + string amsdosfile = GetNomAmsdos(iter->c_str()); + int Indice; + if ( ( Indice = MyDsk.FileIsIn( amsdosfile ) ) != -1 && !Force_Overwrite) { + cerr << "(" << amsdosfile <<") File exists, replace ? (Y/N) (try -f switch for autoreplace...):"; + string answer ; + cin >> answer; + if ( toupper(answer[0]) == 'Y') + MyDsk.RemoveFile(Indice); + else { + cerr<<"Import cancelled, dsk unchanged."<<endl; + cout << MyDsk.ReadDskDir(); + exit(EXIT_SUCCESS); + } + } + else if(Force_Overwrite) + MyDsk.RemoveFile(Indice); + + cerr << "Amsdos file : "<< *iter << endl; + + MyDsk.PutFileInDsk(*iter,AmsdosType,loadAdress,exeAdress,UserNumber,System_file,Read_only); + } + if ( MyDsk.WriteDsk (DskFile) ) + cout << MyDsk.ReadDskDir(); + else cerr<< "Error writing file : " << DskFile << endl; + } + + if ( ModeRemoveFile ) { + if ( ! MyDsk.ReadDsk( (char*)DskFile.c_str() ) ) { + cerr<< "Error reading file ("<< DskFile << ")."<<endl; + exit(EXIT_FAILURE); + } + if ( ! MyDsk.CheckDsk() ) { + cerr <<"unsupported DSK file ("<< DskFile << ")."<<endl; + exit(EXIT_FAILURE); + } + int Indice; + for(vector<string>::iterator iter=AmsdosFileList.begin(); iter!=AmsdosFileList.end(); iter++) + { + char* amsdosF = GetNomAmsdos(iter->c_str()); + cerr << "Amsdos file : " << amsdosF << endl; + if ( (Indice= MyDsk.FileIsIn( amsdosF ))<0) { + cerr << "Error : file "<< amsdosF << " not found."<< endl; + exit(EXIT_FAILURE); + } + MyDsk.RemoveFile(Indice); + if ( MyDsk.WriteDsk ((char*)DskFile.c_str()) ) + cout << MyDsk.ReadDskDir(); + else cerr<< "Error writing file " << (*iter) << endl; + } + } + + if ( ModeGetFile ) { + if ( ! MyDsk.ReadDsk( (char*)DskFile.c_str() ) ) { + cerr<< "Error reading dskfile ("<< DskFile << ")."<<endl; + exit(EXIT_FAILURE); + } + if ( ! MyDsk.CheckDsk() ) { + cerr <<"Unsupported dsk ("<< DskFile << ")."<<endl; + exit(EXIT_FAILURE); + } + int Indice; + + for(vector<string>::iterator iter=AmsdosFileList.begin(); iter!=AmsdosFileList.end(); iter++) + { + char* amsdosF = GetNomAmsdos(iter->c_str()); + cerr << "Fichier Amsdos : " << amsdosF << endl; + if ( (Indice= MyDsk.FileIsIn( amsdosF ))<0) { + cerr << "Error : file "<< amsdosF << " not found."<< endl; + exit(EXIT_FAILURE); + } + if ( ! MyDsk.GetFileInDsk((char*)(*iter).c_str(),Indice) ) { + cerr <<"System error : unable to copy ("<<AmsdosFile<<")."<<endl; + exit(EXIT_FAILURE); + } + } + } + + cerr << "------------------------------------" << endl; + + return(EXIT_SUCCESS); +} + + + + +void help(void) +{ + cout <<endl; + cout << "--------------------------------------------------------------------------------" << endl; + cout << "################################################################################"<< endl; + cout << VERSION <<" (by Demoniak, Sid, PulkoMandy), http://github.com/cpcsdk " << endl; + cout << "################################################################################"<< endl; + cout << endl; + cout << "Usage : " << endl; + cout << "\t"<< PROGNAME << " <DSKfile> [OPTIONS] [files to process]" << endl; + cout << "OPTIONS : EXAMPLE" << endl; + cout << "-l : List disk catalog iDSK floppy.dsk -l" << endl; + cout << "-g : export ('Get') file iDSK floppy.dsk -g myprog.bas"<<endl; + cout << "-r : Remove file iDSK floppy.dsk -r myprog.bas" << endl; + cout << "-n : create New dsk file iDSK floppy2.dsk -n" << endl; + cout << "-z : disassemble a binary file iDSK floppy.dsk -z myprog.bin" << endl; + cout << "-b : list a Basic file iDSK floppy.dsk -b myprog.bas" << endl; + cout << "-d : list a Dams file iDSK floppy.dsk -d myprog.dms" << endl; + cout << "-h : list a binary file as Hexadecimal iDSK floppy.dsk -h myprog.bin" << endl; + cout << "-i : Import file iDSK floppy.dsk -i myprog.bas" << endl + << " -t : fileType (0=ASCII/1=BINARY) ... -t 1" << endl; + cout << " -e : hex Execute address of file ... -e C000 -t 1" << endl; + cout << " -c : hex loading address of file ... -e C000 -c 4000 -t 1" << endl; + cout << " -f : Force overwriting if file exists ... -f" << endl + << " -o : insert a read-Only file ... -o" << endl + << " -s : insert a System file ... -s" << endl + << " -u : insert file with User number ... -u 3" << endl; + cout << "--------------------------------------------------------------------------------" << endl; + cout << "Please report bugs ! - Demoniak/Sid/PulkoMandy" << endl; + exit (0); +} + diff --git a/tools/iDSK/src/Main.h b/tools/iDSK/src/Main.h new file mode 100644 index 0000000..d6d25b6 --- /dev/null +++ b/tools/iDSK/src/Main.h @@ -0,0 +1,19 @@ +#ifndef __MAIN_CPP__ +#define __MAIN_CPP__ +#define VERSION "iDSK version 0.16" +#define PROGNAME "iDSK" +char Nom[ 256 ]; +char Msg[ 128 ]; +StDirEntry TabDir[ 64 ]; +int PosItem[ 64 ]; +int Langue; +bool IsDsk, IsDskValid, IsDskSaved; +int TypeModeImport, TypeModeExport; + + + +void help(void); +void DecomposeArg (char **argv,int argc); + + +#endif diff --git a/tools/iDSK/src/MyType.h b/tools/iDSK/src/MyType.h new file mode 100644 index 0000000..132a1fd --- /dev/null +++ b/tools/iDSK/src/MyType.h @@ -0,0 +1,19 @@ +#ifndef MYTYPE_H_ +#define MYTYPE_H_ + +/* types definitions to be coherent with Visual Basic C++ types */ + +typedef unsigned char BYTE; /* unsigned 8-bit type */ +typedef unsigned short WORD; /* unsigned 16-bit type */ +typedef unsigned long DWORD; /* unsigned 32-bit type */ + + +/* constant defintion usefull in the code */ + +#define TRUE 1 +#define FALSE 0 +#define MODE_ASCII 0 +#define MODE_BINAIRE 1 + + +#endif /*MYTYPE_H_*/ diff --git a/tools/iDSK/src/Outils.cpp b/tools/iDSK/src/Outils.cpp new file mode 100644 index 0000000..54e3c22 --- /dev/null +++ b/tools/iDSK/src/Outils.cpp @@ -0,0 +1,165 @@ +#include <iostream> +#include <cstring> +#include <cstdio> +using namespace std; +#include "Outils.h" + +// +// Initialise une chaine au format hexad�cimal en fonction de la valeur d'entr�e +// +void Hex( char Chaine[], int Valeur, int Digit ) +{ + static char TabDigit[ 17 ] = "0123456789ABCDEF"; + + while( Digit ) + * Chaine++ = TabDigit[ ( Valeur >> ( 4 * ( --Digit ) ) ) & 0x0F ]; +} + + +// +// Conversion hexa->d�cimal +// +int HexToDec( char * Valeur ) +{ + char * p = strchr( Valeur, 'X' ); + if ( p ) + Valeur = ++p; + + p = strchr( Valeur, 'x' ); + if ( p ) + Valeur = ++p; + + p = strchr( Valeur, '#' ); + if ( p ) + Valeur = ++p; + + p = strchr( Valeur, '$' ); + if ( p ) + Valeur = ++p; + + p = strchr( Valeur, '&' ); + if ( p ) + Valeur = ++p; + + int Ret = 0, i = 0; + while( Valeur[ i ] ) + { + Ret <<= 4; + char c = Valeur[ i++ ]; + if ( c >= '0' && c <= '9' ) + Ret += c - '0'; + else + Ret += ( c & 0x5F ) - 0x37; + } + return( Ret ); +} + + +// +// Conversion d'un secteur (512 octets) en affichage Hexa et ASCII +// +void SetBuffViewHexa( unsigned char * src, char * Hex, char * Ascii, unsigned short Offset, int AddOffset) +{ + const char * CodeHexa = "0123456789ABCDEF"; + int q = 0,i; + + // + // Parcourir les 512 octets de la source et remplir les buffers + // + for ( i = 0; i < 512; i++ ) + { + unsigned char b = * src++; + if ( b > 32 && b < 127 ) + { + Ascii[ i ] = b; + // cout << "b32:" << (int)b <<" Ascii["<<i<<"]:"<< Ascii[ i ] << endl; + } + else + { + Ascii[ i ] = '.'; + } + if ( AddOffset && ( ! ( i & 0x0F ) ) ) + { + Hex[ q++ ] = '#'; + Hex[ q++ ] = CodeHexa[ Offset >> 12 ]; + Hex[ q++ ] = CodeHexa[ ( Offset >> 8 ) & 0x0F ]; + Hex[ q++ ] = CodeHexa[ ( Offset >> 4 ) & 0x0F ]; + Hex[ q++ ] = CodeHexa[ Offset & 0x0F ]; + Hex[ q++ ] = ':'; + } + Offset++; + Hex[ q++ ] = CodeHexa[ b >> 4 ]; + Hex[ q++ ] = CodeHexa[ b & 0x0F ]; + Hex[ q++ ] = ' '; + } + Hex[ q ] = 0; + Ascii[ i ] = 0; +} + + +// +// Retourne le num�ro d'user sous forme de chaine +// +char * GetUser( int u ) +{ + static char User[ 8 ]; + sprintf(User, "%d", u); + return( User); +} + + + +// +// Retourne la taille du fichier sous forme de chaine +// +char * GetTaille( int t ) +{ + static char Taille[ 16 ]; + + sprintf( Taille, "%d Ko", t ); + return( Taille ); +} + + +// +// Retourne le nom du fichier formatt� amsdos (8+3) +// +char * GetNomAmsdos(const char * AmsName ) +{ + // Extract the name (without directory components) + const char* lastSlash = strrchr(AmsName, '/'); + const char* lastBackslash = strrchr(AmsName, '\\'); + if (lastSlash > lastBackslash) + AmsName = lastSlash + 1; + else if (lastSlash < lastBackslash) + AmsName = lastBackslash + 1; + + static char NomAmsdos[ 16 ]; + int i; + + char * p = NomAmsdos; + for ( i = 0; i < 8; i++ ) { + if ( * AmsName != ' ' && *AmsName != '.' ) + * p++ = * AmsName++; + /*if ( * AmsName == '-' ) + * p++ = * AmsName++;*/ + } + + while( * AmsName != '.' && * AmsName ) + AmsName++; + + AmsName++; + + * p = 0; + strcat( NomAmsdos, "." ); + + for ( i = 0; * AmsName && i < 3; i++ ) + *++p = * AmsName++; + + * ++p = 0; + i = 0; + while( NomAmsdos[ i ] ) + NomAmsdos[ i++ ] &= 0x7F; + + return( NomAmsdos ); +} diff --git a/tools/iDSK/src/Outils.h b/tools/iDSK/src/Outils.h new file mode 100644 index 0000000..3e64dc4 --- /dev/null +++ b/tools/iDSK/src/Outils.h @@ -0,0 +1,19 @@ +#ifndef __OUTILS_H__
+#define __OUTILS_H__
+
+
+void Hex( char Chaine[], int Valeur, int Digit );
+
+int HexToDec( char * Valeur );
+
+void SetBuffViewHexa( unsigned char * src, char * Hex, char * Ascii,unsigned short Offset, int AddOffset);
+
+char * GetNomAmsdos( const char * AmsName );
+
+char * GetUser( int u );
+
+char * GetTaille( int t );
+
+
+
+#endif
diff --git a/tools/iDSK/src/ViewFile.cpp b/tools/iDSK/src/ViewFile.cpp new file mode 100644 index 0000000..9ad2de7 --- /dev/null +++ b/tools/iDSK/src/ViewFile.cpp @@ -0,0 +1,36 @@ +#include <iostream> +using namespace std; +#include "GestDsk.h" +#include "Outils.h" +#include "Basic.h" +#include "Desass.h" +#include "Dams.h" +#include "endianPPC.h" +#include "ViewFile.h" + +string ViewDams( ) +{ + cerr << "Taille du fichier : " << TailleFic << endl; + Dams( BufFile, TailleFic , Listing ); + return Listing; + //cout << Listing << endl; +} + + +string ViewDesass( ) +{ + cerr << "Taille du fichier : " << TailleFic << endl; + Desass( BufFile, Listing, TailleFic ); + return Listing; + //cout << Listing << endl; +} +string ViewBasic( ) +{ + bool IsBasic=true; + //cout << "Entre Ici\n"; + cerr << "Taille du fichier : " << TailleFic << endl; + Basic( BufFile, Listing, IsBasic, true ); + //cout << Listing << endl; + return Listing; + +} diff --git a/tools/iDSK/src/ViewFile.h b/tools/iDSK/src/ViewFile.h new file mode 100644 index 0000000..fd9b645 --- /dev/null +++ b/tools/iDSK/src/ViewFile.h @@ -0,0 +1,13 @@ +#ifndef __VIEWFILE_H__ +#define __VIEWFILE_H__ + + + + +string ViewDams(); +string ViewLine(); +string ViewDesass(); +string ViewBasic(); + + +#endif diff --git a/tools/iDSK/src/endianPPC.cpp b/tools/iDSK/src/endianPPC.cpp new file mode 100644 index 0000000..7b51225 --- /dev/null +++ b/tools/iDSK/src/endianPPC.cpp @@ -0,0 +1,20 @@ +#include <iostream> +#include <cstdlib> +using namespace std; +#include "endianPPC.h" + +#ifndef _MSC_VER +#include <sys/param.h> +#include <endian.h> +#endif + +bool isBigEndian(void) +{ +#ifdef BYTE_ORDER + return BYTE_ORDER == BIG_ENDIAN; +#elif defined _MSC_VER + return true; // It doesn't run on anything except x86, right? +#else + return __BYTE_ORDER == __BIG_ENDIAN; +#endif +} diff --git a/tools/iDSK/src/endianPPC.h b/tools/iDSK/src/endianPPC.h new file mode 100644 index 0000000..9def637 --- /dev/null +++ b/tools/iDSK/src/endianPPC.h @@ -0,0 +1,22 @@ +#ifndef __ENDIANPPC_H__ +#define __ENDIANPPC_H__ + +/* macros convertion little endian convertion to big endian convertion */ + + +#define SWAP_2(x) ( (((x) & 0xff) << 8) | ((unsigned short)(x) >> 8) ) +#define SWAP_4(x) ( ((x) << 24) | \ + (((x) << 8) & 0x00ff0000) | \ + (((x) >> 8) & 0x0000ff00) | \ + ((x) >> 24) ) +#define FIX_SHORT(x) (*(unsigned short *)&(x) = SWAP_2(*(unsigned short *)&(x))) +#define FIX_INT(x) (*(unsigned int *)&(x) = SWAP_4(*(unsigned int *)&(x))) +#define FIX_FLOAT(x) FIX_INT(x) + + + +/* endianness test function */ + +bool isBigEndian(void); + +#endif diff --git a/tools/iDSK/src/getopt_pp.cpp b/tools/iDSK/src/getopt_pp.cpp new file mode 100644 index 0000000..b22c81f --- /dev/null +++ b/tools/iDSK/src/getopt_pp.cpp @@ -0,0 +1,307 @@ +/* +GetOpt_pp: Yet another C++ version of getopt. + This file is part of GetOpt_pp. + + Copyright (C) Daniel Gutson, FuDePAN 2007-2010 + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt in the root directory or + copy at http://www.boost.org/LICENSE_1_0.txt) + + GetOpt_pp IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include <fstream> + +#if __APPLE__ +#include <crt_externs.h> +#define environ (*_NSGetEnviron()) +#elif _WIN32 +#include <Stdio.h> +#define environ _environ +#else +#include <unistd.h> +#endif + +#include "getopt_pp.h" + +namespace GetOpt +{ + +GETOPT_INLINE Token* GetOpt_pp::_add_token(const std::string& value, Token::Type type) +{ + Token* const ret = new Token(value, type); + if (_first_token == NULL) + _first_token = ret; + else + _last_token->link_to(ret); + _last_token = ret; + return ret; +} + +GETOPT_INLINE void GetOpt_pp::_init_flags() +{ + std::stringstream ss; + _flags = ss.flags(); +} + +GETOPT_INLINE void GetOpt_pp::_parse_sub_file(const std::string& file) +{ + std::ifstream ifile(file.c_str()); + if (!ifile) + throw OptionsFileNotFoundEx(file); + + std::vector<std::string> args; + std::string arg; + + while (ifile >> arg) + args.push_back(arg); + + _parse(args); +} + +GETOPT_INLINE void GetOpt_pp::_parse(const std::vector<std::string>& args) +{ + bool any_option_processed = false; + const size_t argc = args.size(); + + size_t start = 0; + if ( _app_name.empty() ) + { + _app_name = args[0]; + start = 1; + } + + // parse arguments by their '-' or '--': + // (this will be a state machine soon) + for (size_t i = start; i < argc; i++) + { + const std::string& currentArg = args[i]; + + if (currentArg[0] == '-' && currentArg.size() > 1) + { + // see what's next, differentiate whether it's short or long: + if (currentArg[1] == '-') + { + if ( currentArg.size() > 2 ) + { + // long option + _longOps[currentArg.substr(2)].token = _add_token(currentArg.substr(2), Token::LongOption); + } + else + { + // it's the -- option alone + _longOps[currentArg].token = _add_token(currentArg, Token::GlobalArgument); + } + + any_option_processed = true; + } + else + { + // check if it is a negative number: rules + // * floating point negative numbers are straight classified as 'arguments' + // * integer negative numbers of more than 1 digit length are also 'arguments' + // * integer negatives of 1 digit length can be either arguments or short options. + // * anything else: short options. + int anInt; + float aFloat; + std::stringstream dummy; + if ( convert(currentArg, anInt, dummy.flags()) == _Option::OK ) + { + if ( currentArg.size() > 2 ) // if it's larger than -d (d=digit), then assume it's a negative number: + _add_token(currentArg, any_option_processed ? Token::UnknownYet : Token::GlobalArgument); + else // size == 2: it's a 1 digit negative number + _shortOps[currentArg[1]].token = _add_token(currentArg, Token::PossibleNegativeArgument); + } + else if ( convert(currentArg, aFloat, dummy.flags()) == _Option::OK ) + _add_token(currentArg, any_option_processed ? Token::UnknownYet : Token::GlobalArgument); + else + { + // short option + // iterate over all of them, keeping the last one in currentData + // (so the intermediates will generate 'existent' arguments, as of '-abc') + for( size_t j = 1; j < currentArg.size(); j++ ) + _shortOps[currentArg[j]].token = _add_token(std::string(currentArg, j, 1), Token::ShortOption); + } + + any_option_processed = true; + } + } + else if ( currentArg[0] == '@' && currentArg.size() > 1 ) + { + // suboptions file + _parse_sub_file(currentArg.substr(1)); + } + else + { + _add_token(currentArg, any_option_processed ? Token::UnknownYet : Token::GlobalArgument); + } + } + + _last = _Option::OK; // TODO: IMPROVE!! +} + +GETOPT_INLINE void GetOpt_pp::_parse_env() +{ + // this will be optimized in version 3 + std::string var_name; + std::string var_value; + size_t var = 0; + std::string::size_type pos; + OptionData* data; + + while (environ[var] != NULL) + { + var_name = environ[var]; + pos = var_name.find('='); + + if (pos != std::string::npos) + { + var_value = var_name.substr(pos + 1); + var_name = var_name.substr(0, pos); + + if (_longOps.find(var_name) == _longOps.end()) + { + data = &_longOps[var_name]; + data->token = _add_token(var_name, Token::LongOption); + data->flags = OptionData::Envir; + _add_token(var_value, Token::OptionArgument); + } + } + else + (data = &_longOps[var_name])->flags = OptionData::Envir; + + var++; + } +} + + +GETOPT_INLINE void GetOpt_pp::_argc_argv_to_vector(int argc, const char* const* const argv, std::vector<std::string>& args) +{ + for (int i = 0; i < argc; i++) + args.push_back(argv[i]); +} + +GETOPT_INLINE GetOpt_pp::TokensDeleter::~TokensDeleter() +{ + Token* next; + Token* current(_first); + while (current != NULL) + { + next = current->next; + delete current; + current = next; + } +} + +GETOPT_INLINE GetOpt_pp::GetOpt_pp(int argc, const char* const* const argv) + : _exc(std::ios_base::goodbit), _first_token(NULL), _last_token(NULL), _tokens_deleter(_first_token) +{ + _init_flags(); + std::vector<std::string> args; + _argc_argv_to_vector(argc, argv, args); + _parse(args); +} + +GETOPT_INLINE GetOpt_pp::GetOpt_pp(int argc, const char* const* const argv, _EnvTag) + : _first_token(NULL), _last_token(NULL), _tokens_deleter(_first_token) +{ + _init_flags(); + std::vector<std::string> args; + _argc_argv_to_vector(argc, argv, args); + _parse(args); + _parse_env(); +} + +GETOPT_INLINE GetOpt_pp& GetOpt_pp::operator >> (const _Option& opt) throw(GetOptEx) +{ + if (_last != _Option::ParsingError) + { + _last = opt(_shortOps, _longOps, _first_token, _flags); + + switch (_last) + { + case _Option::OK: + break; + + case _Option::OptionNotFound: + if (_exc & std::ios_base::eofbit) + throw OptionNotFoundEx(); + break; + + case _Option::BadType: + if (_exc & std::ios_base::failbit) + throw InvalidFormatEx(); + break; + + case _Option::NoArgs: + if (_exc & std::ios_base::eofbit) + throw ArgumentNotFoundEx(); + break; + + case _Option::TooManyArgs: + if (_exc & std::ios_base::failbit) + throw TooManyArgumentsEx(); + break; + + case _Option::OptionNotFound_NoEx: + break; // Ok, it will be read by casting to bool + + case _Option::ParsingError: + break; // just to disable warning + } + } + else if (_exc & std::ios_base::failbit) + throw ParsingErrorEx(); + + return *this; +} + +GETOPT_INLINE GetOpt_pp& GetOpt_pp::operator >> (std::ios_base & (*iomanip)(std::ios_base&)) +{ + std::stringstream ss; + ss.flags(_flags); + _flags = (ss << iomanip).flags(); + return *this; +} + +GETOPT_INLINE bool GetOpt_pp::options_remain() const +{ + bool remain = false; + ShortOptions::const_iterator it = _shortOps.begin(); + while (it != _shortOps.end() && !remain) + { + remain = (it->second.flags == OptionData::CmdLine_NotExtracted); + ++it; + } + + if (!remain) + { + LongOptions::const_iterator it = _longOps.begin(); + while (it != _longOps.end() && !remain) + { + remain = (it->second.flags == OptionData::CmdLine_NotExtracted); + ++it; + } + } + + if (!remain) + { + // check for the global arguments: + Token* token = _first_token; + while (!remain && token != NULL) + { + remain = (token->type == Token::GlobalArgument || token->type == Token::UnknownYet); + token = token->next; + } + } + + return remain; +} + +} diff --git a/tools/iDSK/src/getopt_pp.h b/tools/iDSK/src/getopt_pp.h new file mode 100644 index 0000000..e0f991a --- /dev/null +++ b/tools/iDSK/src/getopt_pp.h @@ -0,0 +1,745 @@ +/* +GetOpt_pp: Yet another C++ version of getopt. + This file is part of GetOpt_pp. + + Copyright (C) Daniel Gutson, FuDePAN 2007-2010 + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt in the root directory or + copy at http://www.boost.org/LICENSE_1_0.txt) + + GetOpt_pp IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#ifndef GETOPT_PP_H +#define GETOPT_PP_H + +#include <string> +#include <vector> // candidate to be removed +#include <map> +#include <sstream> +#include <list> + +/* + DESIGN GOALS: + - EASY to use + - EASY to learn + - mimc STL's streams + - EASY to extend +*/ + +#ifndef GETOPT_INLINE +# define GETOPT_INLINE +#endif + +namespace GetOpt +{ + +struct Token +{ + enum Type + { + ShortOption, + LongOption, + GlobalArgument, + GlobalArgumentUsed, // already read, skip in the next read + OptionArgument, + PossibleNegativeArgument, + UnknownYet // can be a global option, or an option of the previous one + }; + + Type type; + std::string value; + Token* next; + + Token(const std::string& value, Type type = UnknownYet) + : type(type), value(value), next(NULL) + {} + + bool is_last() const + { + return next == NULL; + } + + void link_to(Token* new_next) + { + next = new_next; + } + + Token* get_next_option_argument() const + { + if (is_last()) + return NULL; + else + { + if (next->type == UnknownYet || next->type == OptionArgument || next->type == PossibleNegativeArgument) + return next; + else + return NULL; + } + } +}; + +struct OptionData +{ + enum _Flags + { + CmdLine_NotExtracted, + CmdLine_Extracted, + Envir + }; + + _Flags flags; + Token* token; + OptionData() : flags(CmdLine_NotExtracted) {} +}; + +typedef std::map<std::string, OptionData> LongOptions; +typedef std::map<char, OptionData> ShortOptions; + + +struct _Option +{ + enum Result + { + OK, + ParsingError, + OptionNotFound, + BadType, + NoArgs, + TooManyArgs, + OptionNotFound_NoEx + }; + + virtual Result operator()(ShortOptions& short_ops, LongOptions& long_ops, Token* first, std::ios::fmtflags flags) const = 0; + virtual ~_Option() {} + + static const char NO_SHORT_OPT = 0; +protected: + static void setTokenAsUsed(Token* token, ShortOptions& short_ops, Token::Type usedAs) + { + if (token->type == Token::PossibleNegativeArgument) + short_ops.erase(token->value[1]); + + token->type = usedAs; + } +}; + +template <class T> inline _Option::Result convert(const std::string& s, T& result, std::ios::fmtflags flags) +{ + std::stringstream ss; + ss.clear(); + ss.flags(flags); + ss << s; + ss >> result; + if (ss.fail() || !ss.eof()) + return _Option::BadType; + else + return _Option::OK; +} + +template <> inline _Option::Result convert<std::string>(const std::string& s, std::string& result, std::ios::fmtflags /*flags*/) +{ + result = s; + return _Option::OK; +} + + +template <class T> class _OptionTBase : public _Option +{ + const char short_opt; + const std::string long_opt; +protected: + T& target; + virtual Result _assign(Token* token, std::ios::fmtflags flags, ShortOptions& short_ops) const = 0; + +public: + _OptionTBase(const _OptionTBase<T>& other) + : _Option(), short_opt(other.short_opt), long_opt(other.long_opt), target(other.target) + {} + + _OptionTBase(char short_opt, const std::string& long_opt, T& target) + : short_opt(short_opt), long_opt(long_opt), target(target) + {} + + virtual Result operator()(ShortOptions& short_ops, LongOptions& long_ops, Token* /*first*/, std::ios::fmtflags flags) const + { + Result ret = OptionNotFound; + ShortOptions::iterator it; + if (short_opt == _Option::NO_SHORT_OPT) + it = short_ops.end(); + else + it = short_ops.find(short_opt); + + if (it != short_ops.end()) + { + it->second.flags = OptionData::CmdLine_Extracted; + ret = _assign(it->second.token, flags, short_ops); + } + else if (!long_opt.empty()) + { + LongOptions::iterator it = long_ops.find(long_opt); + if (it != long_ops.end()) + { + it->second.flags = OptionData::CmdLine_Extracted; + ret = _assign(it->second.token, flags, short_ops); + } + } + + return ret; + } +}; + + +template <class T> class _OptionT : public _OptionTBase<T> +{ +protected: + virtual _Option::Result _assign(Token* token, std::ios::fmtflags flags, ShortOptions& short_ops) const + { + Token* const option_token = token->get_next_option_argument(); + if (option_token == NULL) + return _Option::NoArgs; + else + { + this->setTokenAsUsed(option_token, short_ops, Token::OptionArgument); + return convert<T>(option_token->value, this->target, flags); + } + } +public: + _OptionT(const _OptionT<T>& other) + : _OptionTBase<T>(other) + {} + + _OptionT(char short_opt, const std::string& long_opt, T& target) + : _OptionTBase<T>(short_opt, long_opt, target) + {} + +}; + +template <class T> class _OptionT<std::vector<T> > : public _OptionTBase<std::vector<T> > +{ +protected: + virtual _Option::Result _assign(Token* token, std::ios::fmtflags flags, ShortOptions& short_ops) const + { + Token* option_token = token->get_next_option_argument(); + if (option_token != NULL) + { + _Option::Result result; + //OptionArgs::const_iterator it = args.begin(); + T temp; + + do + { + this->setTokenAsUsed(option_token, short_ops, Token::OptionArgument); + result = convert<T>(option_token->value, temp, flags); + if (result == _Option::OK) + this->target.push_back(temp); + + option_token = option_token->get_next_option_argument(); + } + while (option_token != NULL && result == _Option::OK); + + return result; + } + else + return _Option::NoArgs; + } + +public: + _OptionT(const _OptionT<std::vector<T> >& other) + : _OptionTBase<std::vector<T> >(other) + {} + + _OptionT(char short_opt, const std::string& long_opt, std::vector<T>& target) + : _OptionTBase<std::vector<T> >(short_opt, long_opt, target) + {} +}; + + +template <class T, class BaseOption> +class _DefValOption : public BaseOption +{ + const T default_value; +public: + + _DefValOption(const _DefValOption<T, BaseOption>& other) + : BaseOption(other), default_value(other.default_value) + {} + + _DefValOption(char short_opt, const std::string& long_opt, T& target, const T& default_value) + : BaseOption(short_opt, long_opt, target), default_value(default_value) + {} + + virtual _Option::Result operator()(ShortOptions& short_ops, LongOptions& long_ops, Token* first, std::ios::fmtflags flags) const + { + _Option::Result ret = BaseOption::operator()(short_ops, long_ops, first, flags); + + if (ret == _Option::OptionNotFound) + { + this->target = default_value; + ret = _Option::OK; + } + + return ret; + } +}; + +template <class T> +class _GlobalOption : public _Option +{ + T& target; + virtual Result operator()(ShortOptions& short_ops, LongOptions& long_ops, Token* first, std::ios::fmtflags flags) const + { + // find first token GlobalArgument or UnknownYet (candidate) or PossibleNegativeArgument (candidate too) + Token* token(first); + bool found(false); + while (token != NULL && !found) + { + found = (token->type == Token::GlobalArgument || token->type == Token::UnknownYet || token->type == Token::PossibleNegativeArgument); + if (!found) + token = token->next; + } + if (found) + { + this->setTokenAsUsed(token, short_ops, Token::GlobalArgumentUsed); + return convert<T>(token->value, target, flags); + } + else + return OptionNotFound; + } +public: + _GlobalOption(const _GlobalOption<T>& other) + : target(other.target) + {} + + _GlobalOption(T& target) + : target(target) + {} +}; + +template <class T> +class _GlobalOption<std::vector<T> > : public _Option +{ + std::vector<T>& target; + virtual Result operator()(ShortOptions& short_ops, LongOptions& /*long_ops*/, Token* first, std::ios::fmtflags flags) const + { + // find first token GlobalArgument or UnknownYet (candidate) or PossibleNegativeArgument (candidate too) + Token* token(first); + bool found_any(false); + T tmp; + Result res(OK); + + while (token != NULL && res == OK) + { + if (token->type == Token::GlobalArgument || token->type == Token::UnknownYet || token->type == Token::PossibleNegativeArgument) + { + res = convert<T>(token->value, tmp, flags); + if (res == OK) + { + this->setTokenAsUsed(token, short_ops, Token::GlobalArgumentUsed); + found_any = true; + target.push_back(tmp); + } + } + token = token->next; + } + if (res == OK) + { + if (found_any) + return res; + else + return OptionNotFound; + } + else + return res; + } +public: + _GlobalOption(const _GlobalOption<std::vector<T> >& other) + : target(other.target) + {} + + _GlobalOption(std::vector<T>& target) + : target(target) + {} +}; + +template <class T> +inline _OptionT<T> Option(char short_opt, const std::string& long_opt, T& target) +{ + return _OptionT<T>(short_opt, long_opt, target); +} + +template <class T> +inline _OptionT<T> Option(char short_opt, T& target) +{ + return _OptionT<T>(short_opt, std::string(), target); +} + +// LongOpt only +template <class T> +inline _OptionT<T> Option(const std::string& long_opt, T& target) +{ + return _OptionT<T>(_Option::NO_SHORT_OPT, long_opt, target); +} + +// Defaulted version +template <class T> +inline _DefValOption<T, _OptionT<T> > +Option(char short_opt, const std::string& long_opt, T& target, const T& def) +{ + return _DefValOption<T, _OptionT<T> >(short_opt, long_opt, target, def); +} + +template <class T> +inline _DefValOption<T, _OptionT<T> > Option(char short_opt, T& target, const T& def) +{ + return _DefValOption<T, _OptionT<T> >(short_opt, std::string(), target, def); +} + +// no short opt. +template <class T> +inline _DefValOption<T, _OptionT<T> > +Option(const std::string& long_opt, T& target, const T& def) +{ + return _DefValOption<T, _OptionT<T> >(_Option::NO_SHORT_OPT, long_opt, target, def); +} + +// Defaults for strings: +inline _DefValOption<std::string, _OptionT<std::string> > +Option(char short_opt, const std::string& long_opt, std::string& target, const char* def) +{ + return _DefValOption<std::string, _OptionT<std::string> >(short_opt, long_opt, target, def); +} + +inline _OptionT<std::string> Option(char short_opt, std::string& target, const char* def) +{ + return _DefValOption<std::string, _OptionT<std::string> >(short_opt, std::string(), target, def); +} + +// no short opt. +inline _DefValOption<std::string, _OptionT<std::string> > +Option(const std::string& long_opt, std::string& target, const char* def) +{ + return _DefValOption<std::string, _OptionT<std::string> >(_Option::NO_SHORT_OPT, long_opt, target, def); +} + +// Global Option: +template <class T> +inline _GlobalOption<T> GlobalOption(T& target) +{ + return _GlobalOption<T>(target); +} + +class OptionPresent : public _Option +{ + const char short_opt; + const std::string long_opt; + bool* const present; +public: + // two combinations: with/without target, and with/without long opt. + + // WITH long_opt: + OptionPresent(char short_opt, const std::string& long_opt, bool& present) + : short_opt(short_opt), long_opt(long_opt), present(&present) + {} + + OptionPresent(char short_opt, const std::string& long_opt) + : short_opt(short_opt), long_opt(long_opt), present(NULL) + {} + + // WITHOUT long_opt: + OptionPresent(char short_opt, bool& present) + : short_opt(short_opt), present(&present) + {} + + OptionPresent(char short_opt) + : short_opt(short_opt), present(NULL) + {} + + // WITHOUT short_opt + OptionPresent(const std::string& long_opt, bool& present) + : short_opt(_Option::NO_SHORT_OPT), long_opt(long_opt), present(&present) + {} + + OptionPresent(const std::string& long_opt) + : short_opt(_Option::NO_SHORT_OPT), long_opt(long_opt), present(NULL) + {} +protected: + virtual Result operator()(ShortOptions& short_ops, LongOptions& long_ops, Token* /*first*/, std::ios::fmtflags /*flags*/) const + { + bool found; + ShortOptions::iterator it = short_ops.find(short_opt); + + found = (it != short_ops.end()); + if (found) + { + it->second.flags = OptionData::CmdLine_Extracted; + } + else if (!long_opt.empty()) + { + LongOptions::iterator it = long_ops.find(long_opt); + found = (it != long_ops.end()); + if (found) + { + it->second.flags = OptionData::CmdLine_Extracted; + } + } + + if (present != NULL) + { + *present = found; + return OK; + } + else + { + return found ? OK : OptionNotFound_NoEx; + } + } +}; + +class GetOptEx : public std::exception {}; +struct ParsingErrorEx : GetOptEx {}; +struct InvalidFormatEx : GetOptEx {}; +struct ArgumentNotFoundEx : GetOptEx {}; +struct TooManyArgumentsEx : GetOptEx {}; +struct OptionNotFoundEx : GetOptEx {}; +struct TooManyOptionsEx : GetOptEx {}; +struct OptionsFileNotFoundEx : GetOptEx +{ + const std::string targetFile; + OptionsFileNotFoundEx(const std::string& file) : targetFile(file) {} + ~OptionsFileNotFoundEx() throw() {} +}; + +enum _EnvTag +{ + Include_Environment +}; + +class GetOpt_pp +{ + ShortOptions _shortOps; + LongOptions _longOps; + std::ios_base::iostate _exc; + _Option::Result _last; + std::ios::fmtflags _flags; + std::string _app_name; + Token* _first_token; + Token* _last_token; + + class TokensDeleter + { + Token*& _first; + public: + TokensDeleter(Token*& first) : _first(first) {} + + GETOPT_INLINE ~TokensDeleter(); + }; + + TokensDeleter _tokens_deleter; + + GETOPT_INLINE Token* _add_token(const std::string& value, Token::Type type); + GETOPT_INLINE void _init_flags(); + GETOPT_INLINE void _parse(const std::vector<std::string>& args); + GETOPT_INLINE void _parse_env(); + static GETOPT_INLINE void _argc_argv_to_vector(int argc, const char* const* const argv, std::vector<std::string>& args); + GETOPT_INLINE void _parse_sub_file(const std::string& file); +public: + GETOPT_INLINE GetOpt_pp(int argc, const char* const* const argv); + GETOPT_INLINE GetOpt_pp(int argc, const char* const* const argv, _EnvTag); + + std::ios_base::iostate exceptions() const + { + return _exc; + } + void exceptions(std::ios_base::iostate except) + { + _exc = except; + } + void exceptions_all() + { + _exc = std::ios_base::failbit | std::ios_base::eofbit; + } + + operator bool() const + { + return _last == _Option::OK; + } + + GETOPT_INLINE bool options_remain() const; + + void end_of_options() const throw(GetOptEx) + { + if (options_remain() && (_exc & std::ios_base::eofbit)) + throw TooManyOptionsEx(); + } + + std::ios::fmtflags flags() const + { + return _flags; + } + void flags(std::ios::fmtflags flags) + { + _flags = flags; + } + + const std::string& app_name() const + { + return _app_name; + } + + GETOPT_INLINE GetOpt_pp& operator >> (const _Option& opt) throw(GetOptEx); + + GETOPT_INLINE GetOpt_pp& operator >> (std::ios_base& (*iomanip)(std::ios_base&)); + + // Alternative to manipulators, for those who don't like them: the 'getopt' method :) + // Combination 1: with long option: + template <class T> inline T getopt(char short_opt, const std::string& long_opt) throw(GetOptEx) + { + T result; + operator >> (Option(short_opt, long_opt, result)); + return result; + } + + template <class T> inline T getopt(char short_opt, const std::string& long_opt, const T& def_value) + { + T result; + operator >> (Option(short_opt, long_opt, result, def_value)); + return result; + } + + // Combination 2: without long option: + template <class T> inline T getopt(char short_opt) throw(GetOptEx) + { + T result; + operator >> (Option(short_opt, result)); + return result; + } + + template <class T> inline T getopt(char short_opt, const T& def_value) + { + T result; + operator >> (Option(short_opt, result, def_value)); + return result; + } + + struct ItCtorData + { + ShortOptions::const_iterator short_iter; + LongOptions::const_iterator long_iter; + GetOpt_pp* getopt_pp; + }; + + template <class Container, class Adapter, class OptionType> + class _iterator + { + typename Container::const_iterator _it; + GetOpt_pp* _getopt_pp; + public: + _iterator(const ItCtorData& ctor_data) + { + _it = Adapter::adapt(ctor_data); + _getopt_pp = ctor_data.getopt_pp; + } + + _iterator() : _getopt_pp(NULL) + {} + + _iterator<Container, Adapter, OptionType>& operator = (const _iterator<Container, Adapter, OptionType>& other) + { + _it = other._it; + _getopt_pp = other._getopt_pp; + return *this; + } + + bool operator != (const _iterator<Container, Adapter, OptionType>& other) const + { + return _it != other._it; + } + + OptionType option() const + { + return _it->first; + } + OptionType operator*() const + { + return option(); + } + + _iterator<Container, Adapter, OptionType>& operator ++() + { + ++_it; + return *this; + } + + template <class T> + GetOpt_pp& operator >> (T& t) + { + Adapter::extract(t, *_getopt_pp, option()); + return *_getopt_pp; + } + }; + + ItCtorData begin() + { + ItCtorData ret; + ret.short_iter = _shortOps.begin(); + ret.long_iter = _longOps.begin(); + ret.getopt_pp = this; + return ret; + } + + ItCtorData end() + { + ItCtorData ret; + ret.short_iter = _shortOps.end(); + ret.long_iter = _longOps.end(); + ret.getopt_pp = this; + return ret; + } + + struct ShortAdapter + { + static ShortOptions::const_iterator adapt(const ItCtorData& data) + { + return data.short_iter; + } + + template <class T> + static void extract(T& t, GetOpt_pp& getopt_pp, char option) + { + getopt_pp >> Option(option, t); + } + }; + + struct LongAdapter + { + static LongOptions::const_iterator adapt(const ItCtorData& data) + { + return data.long_iter; + } + + template <class T> + static void extract(T& t, GetOpt_pp& getopt_pp, const std::string& option) + { + getopt_pp >> Option('\0', option, t); + } + }; + + typedef _iterator<ShortOptions, ShortAdapter, char> short_iterator; + typedef _iterator<LongOptions, LongAdapter, const std::string&> long_iterator; +}; + +class Environment +{ + // Coming soon! +}; + +} + +#endif diff --git a/tools/img2f.py b/tools/img2f.py new file mode 100755 index 0000000..23ac1a7 --- /dev/null +++ b/tools/img2f.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python + +__version__ = "1.0" + +from argparse import ArgumentParser +from PIL import Image + +def main(): + + parser = ArgumentParser(description="Image to cpcrslib font", + epilog="Copyright (C) 2015 Juan J Martinez <jjm@usebox.net>", + ) + + parser.add_argument("--version", action="version", version="%(prog)s " + __version__) + parser.add_argument("image", help="image to convert") + parser.add_argument("id", help="variable name") + parser.add_argument("--effect", dest="effect", action="store_true") + + args = parser.parse_args() + + try: + image = Image.open(args.image) + except IOError: + parser.error("failed to open the image") + + if image.mode != "P": + parser.error("not an indexed image (no palette)") + + (w, h) = image.size + data = image.getdata() + + out = [] + for y in range(0, h, 8): + for x in range(0, w, 4): + for j in range(8): + row = 0 + for i in range(4): + if data[x + i + (j + y) * w] != 0: + if args.effect and j in (2, 3, 4, 5): + row |= 1 << (7 - ((i * 2) + 1)) + row |= 1 << (7 - (i * 2)) + out.append(row) + + data_out = "" + for part in range(0, len(out), 8): + if data_out: + data_out += ",\n" + data_out += ', '.join(["0x%02x" % b for b in out[part: part + 8]]) + + print("const unsigned char %s[] = {\n%s\n};\n" % (args.id, data_out)) + +if __name__ == "__main__": + main() + diff --git a/tools/img2sprite.py b/tools/img2sprite.py new file mode 100755 index 0000000..6463e0c --- /dev/null +++ b/tools/img2sprite.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python + +__version__ = "1.0" + +import sys +from argparse import ArgumentParser +from PIL import Image + +DEF_W = 8 +DEF_H = 16 + +def encode_byte(a, b): + return (a & 1) << 7 | (b & 1) << 6 \ + | (a & 4) << 3 | (b & 4) << 2 \ + | (a & 2) << 2 | (b & 2) << 1 \ + | (a & 8) >> 2 | (b & 8) >> 3 + +def main(): + + parser = ArgumentParser(description="Image cpcrslib sprite", + epilog="Copyright (C) 2015 Juan J Martinez <jjm@usebox.net>", + ) + + parser.add_argument("--version", action="version", version="%(prog)s " + __version__) + parser.add_argument("-i", "--id", dest="id", default="sprite", type=str, + help="variable name (default: sprite)") + parser.add_argument("--width", dest="w", default=DEF_W, type=int, + help="sprite width (default: %s)" % DEF_W) + parser.add_argument("--height", dest="h", default=DEF_H, type=int, + help="sprite height (default: %s)" % DEF_H) + parser.add_argument("--transparent-color", dest="tc", default=None, type=int, + help="palette index for the transparent color (default: None)") + parser.add_argument("-d", "--dimension", dest="dim", action="store_true", + help="include the sprite dimensions in the output") + parser.add_argument("-b", "--binary", dest="binary", action="store_true", + help="output binary instead of C code") + + + parser.add_argument("image", help="image to convert", nargs="?") + + args = parser.parse_args() + + if not args.image: + parser.error("required parameter: image") + + if args.tc: + try: + args.tc = int(args.tc) + if args.tc < 0 or args.tc > 15: + raise ValueError() + except ValueError: + parser.error("--transparent-color expects an integer in [0, 15]") + + try: + image = Image.open(args.image) + except IOError: + parser.error("failed to open the image") + + if image.mode != "P": + parser.error("not an indexed image (no palette)") + + (w, h) = image.size + + if w % args.w or h % args.h: + parser.error("%s size is not multiple of the image size" % args.image) + + data = image.getdata() + + out = [] + for x in range(0, w, args.w): + frame = [] + for y in range(h): # FIXME: different heights! + if args.dim: + out.extend([args.w // 2, args.h]) + for i in range(0, args.w, 2): + a = data[x + i + (y * w)] + b = data[x + i + 1 + (y * w)] + + if args.tc is not None: + mask_a = mask_b = 0 + if a == args.tc: + mask_a = 0xf + a = 0 + if b == args.tc: + mask_b = 0xf + b = 0 + frame.append(encode_byte(mask_a, mask_b)) + + frame.append(encode_byte(a, b)) + out.append(frame) + + if args.binary: + for frame in out: + sys.stdout.write(bytearray(frame)) + return + + frames = len(out) + + data_out = "" + for block in out: + if data_out: + data_out += ",\n" + data_out += "{" + for part in range(0, len(block), 4): + if data_out and data_out[-1] != "{": + data_out += ",\n" + data_out += ', '.join(["0x%02x" % b for b in block[part: part + 4]]) + data_out += "}" + + print("/* %sx%s (frames: %s, mask: %s, dim: %s) */" % (args.w, args.h, frames, args.tc is not None, args.dim)) + print("const unsigned char %s[%d][%d] = {\n%s\n};\n" % (args.id, len(out), len(out[0]), data_out)) + +if __name__ == "__main__": + main() + diff --git a/tools/map.py b/tools/map.py new file mode 100755 index 0000000..e5d3199 --- /dev/null +++ b/tools/map.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python + +__version__ = "1.0" + +import sys +from argparse import ArgumentParser +import json +import subprocess +from collections import defaultdict + +DEF_ROOM_WIDTH = 20 +DEF_ROOM_HEIGHT = 10 + +def find_name(data, name): + for item in data: + if item.get("name").lower() == name.lower(): + return item + raise ValueError("%r not found" % name) + +def main(): + + parser = ArgumentParser(description="Map importer", + epilog="Copyright (C) 2015 Juan J Martinez <jjm@usebox.net>", + ) + + parser.add_argument("--version", action="version", version="%(prog)s " + __version__) + parser.add_argument("--room-width", dest="rw", default=DEF_ROOM_WIDTH, type=int, + help="room width (default: %s)" % DEF_ROOM_WIDTH) + parser.add_argument("--room-height", dest="rh", default=DEF_ROOM_HEIGHT, type=int, + help="room height (default: %s)" % DEF_ROOM_HEIGHT) + parser.add_argument("-b", dest="bin", action="store_true", + help="output binary data (default: C code)") + parser.add_argument("--ucl", dest="ucl", action="store_true", + help="UCL compress (requires ucl binary in the path)") + parser.add_argument("map_json", help="Map to import") + parser.add_argument("id", help="variable name") + + args = parser.parse_args() + + with open(args.map_json, "rt") as fd: + data = json.load(fd) + + mh = data.get("height", 0) + mw = data.get("width", 0) + + if mh < args.rh or mh % args.rh: + parser.error("Map size in not multiple of the room size") + if mw < args.rw or mw % args.rw: + parser.error("Map size in not multiple of the room size") + + tilewidth = data["tilewidth"] + tileheight = data["tileheight"] + + tile_layer = find_name(data["layers"], "Map")["data"] + + def_tileset = find_name(data["tilesets"], "default") + tileprops = def_tileset.get("tileproperties", {}) + firstgid = def_tileset.get("firstgid") + + out = [] + for y in range(0, mh, args.rh): + for x in range(0, mw, args.rw): + current = [] + for j in range(args.rh): + for i in range(args.rw / 2): + a = (tile_layer[x + (i * 2) + (y + j) * mw] - firstgid) & 0b111 + if str(a) in tileprops and tileprops[str(a)].get("blocked"): + a |= 0b1000 + + b = (tile_layer[x + (i * 2) + 1 + (y + j) * mw] - firstgid) & 0b111 + if str(b) in tileprops and tileprops[str(b)].get("blocked"): + b |= 0b1000 + + current.append((a << 4) | b) + out.append(current) + + if args.ucl: + compressed = [] + for block in out: + p = subprocess.Popen(["ucl",], stdin=subprocess.PIPE, stdout=subprocess.PIPE) + output, err = p.communicate(bytearray(block)) + compressed.append([ord(b) for b in output]) + out = compressed + + if args.bin: + sys.stdout.write(bytearray(out)) + return + + print("#define WMAPS %d" % (mw // args.rw)) + + if args.ucl: + data_out = "" + for i, block in enumerate(out): + data_out_part = "" + for part in range(0, len(block), args.rw // 2): + if data_out_part: + data_out_part += ",\n" + data_out_part += ', '.join(["0x%02x" % b for b in block[part: part + args.rw // 2]]) + data_out += "const unsigned char %s_%d[%d] = {\n" % (args.id, i, len(block)) + data_out += data_out_part + "\n};\n" + + data_out += "const unsigned char *%s[%d] = { " % (args.id, len(out)) + data_out += ', '.join(["%s_%d" % (args.id, i) for i in range(len(out))]) + data_out += " };\n" + print(data_out) + + else: + data_out = "" + for block in out: + if data_out: + data_out += ",\n" + data_out += "{" + for part in range(0, len(block), args.rw // 2): + if data_out and data_out[-1] != "{": + data_out += ",\n" + data_out += ', '.join(["0x%02x" % b for b in block[part: part + args.rw // 2]]) + data_out += "}\n" + + print("const unsigned char %s[%d][%d] = {\n%s\n};\n" % (args.id, + len(out), args.rh * args.rw / 2, data_out)) + + enemies = 0 + entities_layer = find_name(data["layers"], "Entities") + if len(entities_layer): + map_ents = defaultdict(list) + ent_tileset = find_name(data["tilesets"], "Entities") + firstgid = ent_tileset.get("firstgid") + for obj in entities_layer["objects"]: + m = ((obj["x"] // tilewidth) // args.rw) \ + + (((obj["y"] // tileheight) // args.rh) * (mw // args.rw)) + x = obj["x"] % (args.rw * tilewidth) + y = obj["y"] % (args.rh * tileheight) - ent_tileset["tileheight"] + t = int(ent_tileset["tileproperties"][str(obj["gid"] - firstgid)]["id"]) + # enemies start at id 10 + if t > 9: + enemies += 1 + map_ents[m].extend([t, x, y]) + if "teleport" in obj.get("properties", {}): + tele = json.loads(obj["properties"]["teleport"]) + tm = ((tele[0] // tilewidth) // args.rw) \ + + (((tele[1] // tileheight) // args.rh) * (mw // args.rw)) + map_ents[m].extend([tm, tele[0] % (tilewidth * args.rw), tele[1] % (tileheight * args.rh) - ent_tileset["tileheight"]]) + + for m, ents in map_ents.items(): + data_out = ", ".join(["0x%02x" % e for e in ents]) + ", 0xff" + print("const unsigned char %s_e%d[%d] = { %s };" % (args.id, m, len(ents) + 1, data_out)) + + map_map = [] + for i in range(len(out)): + if i in map_ents: + map_map.append("%s_e%d" % (args.id, i)) + else: + map_map.append("(unsigned char *)0") + + print("const unsigned char *%s_ents[%d] = { %s };\n" % (args.id, + len(out), ", ".join(map_map))) + + print("const unsigned char %s_enemies = %s;" % (args.id, enemies)) + +if __name__ == "__main__": + main() + diff --git a/tools/ucl.c b/tools/ucl.c new file mode 100644 index 0000000..e61e0e0 --- /dev/null +++ b/tools/ucl.c @@ -0,0 +1,94 @@ +/* +ucl compression tool +Copyright (C) 2015 by Juan J. Martinez - usebox.net + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include <stdio.h> +#include <string.h> + +#include <ucl/ucl.h> + +#define MAX_MEM 65536 + +ucl_byte buffer[MAX_MEM]; + +int +main() +{ + ucl_uint in_len = 0; + ucl_uint out_len; + ucl_byte *in; + ucl_byte *out; + + if (ucl_init() != UCL_E_OK) + { + fprintf(stderr, "ucl: failed to init UCL\n"); + return 1; + } + + while(!feof(stdin)) + { + buffer[in_len++] = getc(stdin); + if (in_len > MAX_MEM) + { + fprintf(stderr, "input too large (limit %i)\n", MAX_MEM); + return 1; + } + } + in_len--; + + out_len = in_len + in_len / 8 + 256; + + in = ucl_malloc(in_len + 8192); + out = ucl_malloc(out_len + 8192); + if (!in || !out) + { + fprintf(stderr, "ucl: out of memory\n"); + return 1; + } + + memcpy(in, buffer, in_len); + + if (ucl_nrv2b_99_compress(in, in_len, out, &out_len, NULL, 10, NULL, NULL) != UCL_E_OK) + { + fprintf(stderr, "ucl: compress error\n"); + return 1; + } + + if (out_len >= in_len) + { + fprintf(stderr, "ucl: content can't be compressed\n"); + return 1; + } + + fwrite(out, 1, out_len, stdout); + fclose(stdout); + + ucl_free(out); + ucl_free(in); + + fprintf(stderr, "ucl: %i bytes compressed into %i bytes\n", in_len, out_len); + + return 0; +} + + + |